Unverified Commit 77ea848c authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Inject Usage dependency into FallbackDiscovery and BuildEvent (#53443)

* Usage dependency injection

* Review edits
parent c3ec1caa
......@@ -242,9 +242,9 @@ Future<void> buildGradleApp({
final bool usesAndroidX = isAppUsingAndroidX(project.android.hostAppGradleRoot);
if (usesAndroidX) {
BuildEvent('app-using-android-x').send();
BuildEvent('app-using-android-x', flutterUsage: globals.flutterUsage).send();
} else if (!usesAndroidX) {
BuildEvent('app-not-using-android-x').send();
BuildEvent('app-not-using-android-x', flutterUsage: globals.flutterUsage).send();
globals.printStatus("$warningMark Your app isn't using AndroidX.", emphasis: true);
globals.printStatus(
'To avoid potential build failures, you can quickly migrate your app '
......@@ -404,7 +404,7 @@ Future<void> buildGradleApp({
if (exitCode != 0) {
if (detectedGradleError == null) {
BuildEvent('gradle-unkown-failure').send();
BuildEvent('gradle-unkown-failure', flutterUsage: globals.flutterUsage).send();
throwToolExit(
'Gradle task $assembleTask failed with exit code $exitCode',
exitCode: exitCode,
......@@ -430,7 +430,7 @@ Future<void> buildGradleApp({
shouldBuildPluginAsAar: shouldBuildPluginAsAar,
retries: retries - 1,
);
BuildEvent(successEventLabel).send();
BuildEvent(successEventLabel, flutterUsage: globals.flutterUsage).send();
return;
case GradleBuildStatus.retryWithAarPlugins:
await buildGradleApp(
......@@ -442,13 +442,13 @@ Future<void> buildGradleApp({
shouldBuildPluginAsAar: true,
retries: retries - 1,
);
BuildEvent(successEventLabel).send();
BuildEvent(successEventLabel, flutterUsage: globals.flutterUsage).send();
return;
case GradleBuildStatus.exit:
// noop.
}
}
BuildEvent('gradle-${detectedGradleError.eventLabel}-failure').send();
BuildEvent('gradle-${detectedGradleError.eventLabel}-failure', flutterUsage: globals.flutterUsage).send();
throwToolExit(
'Gradle task $assembleTask failed with exit code $exitCode',
exitCode: exitCode,
......@@ -697,7 +697,7 @@ String _calculateSha(File file) {
}
void _exitWithUnsupportedProjectMessage() {
BuildEvent('unsupported-project', eventError: 'gradle-plugin').send();
BuildEvent('unsupported-project', eventError: 'gradle-plugin', flutterUsage: globals.flutterUsage).send();
throwToolExit(
'$warningMark Your app is using an unsupported Gradle project. '
'To fix this problem, create a new project by running `flutter create -t app <app-directory>` '
......@@ -706,7 +706,7 @@ void _exitWithUnsupportedProjectMessage() {
}
void _exitWithProjectNotUsingGradleMessage() {
BuildEvent('unsupported-project', eventError: 'app-not-using-gradle').send();
BuildEvent('unsupported-project', eventError: 'app-not-using-gradle', flutterUsage: globals.flutterUsage).send();
throwToolExit(
'$warningMark The build process for Android has changed, and the '
'current project configuration is no longer valid. Please consult\n\n'
......@@ -770,7 +770,7 @@ Future<void> buildPluginsAsAar(
} on ToolExit {
// Log the entire plugin entry in `.flutter-plugins` since it
// includes the plugin name and the version.
BuildEvent('gradle-plugin-aar-failure', eventError: plugin).send();
BuildEvent('gradle-plugin-aar-failure', eventError: plugin, flutterUsage: globals.flutterUsage).send();
throwToolExit('The plugin $pluginName could not be built due to the issue above.');
}
}
......@@ -866,12 +866,13 @@ void _exitWithExpectedFileNotFound({
assert(fileExtension != null);
final String androidGradlePluginVersion =
getGradleVersionForAndroidPlugin(project.android.hostAppGradleRoot);
getGradleVersionForAndroidPlugin(project.android.hostAppGradleRoot);
BuildEvent('gradle-expected-file-not-found',
settings:
'androidGradlePluginVersion: $androidGradlePluginVersion, '
'fileExtension: $fileExtension'
).send();
'androidGradlePluginVersion: $androidGradlePluginVersion, '
'fileExtension: $fileExtension',
flutterUsage: globals.flutterUsage,
).send();
throwToolExit(
'Gradle build failed to produce an $fileExtension file. '
"It's likely that this file was generated under ${project.android.buildDirectory.path}, "
......
......@@ -183,6 +183,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent(
'gradle-android-x-failure',
eventError: 'app-not-using-plugins',
flutterUsage: globals.flutterUsage,
).send();
}
if (hasPlugins && !usesAndroidX) {
......@@ -195,6 +196,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent(
'gradle-android-x-failure',
eventError: 'app-not-using-androidx',
flutterUsage: globals.flutterUsage,
).send();
}
if (hasPlugins && usesAndroidX && shouldBuildPluginAsAar) {
......@@ -204,6 +206,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent(
'gradle-android-x-failure',
eventError: 'using-jetifier',
flutterUsage: globals.flutterUsage,
).send();
}
if (hasPlugins && usesAndroidX && !shouldBuildPluginAsAar) {
......@@ -214,6 +217,7 @@ final GradleHandledError androidXFailureHandler = GradleHandledError(
BuildEvent(
'gradle-android-x-failure',
eventError: 'not-using-jetifier',
flutterUsage: globals.flutterUsage,
).send();
return GradleBuildStatus.retryWithAarPlugins;
}
......
......@@ -301,7 +301,7 @@ void writeLocalProperties(File properties) {
}
void exitWithNoSdkMessage() {
BuildEvent('unsupported-project', eventError: 'android-sdk-not-found').send();
BuildEvent('unsupported-project', eventError: 'android-sdk-not-found', flutterUsage: globals.flutterUsage).send();
throwToolExit(
'$warningMark No Android SDK found. '
'Try setting the ANDROID_HOME environment variable.'
......
......@@ -89,7 +89,7 @@ class BuildIOSCommand extends BuildSubCommand {
);
if (!result.success) {
await diagnoseXcodeBuildFailure(result);
await diagnoseXcodeBuildFailure(result, globals.flutterUsage, globals.logger);
throwToolExit('Encountered error while building for $logTarget.');
}
......
......@@ -220,6 +220,7 @@ Future<T> runInContext<T>(
platform: globals.platform,
fileSystem: globals.fs,
terminal: globals.terminal,
usage: globals.flutterUsage,
),
},
);
......
......@@ -242,7 +242,7 @@ class IOSDevice extends Device {
);
if (!buildResult.success) {
_logger.printError('Could not build the precompiled application for the device.');
await diagnoseXcodeBuildFailure(buildResult);
await diagnoseXcodeBuildFailure(buildResult, globals.flutterUsage, _logger);
_logger.printError('');
return LaunchResult.failed();
}
......@@ -338,6 +338,7 @@ class IOSDevice extends Device {
mDnsObservatoryDiscovery: MDnsObservatoryDiscovery.instance,
portForwarder: portForwarder,
protocolDiscovery: observatoryDiscovery,
flutterUsage: globals.flutterUsage,
);
final Uri localUri = await fallbackDiscovery.discover(
assumedDevicePort: assumedObservatoryPort,
......
......@@ -9,7 +9,6 @@ import 'package:vm_service/vm_service_io.dart' as vm_service_io;
import '../base/io.dart';
import '../base/logger.dart';
import '../device.dart';
import '../globals.dart' as globals;
import '../mdns_discovery.dart';
import '../protocol_discovery.dart';
import '../reporting/reporting.dart';
......@@ -42,12 +41,14 @@ class FallbackDiscovery {
@required MDnsObservatoryDiscovery mDnsObservatoryDiscovery,
@required Logger logger,
@required ProtocolDiscovery protocolDiscovery,
@required Usage flutterUsage,
Future<VmService> Function(String wsUri, {Log log}) vmServiceConnectUri =
vm_service_io.vmServiceConnectUri,
}) : _logger = logger,
_mDnsObservatoryDiscovery = mDnsObservatoryDiscovery,
_portForwarder = portForwarder,
_protocolDiscovery = protocolDiscovery,
_flutterUsage = flutterUsage,
_vmServiceConnectUri = vmServiceConnectUri;
static const String _kEventName = 'ios-handshake';
......@@ -56,6 +57,7 @@ class FallbackDiscovery {
final MDnsObservatoryDiscovery _mDnsObservatoryDiscovery;
final Logger _logger;
final ProtocolDiscovery _protocolDiscovery;
final Usage _flutterUsage;
final Future<VmService> Function(String wsUri, {Log log}) _vmServiceConnectUri;
/// Attempt to discover the observatory port.
......@@ -87,7 +89,7 @@ class FallbackDiscovery {
UsageEvent(
_kEventName,
'mdns-success',
flutterUsage: globals.flutterUsage,
flutterUsage: _flutterUsage,
).send();
return result;
}
......@@ -98,7 +100,7 @@ class FallbackDiscovery {
UsageEvent(
_kEventName,
'mdns-failure',
flutterUsage: globals.flutterUsage,
flutterUsage: _flutterUsage,
).send();
try {
......@@ -107,7 +109,7 @@ class FallbackDiscovery {
UsageEvent(
_kEventName,
'fallback-success',
flutterUsage: globals.flutterUsage,
flutterUsage: _flutterUsage,
).send();
return result;
}
......@@ -121,7 +123,7 @@ class FallbackDiscovery {
UsageEvent(
_kEventName,
'fallback-failure',
flutterUsage: globals.flutterUsage,
flutterUsage: _flutterUsage,
).send();
return null;
}
......@@ -167,7 +169,7 @@ class FallbackDiscovery {
UsageEvent(
_kEventName,
'success',
flutterUsage: globals.flutterUsage,
flutterUsage: _flutterUsage,
).send();
return Uri.parse('http://localhost:$hostPort');
}
......@@ -207,7 +209,7 @@ class FallbackDiscovery {
_kEventName,
eventAction,
label: eventLabel,
flutterUsage: globals.flutterUsage,
flutterUsage: _flutterUsage,
).send();
}
}
......@@ -342,6 +342,7 @@ Future<XcodeBuildResult> buildXcodeProject({
if (e.toString().contains('timed out')) {
BuildEvent('xcode-show-build-settings-timeout',
command: showBuildSettingsCommand.join(' '),
flutterUsage: globals.flutterUsage,
).send();
}
rethrow;
......@@ -447,13 +448,14 @@ return result.exitCode != 0 &&
result.stdout.contains('there are two concurrent builds running');
}
Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsage, Logger logger) async {
if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice &&
result.stdout?.toUpperCase()?.contains('BITCODE') == true) {
BuildEvent('xcode-bitcode-failure',
command: result.xcodeBuildExecution.buildCommands.toString(),
settings: result.xcodeBuildExecution.buildSettings.toString(),
flutterUsage: flutterUsage,
).send();
}
......@@ -463,11 +465,11 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
if (result.stdout?.contains('Building for iOS') == true
&& result.stdout?.contains('but the linked and embedded framework') == true
&& result.stdout?.contains('was built for iOS') == true) {
globals.printError('');
globals.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
globals.printError('');
globals.printError('You can temporarily work around this issue by running:');
globals.printError(' rm -rf ios/Flutter/App.framework');
logger.printError('');
logger.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
logger.printError('');
logger.printError('You can temporarily work around this issue by running:');
logger.printError(' rm -rf ios/Flutter/App.framework');
return;
}
......@@ -476,7 +478,7 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
result.stdout?.contains('BCEROR') == true &&
// May need updating if Xcode changes its outputs.
result.stdout?.contains("Xcode couldn't find a provisioning profile matching") == true) {
globals.printError(noProvisioningProfileInstruction, emphasis: true);
logger.printError(noProvisioningProfileInstruction, emphasis: true);
return;
}
// Make sure the user has specified one of:
......@@ -486,26 +488,26 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
result.xcodeBuildExecution.buildForPhysicalDevice &&
!<String>['DEVELOPMENT_TEAM', 'PROVISIONING_PROFILE'].any(
result.xcodeBuildExecution.buildSettings.containsKey)) {
globals.printError(noDevelopmentTeamInstruction, emphasis: true);
logger.printError(noDevelopmentTeamInstruction, emphasis: true);
return;
}
if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice &&
result.xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') == true) {
globals.printError('');
globals.printError('It appears that your application still contains the default signing identifier.');
globals.printError("Try replacing 'com.example' with your signing id in Xcode:");
globals.printError(' open ios/Runner.xcworkspace');
logger.printError('');
logger.printError('It appears that your application still contains the default signing identifier.');
logger.printError("Try replacing 'com.example' with your signing id in Xcode:");
logger.printError(' open ios/Runner.xcworkspace');
return;
}
if (result.stdout?.contains('Code Sign error') == true) {
globals.printError('');
globals.printError('It appears that there was a problem signing your application prior to installation on the device.');
globals.printError('');
globals.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
globals.printError(' open ios/Runner.xcworkspace');
globals.printError('');
globals.printError("Also try selecting 'Product > Build' to fix the problem:");
logger.printError('');
logger.printError('It appears that there was a problem signing your application prior to installation on the device.');
logger.printError('');
logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
logger.printError(' open ios/Runner.xcworkspace');
logger.printError('');
logger.printError("Also try selecting 'Product > Build' to fix the problem:");
return;
}
}
......
......@@ -254,17 +254,20 @@ class XcodeProjectInterpreter {
@required Logger logger,
@required FileSystem fileSystem,
@required Terminal terminal,
@required Usage usage,
}) : _platform = platform,
_fileSystem = fileSystem,
_terminal = terminal,
_logger = logger,
_processUtils = ProcessUtils(logger: logger, processManager: processManager);
_fileSystem = fileSystem,
_terminal = terminal,
_logger = logger,
_processUtils = ProcessUtils(logger: logger, processManager: processManager),
_usage = usage;
final Platform _platform;
final FileSystem _fileSystem;
final ProcessUtils _processUtils;
final Terminal _terminal;
final Logger _logger;
final Usage _usage;
static const String _executable = '/usr/bin/xcodebuild';
static final RegExp _versionRegex = RegExp(r'Xcode ([0-9.]+)');
......@@ -359,6 +362,7 @@ class XcodeProjectInterpreter {
if (error is ProcessException && error.toString().contains('timed out')) {
BuildEvent('xcode-show-build-settings-timeout',
command: showBuildSettingsCommand.join(' '),
flutterUsage: _usage,
).send();
}
_logger.printTrace('Unexpected failure to get the build settings: $error.');
......
......@@ -135,10 +135,14 @@ class PubResultEvent extends UsageEvent {
/// An event that reports something about a build.
class BuildEvent extends UsageEvent {
BuildEvent(String label, {
this.command,
this.settings,
this.eventError,
}) : super(
String command,
String settings,
String eventError,
@required Usage flutterUsage,
}) : _command = command,
_settings = settings,
_eventError = eventError,
super(
// category
'build',
// parameter
......@@ -146,22 +150,22 @@ class BuildEvent extends UsageEvent {
? 'unspecified'
: FlutterCommand.current.name,
label: label,
flutterUsage: globals.flutterUsage,
flutterUsage: flutterUsage,
);
final String command;
final String settings;
final String eventError;
final String _command;
final String _settings;
final String _eventError;
@override
void send() {
final Map<String, String> parameters = _useCdKeys(<CustomDimensions, String>{
if (command != null)
CustomDimensions.buildEventCommand: command,
if (settings != null)
CustomDimensions.buildEventSettings: settings,
if (eventError != null)
CustomDimensions.buildEventError: eventError,
if (_command != null)
CustomDimensions.buildEventCommand: _command,
if (_settings != null)
CustomDimensions.buildEventSettings: _settings,
if (_eventError != null)
CustomDimensions.buildEventError: _eventError,
});
flutterUsage.sendEvent(
category,
......
......@@ -83,6 +83,8 @@ abstract class Usage {
analyticsIOFactory: analyticsIOFactory,
runningOnBot: runningOnBot);
factory Usage.test() => _DefaultUsage.test();
/// Uses the global [Usage] instance to send a 'command' to analytics.
static void command(String command, {
Map<CustomDimensions, String> parameters,
......@@ -265,6 +267,10 @@ class _DefaultUsage implements Usage {
_analytics.analyticsOpt = AnalyticsOpt.optOut;
}
_DefaultUsage.test() :
_suppressAnalytics = true,
_analytics = AnalyticsMock();
Analytics _analytics;
bool _printedWelcome = false;
......
......@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/base/build.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import '../../src/common.dart';
import '../../src/context.dart';
......@@ -189,6 +190,7 @@ void main() {
logger: logger,
fileSystem: fileSystem,
terminal: Terminal.test(),
usage: Usage.test(),
),
),
artifacts: mockArtifacts,
......
......@@ -8,15 +8,14 @@ import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/fallback_discovery.dart';
import 'package:flutter_tools/src/mdns_discovery.dart';
import 'package:flutter_tools/src/protocol_discovery.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:vm_service/vm_service.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
// This test still uses `testUsingContext` due to analytics usage.
void main() {
BufferLogger logger;
FallbackDiscovery fallbackDiscovery;
......@@ -39,6 +38,7 @@ void main() {
mDnsObservatoryDiscovery: mockMDnsObservatoryDiscovery,
portForwarder: mockPortForwarder,
protocolDiscovery: mockPrototcolDiscovery,
flutterUsage: Usage.test(),
vmServiceConnectUri: (String uri, {Log log}) async {
return mockVmService;
},
......@@ -47,7 +47,7 @@ void main() {
.thenAnswer((Invocation invocation) async => 1);
});
testUsingContext('Selects assumed port if VM service connection is successful', () async {
testWithoutContext('Selects assumed port if VM service connection is successful', () async {
when(mockVmService.getVM()).thenAnswer((Invocation invocation) async {
return VM.parse(<String, Object>{})..isolates = <IsolateRef>[
IsolateRef.parse(<String, Object>{}),
......@@ -68,7 +68,7 @@ void main() {
), Uri.parse('http://localhost:1'));
});
testUsingContext('Selects assumed port when another isolate has no root library', () async {
testWithoutContext('Selects assumed port when another isolate has no root library', () async {
when(mockVmService.getVM()).thenAnswer((Invocation invocation) async {
return VM.parse(<String, Object>{})..isolates = <IsolateRef>[
IsolateRef.parse(<String, Object>{})..id = '1',
......@@ -93,7 +93,7 @@ void main() {
), Uri.parse('http://localhost:1'));
});
testUsingContext('Selects mdns discovery if VM service connecton fails due to Sentinel', () async {
testWithoutContext('Selects mdns discovery if VM service connecton fails due to Sentinel', () async {
when(mockVmService.getVM()).thenAnswer((Invocation invocation) async {
return VM.parse(<String, Object>{})..isolates = <IsolateRef>[
IsolateRef(
......@@ -124,7 +124,7 @@ void main() {
), Uri.parse('http://localhost:1234'));
});
testUsingContext('Selects mdns discovery if VM service connecton fails', () async {
testWithoutContext('Selects mdns discovery if VM service connecton fails', () async {
when(mockVmService.getVM()).thenThrow(Exception());
when(mockMDnsObservatoryDiscovery.getObservatoryUri(
......@@ -146,7 +146,7 @@ void main() {
), Uri.parse('http://localhost:1234'));
});
testUsingContext('Selects log scanning if both VM Service and mDNS fails', () async {
testWithoutContext('Selects log scanning if both VM Service and mDNS fails', () async {
when(mockVmService.getVM()).thenThrow(Exception());
when(mockMDnsObservatoryDiscovery.getObservatoryUri(
'hello',
......
......@@ -132,7 +132,7 @@ void main() {
),
);
await diagnoseXcodeBuildFailure(buildResult);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
verify(mockUsage.sendEvent('build',
any,
label: 'xcode-bitcode-failure',
......@@ -140,8 +140,6 @@ void main() {
cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(),
cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(),
})).called(1);
}, overrides: <Type, Generator>{
Usage: () => mockUsage,
});
testUsingContext('No provisioning profile shows message', () async {
......@@ -210,9 +208,9 @@ Error launching application on iPhone.''',
),
);
await diagnoseXcodeBuildFailure(buildResult);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect(
testLogger.errorText,
logger.errorText,
contains("No Provisioning Profile was found for your project's Bundle Identifier or your \ndevice."),
);
}, overrides: noColorTerminalOverride);
......@@ -291,9 +289,9 @@ Could not build the precompiled application for the device.''',
),
);
await diagnoseXcodeBuildFailure(buildResult);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect(
testLogger.errorText,
logger.errorText,
contains('Building a deployable iOS app requires a selected Development Team with a \nProvisioning Profile.'),
);
}, overrides: noColorTerminalOverride);
......@@ -328,9 +326,9 @@ Exited (sigterm)''',
),
);
await diagnoseXcodeBuildFailure(buildResult);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect(
testLogger.errorText,
logger.errorText,
contains('Your Xcode project requires migration.'),
);
}, overrides: noColorTerminalOverride);
......@@ -365,9 +363,9 @@ Exited (sigterm)''',
),
);
await diagnoseXcodeBuildFailure(buildResult);
await diagnoseXcodeBuildFailure(buildResult, mockUsage, logger);
expect(
testLogger.errorText,
logger.errorText,
contains('Your Xcode project requires migration.'),
);
}, overrides: noColorTerminalOverride);
......
......@@ -13,6 +13,7 @@ import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart';
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';
import 'package:platform/platform.dart';
......@@ -48,6 +49,7 @@ void main() {
platform: platform,
processManager: processManager,
terminal: terminal,
usage: null,
);
});
......@@ -130,6 +132,7 @@ void main() {
platform: platform,
processManager: processManager,
terminal: terminal,
usage: Usage.test(),
);
fileSystem.file(xcodebuild).deleteSync();
......@@ -261,6 +264,7 @@ void main() {
platform: platform,
processManager: processManager,
terminal: terminal,
usage: Usage.test(),
);
expect(await xcodeProjectInterpreter.getInfo(workingDirectory), isNotNull);
......@@ -282,6 +286,7 @@ void main() {
platform: platform,
processManager: processManager,
terminal: terminal,
usage: Usage.test(),
);
expect(
......
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