Unverified Commit 6ecb8cbc authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Replace MockUsage with TestUsage (#74946)

parent 0491db4a
......@@ -473,6 +473,7 @@ class TestUsage implements Usage {
final List<TestUsageEvent> events = <TestUsageEvent>[];
final List<dynamic> exceptions = <dynamic>[];
final List<TestTimingEvent> timings = <TestTimingEvent>[];
int ensureAnalyticsSentCalls = 0;
@override
bool enabled = true;
......@@ -484,8 +485,8 @@ class TestUsage implements Usage {
String get clientId => 'test-client';
@override
Future<void> ensureAnalyticsSent() {
throw UnimplementedError();
Future<void> ensureAnalyticsSent() async {
ensureAnalyticsSentCalls++;
}
@override
......
......@@ -25,7 +25,7 @@ void main() {
MockAndroidStudio mockAndroidStudio;
MockAndroidSdk mockAndroidSdk;
MockFlutterVersion mockFlutterVersion;
MockUsage mockUsage;
TestUsage testUsage;
setUpAll(() {
Cache.disableLocking();
......@@ -35,27 +35,13 @@ void main() {
mockAndroidStudio = MockAndroidStudio();
mockAndroidSdk = MockAndroidSdk();
mockFlutterVersion = MockFlutterVersion();
mockUsage = MockUsage();
testUsage = TestUsage();
});
void verifyNoAnalytics() {
verifyNever(mockUsage.sendCommand(
any,
parameters: anyNamed('parameters'),
));
verifyNever(mockUsage.sendEvent(
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
parameters: anyNamed('parameters'),
));
verifyNever(mockUsage.sendTiming(
any,
any,
any,
label: anyNamed('label'),
));
expect(testUsage.commands, isEmpty);
expect(testUsage.events, isEmpty);
expect(testUsage.timings, isEmpty);
}
group('config', () {
......@@ -76,7 +62,7 @@ void main() {
}, overrides: <Type, Generator>{
AndroidStudio: () => mockAndroidStudio,
AndroidSdk: () => mockAndroidSdk,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('Can set build-dir', () async {
......@@ -91,7 +77,7 @@ void main() {
expect(getBuildDirectory(), 'foo');
verifyNoAnalytics();
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('throws error on absolute path to build-dir', () async {
......@@ -104,7 +90,7 @@ void main() {
]), throwsToolExit());
verifyNoAnalytics();
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('allows setting and removing feature flags', () async {
......@@ -149,7 +135,7 @@ void main() {
}, overrides: <Type, Generator>{
AndroidStudio: () => mockAndroidStudio,
AndroidSdk: () => mockAndroidSdk,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('warns the user to reload IDE', () async {
......@@ -166,7 +152,7 @@ void main() {
containsIgnoringWhitespace('You may need to restart any open editors'),
);
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('displays which config settings are available on stable', () async {
......@@ -207,49 +193,33 @@ void main() {
AndroidStudio: () => mockAndroidStudio,
AndroidSdk: () => mockAndroidSdk,
FlutterVersion: () => mockFlutterVersion,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('no-analytics flag flips usage flag and sends event', () async {
final ConfigCommand configCommand = ConfigCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
when(mockUsage.sendEvent(
captureAny,
captureAny,
label: captureAnyNamed('label'),
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).thenAnswer((Invocation invocation) async {
expect(mockUsage.enabled, true);
expect(invocation.positionalArguments, <String>['analytics', 'enabled']);
expect(invocation.namedArguments[#label], 'false');
});
expect(testUsage.enabled, true);
await commandRunner.run(<String>[
'config',
'--no-analytics',
]);
expect(mockUsage.enabled, false);
expect(testUsage.enabled, false);
// Verify that we flushed the analytics queue.
verify(mockUsage.ensureAnalyticsSent());
expect(testUsage.ensureAnalyticsSentCalls, 1);
// Verify that we only send the analytics disable event, and no other
// info.
verifyNever(mockUsage.sendCommand(
any,
parameters: anyNamed('parameters'),
));
verifyNever(mockUsage.sendTiming(
any,
any,
any,
label: anyNamed('label'),
));
expect(testUsage.events, equals(<TestUsageEvent>[
const TestUsageEvent('analytics', 'enabled', label: 'false'),
]));
expect(testUsage.commands, isEmpty);
expect(testUsage.timings, isEmpty);
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('analytics flag flips usage flag and sends event', () async {
......@@ -261,39 +231,24 @@ void main() {
'--analytics',
]);
expect(mockUsage.enabled, true);
expect(testUsage.enabled, true);
// Verify that we only send the analytics disable event, and no other
// Verify that we only send the analytics enable event, and no other
// info.
verifyNever(mockUsage.sendCommand(
any,
parameters: anyNamed('parameters'),
));
verifyNever(mockUsage.sendTiming(
any,
any,
any,
label: anyNamed('label'),
));
expect(verify(mockUsage.sendEvent(
captureAny,
captureAny,
label: captureAnyNamed('label'),
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).captured,
<dynamic>['analytics', 'enabled', 'true'],
);
expect(testUsage.events, equals(<TestUsageEvent>[
const TestUsageEvent('analytics', 'enabled', label: 'true'),
]));
expect(testUsage.commands, isEmpty);
expect(testUsage.timings, isEmpty);
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('analytics reported disabled when suppressed', () async {
final ConfigCommand configCommand = ConfigCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
mockUsage.suppressAnalytics = true;
testUsage.suppressAnalytics = true;
await commandRunner.run(<String>[
'config',
......@@ -304,7 +259,7 @@ void main() {
containsIgnoringWhitespace('Analytics reporting is currently disabled'),
);
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
}
......@@ -320,11 +275,3 @@ class MockAndroidSdk extends Mock implements AndroidSdk {
}
class MockFlutterVersion extends Mock implements FlutterVersion {}
class MockUsage extends Mock implements Usage {
@override
bool enabled = true;
@override
bool suppressAnalytics = false;
}
......@@ -221,132 +221,123 @@ void main() {
});
group('doctor usage params', () {
Usage mockUsage;
TestUsage testUsage;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
});
testUsingContext('contains installed', () async {
final Doctor doctor = Doctor(logger: logger);
await doctor.diagnose(verbose: false);
expect(
verify(mockUsage.sendEvent(
expect(testUsage.events.length, 3);
expect(testUsage.events, contains(
const TestUsageEvent(
'doctor-result',
'PassingValidator',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['installed', 'installed', 'installed'],
);
label: 'installed',
),
));
}, overrides: <Type, Generator>{
DoctorValidatorsProvider: () => FakeDoctorValidatorsProvider(),
Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('contains installed and partial', () async {
await FakePassingDoctor(logger).diagnose(verbose: false);
expect(
verify(mockUsage.sendEvent(
expect(testUsage.events, unorderedEquals(<TestUsageEvent>[
const TestUsageEvent(
'doctor-result',
'PassingValidator',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['installed', 'installed'],
);
expect(
verify(mockUsage.sendEvent(
label: 'installed',
),
const TestUsageEvent(
'doctor-result',
'PassingValidator',
label: 'installed',
),
const TestUsageEvent(
'doctor-result',
'PartialValidatorWithHintsOnly',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['partial'],
);
expect(
verify(mockUsage.sendEvent(
label: 'partial',
),
const TestUsageEvent(
'doctor-result',
'PartialValidatorWithErrors',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['partial'],
);
label: 'partial',
),
]));
}, overrides: <Type, Generator>{
Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('contains installed, missing and partial', () async {
await FakeDoctor(logger).diagnose(verbose: false);
expect(
verify(mockUsage.sendEvent(
expect(testUsage.events, unorderedEquals(<TestUsageEvent>[
const TestUsageEvent(
'doctor-result',
'PassingValidator',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['installed'],
);
expect(
verify(mockUsage.sendEvent(
label: 'installed',
),
const TestUsageEvent(
'doctor-result',
'MissingValidator',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['missing'],
);
expect(
verify(mockUsage.sendEvent(
label: 'missing',
),
const TestUsageEvent(
'doctor-result',
'NotAvailableValidator',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['notAvailable'],
);
expect(
verify(mockUsage.sendEvent(
label: 'notAvailable',
),
const TestUsageEvent(
'doctor-result',
'PartialValidatorWithHintsOnly',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['partial'],
);
expect(
verify(mockUsage.sendEvent(
label: 'partial',
),
const TestUsageEvent(
'doctor-result',
'PartialValidatorWithErrors',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['partial'],
);
label: 'partial',
),
]));
}, overrides: <Type, Generator>{
Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('events for grouped validators are properly decomposed', () async {
await FakeGroupedDoctor(logger).diagnose(verbose: false);
expect(
verify(mockUsage.sendEvent(
expect(testUsage.events, unorderedEquals(<TestUsageEvent>[
const TestUsageEvent(
'doctor-result',
'PassingGroupedValidator',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['installed', 'installed', 'installed'],
);
expect(
verify(mockUsage.sendEvent(
label: 'installed',
),
const TestUsageEvent(
'doctor-result',
'PassingGroupedValidator',
label: 'installed',
),
const TestUsageEvent(
'doctor-result',
'PassingGroupedValidator',
label: 'installed',
),
const TestUsageEvent(
'doctor-result',
'MissingGroupedValidator',
label: captureAnyNamed('label'),
)).captured,
<dynamic>['missing'],
);
label: 'missing',
),
]));
}, overrides: <Type, Generator>{
Platform: _kNoColorOutputPlatform,
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
......@@ -726,8 +717,6 @@ class NoOpDoctor implements Doctor {
List<Workflow> get workflows => <Workflow>[];
}
class MockUsage extends Mock implements Usage {}
class PassingValidator extends DoctorValidator {
PassingValidator(String name) : super(name);
......
......@@ -484,7 +484,6 @@ void main() {
}
class MockCache extends Mock implements Cache {}
class MockUsage extends Mock implements Usage {}
class MockDeviceManager extends Mock implements DeviceManager {}
class MockDevice extends Mock implements Device {
......
......@@ -41,10 +41,10 @@ void main() {
group('Usage', () {
Directory tempDir;
Usage mockUsage;
TestUsage testUsage;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
});
......@@ -96,17 +96,17 @@ void main() {
await runCommandIn(projectPath,
arguments: <String>['--target-platform=android-arm']);
verify(mockUsage.sendEvent(
'tool-command-result',
'aar',
label: 'success',
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'tool-command-result',
'aar',
label: 'success',
),
));
},
overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
......@@ -297,4 +297,3 @@ class MockAndroidBuilder extends Mock implements AndroidBuilder {}
class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockUsage extends Mock implements Usage {}
......@@ -30,10 +30,10 @@ void main() {
group('Usage', () {
Directory tempDir;
Usage mockUsage;
TestUsage testUsage;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
});
......@@ -103,17 +103,17 @@ void main() {
await runBuildApkCommand(projectPath);
verify(mockUsage.sendEvent(
'tool-command-result',
'apk',
label: 'success',
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'tool-command-result',
'apk',
label: 'success',
),
));
},
overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
......@@ -122,10 +122,10 @@ void main() {
ProcessManager mockProcessManager;
String gradlew;
AndroidSdk mockAndroidSdk;
Usage mockUsage;
TestUsage testUsage;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', 'android',
......@@ -390,18 +390,20 @@ void main() {
containsIgnoringWhitespace('To learn more, see: https://developer.android.com/studio/build/shrink-code'),
);
verify(mockUsage.sendEvent(
'build',
'apk',
label: 'gradle-r8-failure',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'apk',
label: 'gradle-r8-failure',
parameters: <String, String>{},
),
));
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext("reports when the app isn't using AndroidX", () async {
......@@ -452,18 +454,21 @@ void main() {
'following the steps on https://goo.gl/CP92wY'
),
);
verify(mockUsage.sendEvent(
'build',
'apk',
label: 'app-not-using-android-x',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'apk',
label: 'app-not-using-android-x',
parameters: <String, String>{},
),
));
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('reports when the app is using AndroidX', () async {
......@@ -505,18 +510,21 @@ void main() {
),
isFalse,
);
verify(mockUsage.sendEvent(
'build',
'apk',
label: 'app-using-android-x',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'apk',
label: 'app-using-android-x',
parameters: <String, String>{},
),
));
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
}
......@@ -539,4 +547,3 @@ Future<BuildApkCommand> runBuildApkCommand(
class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockUsage extends Mock implements Usage {}
......@@ -29,11 +29,11 @@ void main() {
group('Usage', () {
Directory tempDir;
Usage mockUsage;
TestUsage testUsage;
setUp(() {
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
mockUsage = MockUsage();
testUsage = TestUsage();
});
tearDown(() {
......@@ -85,17 +85,13 @@ void main() {
await runBuildAppBundleCommand(projectPath);
verify(mockUsage.sendEvent(
'tool-command-result',
'appbundle',
label: 'success',
value: anyNamed('value'),
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent('tool-command-result', 'appbundle', label: 'success'),
));
},
overrides: <Type, Generator>{
AndroidBuilder: () => FakeAndroidBuilder(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
......@@ -104,10 +100,10 @@ void main() {
ProcessManager mockProcessManager;
MockAndroidSdk mockAndroidSdk;
String gradlew;
Usage mockUsage;
TestUsage testUsage;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
gradlew = globals.fs.path.join(tempDir.path, 'flutter_project', 'android',
globals.platform.isWindows ? 'gradlew.bat' : 'gradlew');
......@@ -254,18 +250,21 @@ void main() {
'following the steps on https://goo.gl/CP92wY'
),
);
verify(mockUsage.sendEvent(
'build',
'appbundle',
label: 'app-not-using-android-x',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'appbundle',
label: 'app-not-using-android-x',
parameters: <String, String>{},
),
));
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('reports when the app is using AndroidX', () async {
......@@ -310,18 +309,21 @@ void main() {
'following the steps on https://goo.gl/CP92wY'),
)
);
verify(mockUsage.sendEvent(
'build',
'appbundle',
label: 'app-using-android-x',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'appbundle',
label: 'app-using-android-x',
parameters: <String, String>{},
),
));
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
}
......@@ -348,4 +350,3 @@ Matcher not(Matcher target){
class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockUsage extends Mock implements Usage {}
......@@ -153,7 +153,7 @@ void main() {
group('analytics with mocks', () {
MemoryFileSystem memoryFileSystem;
MockStdio mockStdio;
Usage mockUsage;
TestUsage testUsage;
SystemClock mockClock;
Doctor mockDoctor;
List<int> mockTimes;
......@@ -161,7 +161,7 @@ void main() {
setUp(() {
memoryFileSystem = MemoryFileSystem.test();
mockStdio = MockStdio();
mockUsage = MockUsage();
testUsage = TestUsage();
mockClock = MockClock();
mockDoctor = MockDoctor();
when(mockClock.now()).thenAnswer(
......@@ -182,19 +182,15 @@ void main() {
verify(mockClock.now()).called(2);
expect(
verify(mockUsage.sendTiming(
captureAny,
captureAny,
captureAny,
label: captureAnyNamed('label'),
)).captured,
<dynamic>['flutter', 'doctor', const Duration(milliseconds: 1000), 'success'],
);
expect(testUsage.timings, contains(
const TestTimingEvent(
'flutter', 'doctor', Duration(milliseconds: 1000), label: 'success',
),
));
}, overrides: <Type, Generator>{
SystemClock: () => mockClock,
Doctor: () => mockDoctor,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('doctor fail sends warning', () async {
......@@ -207,19 +203,15 @@ void main() {
verify(mockClock.now()).called(2);
expect(
verify(mockUsage.sendTiming(
captureAny,
captureAny,
captureAny,
label: captureAnyNamed('label'),
)).captured,
<dynamic>['flutter', 'doctor', const Duration(milliseconds: 1000), 'warning'],
);
expect(testUsage.timings, contains(
const TestTimingEvent(
'flutter', 'doctor', Duration(milliseconds: 1000), label: 'warning',
),
));
}, overrides: <Type, Generator>{
SystemClock: () => mockClock,
Doctor: () => mockDoctor,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('single command usage path', () async {
......@@ -227,7 +219,7 @@ void main() {
expect(await doctorCommand.usagePath, 'doctor');
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('compound command usage path', () async {
......@@ -236,7 +228,7 @@ void main() {
expect(await buildApkCommand.usagePath, 'build/apk');
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('command sends localtime', () async {
......@@ -383,8 +375,6 @@ class FakeFlutterCommand extends FlutterCommand {
}
}
class MockUsage extends Mock implements Usage {}
class MockDoctor extends Mock implements Doctor {}
class MockFlutterConfig extends Mock implements Config {}
......@@ -24,7 +24,7 @@ import '../../src/mocks.dart';
void main() {
group('gradleErrors', () {
test('list of errors', () {
testWithoutContext('list of errors', () {
// If you added a new Gradle error, please update this test.
expect(gradleErrors,
equals(<GradleHandledError>[
......@@ -325,9 +325,9 @@ Command: /home/android/gradlew assembleRelease
});
group('AndroidX', () {
final Usage mockUsage = MockUsage();
final TestUsage testUsage = TestUsage();
test('pattern', () {
testWithoutContext('pattern', () {
expect(androidXFailureHandler.test(
'AAPT: error: resource android:attr/fontVariationSettings not found.'
), isTrue);
......@@ -357,20 +357,22 @@ Command: /home/android/gradlew assembleRelease
final GradleBuildStatus status = await androidXFailureHandler
.handler(line: '', project: FlutterProject.current());
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'app-not-using-plugins',
},
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'app-not-using-plugins',
},
),
));
expect(status, equals(GradleBuildStatus.exit));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('handler - plugins and no AndroidX', () async {
......@@ -389,20 +391,23 @@ Command: /home/android/gradlew assembleRelease
'Please migrate your app to AndroidX. See https://goo.gl/CP92wY .'
)
);
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'app-not-using-androidx',
},
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'app-not-using-androidx',
},
),
));
expect(status, equals(GradleBuildStatus.exit));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('handler - plugins, AndroidX, and AAR', () async {
......@@ -415,20 +420,22 @@ Command: /home/android/gradlew assembleRelease
shouldBuildPluginAsAar: true,
);
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'using-jetifier',
},
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'using-jetifier',
},
),
));
expect(status, equals(GradleBuildStatus.exit));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('handler - plugins, AndroidX, and no AAR', () async {
......@@ -447,19 +454,22 @@ Command: /home/android/gradlew assembleRelease
'The tool is about to try using Jetifier to solve the incompatibility.'
)
);
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'not-using-jetifier',
},
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-android-x-failure',
parameters: <String, String>{
'cd43': 'not-using-jetifier',
},
),
));
expect(status, equals(GradleBuildStatus.retryWithAarPlugins));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => MockProcessManager(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
......@@ -490,7 +500,7 @@ Command: /home/android/gradlew assembleRelease
});
group('license not accepted', () {
test('pattern', () {
testWithoutContext('pattern', () {
expect(
licenseNotAcceptedHandler.test(
'You have not accepted the license agreements of the following SDK components'
......@@ -525,7 +535,7 @@ Command: /home/android/gradlew assembleRelease
mockProcessManager = MockProcessManager();
});
test('pattern', () {
testWithoutContext('pattern', () {
expect(
flavorUndefinedHandler.test(
'Task assembleFooRelease not found in root project.'
......@@ -657,8 +667,6 @@ assembleProfile
});
}
class MockUsage extends Mock implements Usage {}
bool formatTestErrorMessage(String errorMessage, GradleHandledError error) {
return errorMessage
.split('\n')
......
......@@ -22,7 +22,6 @@ import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
......@@ -139,11 +138,11 @@ void main() {
group('findBundleFile', () {
FileSystem fileSystem;
Usage mockUsage;
TestUsage testUsage;
setUp(() {
fileSystem = MemoryFileSystem.test();
mockUsage = MockUsage();
testUsage = TestUsage();
});
testWithoutContext('Finds app bundle when flavor contains underscores in release mode', () {
......@@ -312,20 +311,20 @@ void main() {
"was generated under ${project.android.buildDirectory.path}, but the tool couldn't find it."
)
);
verify(
mockUsage.sendEvent(
any,
any,
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-expected-file-not-found',
parameters: const <String, String> {
parameters: <String, String> {
'cd37': 'androidGradlePluginVersion: 6.7, fileExtension: .aab',
},
),
).called(1);
));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Usage: () => mockUsage,
Usage: () => testUsage,
});
});
......@@ -1007,7 +1006,7 @@ plugin1=${plugin1.path}
});
group('gradle build', () {
Usage mockUsage;
TestUsage testUsage;
MockAndroidSdk mockAndroidSdk;
MockAndroidStudio mockAndroidStudio;
MockLocalEngineArtifacts mockArtifacts;
......@@ -1018,7 +1017,7 @@ plugin1=${plugin1.path}
Cache cache;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
fileSystem = MemoryFileSystem.test();
fileSystemUtils = MockFileSystemUtils();
mockAndroidSdk = MockAndroidSdk();
......@@ -1117,20 +1116,21 @@ plugin1=${plugin1.path}
expect(handlerCalled, isTrue);
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-random-event-label-failure',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('recognizes common errors - retry build', () async {
......@@ -1198,21 +1198,21 @@ plugin1=${plugin1.path}
));
expect(testFnCalled, equals(2));
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-random-event-label-failure',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('recognizes process exceptions - tool exit', () async {
......@@ -1273,20 +1273,21 @@ plugin1=${plugin1.path}
expect(handlerCalled, isTrue);
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-random-event-label-failure',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('rethrows unrecognized ProcessException', () async {
......@@ -1406,19 +1407,21 @@ plugin1=${plugin1.path}
],
);
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-random-event-label-success',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-success',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('performs code size analysis and sends analytics', () async {
......@@ -1492,17 +1495,19 @@ plugin1=${plugin1.path}
localGradleErrors: <GradleHandledError>[],
);
verify(mockUsage.sendEvent(
'code-size-analysis',
'apk',
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'code-size-analysis',
'apk',
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
FileSystem: () => fileSystem,
Platform: () => android,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('recognizes common errors - retry build with AAR plugins', () async {
......@@ -1576,20 +1581,21 @@ plugin1=${plugin1.path}
expect(testFnCalled, equals(2));
expect(builtPluginAsAar, isTrue);
verify(mockUsage.sendEvent(
any,
any,
label: 'gradle-random-event-label-failure',
parameters: anyNamed('parameters'),
)).called(1);
expect(testUsage.events, contains(
const TestUsageEvent(
'build',
'unspecified',
label: 'gradle-random-event-label-failure',
parameters: <String, String>{},
),
));
}, overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
Cache: () => cache,
Platform: () => android,
FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
Usage: () => testUsage,
});
testUsingContext('indicates that an APK has been built successfully', () async {
......@@ -2797,11 +2803,7 @@ class FakeGradleUtils extends GradleUtils {
class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockAndroidProject extends Mock implements AndroidProject {}
class MockAndroidStudio extends Mock implements AndroidStudio {}
class MockDirectory extends Mock implements Directory {}
class MockFile extends Mock implements File {}
class MockFileSystemUtils extends Mock implements FileSystemUtils {}
class MockFlutterProject extends Mock implements FlutterProject {}
class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
class MockUsage extends Mock implements Usage {}
......@@ -25,7 +25,6 @@ class MockPathContext extends Mock implements path.Context {}
class MockDirectory extends Mock implements Directory {}
class MockRandomAccessFile extends Mock implements RandomAccessFile {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockUsage extends Mock implements Usage {}
final Platform windowsPlatform = FakePlatform(
operatingSystem: 'windows',
......@@ -927,9 +926,11 @@ void main() {
fileSystem.file('source').copySync('dest');
expect(memoryDest.readAsBytesSync(), expectedBytes);
verify(globals.flutterUsage.sendEvent('error-handling', 'copy-fallback')).called(1);
expect((globals.flutterUsage as TestUsage).events, contains(
const TestUsageEvent('error-handling', 'copy-fallback'),
));
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
Usage: () => TestUsage(),
});
// Uses context for analytics.
......@@ -963,7 +964,7 @@ void main() {
verify(dest.deleteSync(recursive: true)).called(1);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
Usage: () => TestUsage(),
});
});
}
......
......@@ -17,7 +17,6 @@ import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:http/http.dart';
import 'package:http/testing.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
import '../src/context.dart';
......@@ -26,16 +25,14 @@ import '../src/testbed.dart';
void main() {
BufferLogger logger;
FileSystem fs;
MockUsage mockUsage;
TestUsage testUsage;
Platform platform;
OperatingSystemUtils operatingSystemUtils;
setUp(() async {
logger = BufferLogger.test();
fs = MemoryFileSystem.test();
mockUsage = MockUsage();
when(mockUsage.clientId).thenReturn('00000000-0000-4000-0000-000000000000');
testUsage = TestUsage();
platform = FakePlatform(environment: <String, String>{}, operatingSystem: 'linux');
operatingSystemUtils = OperatingSystemUtils(
......@@ -63,7 +60,7 @@ void main() {
'version': 'test-version',
},
));
expect(crashInfo.fields['uuid'], '00000000-0000-4000-0000-000000000000');
expect(crashInfo.fields['uuid'], testUsage.clientId);
expect(crashInfo.fields['product'], 'Flutter_Tools');
expect(crashInfo.fields['version'], 'test-version');
expect(crashInfo.fields['osName'], 'linux');
......@@ -101,11 +98,11 @@ void main() {
});
testWithoutContext('suppress analytics', () async {
when(mockUsage.suppressAnalytics).thenReturn(true);
testUsage.suppressAnalytics = true;
final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const SocketException('no internets')),
usage: mockUsage,
usage: testUsage,
platform: platform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -123,7 +120,7 @@ void main() {
group('allow analytics', () {
setUp(() async {
when(mockUsage.suppressAnalytics).thenReturn(false);
testUsage.suppressAnalytics = false;
});
testWithoutContext('should send crash reports', () async {
......@@ -131,7 +128,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender(
client: MockCrashReportSender(requestInfo),
usage: mockUsage,
usage: testUsage,
platform: platform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -150,7 +147,7 @@ void main() {
testWithoutContext('should print an explanatory message when there is a SocketException', () async {
final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const SocketException('no internets')),
usage: mockUsage,
usage: testUsage,
platform: platform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -169,7 +166,7 @@ void main() {
testWithoutContext('should print an explanatory message when there is an HttpException', () async {
final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const HttpException('no internets')),
usage: mockUsage,
usage: testUsage,
platform: platform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -188,7 +185,7 @@ void main() {
testWithoutContext('should print an explanatory message when there is a ClientException', () async {
final CrashReportSender crashReportSender = CrashReportSender(
client: CrashingCrashReportSender(const HttpException('no internets')),
usage: mockUsage,
usage: testUsage,
platform: platform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -209,7 +206,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender(
client: MockCrashReportSender(requestInfo),
usage: mockUsage,
usage: testUsage,
platform: platform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -263,7 +260,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender(
client: mockClient,
usage: mockUsage,
usage: testUsage,
platform: platform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -301,7 +298,7 @@ void main() {
final CrashReportSender crashReportSender = CrashReportSender(
client: mockClient,
usage: mockUsage,
usage: testUsage,
platform: environmentPlatform,
logger: logger,
operatingSystemUtils: operatingSystemUtils,
......@@ -392,5 +389,3 @@ class FakeDoctorValidatorsProvider implements DoctorValidatorsProvider {
@override
List<Workflow> get workflows => <Workflow>[];
}
class MockUsage extends Mock implements Usage {}
......@@ -48,7 +48,7 @@ void main() {
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -86,7 +86,7 @@ void main() {
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -124,7 +124,7 @@ void main() {
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -162,7 +162,7 @@ void main() {
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -199,7 +199,7 @@ void main() {
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -238,7 +238,7 @@ void main() {
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -279,7 +279,7 @@ void main() {
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -304,7 +304,7 @@ void main() {
fileSystem: MockFileSystem(),
logger: logger,
processManager: processMock,
usage: MockUsage(),
usage: TestUsage(),
platform: FakePlatform(
environment: const <String, String>{},
),
......@@ -374,7 +374,7 @@ void main() {
platform: FakePlatform(environment: const <String, String>{}),
fileSystem: MockFileSystem(),
logger: logger,
usage: MockUsage(),
usage: TestUsage(),
botDetector: const BotDetectorAlwaysNo(),
processManager: MockProcessManager(66, stderr: 'err1\nerr2\nerr3\n', stdout: 'out1\nout2\nout3\n'),
);
......@@ -403,7 +403,7 @@ void main() {
final MockFileSystem fsMock = MockFileSystem();
final Pub pub = Pub(
platform: FakePlatform(environment: const <String, String>{}),
usage: MockUsage(),
usage: TestUsage(),
fileSystem: fsMock,
logger: BufferLogger.test(),
processManager: processMock,
......@@ -432,7 +432,7 @@ void main() {
fileSystem: MockFileSystem(),
logger: BufferLogger.test(),
processManager: processMock,
usage: MockUsage(),
usage: TestUsage(),
botDetector: const BotDetectorAlwaysNo(),
platform: FakePlatform(
environment: const <String, String>{
......@@ -461,7 +461,7 @@ void main() {
testWithoutContext('analytics sent on success', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final MockUsage usage = MockUsage();
final TestUsage usage = TestUsage();
final Pub pub = Pub(
fileSystem: fileSystem,
logger: BufferLogger.test(),
......@@ -484,13 +484,14 @@ void main() {
context: PubContext.flutterTests,
generateSyntheticPackage: true,
);
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
expect(usage.events, contains(
const TestUsageEvent('pub-result', 'flutter-tests', label: 'success'),
));
});
testWithoutContext('package_config_subset file is generated from packages and not timestamp', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final MockUsage usage = MockUsage();
final TestUsage usage = TestUsage();
final Pub pub = Pub(
fileSystem: fileSystem,
logger: BufferLogger.test(),
......@@ -536,7 +537,7 @@ void main() {
testWithoutContext('analytics sent on failure', () async {
MockDirectory.findCache = true;
final MockUsage usage = MockUsage();
final TestUsage usage = TestUsage();
final Pub pub = Pub(
usage: usage,
fileSystem: MockFileSystem(),
......@@ -555,11 +556,13 @@ void main() {
// Ignore.
}
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1);
expect(usage.events, contains(
const TestUsageEvent('pub-result', 'flutter-tests', label: 'failure'),
));
});
testWithoutContext('analytics sent on failed version solve', () async {
final MockUsage usage = MockUsage();
final TestUsage usage = TestUsage();
final FileSystem fileSystem = MemoryFileSystem.test();
final Pub pub = Pub(
fileSystem: fileSystem,
......@@ -584,7 +587,9 @@ void main() {
// Ignore.
}
verify(usage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1);
expect(usage.events, contains(
const TestUsageEvent('pub-result', 'flutter-tests', label: 'version-solving-failed'),
));
});
testWithoutContext('Pub error handling', () async {
......@@ -633,7 +638,7 @@ void main() {
),
]);
final Pub pub = Pub(
usage: MockUsage(),
usage: TestUsage(),
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
......@@ -763,5 +768,3 @@ class MockDirectory implements Directory {
}
class MockRandomAccessFile extends Mock implements RandomAccessFile {}
class MockUsage extends Mock implements Usage {}
......@@ -23,9 +23,9 @@ import '../../src/common.dart';
void main () {
group('iOS migration', () {
MockUsage mockUsage;
TestUsage testUsage;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
});
testWithoutContext('migrators succeed', () {
......@@ -61,10 +61,10 @@ void main () {
mockIosProject,
testLogger,
mockXcode,
mockUsage
testUsage
);
expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value')));
expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.existsSync(), isFalse);
......@@ -81,10 +81,10 @@ void main () {
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value')));
expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified);
expect(xcodeProjectInfoFile.readAsStringSync(), contents);
......@@ -102,7 +102,7 @@ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate(), isTrue);
expect(xcodeProjectInfoFile.readAsStringSync(), contents);
......@@ -130,10 +130,10 @@ keep this 2
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value')));
expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.readAsStringSync(), r'''
keep this 1
......@@ -154,11 +154,13 @@ keep this 2
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null));
expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
});
testWithoutContext('migration fails with leftover Flutter.framework reference', () {
......@@ -172,10 +174,12 @@ keep this 2
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null));
expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
});
testWithoutContext('migration fails without Xcode installed', () {
......@@ -188,10 +192,12 @@ keep this 2
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null));
expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
});
testWithoutContext('migration fails on Xcode < 11.4', () {
......@@ -205,10 +211,10 @@ keep this 2
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(any, any, label: anyNamed('label'), value: anyNamed('value')));
expect(testUsage.events, isEmpty);
expect(testLogger.errorText, isEmpty);
});
......@@ -223,10 +229,12 @@ keep this 2
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null));
expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
});
testWithoutContext('migration fails on Xcode 12,0', () {
......@@ -240,10 +248,12 @@ keep this 2
mockIosProject,
testLogger,
mockXcode,
mockUsage,
testUsage,
);
expect(iosProjectMigration.migrate, throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('ios-migration', 'remove-frameworks', label: 'failure', value: null));
expect(testUsage.events, contains(
const TestUsageEvent('ios-migration', 'remove-frameworks', label: 'failure'),
));
});
});
......@@ -556,7 +566,6 @@ keep this 3
class MockIosProject extends Mock implements IosProject {}
class MockXcode extends Mock implements Xcode {}
class MockUsage extends Mock implements Usage {}
class FakeIOSMigrator extends ProjectMigrator {
FakeIOSMigrator({@required this.succeeds})
......
......@@ -129,13 +129,13 @@ void main() {
group('Diagnose Xcode build failure', () {
Map<String, String> buildSettings;
MockUsage mockUsage;
TestUsage testUsage;
setUp(() {
buildSettings = <String, String>{
'PRODUCT_BUNDLE_IDENTIFIER': 'test.app',
};
mockUsage = MockUsage();
testUsage = TestUsage();
});
testUsingContext('Sends analytics when bitcode fails', () async {
......@@ -151,14 +151,18 @@ void main() {
),
);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
verify(mockUsage.sendEvent('build',
any,
label: 'xcode-bitcode-failure',
parameters: <String, String>{
cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(),
cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(),
})).called(1);
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect(testUsage.events, contains(
TestUsageEvent(
'build',
'unspecified',
label: 'xcode-bitcode-failure',
parameters: <String, String>{
cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(),
cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(),
},
),
));
});
testUsingContext('No provisioning profile shows message', () async {
......@@ -227,7 +231,7 @@ Error launching application on iPhone.''',
),
);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect(
logger.errorText,
contains("No Provisioning Profile was found for your project's Bundle Identifier or your \ndevice."),
......@@ -308,7 +312,7 @@ Could not build the precompiled application for the device.''',
),
);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect(
logger.errorText,
contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'),
......@@ -345,7 +349,7 @@ Exited (sigterm)''',
),
);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect(
logger.errorText,
contains('Your Xcode project requires migration.'),
......@@ -382,7 +386,7 @@ Exited (sigterm)''',
),
);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
await diagnoseXcodeBuildFailure(buildResult, testUsage, logger);
expect(
logger.errorText,
contains('Your Xcode project requires migration.'),
......@@ -480,5 +484,3 @@ Exited (sigterm)''',
});
});
}
class MockUsage extends Mock implements Usage {}
......@@ -19,14 +19,14 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart';
void main() {
MockUsage mockUsage;
TestUsage testUsage;
MemoryFileSystem memoryFileSystem;
BufferLogger testLogger;
MockMacOSProject mockMacOSProject;
File xcodeProjectInfoFile;
setUp(() {
mockUsage = MockUsage();
testUsage = TestUsage();
memoryFileSystem = MemoryFileSystem.test();
xcodeProjectInfoFile = memoryFileSystem.file('project.pbxproj');
......@@ -48,15 +48,10 @@ void main() {
RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject,
testLogger,
mockUsage,
testUsage,
);
expect(macosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
));
expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.existsSync(), isFalse);
......@@ -77,15 +72,10 @@ void main() {
RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject,
testLogger,
mockUsage,
testUsage,
);
expect(macosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
));
expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.lastModifiedSync(), projectLastModified);
expect(xcodeProjectInfoFile.readAsStringSync(), contents);
......@@ -103,7 +93,7 @@ shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.
RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject,
testLogger,
mockUsage,
testUsage,
);
expect(macosProjectMigration.migrate(), isTrue);
expect(xcodeProjectInfoFile.readAsStringSync(), contents);
......@@ -126,15 +116,10 @@ keep this 2
RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject,
testLogger,
mockUsage,
testUsage,
);
expect(macosProjectMigration.migrate(), isTrue);
verifyNever(mockUsage.sendEvent(
any,
any,
label: anyNamed('label'),
value: anyNamed('value'),
));
expect(testUsage.events, isEmpty);
expect(xcodeProjectInfoFile.readAsStringSync(), r'''
keep this 1
......@@ -154,13 +139,14 @@ keep this 2
RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject,
testLogger,
mockUsage,
testUsage,
);
expect(macosProjectMigration.migrate,
throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('macos-migration', 'remove-frameworks',
label: 'failure', value: null));
expect(testUsage.events, contains(
const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'),
));
});
testWithoutContext(
......@@ -173,19 +159,18 @@ keep this 2
RemoveMacOSFrameworkLinkAndEmbeddingMigration(
mockMacOSProject,
testLogger,
mockUsage,
testUsage,
);
expect(macosProjectMigration.migrate,
throwsToolExit(message: 'Your Xcode project requires migration'));
verify(mockUsage.sendEvent('macos-migration', 'remove-frameworks',
label: 'failure', value: null));
expect(testUsage.events, contains(
const TestUsageEvent('macos-migration', 'remove-frameworks', label: 'failure'),
));
});
}
class MockMacOSProject extends Mock implements MacOSProject {}
class MockUsage extends Mock implements Usage {}
class FakeMacOSMigrator extends ProjectMigrator {
FakeMacOSMigrator({@required this.succeeds}) : super(null);
......
......@@ -7,14 +7,13 @@
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:package_config/package_config.dart';
import '../../src/common.dart';
void main() {
testWithoutContext('DoctorResultEvent sends usage event for each sub validator', () async {
final Usage usage = MockUsage();
final TestUsage usage = TestUsage();
final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[
FakeDoctorValidator('a'),
FakeDoctorValidator('b'),
......@@ -29,14 +28,16 @@ void main() {
);
expect(doctorResultEvent.send, returnsNormally);
verify(usage.sendEvent('doctor-result', any, label: anyNamed('label'))).called(3);
expect(usage.events.length, 3);
expect(usage.events, contains(
const TestUsageEvent('doctor-result', 'FakeDoctorValidator', label: 'crash'),
));
});
testWithoutContext('DoctorResultEvent does not crash if a synthetic crash result was used instead'
' of validation. This happens when a grouped validator throws an exception, causing subResults to never '
' be instantiated.', () async {
final Usage usage = MockUsage();
final TestUsage usage = TestUsage();
final GroupedValidator groupedValidator = FakeGroupedValidator(<DoctorValidator>[
FakeDoctorValidator('a'),
FakeDoctorValidator('b'),
......@@ -52,11 +53,14 @@ void main() {
expect(doctorResultEvent.send, returnsNormally);
verify(usage.sendEvent('doctor-result', any, label: anyNamed('label'))).called(1);
expect(usage.events.length, 1);
expect(usage.events, contains(
const TestUsageEvent('doctor-result', 'FakeGroupedValidator', label: 'crash'),
));
});
testWithoutContext('Reports null safe analytics events', () {
final Usage usage = MockUsage();
final TestUsage usage = TestUsage();
final PackageConfig packageConfig = PackageConfig(<Package>[
Package('foo', Uri.parse('file:///foo/'), languageVersion: LanguageVersion(2, 12)),
Package('bar', Uri.parse('file:///fizz/'), languageVersion: LanguageVersion(2, 1)),
......@@ -70,15 +74,17 @@ void main() {
usage,
).send();
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound')).called(1);
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
expect(usage.events, unorderedEquals(<TestUsageEvent>[
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'),
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
'cd49': '1', 'cd50': '3',
})).called(1);
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: '2.12')).called(1);
}),
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: '2.12'),
]));
});
testWithoutContext('Does not crash if main package is missing', () {
final Usage usage = MockUsage();
final TestUsage usage = TestUsage();
final PackageConfig packageConfig = PackageConfig(<Package>[
Package('foo', Uri.parse('file:///foo/lib/'), languageVersion: LanguageVersion(2, 12)),
Package('bar', Uri.parse('file:///fizz/lib/'), languageVersion: LanguageVersion(2, 1)),
......@@ -92,15 +98,16 @@ void main() {
usage,
).send();
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound')).called(1);
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
'cd49': '1', 'cd50': '3',
})).called(1);
verifyNever(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: anyNamed('label')));
expect(usage.events, unorderedEquals(<TestUsageEvent>[
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'),
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
'cd49': '1', 'cd50': '3',
}),
]));
});
testWithoutContext('a null language version is treated as unmigrated', () {
final Usage usage = MockUsage();
final TestUsage usage = TestUsage();
final PackageConfig packageConfig = PackageConfig(<Package>[
Package('foo', Uri.parse('file:///foo/lib/'), languageVersion: null),
]);
......@@ -112,11 +119,12 @@ void main() {
usage,
).send();
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound')).called(1);
verify(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
'cd49': '0', 'cd50': '1',
})).called(1);
verifyNever(usage.sendEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: anyNamed('label')));
expect(usage.events, unorderedEquals(<TestUsageEvent>[
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'),
const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: <String, String>{
'cd49': '0', 'cd50': '1',
}),
]));
});
}
......@@ -132,5 +140,3 @@ class FakeDoctorValidator extends DoctorValidator {
return ValidationResult.crash(Object());
}
}
class MockUsage extends Mock implements Usage {}
......@@ -546,16 +546,18 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, true);
expect(result.code, 1);
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
expect((globals.flutterUsage as TestUsage).events, contains(
TestUsageEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1);
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
}),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
Usage: () => TestUsage(),
}), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher,
});
......@@ -633,16 +635,19 @@ void main() {
expect(result.fatal, true);
expect(result.code, kIsolateReloadBarred);
expect(result.message, contains('Unable to hot reload application due to an unrecoverable error'));
verify(globals.flutterUsage.sendEvent('hot', 'reload-barred', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
expect((globals.flutterUsage as TestUsage).events, contains(
TestUsageEvent('hot', 'reload-barred', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1);
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
}),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
Usage: () => TestUsage(),
}), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher,
});
......@@ -700,17 +705,20 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, true);
expect(result.code, 1);
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
expect((globals.flutterUsage as TestUsage).events, contains(
TestUsageEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
})).called(1);
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'false',
}),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher,
Usage: () => MockUsage(),
Usage: () => TestUsage(),
}));
testUsingContext('ResidentRunner does not reload sources if no sources changed', () => testbed.run(() async {
......@@ -1021,13 +1029,16 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, false);
expect(result.code, 0);
expect(verify(globals.flutterUsage.sendEvent('hot', 'reload',
parameters: captureAnyNamed('parameters'))).captured[0],
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm)),
);
final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first;
expect(event.category, 'hot');
expect(event.parameter, 'reload');
expect(event.parameters, containsPair(
cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm),
));
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
Usage: () => TestUsage(),
}), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher,
});
......@@ -1134,15 +1145,18 @@ void main() {
expect(result.fatal, false);
expect(result.code, 0);
verify(globals.flutterUsage.sendEvent('hot', 'reload', parameters: argThat(
containsPair('cd48', 'true'),
named: 'parameters',
))).called(1);
final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first;
expect(event.category, 'hot');
expect(event.parameter, 'reload');
expect(event.parameters, containsPair(
cdKey(CustomDimensions.fastReassemble), 'true',
));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
Platform: () => FakePlatform(operatingSystem: 'linux'),
ProjectFileInvalidator: () => FakeProjectFileInvalidator(),
Usage: () => MockUsage(),
Usage: () => TestUsage(),
FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true),
}), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher,
......@@ -1208,14 +1222,16 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, false);
expect(result.code, 0);
expect(verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured[0],
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm)),
);
final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first;
expect(event.category, 'hot');
expect(event.parameter, 'restart');
expect(event.parameters, containsPair(
cdKey(CustomDimensions.hotEventTargetPlatform), getNameForTargetPlatform(TargetPlatform.android_arm),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
Usage: () => TestUsage(),
}), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher,
});
......@@ -1473,16 +1489,19 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, true);
expect(result.code, 1);
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
expect((globals.flutterUsage as TestUsage).events, contains(
TestUsageEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'true',
})).called(1);
cdKey(CustomDimensions.hotEventSdkName): 'Example',
cdKey(CustomDimensions.hotEventEmulator): 'false',
cdKey(CustomDimensions.hotEventFullRestart): 'true',
}),
));
expect(fakeVmServiceHost.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
Usage: () => TestUsage(),
}), overrides: <Type, Generator>{
DevtoolsLauncher: () => mockDevtoolsLauncher,
});
......@@ -3134,7 +3153,6 @@ class MockDevice extends Mock implements Device {}
class MockDeviceLogReader extends Mock implements DeviceLogReader {}
class MockDevicePortForwarder extends Mock implements DevicePortForwarder {}
class MockDevtoolsLauncher extends Mock implements DevtoolsLauncher {}
class MockUsage extends Mock implements Usage {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockResidentCompiler extends Mock implements ResidentCompiler {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment