blob: 6be487aa786be67fda19e20df7ac5136752c74fc [file] [log] [blame]
// Copyright 2020 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:cocoon_service/cocoon_service.dart';
import 'package:cocoon_service/src/model/appengine/commit.dart';
import 'package:cocoon_service/src/model/appengine/task.dart';
import 'package:cocoon_service/src/request_handling/exceptions.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import '../src/datastore/fake_config.dart';
import '../src/datastore/fake_datastore.dart';
import '../src/request_handling/api_request_handler_tester.dart';
import '../src/request_handling/fake_authentication.dart';
import '../src/service/fake_scheduler.dart';
import '../src/utilities/entity_generators.dart';
import '../src/utilities/mocks.dart';
void main() {
group('ResetProdTask', () {
FakeClientContext clientContext;
late ResetProdTask handler;
late FakeConfig config;
FakeKeyHelper keyHelper;
late MockLuciBuildService mockLuciBuildService;
late ApiRequestHandlerTester tester;
late Commit commit;
late Task task;
setUp(() {
final FakeDatastoreDB datastoreDB = FakeDatastoreDB();
clientContext = FakeClientContext();
clientContext.isDevelopmentEnvironment = false;
keyHelper = FakeKeyHelper(applicationContext: clientContext.applicationContext);
config = FakeConfig(
dbValue: datastoreDB,
keyHelperValue: keyHelper,
supportedBranchesValue: <String>[
Config.defaultBranch(Config.flutterSlug),
],
);
final FakeAuthenticatedContext authContext = FakeAuthenticatedContext(clientContext: clientContext);
tester = ApiRequestHandlerTester(context: authContext);
mockLuciBuildService = MockLuciBuildService();
handler = ResetProdTask(
config: config,
authenticationProvider: FakeAuthenticationProvider(clientContext: clientContext),
luciBuildService: mockLuciBuildService,
scheduler: FakeScheduler(
config: config,
ciYaml: exampleConfig,
),
);
commit = generateCommit(1);
task = generateTask(
1,
name: 'Linux A',
parent: commit,
status: Task.statusFailed,
);
tester.requestData = <String, dynamic>{
'Key': config.keyHelper.encode(task.key),
};
when(
mockLuciBuildService.checkRerunBuilder(
commit: anyNamed('commit'),
datastore: anyNamed('datastore'),
task: anyNamed('task'),
target: anyNamed('target'),
tags: anyNamed('tags'),
ignoreChecks: anyNamed('ignoreChecks'),
),
).thenAnswer((_) async => true);
});
test('Schedule new task', () async {
config.db.values[task.key] = task;
config.db.values[commit.key] = commit;
expect(await tester.post(handler), Body.empty);
});
test('Re-schedule existing task', () async {
config.db.values[task.key] = task;
config.db.values[commit.key] = commit;
expect(await tester.post(handler), Body.empty);
});
test('Re-schedule passing all the parameters', () async {
config.db.values[task.key] = task;
config.db.values[commit.key] = commit;
tester.requestData = <String, dynamic>{
'Commit': commit.sha,
'Task': task.name,
'Repo': commit.slug.name,
};
expect(await tester.post(handler), Body.empty);
verify(
mockLuciBuildService.checkRerunBuilder(
commit: anyNamed('commit'),
datastore: anyNamed('datastore'),
task: anyNamed('task'),
target: anyNamed('target'),
tags: anyNamed('tags'),
ignoreChecks: true,
),
).called(1);
});
test('Rerun all failed tasks when task name is all', () async {
final Task taskA = generateTask(2, name: 'Linux A', parent: commit, status: Task.statusFailed);
final Task taskB = generateTask(3, name: 'Mac A', parent: commit, status: Task.statusFailed);
config.db.values[taskA.key] = taskA;
config.db.values[taskB.key] = taskB;
config.db.values[commit.key] = commit;
tester.requestData = <String, dynamic>{
'Commit': commit.sha,
'Task': 'all',
'Repo': commit.slug.name,
};
expect(await tester.post(handler), Body.empty);
verify(
mockLuciBuildService.checkRerunBuilder(
commit: anyNamed('commit'),
datastore: anyNamed('datastore'),
task: anyNamed('task'),
target: anyNamed('target'),
tags: anyNamed('tags'),
ignoreChecks: false,
),
).called(2);
});
test('Rerun all runs nothing when everything is passed', () async {
final Task task = generateTask(2, name: 'Windows A', parent: commit, status: Task.statusSucceeded);
config.db.values[task.key] = task;
config.db.values[commit.key] = commit;
tester.requestData = <String, dynamic>{
'Commit': commit.sha,
'Task': 'all',
'Repo': commit.slug.name,
};
expect(await tester.post(handler), Body.empty);
verifyNever(
mockLuciBuildService.checkRerunBuilder(
commit: anyNamed('commit'),
datastore: anyNamed('datastore'),
task: anyNamed('task'),
target: anyNamed('target'),
tags: anyNamed('tags'),
ignoreChecks: false,
),
);
});
test('Re-schedule without any parameters raises exception', () async {
tester.requestData = <String, dynamic>{};
expect(() => tester.post(handler), throwsA(isA<BadRequestException>()));
});
test('Re-schedule existing task even though taskName is missing in the task', () async {
config.db.values[task.key] = task;
config.db.values[commit.key] = commit;
expect(await tester.post(handler), Body.empty);
});
test('Fails if task is not rerun', () async {
when(
mockLuciBuildService.checkRerunBuilder(
commit: anyNamed('commit'),
datastore: anyNamed('datastore'),
task: anyNamed('task'),
target: anyNamed('target'),
tags: anyNamed('tags'),
ignoreChecks: true,
),
).thenAnswer((_) async => false);
config.db.values[task.key] = task;
config.db.values[commit.key] = commit;
expect(() => tester.post(handler), throwsA(isA<InternalServerError>()));
});
test('Fails if commit does not exist', () async {
config.db.values[task.key] = task;
expect(() => tester.post(handler), throwsA(isA<StateError>()));
});
});
}