blob: 3e6fb46850089d4937601b4541ad83fb2b4a7bb8 [file] [log] [blame]
// Copyright 2017 The Chromium 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 'dart:async';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/usage.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:mockito/mockito.dart';
import 'package:quiver/time.dart';
import 'package:test/test.dart';
import '../src/context.dart';
void main() {
group('Flutter Command', () {
MockCache cache;
MockClock clock;
MockUsage usage;
List<int> mockTimes;
setUp(() {
cache = new MockCache();
clock = new MockClock();
usage = new MockUsage();
when(usage.isFirstRun).thenReturn(false);
when(clock.now()).thenAnswer(
(Invocation _) => new DateTime.fromMillisecondsSinceEpoch(mockTimes.removeAt(0))
);
});
testUsingContext('honors shouldUpdateCache false', () async {
final DummyFlutterCommand flutterCommand = new DummyFlutterCommand(shouldUpdateCache: false);
await flutterCommand.run();
verifyZeroInteractions(cache);
},
overrides: <Type, Generator>{
Cache: () => cache,
});
testUsingContext('honors shouldUpdateCache true', () async {
final DummyFlutterCommand flutterCommand = new DummyFlutterCommand(shouldUpdateCache: true);
await flutterCommand.run();
verify(cache.updateAll()).called(1);
},
overrides: <Type, Generator>{
Cache: () => cache,
});
testUsingContext('report execution timing by default', () async {
// Crash if called a third time which is unexpected.
mockTimes = <int>[1000, 2000];
final DummyFlutterCommand flutterCommand = new DummyFlutterCommand();
await flutterCommand.run();
verify(clock.now()).called(2);
expect(
verify(usage.sendTiming(captureAny, captureAny, captureAny, label: captureAny)).captured,
<dynamic>['flutter', 'dummy', const Duration(milliseconds: 1000), null]
);
},
overrides: <Type, Generator>{
Clock: () => clock,
Usage: () => usage,
});
testUsingContext('no timing report without usagePath', () async {
// Crash if called a third time which is unexpected.
mockTimes = <int>[1000, 2000];
final DummyFlutterCommand flutterCommand =
new DummyFlutterCommand(noUsagePath: true);
await flutterCommand.run();
verify(clock.now()).called(2);
verifyNever(usage.sendTiming(captureAny, captureAny, captureAny, label: captureAny));
},
overrides: <Type, Generator>{
Clock: () => clock,
Usage: () => usage,
});
testUsingContext('report additional FlutterCommandResult data', () async {
// Crash if called a third time which is unexpected.
mockTimes = <int>[1000, 2000];
final FlutterCommandResult commandResult = new FlutterCommandResult(
ExitStatus.success,
// nulls should be cleaned up.
timingLabelParts: <String> ['blah1', 'blah2', null, 'blah3'],
endTimeOverride: new DateTime.fromMillisecondsSinceEpoch(1500)
);
final DummyFlutterCommand flutterCommand = new DummyFlutterCommand(
commandFunction: () async => commandResult
);
await flutterCommand.run();
verify(clock.now()).called(2);
expect(
verify(usage.sendTiming(captureAny, captureAny, captureAny, label: captureAny)).captured,
<dynamic>[
'flutter',
'dummy',
const Duration(milliseconds: 500), // FlutterCommandResult's end time used instead.
'success-blah1-blah2-blah3',
],
);
},
overrides: <Type, Generator>{
Clock: () => clock,
Usage: () => usage,
});
testUsingContext('report failed execution timing too', () async {
// Crash if called a third time which is unexpected.
mockTimes = <int>[1000, 2000];
final DummyFlutterCommand flutterCommand =
new DummyFlutterCommand(commandFunction: () async { throwToolExit('fail'); });
try {
await flutterCommand.run();
fail('Mock should make this fail');
} on ToolExit {
// Should have still checked time twice.
verify(clock.now()).called(2);
expect(
verify(usage.sendTiming(captureAny, captureAny, captureAny, label: captureAny)).captured,
<dynamic>['flutter', 'dummy', const Duration(milliseconds: 1000), 'fail']
);
}
},
overrides: <Type, Generator>{
Clock: () => clock,
Usage: () => usage,
});
});
}
typedef Future<FlutterCommandResult> CommandFunction();
class DummyFlutterCommand extends FlutterCommand {
DummyFlutterCommand({
this.shouldUpdateCache : false,
this.noUsagePath : false,
this.commandFunction,
});
final bool noUsagePath;
final CommandFunction commandFunction;
@override
final bool shouldUpdateCache;
@override
String get description => 'does nothing';
@override
Future<String> get usagePath => noUsagePath ? null : super.usagePath;
@override
String get name => 'dummy';
@override
Future<FlutterCommandResult> runCommand() async {
return commandFunction == null ? null : commandFunction();
}
}
class MockCache extends Mock implements Cache {}
class MockUsage extends Mock implements Usage {}