diff --git a/dev/benchmarks/complex_layout/fuchsia/meta/complex_layout.cmx b/dev/benchmarks/complex_layout/fuchsia/meta/complex_layout.cmx deleted file mode 100644 index bbe88bf05c5..00000000000 --- a/dev/benchmarks/complex_layout/fuchsia/meta/complex_layout.cmx +++ /dev/null @@ -1,22 +0,0 @@ -{ - "program": { - "data": "data/complex_layout" - }, - "sandbox": { - "services": [ - "fuchsia.cobalt.LoggerFactory", - "fuchsia.fonts.Provider", - "fuchsia.logger.LogSink", - "fuchsia.modular.Clipboard", - "fuchsia.modular.ContextWriter", - "fuchsia.modular.DeviceMap", - "fuchsia.modular.ModuleContext", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.testing.runner.TestRunner", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.policy.Presenter", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/dev/benchmarks/test_apps/stocks/fuchsia/meta/stocks.cmx b/dev/benchmarks/test_apps/stocks/fuchsia/meta/stocks.cmx deleted file mode 100644 index 6a1acee575b..00000000000 --- a/dev/benchmarks/test_apps/stocks/fuchsia/meta/stocks.cmx +++ /dev/null @@ -1,22 +0,0 @@ -{ - "program": { - "data": "data/stocks" - }, - "sandbox": { - "services": [ - "fuchsia.cobalt.LoggerFactory", - "fuchsia.fonts.Provider", - "fuchsia.logger.LogSink", - "fuchsia.modular.Clipboard", - "fuchsia.modular.ContextWriter", - "fuchsia.modular.DeviceMap", - "fuchsia.modular.ModuleContext", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.testing.runner.TestRunner", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.policy.Presenter", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/dev/integration_tests/flutter_gallery/fuchsia/meta/flutter_gallery.cmx b/dev/integration_tests/flutter_gallery/fuchsia/meta/flutter_gallery.cmx deleted file mode 100644 index 42bef318461..00000000000 --- a/dev/integration_tests/flutter_gallery/fuchsia/meta/flutter_gallery.cmx +++ /dev/null @@ -1,18 +0,0 @@ -{ - "program": { - "data": "data/flutter_gallery" - }, - "sandbox": { - "services": [ - "fuchsia.cobalt.LoggerFactory", - "fuchsia.fonts.Provider", - "fuchsia.logger.LogSink", - "fuchsia.modular.Clipboard", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.policy.Presenter", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/dev/integration_tests/flutter_gallery/meta/flutter_gallery.cmx b/dev/integration_tests/flutter_gallery/meta/flutter_gallery.cmx deleted file mode 100644 index e3e3be8758a..00000000000 --- a/dev/integration_tests/flutter_gallery/meta/flutter_gallery.cmx +++ /dev/null @@ -1,22 +0,0 @@ -{ - "program": { - "data": "data/flutter_gallery" - }, - "sandbox": { - "services": [ - "fuchsia.cobalt.LoggerFactory", - "fuchsia.fonts.Provider", - "fuchsia.logger.LogSink", - "fuchsia.modular.Clipboard", - "fuchsia.modular.ContextWriter", - "fuchsia.modular.DeviceMap", - "fuchsia.modular.ModuleContext", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.testing.runner.TestRunner", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.policy.Presenter", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/dev/integration_tests/ui/fuchsia/meta/integration_ui.cmx b/dev/integration_tests/ui/fuchsia/meta/integration_ui.cmx deleted file mode 100644 index 06187c43521..00000000000 --- a/dev/integration_tests/ui/fuchsia/meta/integration_ui.cmx +++ /dev/null @@ -1,22 +0,0 @@ -{ - "program": { - "data": "data/integration_ui" - }, - "sandbox": { - "services": [ - "fuchsia.cobalt.LoggerFactory", - "fuchsia.fonts.Provider", - "fuchsia.logger.LogSink", - "fuchsia.modular.Clipboard", - "fuchsia.modular.ContextWriter", - "fuchsia.modular.DeviceMap", - "fuchsia.modular.ModuleContext", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.testing.runner.TestRunner", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.policy.Presenter", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/examples/hello_world/fuchsia/meta/hello_world.cmx b/examples/hello_world/fuchsia/meta/hello_world.cmx deleted file mode 100644 index f68343617fa..00000000000 --- a/examples/hello_world/fuchsia/meta/hello_world.cmx +++ /dev/null @@ -1,18 +0,0 @@ -{ - "program": { - "data": "data/hello_world" - }, - "sandbox": { - "services": [ - "fuchsia.cobalt.LoggerFactory", - "fuchsia.fonts.Provider", - "fuchsia.logger.LogSink", - "fuchsia.modular.Clipboard", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.policy.Presenter", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart index b36e2223f35..09fe09d9cbf 100644 --- a/packages/flutter_tools/lib/src/commands/build.dart +++ b/packages/flutter_tools/lib/src/commands/build.dart @@ -14,7 +14,6 @@ import 'build_aar.dart'; import 'build_apk.dart'; import 'build_appbundle.dart'; import 'build_bundle.dart'; -import 'build_fuchsia.dart'; import 'build_ios.dart'; import 'build_ios_framework.dart'; import 'build_macos_framework.dart'; @@ -43,7 +42,6 @@ class BuildCommand extends FlutterCommand { verboseHelp: verboseHelp )); _addSubcommand(BuildWindowsCommand(verboseHelp: verboseHelp)); - _addSubcommand(BuildFuchsiaCommand(verboseHelp: verboseHelp)); } void _addSubcommand(BuildSubCommand command) { @@ -83,8 +81,11 @@ abstract class BuildSubCommand extends FlutterCommand { @protected void displayNullSafetyMode(BuildInfo buildInfo) { globals.printStatus(''); - if (buildInfo.nullSafetyMode == NullSafetyMode.sound) { - globals.printStatus('💪 Building with sound null safety 💪', emphasis: true); + if (buildInfo.nullSafetyMode == NullSafetyMode.sound) { + globals.printStatus( + '💪 Building with sound null safety 💪', + emphasis: true, + ); } else { globals.printStatus( 'Building without sound null safety', diff --git a/packages/flutter_tools/lib/src/commands/build_fuchsia.dart b/packages/flutter_tools/lib/src/commands/build_fuchsia.dart deleted file mode 100644 index e0f5fcdee71..00000000000 --- a/packages/flutter_tools/lib/src/commands/build_fuchsia.dart +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import '../base/common.dart'; -import '../build_info.dart'; -import '../cache.dart'; -import '../features.dart'; -import '../fuchsia/fuchsia_build.dart'; -import '../fuchsia/fuchsia_pm.dart'; -import '../globals.dart' as globals; -import '../project.dart'; -import '../runner/flutter_command.dart' show FlutterCommandResult; -import 'build.dart'; - -/// A command to build a Fuchsia target. -class BuildFuchsiaCommand extends BuildSubCommand { - BuildFuchsiaCommand({ - required bool verboseHelp, - }) : super(verboseHelp: verboseHelp) { - addTreeShakeIconsFlag(); - usesTargetOption(); - usesDartDefineOption(); - addBuildModeFlags(verboseHelp: verboseHelp); - addNullSafetyModeOptions(hide: !verboseHelp); - addEnableExperimentation(hide: !verboseHelp); - argParser.addOption( - 'runner-source', - help: 'The package source to use for the flutter_runner. ' - '"${FuchsiaPackageServer.deviceHost}" implies using a runner already on the device. ' - '"${FuchsiaPackageServer.toolHost}" implies using a runner distributed with Flutter.', - allowed: [ - FuchsiaPackageServer.deviceHost, - FuchsiaPackageServer.toolHost, - ], - defaultsTo: FuchsiaPackageServer.toolHost, - ); - argParser.addOption('target-platform', - defaultsTo: 'fuchsia-x64', - allowed: ['fuchsia-arm64', 'fuchsia-x64'], - help: 'The target platform for which the app is compiled.', - ); - } - - @override - final String name = 'fuchsia'; - - @override - bool hidden = true; - - @override - Future> get requiredArtifacts async => { - DevelopmentArtifact.fuchsia, - }; - - @override - String get description => 'Build the Fuchsia target (Experimental).'; - - @override - bool get supported => globals.platform.isLinux || globals.platform.isMacOS; - - @override - Future runCommand() async { - if (!featureFlags.isFuchsiaEnabled) { - throwToolExit( - '"build fuchsia" is currently disabled. See "flutter config" for more ' - 'information.' - ); - } - final BuildInfo buildInfo = await getBuildInfo(); - final FlutterProject flutterProject = FlutterProject.current(); - if (!supported) { - throwToolExit('"build fuchsia" is only supported on Linux and MacOS hosts.'); - } - if (!flutterProject.fuchsia.existsSync()) { - throwToolExit('No Fuchsia project is configured.'); - } - displayNullSafetyMode(buildInfo); - await buildFuchsia( - fuchsiaProject: flutterProject.fuchsia, - target: targetFile, - targetPlatform: getTargetPlatformForName(stringArgDeprecated('target-platform')!), - buildInfo: buildInfo, - runnerPackageSource: stringArgDeprecated('runner-source')!, - ); - return FlutterCommandResult.success(); - } -} diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart deleted file mode 100644 index 41a07fa2eda..00000000000 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import '../artifacts.dart'; -import '../asset.dart'; -import '../base/common.dart'; -import '../base/file_system.dart'; -import '../base/logger.dart'; -import '../base/utils.dart'; -import '../build_info.dart'; -import '../bundle_builder.dart'; -import '../convert.dart'; -import '../devfs.dart'; -import '../globals.dart' as globals; -import '../project.dart'; - -import 'fuchsia_pm.dart'; - -Future _timedBuildStep(String name, Future Function() action) async { - final Stopwatch sw = Stopwatch()..start(); - await action(); - globals.printTrace('$name: ${sw.elapsedMilliseconds} ms.'); - globals.flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds)); -} - -Future _validateCmxFile(FuchsiaProject fuchsiaProject) async { - final String appName = fuchsiaProject.project.manifest.appName; - final String cmxPath = globals.fs.path.join(fuchsiaProject.meta.path, '$appName.cmx'); - final File cmxFile = globals.fs.file(cmxPath); - if (!await cmxFile.exists()) { - throwToolExit('The Fuchsia build requires a .cmx file at $cmxPath for the app: $appName.'); - } -} - -// Building a Fuchsia package has a few steps: -// 1. Do the custom kernel compile using the kernel compiler from the Fuchsia -// SDK. This produces .dilp files (among others) and a manifest file. -// 2. Create a manifest file for assets. -// 3. Using these manifests, use the Fuchsia SDK 'pm' tool to create the -// Fuchsia package. -Future buildFuchsia({ - required FuchsiaProject fuchsiaProject, - required TargetPlatform targetPlatform, - String? target, // E.g., lib/main.dart - BuildInfo buildInfo = BuildInfo.debug, - String runnerPackageSource = FuchsiaPackageServer.toolHost, -}) async { - final String targetPath = target ??= 'lib/main.dart'; - await _validateCmxFile(fuchsiaProject); - final Directory outDir = globals.fs.directory(getFuchsiaBuildDirectory()); - if (!outDir.existsSync()) { - outDir.createSync(recursive: true); - } - - await _timedBuildStep('fuchsia-kernel-compile', - () => globals.fuchsiaSdk!.fuchsiaKernelCompiler.build( - fuchsiaProject: fuchsiaProject, target: targetPath, buildInfo: buildInfo)); - - if (buildInfo.usesAot) { - await _timedBuildStep('fuchsia-gen-snapshot', - () => _genSnapshot(fuchsiaProject, targetPath, buildInfo, targetPlatform)); - } - - await _timedBuildStep('fuchsia-build-assets', - () => _buildAssets(fuchsiaProject, targetPath, buildInfo)); - await _timedBuildStep('fuchsia-build-package', - () => _buildPackage(fuchsiaProject, targetPath, buildInfo, runnerPackageSource)); -} - -Future _genSnapshot( - FuchsiaProject fuchsiaProject, - String target, // lib/main.dart - BuildInfo buildInfo, - TargetPlatform targetPlatform, -) async { - final String outDir = getFuchsiaBuildDirectory(); - final String appName = fuchsiaProject.project.manifest.appName; - final String dilPath = globals.fs.path.join(outDir, '$appName.dil'); - - final String elf = globals.fs.path.join(outDir, 'elf.aotsnapshot'); - - final String genSnapshot = globals.artifacts!.getArtifactPath( - Artifact.genSnapshot, - platform: targetPlatform, - mode: buildInfo.mode, - ); - - final List command = [ - genSnapshot, - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=$elf', - if (buildInfo.isDebug) '--enable-asserts', - dilPath, - ]; - int result; - final Status status = globals.logger.startProgress( - 'Compiling Fuchsia application to native code...', - ); - try { - result = await globals.processUtils.stream(command, trace: true); - } finally { - status.cancel(); - } - if (result != 0) { - throwToolExit('Build process failed'); - } -} - -Future _buildAssets( - FuchsiaProject fuchsiaProject, - String target, // lib/main.dart - BuildInfo buildInfo, -) async { - final String assetDir = getAssetBuildDirectory(); - final AssetBundle? assets = await buildAssets( - manifestPath: fuchsiaProject.project.pubspecFile.path, - packagesPath: fuchsiaProject.project.packagesFile.path, - assetDirPath: assetDir, - ); - - if (assets == null) { - throwToolExit('Unable to find assets.', exitCode: 1); - } - - final Map assetEntries = Map.of( - assets.entries, - ); - await writeBundle(globals.fs.directory(assetDir), assetEntries, assets.entryKinds); - - final String appName = fuchsiaProject.project.manifest.appName; - final String outDir = getFuchsiaBuildDirectory(); - final String assetManifest = globals.fs.path.join(outDir, '${appName}_pkgassets'); - - final File destFile = globals.fs.file(assetManifest); - await destFile.create(recursive: true); - final IOSink outFile = destFile.openWrite(); - - for (final String path in assets.entries.keys) { - outFile.write('data/$appName/$path=$assetDir/$path\n'); - } - await outFile.flush(); - await outFile.close(); -} - -void _rewriteCmx(BuildMode mode, String runnerPackageSource, File src, File dst) { - final Map cmx = castStringKeyedMap(json.decode(src.readAsStringSync())) ?? {}; - // If the app author has already specified the runner in the cmx file, then - // do not override it with something else. - if (cmx.containsKey('runner')) { - dst.writeAsStringSync(json.encode(cmx)); - return; - } - String runner; - switch (mode) { - case BuildMode.debug: - runner = 'flutter_jit_runner'; - break; - case BuildMode.profile: - runner = 'flutter_aot_runner'; - break; - case BuildMode.jitRelease: - runner = 'flutter_jit_product_runner'; - break; - case BuildMode.release: - runner = 'flutter_aot_product_runner'; - break; - default: - throwToolExit('Fuchsia does not support build mode "$mode"'); - } - cmx['runner'] = 'fuchsia-pkg://$runnerPackageSource/$runner#meta/$runner.cmx'; - dst.writeAsStringSync(json.encode(cmx)); -} - -// TODO(zanderso): Allow supplying a signing key. -Future _buildPackage( - FuchsiaProject fuchsiaProject, - String target, // lib/main.dart - BuildInfo buildInfo, - String runnerPackageSource, -) async { - final String outDir = getFuchsiaBuildDirectory(); - final String pkgDir = globals.fs.path.join(outDir, 'pkg'); - final String appName = fuchsiaProject.project.manifest.appName; - final String pkgassets = globals.fs.path.join(outDir, '${appName}_pkgassets'); - final String packageManifest = globals.fs.path.join(pkgDir, 'package_manifest'); - - final Directory pkg = globals.fs.directory(pkgDir); - if (!pkg.existsSync()) { - pkg.createSync(recursive: true); - } - - final File srcCmx = - globals.fs.file(globals.fs.path.join(fuchsiaProject.meta.path, '$appName.cmx')); - final File dstCmx = globals.fs.file(globals.fs.path.join(outDir, '$appName.cmx')); - _rewriteCmx(buildInfo.mode, runnerPackageSource, srcCmx, dstCmx); - - final File manifestFile = globals.fs.file(packageManifest); - - if (buildInfo.usesAot) { - final String elf = globals.fs.path.join(outDir, 'elf.aotsnapshot'); - manifestFile.writeAsStringSync( - 'data/$appName/app_aot_snapshot.so=$elf\n'); - } else { - final String dilpmanifest = globals.fs.path.join(outDir, '$appName.dilpmanifest'); - manifestFile.writeAsStringSync(globals.fs.file(dilpmanifest).readAsStringSync()); - } - - manifestFile.writeAsStringSync(globals.fs.file(pkgassets).readAsStringSync(), - mode: FileMode.append); - manifestFile.writeAsStringSync('meta/$appName.cmx=${dstCmx.path}\n', - mode: FileMode.append); - manifestFile.writeAsStringSync('meta/package=$pkgDir/meta/package\n', - mode: FileMode.append); - - final FuchsiaPM? fuchsiaPM = globals.fuchsiaSdk?.fuchsiaPM; - if (fuchsiaPM == null) { - return; - } - if (!await fuchsiaPM.init(pkgDir, appName)) { - return; - } - if (!await fuchsiaPM.build(pkgDir, packageManifest)) { - return; - } - if (!await fuchsiaPM.archive(pkgDir, packageManifest)) { - return; - } -} diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart index ef7fd60ed2e..fb5645e1a69 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart @@ -23,16 +23,15 @@ import '../device.dart'; import '../device_port_forwarder.dart'; import '../globals.dart' as globals; import '../project.dart'; +import '../runner/flutter_command.dart'; import '../vmservice.dart'; import 'application_package.dart'; -import 'fuchsia_build.dart'; +import 'fuchsia_ffx.dart'; import 'fuchsia_pm.dart'; import 'fuchsia_sdk.dart'; import 'fuchsia_workflow.dart'; import 'pkgctl.dart'; -import 'session_control.dart'; -import 'tiles_ctl.dart'; /// The [FuchsiaDeviceTools] instance. FuchsiaDeviceTools get fuchsiaDeviceTools => context.get()!; @@ -40,8 +39,7 @@ FuchsiaDeviceTools get fuchsiaDeviceTools => context.get()!; /// Fuchsia device-side tools. class FuchsiaDeviceTools { late final FuchsiaPkgctl pkgctl = FuchsiaPkgctl(); - late final FuchsiaTilesCtl tilesCtl = FuchsiaTilesCtl(); - late final FuchsiaSessionControl sessionControl = FuchsiaSessionControl(); + late final FuchsiaFfx ffx = FuchsiaFfx(); } final String _ipv4Loopback = InternetAddress.loopbackIPv4.address; @@ -100,7 +98,7 @@ class _FuchsiaLogReader extends DeviceLogReader { final ApplicationPackage? app = _app; final RegExp matchRegExp = app == null ? _flutterLogOutput - : RegExp('INFO: ${app.name}(\\.cmx)?\\(flutter\\): '); + : RegExp('INFO: ${app.name}(\\.cm)?\\(flutter\\): '); return Stream.eventTransformed( lines, (EventSink output) => _FuchsiaLogSink(output, matchRegExp, startTime), @@ -212,7 +210,7 @@ class FuchsiaDevices extends PollingDeviceDiscovery { } final String name = words[1]; - // TODO(omerlevran): Add support for resolve on the FuchsiaSdk Object. + // TODO(omerlevran): Add support for resolve on the FuchsiaSdk Object. final String? resolvedHost = await _fuchsiaSdk.fuchsiaFfx.resolve(name); if (resolvedHost == null) { _logger.printError('Failed to resolve host for Fuchsia device `$name`'); @@ -225,13 +223,13 @@ class FuchsiaDevices extends PollingDeviceDiscovery { List get wellKnownIds => const []; } - class FuchsiaDevice extends Device { - FuchsiaDevice(super.id, {required this.name}) : super( - platformType: PlatformType.fuchsia, - category: null, - ephemeral: true, - ); + FuchsiaDevice(super.id, {required this.name}) + : super( + platformType: PlatformType.fuchsia, + category: null, + ephemeral: true, + ); @override bool get supportsHotReload => true; @@ -258,14 +256,11 @@ class FuchsiaDevice extends Device { /// Determine if the Fuchsia device is running a session based build. /// - /// If the device is running a session based build, `session_control` should be - /// used to launch apps, otherwise `tiles_ctl` should be used. + /// If the device is running a session based build, `ffx session` should be + /// used to launch apps. Fuchsia flutter apps cannot currently be launched + /// without a session. Future _initIsSession() async { - final RunResult result = await shell('which session_control'); - if (result.exitCode != 0) { - return false; - } - return true; + return await globals.fuchsiaSdk?.fuchsiaFfx.sessionShow() != null; } @override @@ -293,7 +288,8 @@ class FuchsiaDevice extends Device { bool isSupported() => true; @override - bool supportsRuntimeMode(BuildMode buildMode) => buildMode != BuildMode.jitRelease; + bool supportsRuntimeMode(BuildMode buildMode) => + buildMode != BuildMode.jitRelease; @override Future startApp( @@ -313,10 +309,11 @@ class FuchsiaDevice extends Device { } if (!prebuiltApplication) { - await buildFuchsia(fuchsiaProject: FlutterProject.current().fuchsia, - targetPlatform: await targetPlatform, - target: mainPath, - buildInfo: debuggingOptions.buildInfo); + throwToolExit( + 'This tool does not currently build apps for fuchsia.\n' + 'Build the app using a supported Fuchsia workflow.\n' + 'Then use the --${FlutterOptions.kUseApplicationBinary} flag.' + ); } // Stop the app if it's currently running. await stopApp(package); @@ -330,8 +327,8 @@ class FuchsiaDevice extends Device { // Try Start with a fresh package repo in case one was left over from a // previous run. - final Directory packageRepo = - globals.fs.directory(globals.fs.path.join(getFuchsiaBuildDirectory(), '.pkg-repo')); + final Directory packageRepo = globals.fs.directory( + globals.fs.path.join(getFuchsiaBuildDirectory(), '.pkg-repo')); try { if (packageRepo.existsSync()) { packageRepo.deleteSync(recursive: true); @@ -339,7 +336,7 @@ class FuchsiaDevice extends Device { packageRepo.createSync(recursive: true); } on Exception catch (e) { globals.printError('Failed to create Fuchsia package repo directory ' - 'at ${packageRepo.path}: $e'); + 'at ${packageRepo.path}: $e'); return LaunchResult.failed(); } @@ -419,29 +416,20 @@ class FuchsiaDevice extends Device { return LaunchResult.failed(); } - fuchsiaUrl = - 'fuchsia-pkg://$packageServerName/$appName#meta/$appName.cmx'; + fuchsiaUrl = 'fuchsia-pkg://$packageServerName/$appName#meta/$appName.cm'; if (await isSession) { - // Instruct session_control to start the app - if (!await fuchsiaDeviceTools.sessionControl.add(this, fuchsiaUrl)) { - globals.printError('Failed to add the app to session_control'); + // Instruct ffx session to start the app + final bool addedApp = + await globals.fuchsiaSdk?.fuchsiaFfx.sessionAdd(fuchsiaUrl) ?? false; + if (!addedApp) { + globals.printError('Failed to add the app via `ffx session add`'); return LaunchResult.failed(); } } else { - // Ensure tiles_ctl is started, and start the app. - if (!await FuchsiaTilesCtl.ensureStarted(this)) { - globals.printError( - 'Failed to ensure that tiles is started on the device'); - return LaunchResult.failed(); - } - - // Instruct tiles_ctl to start the app. - if (!await fuchsiaDeviceTools.tilesCtl - .add(this, fuchsiaUrl, [])) { - globals.printError('Failed to add the app to tiles'); - return LaunchResult.failed(); - } + globals.printError( + 'Fuchsia flutter apps can only be launched within a session'); + return LaunchResult.failed(); } } finally { // Try to un-teach the package controller about the package server if @@ -491,13 +479,8 @@ class FuchsiaDevice extends Device { // using the session framework afaik. So this is a no-op. return true; } - final int appKey = await FuchsiaTilesCtl.findAppKey(this, app.id); - if (appKey != -1) { - if (!await fuchsiaDeviceTools.tilesCtl.remove(this, appKey)) { - globals.printError('tiles_ctl remove on ${app.id} failed.'); - return false; - } - } + // Fuchsia flutter apps currently require a session, but if that changes, + // add the relevant "stopApp" code here. return true; } @@ -537,12 +520,15 @@ class FuchsiaDevice extends Device { if (outputFile.basename.split('.').last != 'ppm') { throw Exception('${outputFile.path} must be a .ppm file'); } - final RunResult screencapResult = await shell('screencap > /tmp/screenshot.ppm'); + final RunResult screencapResult = + await shell('screencap > /tmp/screenshot.ppm'); if (screencapResult.exitCode != 0) { - throw Exception('Could not take a screenshot on device $name:\n$screencapResult'); + throw Exception( + 'Could not take a screenshot on device $name:\n$screencapResult'); } try { - final RunResult scpResult = await scp('/tmp/screenshot.ppm', outputFile.path); + final RunResult scpResult = + await scp('/tmp/screenshot.ppm', outputFile.path); if (scpResult.exitCode != 0) { throw Exception('Failed to copy screenshot from device:\n$scpResult'); } @@ -551,13 +537,11 @@ class FuchsiaDevice extends Device { final RunResult deleteResult = await shell('rm /tmp/screenshot.ppm'); if (deleteResult.exitCode != 0) { globals.printError( - 'Failed to delete screenshot.ppm from the device:\n$deleteResult' - ); + 'Failed to delete screenshot.ppm from the device:\n$deleteResult'); } } on Exception catch (e) { - globals.printError( - 'Failed to delete screenshot.ppm from the device: $e' - ); + globals + .printError('Failed to delete screenshot.ppm from the device: $e'); } } } @@ -570,7 +554,7 @@ class FuchsiaDevice extends Device { const String defaultName = 'Fuchsia'; if (!globals.fuchsiaArtifacts!.hasSshConfig) { globals.printTrace('Could not determine Fuchsia sdk name or version ' - 'because Fuchsia ssh configuration is missing.'); + 'because Fuchsia ssh configuration is missing.'); return defaultName; } const String versionPath = '/pkgfs/packages/build-info/0/data/version'; @@ -595,6 +579,7 @@ class FuchsiaDevice extends Device { assert(!includePastLogs, 'Past log reading not supported on Fuchsia.'); return _logReader ??= _FuchsiaLogReader(this, globals.systemClock, app); } + _FuchsiaLogReader? _logReader; @override @@ -620,6 +605,7 @@ class FuchsiaDevice extends Device { void fail() { throwToolExit('Failed to get local address, aborting.\n$result'); } + if (result.exitCode != 0) { fail(); } @@ -639,7 +625,8 @@ class FuchsiaDevice extends Device { const String findCommand = 'find /hub -name vmservice-port'; final RunResult findResult = await shell(findCommand); if (findResult.exitCode != 0) { - throwToolExit("'$findCommand' on device $name failed. stderr: '${findResult.stderr}'"); + throwToolExit( + "'$findCommand' on device $name failed. stderr: '${findResult.stderr}'"); } final String findOutput = findResult.stdout; if (findOutput.trim() == '') { @@ -675,7 +662,7 @@ class FuchsiaDevice extends Device { final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig; if (sshConfig == null) { throwToolExit('Cannot interact with device. No ssh config.\n' - 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'); + 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'); } return globals.processUtils.run([ 'ssh', @@ -691,7 +678,7 @@ class FuchsiaDevice extends Device { final File? sshConfig = globals.fuchsiaArtifacts!.sshConfig; if (sshConfig == null) { throwToolExit('Cannot interact with device. No ssh config.\n' - 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'); + 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.'); } return globals.processUtils.run([ 'scp', @@ -714,15 +701,18 @@ class FuchsiaDevice extends Device { // netstat shows that the local port is actually being used on the IPv6 // loopback (::1). final Uri uri = Uri.parse('http://[$_ipv6Loopback]:$port'); - final FlutterVmService vmService = await connectToVmService(uri, logger: globals.logger); - final List flutterViews = await vmService.getFlutterViews(); + final FlutterVmService vmService = + await connectToVmService(uri, logger: globals.logger); + final List flutterViews = + await vmService.getFlutterViews(); for (final FlutterView flutterView in flutterViews) { final vm_service.IsolateRef? uiIsolate = flutterView.uiIsolate; if (uiIsolate == null) { continue; } final int? port = vmService.httpAddress?.port; - if (port != null && (uiIsolate.name?.contains(isolateName) ?? false)) { + if (port != null && + (uiIsolate.name?.contains(isolateName) ?? false)) { return port; } } @@ -733,7 +723,8 @@ class FuchsiaDevice extends Device { throwToolExit('No ports found running $isolateName'); } - FuchsiaIsolateDiscoveryProtocol getIsolateDiscoveryProtocol(String isolateName) { + FuchsiaIsolateDiscoveryProtocol getIsolateDiscoveryProtocol( + String isolateName) { return FuchsiaIsolateDiscoveryProtocol(this, isolateName); } @@ -776,7 +767,7 @@ class FuchsiaIsolateDiscoveryProtocol { _status ??= globals.logger.startProgress( 'Waiting for a connection from $_isolateName on ${_device.name}...', ); - unawaited(_findIsolate()); // Completes the _foundUri Future. + unawaited(_findIsolate()); // Completes the _foundUri Future. return _foundUri.future.then((Uri uri) { _uri = uri; return uri; @@ -813,7 +804,8 @@ class FuchsiaIsolateDiscoveryProtocol { continue; } } - final List flutterViews = await service?.getFlutterViews() ?? []; + final List flutterViews = + await service?.getFlutterViews() ?? []; for (final FlutterView flutterView in flutterViews) { final vm_service.IsolateRef? uiIsolate = flutterView.uiIsolate; if (uiIsolate == null) { @@ -848,7 +840,8 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { Future forward(int devicePort, {int? hostPort}) async { hostPort ??= await globals.os.findFreePort(); if (hostPort == 0) { - throwToolExit('Failed to forward port $devicePort. No free host-side ports'); + throwToolExit( + 'Failed to forward port $devicePort. No free host-side ports'); } final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig; if (sshConfig == null) { @@ -911,7 +904,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { throwToolExit( 'Unforward command failed:\n' 'stdout: ${result.stdout}\n' - 'stderr: ${result.stderr}' + 'stderr: ${result.stderr}', ); } } @@ -919,7 +912,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { @override Future dispose() async { final List forwardedPortsCopy = - List.of(forwardedPorts); + List.of(forwardedPorts); for (final ForwardedPort port in forwardedPortsCopy) { await unforward(port); } diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_ffx.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_ffx.dart index 6a39591d6f3..54f0bca1311 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_ffx.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_ffx.dart @@ -8,6 +8,7 @@ import 'package:process/process.dart'; import '../base/common.dart'; import '../base/logger.dart'; import '../base/process.dart'; +import '../globals.dart' as globals; import 'fuchsia_sdk.dart'; // Usage: ffx [-c ] [-e ] [-t ] [-T ] [-v] [] [] @@ -26,17 +27,21 @@ import 'fuchsia_sdk.dart'; // config View and switch default and user configurations // daemon Interact with/control the ffx daemon // target Interact with a target device or emulator +// session Control the current session. See +// https://fuchsia.dev/fuchsia-src/concepts/session/introduction +// for details. /// A simple wrapper for the Fuchsia SDK's 'ffx' tool. class FuchsiaFfx { FuchsiaFfx({ - required FuchsiaArtifacts? fuchsiaArtifacts, - required Logger logger, - required ProcessManager processManager, - }) : _fuchsiaArtifacts = fuchsiaArtifacts, - _logger = logger, - _processUtils = - ProcessUtils(logger: logger, processManager: processManager); + FuchsiaArtifacts? fuchsiaArtifacts, + Logger? logger, + ProcessManager? processManager, + }) : _fuchsiaArtifacts = fuchsiaArtifacts ?? globals.fuchsiaArtifacts, + _logger = logger ?? globals.logger, + _processUtils = ProcessUtils( + logger: logger ?? globals.logger, + processManager: processManager ?? globals.processManager); final FuchsiaArtifacts? _fuchsiaArtifacts; final Logger _logger; @@ -53,8 +58,7 @@ class FuchsiaFfx { } final List command = [ ffx.path, - if (timeout != null) - ...['-T', '${timeout.inSeconds}'], + if (timeout != null) ...['-T', '${timeout.inSeconds}'], 'target', 'list', // TODO(akbiggs): Revert -f back to --format once we've verified that @@ -97,4 +101,50 @@ class FuchsiaFfx { } return result.stdout.trim(); } + + /// Show information about the current session + /// + /// Returns `null` if the command failed, which can be interpreted as there is + /// no usable session. + Future sessionShow() async { + final File? ffx = _fuchsiaArtifacts?.ffx; + if (ffx == null || !ffx.existsSync()) { + throwToolExit('Fuchsia ffx tool not found.'); + } + final List command = [ + ffx.path, + 'session', + 'show', + ]; + final RunResult result = await _processUtils.run(command); + if (result.exitCode != 0) { + _logger.printError('ffx failed: ${result.stderr}'); + return null; + } + return result.stdout; + } + + /// Add an element to the current session + /// + /// [url] should be formatted as a Fuchsia-style package URL, e.g.: + /// fuchsia-pkg://fuchsia.com/flutter_gallery#meta/flutter_gallery.cmx + /// Returns true on success and false on failure. + Future sessionAdd(String url) async { + final File? ffx = _fuchsiaArtifacts?.ffx; + if (ffx == null || !ffx.existsSync()) { + throwToolExit('Fuchsia ffx tool not found.'); + } + final List command = [ + ffx.path, + 'session', + 'add', + url, + ]; + final RunResult result = await _processUtils.run(command); + if (result.exitCode != 0) { + _logger.printError('ffx failed: ${result.stderr}'); + return false; + } + return true; + } } diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart index 104b8d949d4..d79d5beeff3 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_pm.dart @@ -41,7 +41,7 @@ class FuchsiaPM { /// which describe the contents of the Fuchsia package. It must also contain /// two other entries: /// - /// meta/$APPNAME.cmx=/path/to/cmx/on/the/host/$APPNAME.cmx + /// meta/$APPNAME.cm=/path/to/cm/on/the/host/$APPNAME.cm /// meta/package=/path/to/package/file/from/init/package /// /// where $APPNAME is the same [appName] passed to [init], and meta/package @@ -232,12 +232,14 @@ class FuchsiaPackageServer { if (_process == null) { return false; } - return (await globals.fuchsiaSdk?.fuchsiaPM.publish(_repo, package.path)) ?? false; + return (await globals.fuchsiaSdk?.fuchsiaPM.publish(_repo, package.path)) ?? + false; } @override String toString() { - final String p = (_process == null) ? 'stopped' : 'running ${_process?.pid}'; + final String p = + (_process == null) ? 'stopped' : 'running ${_process?.pid}'; return 'FuchsiaPackageServer at $_host:$_port ($p)'; } } diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart index 84fd9dce997..e4c3126999e 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_sdk.dart @@ -31,11 +31,7 @@ class FuchsiaSdk { late final FuchsiaKernelCompiler fuchsiaKernelCompiler = FuchsiaKernelCompiler(); /// Interface to the 'ffx' tool. - late final FuchsiaFfx fuchsiaFfx = FuchsiaFfx( - fuchsiaArtifacts: globals.fuchsiaArtifacts, - logger: globals.logger, - processManager: globals.processManager, - ); + late final FuchsiaFfx fuchsiaFfx = FuchsiaFfx(); /// Returns any attached devices is a newline-denominated String. /// diff --git a/packages/flutter_tools/lib/src/fuchsia/session_control.dart b/packages/flutter_tools/lib/src/fuchsia/session_control.dart deleted file mode 100644 index 42e11107cfa..00000000000 --- a/packages/flutter_tools/lib/src/fuchsia/session_control.dart +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import '../base/process.dart'; - -import 'fuchsia_device.dart'; - -// Usage: session_control [] -// -// Various operations to control sessions. -// -// Options: -// --help display usage information -// -// Commands: -// launch Launch a new session. -// restart Restart the current session. -// add Add an element to the current session. -// -// Usage: session_control launch -// -// Launch a new session. -// -// Options: -// --help display usage information -// -// Usage: session_control restart -// -// Restart the current session. -// -// Options: -// --help display usage information -// -// -// Usage: session_control add -// -// Add an element to the current session. -// -// Options: -// --help display usage information - -/// A simple wrapper around the 'session_control' tool running on the Fuchsia device. -class FuchsiaSessionControl { - /// Instructs session_control on the device to add the app at [url] as an element. - /// - /// [url] should be formatted as a Fuchsia-style package URL, e.g.: - /// fuchsia-pkg://fuchsia.com/flutter_gallery#meta/flutter_gallery.cmx - /// Returns true on success and false on failure. - Future add(FuchsiaDevice device, String url) async { - final RunResult result = await device.shell('session_control add $url'); - return result.exitCode == 0; - } -} diff --git a/packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart b/packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart deleted file mode 100644 index e626e2eff0b..00000000000 --- a/packages/flutter_tools/lib/src/fuchsia/tiles_ctl.dart +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import '../base/process.dart'; -import '../globals.dart' as globals; - -import 'fuchsia_device.dart'; - -// Usage: tiles_ctl -// Supported commands: -// start -// add [--disable-focus] [...] -// remove -// list -// quit - -/// A simple wrapper around the 'tiles_ctl' tool running on the Fuchsia device. -class FuchsiaTilesCtl { - /// Finds the key for the app called [appName], or returns -1 if it can't be - /// found. - static Future findAppKey(FuchsiaDevice device, String appName) async { - final FuchsiaTilesCtl tilesCtl = fuchsiaDeviceTools.tilesCtl; - final Map? runningApps = await tilesCtl.list(device); - if (runningApps == null) { - globals.printTrace('tiles_ctl is not running'); - return -1; - } - for (final MapEntry entry in runningApps.entries) { - if (entry.value.contains('$appName#meta')) { - return entry.key; - } - } - return -1; - } - - /// Ensures that tiles is running on the device. - static Future ensureStarted(FuchsiaDevice device) async { - final FuchsiaTilesCtl tilesCtl = fuchsiaDeviceTools.tilesCtl; - final Map? runningApps = await tilesCtl.list(device); - if (runningApps == null) { - return tilesCtl.start(device); - } - return true; - } - - /// Instructs 'tiles' to start on the device. - /// - /// Returns true on success and false on failure. - Future start(FuchsiaDevice device) async { - final RunResult result = await device.shell('tiles_ctl start'); - return result.exitCode == 0; - } - - /// Returns a mapping of tile keys to app URLs. - /// - /// Returns an empty mapping if tiles_ctl is running but no apps are running. - /// Returns null if tiles_ctl is not running. - Future?> list(FuchsiaDevice device) async { - // Output of tiles_ctl list has the format: - // Found 1 tiles: - // Tile key 1 url fuchsia-pkg://fuchsia.com/stocks#meta/stocks.cmx ... - final Map tiles = {}; - final RunResult result = await device.shell('tiles_ctl list'); - if (result.exitCode != 0) { - return null; - } - // Look for evidence that tiles_ctl is not running. - if (result.stdout.contains("Couldn't find tiles component in realm")) { - return null; - } - // Find lines beginning with 'Tile' - for (final String line in result.stdout.split('\n')) { - final List words = line.split(' '); - if (words.isNotEmpty && words[0] == 'Tile') { - final int? key = int.tryParse(words[2]); - if (key != null) { - final String url = words[4]; - tiles[key] = url; - } - } - } - return tiles; - } - - /// Instructs tiles on the device to begin running the app at [url] in a new - /// tile. - /// - /// The app is passed the arguments in [args]. Flutter apps receive these - /// arguments as arguments to `main()`. [url] should be formatted as a - /// Fuchsia-style package URL, e.g.: - /// fuchsia-pkg://fuchsia.com/flutter_gallery#meta/flutter_gallery.cmx - /// Returns true on success and false on failure. - Future add(FuchsiaDevice device, String url, List args) async { - final RunResult result = await device.shell( - 'tiles_ctl add $url ${args.join(" ")}'); - return result.exitCode == 0; - } - - /// Instructs tiles on the device to remove the app with key [key]. - /// - /// Returns true on success and false on failure. - Future remove(FuchsiaDevice device, int key) async { - final RunResult result = await device.shell('tiles_ctl remove $key'); - return result.exitCode == 0; - } - - /// Instructs tiles on the device to quit. - /// - /// Returns true on success and false on failure. - Future quit(FuchsiaDevice device) async { - final RunResult result = await device.shell('tiles_ctl quit'); - return result.exitCode == 0; - } -} diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_fuchsia_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_fuchsia_test.dart deleted file mode 100644 index 30faad0cb59..00000000000 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_fuchsia_test.dart +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// @dart = 2.8 - -import 'package:args/command_runner.dart'; -import 'package:file/memory.dart'; -import 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/cache.dart'; -import 'package:flutter_tools/src/commands/build.dart'; -import 'package:flutter_tools/src/commands/build_fuchsia.dart'; -import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/fuchsia/fuchsia_kernel_compiler.dart'; -import 'package:flutter_tools/src/fuchsia/fuchsia_pm.dart'; -import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'; -import 'package:flutter_tools/src/project.dart'; -import 'package:meta/meta.dart'; -import 'package:test/fake.dart'; - -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; -import '../../src/test_flutter_command_runner.dart'; - -// Defined globally for fakes to use. -FileSystem fileSystem; - -void main() { - Cache.disableLocking(); - - final Platform linuxPlatform = FakePlatform( - environment: const { - 'FLUTTER_ROOT': '/', - }, - ); - final Platform windowsPlatform = FakePlatform( - operatingSystem: 'windows', - environment: const { - 'FLUTTER_ROOT': '/', - }, - ); - FakeFuchsiaSdk fuchsiaSdk; - - setUp(() { - fuchsiaSdk = FakeFuchsiaSdk(); - fileSystem = MemoryFileSystem.test(); - }); - - group('Fuchsia build fails gracefully when', () { - testUsingContext('The feature is disabled', () async { - final BuildCommand command = BuildCommand(); - fileSystem.directory('fuchsia').createSync(recursive: true); - fileSystem.file('.packages').createSync(); - fileSystem.file('pubspec.yaml').createSync(); - fileSystem.file('lib/main.dart').createSync(recursive: true); - - expect( - createTestCommandRunner(command).run(const ['build', 'fuchsia']), - throwsToolExit(message: '"build fuchsia" is currently disabled'), - ); - }, overrides: { - Platform: () => linuxPlatform, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => TestFeatureFlags(), - }); - testUsingContext('there is no Fuchsia project', () async { - final BuildCommand command = BuildCommand(); - - expect( - createTestCommandRunner(command).run(const ['build', 'fuchsia']), - throwsToolExit(), - ); - }, overrides: { - Platform: () => linuxPlatform, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => TestFeatureFlags(isFuchsiaEnabled: true), - }); - - testUsingContext('there is no cmx file', () async { - final BuildCommand command = BuildCommand(); - fileSystem.directory('fuchsia').createSync(recursive: true); - fileSystem.file('.packages').createSync(); - fileSystem.file('pubspec.yaml').createSync(); - - expect( - createTestCommandRunner(command).run(const ['build', 'fuchsia']), - throwsToolExit(), - ); - }, overrides: { - Platform: () => linuxPlatform, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => TestFeatureFlags(isFuchsiaEnabled: true), - }); - - testUsingContext('on Windows platform', () async { - final BuildCommand command = BuildCommand(); - const String appName = 'app_name'; - fileSystem - .file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx')) - ..createSync(recursive: true) - ..writeAsStringSync('{}'); - fileSystem.file('.packages').createSync(); - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - pubspecFile.writeAsStringSync('name: $appName'); - - final bool supported = BuildFuchsiaCommand(verboseHelp: false).supported; - expect( - createTestCommandRunner(command).run(const ['build', 'fuchsia']), - supported ? throwsToolExit() : throwsA(isA()), - ); - }, overrides: { - Platform: () => windowsPlatform, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => TestFeatureFlags(isFuchsiaEnabled: true), - }); - - testUsingContext('there is no Fuchsia kernel compiler', () async { - final BuildCommand command = BuildCommand(); - const String appName = 'app_name'; - fileSystem - .file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx')) - ..createSync(recursive: true) - ..writeAsStringSync('{}'); - fileSystem.file('.packages').createSync(); - fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true); - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - pubspecFile.writeAsStringSync('name: $appName'); - - expect( - createTestCommandRunner(command).run(const ['build', 'fuchsia']), - throwsToolExit(), - ); - }, overrides: { - Platform: () => linuxPlatform, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => TestFeatureFlags(isFuchsiaEnabled: true), - }); - }); - - testUsingContext('Fuchsia build parts fit together right', () async { - final BuildCommand command = BuildCommand(); - const String appName = 'app_name'; - fileSystem - .file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx')) - ..createSync(recursive: true) - ..writeAsStringSync('{}'); - fileSystem.file('.packages').createSync(); - fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true); - final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); - pubspecFile.writeAsStringSync('name: $appName'); - - await createTestCommandRunner(command) - .run(const ['build', 'fuchsia']); - final String farPath = fileSystem.path.join( - getFuchsiaBuildDirectory(), 'pkg', 'app_name-0.far', - ); - - expect(fileSystem.file(farPath), exists); - }, overrides: { - Platform: () => linuxPlatform, - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.any(), - FuchsiaSdk: () => fuchsiaSdk, - FeatureFlags: () => TestFeatureFlags(isFuchsiaEnabled: true), - }); -} - -class FakeFuchsiaPM extends Fake implements FuchsiaPM { - String _appName; - - @override - Future init(String buildPath, String appName) async { - if (!fileSystem.directory(buildPath).existsSync()) { - return false; - } - fileSystem - .file(fileSystem.path.join(buildPath, 'meta', 'package')) - .createSync(recursive: true); - _appName = appName; - return true; - } - - @override - Future build(String buildPath, String manifestPath) async { - if (!fileSystem.file(fileSystem.path.join(buildPath, 'meta', 'package')).existsSync() || - !fileSystem.file(manifestPath).existsSync()) { - return false; - } - fileSystem.file(fileSystem.path.join(buildPath, 'meta.far')).createSync(recursive: true); - return true; - } - - @override - Future archive(String buildPath, String manifestPath) async { - if (!fileSystem.file(fileSystem.path.join(buildPath, 'meta', 'package')).existsSync() || - !fileSystem.file(manifestPath).existsSync()) { - return false; - } - if (_appName == null) { - return false; - } - fileSystem - .file(fileSystem.path.join(buildPath, '$_appName-0.far')) - .createSync(recursive: true); - return true; - } -} - -class FakeFuchsiaKernelCompiler extends Fake implements FuchsiaKernelCompiler { - @override - Future build({ - @required FuchsiaProject fuchsiaProject, - @required String target, // E.g., lib/main.dart - BuildInfo buildInfo = BuildInfo.debug, - }) async { - final String outDir = getFuchsiaBuildDirectory(); - final String appName = fuchsiaProject.project.manifest.appName; - final String manifestPath = fileSystem.path.join(outDir, '$appName.dilpmanifest'); - fileSystem.file(manifestPath).createSync(recursive: true); - } -} - -class FakeFuchsiaSdk extends Fake implements FuchsiaSdk { - @override - final FuchsiaPM fuchsiaPM = FakeFuchsiaPM(); - - @override - final FuchsiaKernelCompiler fuchsiaKernelCompiler = - FakeFuchsiaKernelCompiler(); -} diff --git a/packages/flutter_tools/test/general.shard/commands/build_test.dart b/packages/flutter_tools/test/general.shard/commands/build_test.dart index b9125560689..ad90b8c8b77 100644 --- a/packages/flutter_tools/test/general.shard/commands/build_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/build_test.dart @@ -12,7 +12,6 @@ import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build_aar.dart'; import 'package:flutter_tools/src/commands/build_apk.dart'; import 'package:flutter_tools/src/commands/build_appbundle.dart'; -import 'package:flutter_tools/src/commands/build_fuchsia.dart'; import 'package:flutter_tools/src/commands/build_ios.dart'; import 'package:flutter_tools/src/commands/build_ios_framework.dart'; import 'package:flutter_tools/src/commands/build_linux.dart'; @@ -36,9 +35,11 @@ void main() { BuildIOSCommand(verboseHelp: false), BuildIOSArchiveCommand(verboseHelp: false), BuildAppBundleCommand(), - BuildFuchsiaCommand(verboseHelp: false), BuildAarCommand(verboseHelp: false), - BuildIOSFrameworkCommand(verboseHelp: false, buildSystem: globals.buildSystem), + BuildIOSFrameworkCommand( + verboseHelp: false, + buildSystem: globals.buildSystem, + ), AttachCommand(), ]; @@ -53,7 +54,8 @@ void main() { } }); - testUsingContext('BuildSubCommand displays current null safety mode', () async { + testUsingContext('BuildSubCommand displays current null safety mode', + () async { const BuildInfo unsound = BuildInfo( BuildMode.debug, '', @@ -67,11 +69,13 @@ void main() { ); FakeBuildSubCommand().test(unsound); - expect(testLogger.statusText, contains('Building without sound null safety')); + expect( + testLogger.statusText, contains('Building without sound null safety')); testLogger.clear(); FakeBuildSubCommand().test(sound); - expect(testLogger.statusText, contains('💪 Building with sound null safety 💪')); + expect(testLogger.statusText, + contains('💪 Building with sound null safety 💪')); }); testUsingContext('Include only supported sub commands', () { diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart index 228aba1e0cf..11ed2d71cab 100644 --- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart +++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_start_test.dart @@ -22,8 +22,6 @@ import 'package:flutter_tools/src/fuchsia/fuchsia_kernel_compiler.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_pm.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'; import 'package:flutter_tools/src/fuchsia/pkgctl.dart'; -import 'package:flutter_tools/src/fuchsia/session_control.dart'; -import 'package:flutter_tools/src/fuchsia/tiles_ctl.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:meta/meta.dart'; @@ -42,7 +40,6 @@ void main() { Artifacts artifacts; FakeProcessManager fakeSuccessfulProcessManager; FakeProcessManager fakeFailedProcessManagerForHostAddress; - FakeProcessManager fakeSuccessfulProcessManagerWithSession; File sshConfig; setUp(() { @@ -50,56 +47,69 @@ void main() { osUtils = FakeOperatingSystemUtils(); fuchsiaDeviceTools = FakeFuchsiaDeviceTools(); fuchsiaSdk = FakeFuchsiaSdk(); - sshConfig = MemoryFileSystem.test().file('ssh_config')..writeAsStringSync('\n'); + sshConfig = MemoryFileSystem.test().file('ssh_config') + ..writeAsStringSync('\n'); artifacts = Artifacts.test(); - for (final BuildMode mode in [BuildMode.debug, BuildMode.release]) { - memoryFileSystem.file( - artifacts.getArtifactPath(Artifact.fuchsiaKernelCompiler, - platform: TargetPlatform.fuchsia_arm64, mode: mode), - ).createSync(); + for (final BuildMode mode in [ + BuildMode.debug, + BuildMode.release + ]) { + memoryFileSystem + .file( + artifacts.getArtifactPath(Artifact.fuchsiaKernelCompiler, + platform: TargetPlatform.fuchsia_arm64, mode: mode), + ) + .createSync(); - memoryFileSystem.file( - artifacts.getArtifactPath(Artifact.platformKernelDill, - platform: TargetPlatform.fuchsia_arm64, mode: mode), - ).createSync(); + memoryFileSystem + .file( + artifacts.getArtifactPath(Artifact.platformKernelDill, + platform: TargetPlatform.fuchsia_arm64, mode: mode), + ) + .createSync(); - memoryFileSystem.file( - artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, - platform: TargetPlatform.fuchsia_arm64, mode: mode), - ).createSync(); + memoryFileSystem + .file( + artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, + platform: TargetPlatform.fuchsia_arm64, mode: mode), + ) + .createSync(); - memoryFileSystem.file( - artifacts.getArtifactPath(Artifact.fuchsiaFlutterRunner, - platform: TargetPlatform.fuchsia_arm64, mode: mode), - ).createSync(); + memoryFileSystem + .file( + artifacts.getArtifactPath(Artifact.fuchsiaFlutterRunner, + platform: TargetPlatform.fuchsia_arm64, mode: mode), + ) + .createSync(); } fakeSuccessfulProcessManager = FakeProcessManager.list([ - const FakeCommand( - command: ['ssh', '-F', '/ssh_config', '123', 'which session_control'], - exitCode: 1, - ), FakeCommand( - command: ['ssh', '-F', sshConfig.absolute.path, '123', r'echo $SSH_CONNECTION'], - stdout: 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', + command: [ + 'ssh', + '-F', + sshConfig.absolute.path, + '123', + r'echo $SSH_CONNECTION' + ], + stdout: + 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', ), ]); - fakeFailedProcessManagerForHostAddress = FakeProcessManager.list([ + fakeFailedProcessManagerForHostAddress = + FakeProcessManager.list([ FakeCommand( - command: ['ssh', '-F', sshConfig.absolute.path, '123', r'echo $SSH_CONNECTION'], - stdout: 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', + command: [ + 'ssh', + '-F', + sshConfig.absolute.path, + '123', + r'echo $SSH_CONNECTION' + ], + stdout: + 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', exitCode: 1, ), ]); - fakeSuccessfulProcessManagerWithSession = FakeProcessManager.list([ - const FakeCommand( - command: ['ssh', '-F', '/ssh_config', '123', 'which session_control'], - stdout: '/bin/session_control', - ), - FakeCommand( - command: ['ssh', '-F', sshConfig.absolute.path, '123', r'echo $SSH_CONNECTION'], - stdout: 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', - ), - ]); }); Future setupAndStartApp({ @@ -117,15 +127,21 @@ void main() { final File far = globals.fs.file('app_name-0.far')..createSync(); app = FuchsiaApp.fromPrebuiltApp(far); } else { - globals.fs.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cmx')) + globals.fs.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cm')) ..createSync(recursive: true) ..writeAsStringSync('{}'); globals.fs.file('.packages').createSync(); - globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); - app = BuildableFuchsiaApp(project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory).fuchsia); + globals.fs + .file(globals.fs.path.join('lib', 'main.dart')) + .createSync(recursive: true); + app = BuildableFuchsiaApp( + project: + FlutterProject.fromDirectoryTest(globals.fs.currentDirectory) + .fuchsia); } - final DebuggingOptions debuggingOptions = DebuggingOptions.disabled(BuildInfo(mode, null, treeShakeIcons: false)); + final DebuggingOptions debuggingOptions = DebuggingOptions.disabled( + BuildInfo(mode, null, treeShakeIcons: false)); return device.startApp( app, prebuiltApplication: prebuilt, @@ -133,10 +149,12 @@ void main() { ); } - testUsingContext('start prebuilt in release mode', () async { + testUsingContext( + 'start prebuilt in release mode fails without session', + () async { final LaunchResult launchResult = await setupAndStartApp(prebuilt: true, mode: BuildMode.release); - expect(launchResult.started, isTrue); + expect(launchResult.started, isFalse); expect(launchResult.hasObservatory, isFalse); }, overrides: { Artifacts: () => artifacts, @@ -150,20 +168,22 @@ void main() { testUsingContext('start prebuilt in release mode with session', () async { final LaunchResult launchResult = - await setupAndStartApp(prebuilt: true, mode: BuildMode.release); + await setupAndStartApp(prebuilt: true, mode: BuildMode.release); expect(launchResult.started, isTrue); expect(launchResult.hasObservatory, isFalse); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, - ProcessManager: () => fakeSuccessfulProcessManagerWithSession, + ProcessManager: () => fakeSuccessfulProcessManager, FuchsiaDeviceTools: () => fuchsiaDeviceTools, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), - FuchsiaSdk: () => fuchsiaSdk, + FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()), OperatingSystemUtils: () => osUtils, }); - testUsingContext('start and stop prebuilt in release mode', () async { + testUsingContext( + 'start and stop prebuilt in release mode fails without session', + () async { const String appName = 'app_name'; final FuchsiaDevice device = FuchsiaDeviceWithFakeDiscovery('123'); globals.fs.directory('fuchsia').createSync(recursive: true); @@ -172,14 +192,12 @@ void main() { final File far = globals.fs.file('app_name-0.far')..createSync(); final FuchsiaApp app = FuchsiaApp.fromPrebuiltApp(far); - final DebuggingOptions debuggingOptions = - DebuggingOptions.disabled(const BuildInfo(BuildMode.release, null, treeShakeIcons: false)); + final DebuggingOptions debuggingOptions = DebuggingOptions.disabled( + const BuildInfo(BuildMode.release, null, treeShakeIcons: false)); final LaunchResult launchResult = await device.startApp(app, - prebuiltApplication: true, - debuggingOptions: debuggingOptions); - expect(launchResult.started, isTrue); + prebuiltApplication: true, debuggingOptions: debuggingOptions); + expect(launchResult.started, isFalse); expect(launchResult.hasObservatory, isFalse); - expect(await device.stopApp(app), isTrue); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, @@ -190,7 +208,8 @@ void main() { OperatingSystemUtils: () => osUtils, }); - testUsingContext('start and stop prebuilt in release mode with session', () async { + testUsingContext('start and stop prebuilt in release mode with session', + () async { const String appName = 'app_name'; final FuchsiaDevice device = FuchsiaDeviceWithFakeDiscovery('123'); globals.fs.directory('fuchsia').createSync(recursive: true); @@ -199,29 +218,29 @@ void main() { final File far = globals.fs.file('app_name-0.far')..createSync(); final FuchsiaApp app = FuchsiaApp.fromPrebuiltApp(far); - final DebuggingOptions debuggingOptions = - DebuggingOptions.disabled(const BuildInfo(BuildMode.release, null, treeShakeIcons: false)); + final DebuggingOptions debuggingOptions = DebuggingOptions.disabled( + const BuildInfo(BuildMode.release, null, treeShakeIcons: false)); final LaunchResult launchResult = await device.startApp(app, - prebuiltApplication: true, - debuggingOptions: debuggingOptions); + prebuiltApplication: true, debuggingOptions: debuggingOptions); expect(launchResult.started, isTrue); expect(launchResult.hasObservatory, isFalse); expect(await device.stopApp(app), isTrue); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, - ProcessManager: () => fakeSuccessfulProcessManagerWithSession, + ProcessManager: () => fakeSuccessfulProcessManager, FuchsiaDeviceTools: () => fuchsiaDeviceTools, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), - FuchsiaSdk: () => fuchsiaSdk, + FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()), OperatingSystemUtils: () => osUtils, }); - testUsingContext('start prebuilt in debug mode', () async { + testUsingContext( + 'start prebuilt in debug mode fails without session', + () async { final LaunchResult launchResult = await setupAndStartApp(prebuilt: true, mode: BuildMode.debug); - expect(launchResult.started, isTrue); - expect(launchResult.hasObservatory, isTrue); + expect(launchResult.started, isFalse); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, @@ -234,32 +253,32 @@ void main() { testUsingContext('start prebuilt in debug mode with session', () async { final LaunchResult launchResult = - await setupAndStartApp(prebuilt: true, mode: BuildMode.debug); + await setupAndStartApp(prebuilt: true, mode: BuildMode.debug); expect(launchResult.started, isTrue); expect(launchResult.hasObservatory, isTrue); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, - ProcessManager: () => fakeSuccessfulProcessManagerWithSession, + ProcessManager: () => fakeSuccessfulProcessManager, FuchsiaDeviceTools: () => fuchsiaDeviceTools, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), - FuchsiaSdk: () => fuchsiaSdk, + FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()), OperatingSystemUtils: () => osUtils, }); - testUsingContext('start buildable in release mode', () async { - final LaunchResult launchResult = - await setupAndStartApp(prebuilt: false, mode: BuildMode.release); - expect(launchResult.started, isTrue); - expect(launchResult.hasObservatory, isFalse); + testUsingContext( + 'start buildable in release mode fails without session', + () async { + expect( + () async => setupAndStartApp(prebuilt: false, mode: BuildMode.release), + throwsToolExit( + message: 'This tool does not currently build apps for fuchsia.\n' + 'Build the app using a supported Fuchsia workflow.\n' + 'Then use the --use-application-binary flag.')); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, ProcessManager: () => FakeProcessManager.list([ - const FakeCommand( - command: ['ssh', '-F', '/ssh_config', '123', 'which session_control'], - exitCode: 1, - ), const FakeCommand( command: [ 'Artifact.genSnapshot.TargetPlatform.fuchsia_arm64.release', @@ -270,8 +289,15 @@ void main() { ], ), FakeCommand( - command: ['ssh', '-F', sshConfig.absolute.path, '123', r'echo $SSH_CONNECTION'], - stdout: 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', + command: [ + 'ssh', + '-F', + sshConfig.absolute.path, + '123', + r'echo $SSH_CONNECTION' + ], + stdout: + 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', ), ]), FuchsiaDeviceTools: () => fuchsiaDeviceTools, @@ -280,44 +306,55 @@ void main() { OperatingSystemUtils: () => osUtils, }); - testUsingContext('start buildable in release mode with session', () async { - final LaunchResult launchResult = - await setupAndStartApp(prebuilt: false, mode: BuildMode.release); - expect(launchResult.started, isTrue); - expect(launchResult.hasObservatory, isFalse); + testUsingContext( + 'start buildable in release mode with session fails, does not build apps yet', + () async { + expect( + () async => setupAndStartApp(prebuilt: false, mode: BuildMode.release), + throwsToolExit( + message: 'This tool does not currently build apps for fuchsia.\n' + 'Build the app using a supported Fuchsia workflow.\n' + 'Then use the --use-application-binary flag.')); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, ProcessManager: () => FakeProcessManager.list([ - const FakeCommand( - command: ['ssh', '-F', '/ssh_config', '123', 'which session_control'], - stdout: '/bin/session_control', - ), - const FakeCommand( - command: [ - 'Artifact.genSnapshot.TargetPlatform.fuchsia_arm64.release', - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=build/fuchsia/elf.aotsnapshot', - 'build/fuchsia/app_name.dil', - ], - ), - FakeCommand( - command: ['ssh', '-F', sshConfig.absolute.path, '123', r'echo $SSH_CONNECTION'], - stdout: 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', - ), - ]), + const FakeCommand( + command: [ + 'Artifact.genSnapshot.TargetPlatform.fuchsia_arm64.release', + '--deterministic', + '--snapshot_kind=app-aot-elf', + '--elf=build/fuchsia/elf.aotsnapshot', + 'build/fuchsia/app_name.dil', + ], + ), + FakeCommand( + command: [ + 'ssh', + '-F', + sshConfig.absolute.path, + '123', + r'echo $SSH_CONNECTION' + ], + stdout: + 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', + ), + ]), FuchsiaDeviceTools: () => fuchsiaDeviceTools, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), - FuchsiaSdk: () => fuchsiaSdk, + FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()), OperatingSystemUtils: () => osUtils, }); - testUsingContext('start buildable in debug mode', () async { - final LaunchResult launchResult = - await setupAndStartApp(prebuilt: false, mode: BuildMode.debug); - expect(launchResult.started, isTrue); - expect(launchResult.hasObservatory, isTrue); + testUsingContext( + 'start buildable in debug mode fails without session', + () async { + expect( + () async => setupAndStartApp(prebuilt: false, mode: BuildMode.debug), + throwsToolExit( + message: 'This tool does not currently build apps for fuchsia.\n' + 'Build the app using a supported Fuchsia workflow.\n' + 'Then use the --use-application-binary flag.')); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, @@ -328,37 +365,42 @@ void main() { OperatingSystemUtils: () => osUtils, }); - testUsingContext('start buildable in debug mode with session', () async { - final LaunchResult launchResult = - await setupAndStartApp(prebuilt: false, mode: BuildMode.debug); - expect(launchResult.started, isTrue); - expect(launchResult.hasObservatory, isTrue); + testUsingContext( + 'start buildable in debug mode with session fails, does not build apps yet', + () async { + expect( + () async => setupAndStartApp(prebuilt: false, mode: BuildMode.debug), + throwsToolExit( + message: 'This tool does not currently build apps for fuchsia.\n' + 'Build the app using a supported Fuchsia workflow.\n' + 'Then use the --use-application-binary flag.')); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, - ProcessManager: () => fakeSuccessfulProcessManagerWithSession, + ProcessManager: () => fakeSuccessfulProcessManager, FuchsiaDeviceTools: () => fuchsiaDeviceTools, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), - FuchsiaSdk: () => fuchsiaSdk, + FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()), OperatingSystemUtils: () => osUtils, }); testUsingContext('fail when cant get ssh config', () async { - expect(() async => - setupAndStartApp(prebuilt: true, mode: BuildMode.release), - throwsToolExit(message: 'Cannot interact with device. No ssh config.\n' - 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.')); + expect( + () async => setupAndStartApp(prebuilt: true, mode: BuildMode.release), + throwsToolExit( + message: 'Cannot interact with device. No ssh config.\n' + 'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.')); }, overrides: { Artifacts: () => artifacts, FileSystem: () => memoryFileSystem, ProcessManager: () => FakeProcessManager.any(), FuchsiaArtifacts: () => FuchsiaArtifacts(), + FuchsiaSdk: () => FakeFuchsiaSdk(ffx: FakeFuchsiaFfxWithSession()), OperatingSystemUtils: () => osUtils, }); testUsingContext('fail when cant get host address', () async { - expect(() async => - FuchsiaDeviceWithFakeDiscovery('123').hostAddress, + expect(() async => FuchsiaDeviceWithFakeDiscovery('123').hostAddress, throwsToolExit(message: 'Failed to get local address, aborting.')); }, overrides: { Artifacts: () => artifacts, @@ -400,37 +442,6 @@ void main() { FuchsiaSdk: () => fuchsiaSdk, OperatingSystemUtils: () => osUtils, }); - - testUsingContext('fail with correct LaunchResult when tiles fails', () async { - final LaunchResult launchResult = - await setupAndStartApp(prebuilt: true, mode: BuildMode.release); - expect(launchResult.started, isFalse); - expect(launchResult.hasObservatory, isFalse); - }, overrides: { - Artifacts: () => artifacts, - FileSystem: () => memoryFileSystem, - ProcessManager: () => fakeSuccessfulProcessManager, - FuchsiaDeviceTools: () => FakeFuchsiaDeviceTools(tiles: FailingTilesCtl()), - FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), - FuchsiaSdk: () => fuchsiaSdk, - OperatingSystemUtils: () => osUtils, - }); - - testUsingContext('fail with correct LaunchResult when tiles fails with session', () async { - final LaunchResult launchResult = - await setupAndStartApp(prebuilt: true, mode: BuildMode.release); - expect(launchResult.started, isFalse); - expect(launchResult.hasObservatory, isFalse); - }, overrides: { - Artifacts: () => artifacts, - FileSystem: () => memoryFileSystem, - ProcessManager: () => fakeSuccessfulProcessManagerWithSession, - FuchsiaDeviceTools: () => FakeFuchsiaDeviceTools(sessionControl: FailingFuchsiaSessionControl()), - FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), - FuchsiaSdk: () => fuchsiaSdk, - OperatingSystemUtils: () => osUtils, - }); - }); } @@ -440,34 +451,41 @@ Process _createFakeProcess({ String stderr = '', bool persistent = false, }) { - final Stream> stdoutStream = Stream>.fromIterable(>[ + final Stream> stdoutStream = + Stream>.fromIterable(>[ utf8.encode(stdout), ]); - final Stream> stderrStream = Stream>.fromIterable(>[ + final Stream> stderrStream = + Stream>.fromIterable(>[ utf8.encode(stderr), ]); final Completer exitCodeCompleter = Completer(); final Process process = FakeProcess( stdout: stdoutStream, stderr: stderrStream, - exitCode: persistent ? exitCodeCompleter.future : Future.value(exitCode), + exitCode: + persistent ? exitCodeCompleter.future : Future.value(exitCode), ); return process; } class FuchsiaDeviceWithFakeDiscovery extends FuchsiaDevice { - FuchsiaDeviceWithFakeDiscovery(String id, {String name}) : super(id, name: name); + FuchsiaDeviceWithFakeDiscovery(String id, {String name}) + : super(id, name: name); @override - FuchsiaIsolateDiscoveryProtocol getIsolateDiscoveryProtocol(String isolateName) { + FuchsiaIsolateDiscoveryProtocol getIsolateDiscoveryProtocol( + String isolateName) { return FakeFuchsiaIsolateDiscoveryProtocol(); } @override - Future get targetPlatform async => TargetPlatform.fuchsia_arm64; + Future get targetPlatform async => + TargetPlatform.fuchsia_arm64; } -class FakeFuchsiaIsolateDiscoveryProtocol implements FuchsiaIsolateDiscoveryProtocol { +class FakeFuchsiaIsolateDiscoveryProtocol + implements FuchsiaIsolateDiscoveryProtocol { @override FutureOr get uri => Uri.parse('http://[::1]:37'); @@ -513,112 +531,18 @@ class FailingPkgctl implements FuchsiaPkgctl { } } -class FakeFuchsiaTilesCtl implements FuchsiaTilesCtl { - final Map _runningApps = {}; - bool _started = false; - int _nextAppId = 1; - - @override - Future start(FuchsiaDevice device) async { - _started = true; - return true; - } - - @override - Future> list(FuchsiaDevice device) async { - if (!_started) { - return null; - } - return _runningApps; - } - - @override - Future add(FuchsiaDevice device, String url, List args) async { - if (!_started) { - return false; - } - _runningApps[_nextAppId] = url; - _nextAppId++; - return true; - } - - @override - Future remove(FuchsiaDevice device, int key) async { - if (!_started) { - return false; - } - _runningApps.remove(key); - return true; - } - - @override - Future quit(FuchsiaDevice device) async { - if (!_started) { - return false; - } - _started = false; - return true; - } -} - -class FailingTilesCtl implements FuchsiaTilesCtl { - @override - Future start(FuchsiaDevice device) async { - return false; - } - - @override - Future> list(FuchsiaDevice device) async { - return null; - } - - @override - Future add(FuchsiaDevice device, String url, List args) async { - return false; - } - - @override - Future remove(FuchsiaDevice device, int key) async { - return false; - } - - @override - Future quit(FuchsiaDevice device) async { - return false; - } -} - -class FakeFuchsiaSessionControl implements FuchsiaSessionControl { - @override - Future add(FuchsiaDevice device, String url) async { - return true; - } -} - -class FailingFuchsiaSessionControl implements FuchsiaSessionControl { - @override - Future add(FuchsiaDevice device, String url) async { - return false; - } -} - class FakeFuchsiaDeviceTools implements FuchsiaDeviceTools { FakeFuchsiaDeviceTools({ FuchsiaPkgctl pkgctl, - FuchsiaTilesCtl tiles, - FuchsiaSessionControl sessionControl, + FuchsiaFfx ffx, }) : pkgctl = pkgctl ?? FakeFuchsiaPkgctl(), - tilesCtl = tiles ?? FakeFuchsiaTilesCtl(), - sessionControl = sessionControl ?? FakeFuchsiaSessionControl(); + ffx = ffx ?? FakeFuchsiaFfx(); @override final FuchsiaPkgctl pkgctl; @override - final FuchsiaTilesCtl tilesCtl; - - @override - final FuchsiaSessionControl sessionControl; + final FuchsiaFfx ffx; } class FakeFuchsiaPM implements FuchsiaPM { @@ -638,17 +562,23 @@ class FakeFuchsiaPM implements FuchsiaPM { @override Future build(String buildPath, String manifestPath) async { - if (!globals.fs.file(globals.fs.path.join(buildPath, 'meta', 'package')).existsSync() || + if (!globals.fs + .file(globals.fs.path.join(buildPath, 'meta', 'package')) + .existsSync() || !globals.fs.file(manifestPath).existsSync()) { return false; } - globals.fs.file(globals.fs.path.join(buildPath, 'meta.far')).createSync(recursive: true); + globals.fs + .file(globals.fs.path.join(buildPath, 'meta.far')) + .createSync(recursive: true); return true; } @override Future archive(String buildPath, String manifestPath) async { - if (!globals.fs.file(globals.fs.path.join(buildPath, 'meta', 'package')).existsSync() || + if (!globals.fs + .file(globals.fs.path.join(buildPath, 'meta', 'package')) + .existsSync() || !globals.fs.file(manifestPath).existsSync()) { return false; } @@ -692,7 +622,6 @@ class FailingPM implements FuchsiaPM { return false; } - @override Future build(String buildPath, String manifestPath) async { return false; @@ -728,7 +657,8 @@ class FakeFuchsiaKernelCompiler implements FuchsiaKernelCompiler { }) async { final String outDir = getFuchsiaBuildDirectory(); final String appName = fuchsiaProject.project.manifest.appName; - final String manifestPath = globals.fs.path.join(outDir, '$appName.dilpmanifest'); + final String manifestPath = + globals.fs.path.join(outDir, '$appName.dilpmanifest'); globals.fs.file(manifestPath).createSync(recursive: true); } } @@ -743,6 +673,38 @@ class FakeFuchsiaFfx implements FuchsiaFfx { Future resolve(String deviceName) async { return '192.168.42.10'; } + + @override + Future sessionShow() async { + return null; + } + + @override + Future sessionAdd(String url) async { + return false; + } +} + +class FakeFuchsiaFfxWithSession implements FuchsiaFfx { + @override + Future> list({Duration timeout}) async { + return ['192.168.42.172 scare-cable-skip-ffx']; + } + + @override + Future resolve(String deviceName) async { + return '192.168.42.10'; + } + + @override + Future sessionShow() async { + return 'session info'; + } + + @override + Future sessionAdd(String url) async { + return true; + } } class FakeFuchsiaSdk extends Fake implements FuchsiaSdk { @@ -750,9 +712,9 @@ class FakeFuchsiaSdk extends Fake implements FuchsiaSdk { FuchsiaPM pm, FuchsiaKernelCompiler compiler, FuchsiaFfx ffx, - }) : fuchsiaPM = pm ?? FakeFuchsiaPM(), - fuchsiaKernelCompiler = compiler ?? FakeFuchsiaKernelCompiler(), - fuchsiaFfx = ffx ?? FakeFuchsiaFfx(); + }) : fuchsiaPM = pm ?? FakeFuchsiaPM(), + fuchsiaKernelCompiler = compiler ?? FakeFuchsiaKernelCompiler(), + fuchsiaFfx = ffx ?? FakeFuchsiaFfx(); @override final FuchsiaPM fuchsiaPM; diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart index d761b9e561b..d6636bc6f30 100644 --- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart +++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart @@ -40,7 +40,7 @@ final vm_service.Isolate fakeIsolate = vm_service.Isolate( id: '1', pauseEvent: vm_service.Event( kind: vm_service.EventKind.kResume, - timestamp: 0 + timestamp: 0, ), breakpoints: [], exceptionPauseMode: null, @@ -87,8 +87,10 @@ void main() { expect(device.supportsRuntimeMode(BuildMode.jitRelease), false); }); - testWithoutContext('lists nothing when workflow cannot list devices', () async { - final FakeFuchsiaWorkflow fuchsiaWorkflow = FakeFuchsiaWorkflow(canListDevices: false); + testWithoutContext('lists nothing when workflow cannot list devices', + () async { + final FakeFuchsiaWorkflow fuchsiaWorkflow = + FakeFuchsiaWorkflow(canListDevices: false); final FuchsiaDevices fuchsiaDevices = FuchsiaDevices( platform: FakePlatform(), fuchsiaSdk: FakeFuchsiaSdk(devices: 'ignored'), @@ -102,7 +104,9 @@ void main() { testWithoutContext('can parse ffx output for single device', () async { final FakeFuchsiaWorkflow fuchsiaWorkflow = FakeFuchsiaWorkflow(); - final FakeFuchsiaSdk fuchsiaSdk = FakeFuchsiaSdk(devices: '2001:0db8:85a3:0000:0000:8a2e:0370:7334 paper-pulp-bush-angel'); + final FakeFuchsiaSdk fuchsiaSdk = FakeFuchsiaSdk( + devices: + '2001:0db8:85a3:0000:0000:8a2e:0370:7334 paper-pulp-bush-angel'); final FuchsiaDevices fuchsiaDevices = FuchsiaDevices( platform: FakePlatform(environment: {}), fuchsiaSdk: fuchsiaSdk, @@ -118,10 +122,10 @@ void main() { testWithoutContext('can parse ffx output for multiple devices', () async { final FakeFuchsiaWorkflow fuchsiaWorkflow = FakeFuchsiaWorkflow(); - final FakeFuchsiaSdk fuchsiaSdk = FakeFuchsiaSdk(devices: - '2001:0db8:85a3:0000:0000:8a2e:0370:7334 paper-pulp-bush-angel\n' - '2001:0db8:85a3:0000:0000:8a2e:0370:7335 foo-bar-fiz-buzz' - ); + final FakeFuchsiaSdk fuchsiaSdk = FakeFuchsiaSdk( + devices: + '2001:0db8:85a3:0000:0000:8a2e:0370:7334 paper-pulp-bush-angel\n' + '2001:0db8:85a3:0000:0000:8a2e:0370:7335 foo-bar-fiz-buzz'); final FuchsiaDevices fuchsiaDevices = FuchsiaDevices( platform: FakePlatform(), fuchsiaSdk: fuchsiaSdk, @@ -138,7 +142,8 @@ void main() { }); testWithoutContext('can parse junk output from ffx', () async { - final FakeFuchsiaWorkflow fuchsiaWorkflow = FakeFuchsiaWorkflow(canListDevices: false); + final FakeFuchsiaWorkflow fuchsiaWorkflow = + FakeFuchsiaWorkflow(canListDevices: false); final FakeFuchsiaSdk fuchsiaSdk = FakeFuchsiaSdk(devices: 'junk'); final FuchsiaDevices fuchsiaDevices = FuchsiaDevices( platform: FakePlatform(), @@ -163,7 +168,8 @@ void main() { testWithoutContext('default capabilities', () async { final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); - final FlutterProject project = FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); + final FlutterProject project = + FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); memoryFileSystem.directory('fuchsia').createSync(recursive: true); memoryFileSystem.file('pubspec.yaml').createSync(); @@ -181,7 +187,8 @@ void main() { testWithoutContext('supported for project', () async { final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); - final FlutterProject project = FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); + final FlutterProject project = + FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); memoryFileSystem.directory('fuchsia').createSync(recursive: true); memoryFileSystem.file('pubspec.yaml').createSync(); @@ -190,13 +197,15 @@ void main() { testWithoutContext('not supported for project', () async { final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); - final FlutterProject project = FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); + final FlutterProject project = + FlutterProject.fromDirectoryTest(memoryFileSystem.currentDirectory); memoryFileSystem.file('pubspec.yaml').createSync(); expect(device.isSupportedForProject(project), false); }); - testUsingContext('targetPlatform does not throw when sshConfig is missing', () async { + testUsingContext('targetPlatform does not throw when sshConfig is missing', + () async { final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); expect(await device.targetPlatform, TargetPlatform.fuchsia_arm64); @@ -236,8 +245,15 @@ void main() { testUsingContext('hostAddress parsing works', () async { processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/ssh_config', 'id', r'echo $SSH_CONNECTION'], - stdout: 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', + command: [ + 'ssh', + '-F', + '/ssh_config', + 'id', + r'echo $SSH_CONNECTION' + ], + stdout: + 'fe80::8c6c:2fff:fe3d:c5e1%ethp0003 50666 fe80::5054:ff:fe63:5e7a%ethp0003 22', )); final FuchsiaDevice device = FuchsiaDevice('id', name: 'device'); @@ -248,9 +264,16 @@ void main() { ProcessManager: () => processManager, }); - testUsingContext('hostAddress parsing throws tool error on failure', () async { + testUsingContext('hostAddress parsing throws tool error on failure', + () async { processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/ssh_config', 'id', r'echo $SSH_CONNECTION'], + command: [ + 'ssh', + '-F', + '/ssh_config', + 'id', + r'echo $SSH_CONNECTION' + ], exitCode: 1, )); @@ -262,9 +285,16 @@ void main() { ProcessManager: () => processManager, }); - testUsingContext('hostAddress parsing throws tool error on empty response', () async { + testUsingContext('hostAddress parsing throws tool error on empty response', + () async { processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/ssh_config', 'id', r'echo $SSH_CONNECTION'], + command: [ + 'ssh', + '-F', + '/ssh_config', + 'id', + r'echo $SSH_CONNECTION' + ], )); final FuchsiaDevice device = FuchsiaDevice('id', name: 'device'); @@ -287,28 +317,38 @@ void main() { testUsingContext('No vmservices found', () async { processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/artifact', 'id', 'find /hub -name vmservice-port'], + command: [ + 'ssh', + '-F', + '/artifact', + 'id', + 'find /hub -name vmservice-port' + ], )); final FuchsiaDevice device = FuchsiaDevice('id', name: 'device'); - await expectLater(device.servicePorts, throwsToolExit(message: 'No Dart Observatories found. Are you running a debug build?')); + await expectLater( + device.servicePorts, + throwsToolExit( + message: + 'No Dart Observatories found. Are you running a debug build?')); }, overrides: { ProcessManager: () => processManager, FuchsiaArtifacts: () => FuchsiaArtifacts( - sshConfig: artifactFile, - ffx: artifactFile, - ), + sshConfig: artifactFile, + ffx: artifactFile, + ), FuchsiaSdk: () => FakeFuchsiaSdk(), }); group('device logs', () { const String exampleUtcLogs = ''' -[2018-11-09 01:27:45][3][297950920][log] INFO: example_app.cmx(flutter): Error doing thing +[2018-11-09 01:27:45][3][297950920][log] INFO: example_app.cm(flutter): Error doing thing [2018-11-09 01:27:58][46257][46269][foo] INFO: Using a thing [2018-11-09 01:29:58][46257][46269][foo] INFO: Blah blah blah -[2018-11-09 01:29:58][46257][46269][foo] INFO: other_app.cmx(flutter): Do thing +[2018-11-09 01:29:58][46257][46269][foo] INFO: other_app.cm(flutter): Do thing [2018-11-09 01:30:02][41175][41187][bar] INFO: Invoking a bar -[2018-11-09 01:30:12][52580][52983][log] INFO: example_app.cmx(flutter): Did thing this time +[2018-11-09 01:30:12][52580][52983][log] INFO: example_app.cm(flutter): Did thing this time '''; FakeProcessManager processManager; @@ -316,21 +356,29 @@ void main() { File sshConfig; setUp(() { - processManager = FakeProcessManager.empty(); + processManager = FakeProcessManager.empty(); final FileSystem memoryFileSystem = MemoryFileSystem.test(); ffx = memoryFileSystem.file('ffx')..writeAsStringSync('\n'); - sshConfig = memoryFileSystem.file('ssh_config')..writeAsStringSync('\n'); + sshConfig = memoryFileSystem.file('ssh_config') + ..writeAsStringSync('\n'); }); testUsingContext('can be parsed for an app', () async { final Completer lock = Completer(); processManager.addCommand(FakeCommand( - command: const ['ssh', '-F', '/ssh_config', 'id', 'log_listener --clock Local'], + command: const [ + 'ssh', + '-F', + '/ssh_config', + 'id', + 'log_listener --clock Local' + ], stdout: exampleUtcLogs, completer: lock, )); final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester'); - final DeviceLogReader reader = device.getLogReader(app: FuchsiaModulePackage(name: 'example_app')); + final DeviceLogReader reader = + device.getLogReader(app: FuchsiaModulePackage(name: 'example_app')); final List logLines = []; reader.logLines.listen((String line) { logLines.add(line); @@ -355,12 +403,19 @@ void main() { testUsingContext('cuts off prior logs', () async { final Completer lock = Completer(); processManager.addCommand(FakeCommand( - command: const ['ssh', '-F', '/ssh_config', 'id', 'log_listener --clock Local'], + command: const [ + 'ssh', + '-F', + '/ssh_config', + 'id', + 'log_listener --clock Local' + ], stdout: exampleUtcLogs, completer: lock, )); final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester'); - final DeviceLogReader reader = device.getLogReader(app: FuchsiaModulePackage(name: 'example_app')); + final DeviceLogReader reader = + device.getLogReader(app: FuchsiaModulePackage(name: 'example_app')); final List logLines = []; reader.logLines.listen((String line) { logLines.add(line); @@ -376,13 +431,20 @@ void main() { }, overrides: { ProcessManager: () => processManager, SystemClock: () => SystemClock.fixed(DateTime(2018, 11, 9, 1, 29, 45)), - FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig, ffx: ffx), + FuchsiaArtifacts: () => + FuchsiaArtifacts(sshConfig: sshConfig, ffx: ffx), }); testUsingContext('can be parsed for all apps', () async { final Completer lock = Completer(); processManager.addCommand(FakeCommand( - command: const ['ssh', '-F', '/ssh_config', 'id', 'log_listener --clock Local'], + command: const [ + 'ssh', + '-F', + '/ssh_config', + 'id', + 'log_listener --clock Local' + ], stdout: exampleUtcLogs, completer: lock, )); @@ -407,7 +469,8 @@ void main() { }, overrides: { ProcessManager: () => processManager, SystemClock: () => SystemClock.fixed(DateTime(2018, 11, 9, 1, 25, 45)), - FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig, ffx: ffx), + FuchsiaArtifacts: () => + FuchsiaArtifacts(sshConfig: sshConfig, ffx: ffx), }); }); }); @@ -432,8 +495,8 @@ void main() { expect(device.supportsScreenshot, false); }, overrides: { Platform: () => FakePlatform( - operatingSystem: 'windows', - ), + operatingSystem: 'windows', + ), }); test("takeScreenshot throws if file isn't .ppm", () async { @@ -441,43 +504,38 @@ void main() { await expectLater( () => device.takeScreenshot(globals.fs.file('file.invalid')), throwsA(isA().having( - (Exception exception) => exception.toString(), - 'message', - contains('file.invalid must be a .ppm file') - )), + (Exception exception) => exception.toString(), + 'message', + contains('file.invalid must be a .ppm file'))), ); }); testUsingContext('takeScreenshot throws if screencap failed', () async { - processManager.addCommand(const FakeCommand( - command: [ - 'ssh', - '-F', - '/fuchsia/out/default/.ssh', - '0.0.0.0', - 'screencap > /tmp/screenshot.ppm', - ], - exitCode: 1, - stderr: '' - )); + processManager.addCommand(const FakeCommand(command: [ + 'ssh', + '-F', + '/fuchsia/out/default/.ssh', + '0.0.0.0', + 'screencap > /tmp/screenshot.ppm', + ], exitCode: 1, stderr: '')); final FuchsiaDevice device = FuchsiaDevice('0.0.0.0', name: 'tester'); await expectLater( () => device.takeScreenshot(globals.fs.file('file.ppm')), throwsA(isA().having( - (Exception exception) => exception.toString(), - 'message', - contains('Could not take a screenshot on device tester:\n') - )), + (Exception exception) => exception.toString(), + 'message', + contains( + 'Could not take a screenshot on device tester:\n'))), ); }, overrides: { ProcessManager: () => processManager, FileSystem: () => MemoryFileSystem.test(), Platform: () => FakePlatform( - environment: { - 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', - }, - ), + environment: { + 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', + }, + ), }); testUsingContext('takeScreenshot throws if scp failed', () async { @@ -515,22 +573,24 @@ void main() { await expectLater( () => device.takeScreenshot(globals.fs.file('file.ppm')), throwsA(isA().having( - (Exception exception) => exception.toString(), - 'message', - contains('Failed to copy screenshot from device:\n') - )), + (Exception exception) => exception.toString(), + 'message', + contains( + 'Failed to copy screenshot from device:\n'))), ); }, overrides: { ProcessManager: () => processManager, FileSystem: () => MemoryFileSystem.test(), Platform: () => FakePlatform( - environment: { - 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', - }, - ), + environment: { + 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', + }, + ), }); - testUsingContext("takeScreenshot prints error if can't delete file from device", () async { + testUsingContext( + "takeScreenshot prints error if can't delete file from device", + () async { final FuchsiaDevice device = FuchsiaDevice('0.0.0.0', name: 'tester'); processManager.addCommand(const FakeCommand( command: [ @@ -565,16 +625,17 @@ void main() { await device.takeScreenshot(globals.fs.file('file.ppm')); expect( testLogger.errorText, - contains('Failed to delete screenshot.ppm from the device:\n'), + contains( + 'Failed to delete screenshot.ppm from the device:\n'), ); }, overrides: { ProcessManager: () => processManager, FileSystem: () => MemoryFileSystem.test(), Platform: () => FakePlatform( - environment: { - 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', - }, - ), + environment: { + 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', + }, + ), }, testOn: 'posix'); testUsingContext('takeScreenshot returns', () async { @@ -607,15 +668,16 @@ void main() { ], )); - expect(() => device.takeScreenshot(globals.fs.file('file.ppm')), returnsNormally); + expect(() => device.takeScreenshot(globals.fs.file('file.ppm')), + returnsNormally); }, overrides: { ProcessManager: () => processManager, FileSystem: () => MemoryFileSystem.test(), Platform: () => FakePlatform( - environment: { - 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', - }, - ), + environment: { + 'FUCHSIA_SSH_CONFIG': '/fuchsia/out/default/.ssh', + }, + ), }); }); @@ -625,21 +687,36 @@ void main() { setUp(() { processManager = FakeProcessManager.empty(); - sshConfig = MemoryFileSystem.test().file('irrelevant')..writeAsStringSync('\n'); + sshConfig = MemoryFileSystem.test().file('irrelevant') + ..writeAsStringSync('\n'); }); - testUsingContext('`unforward` prints stdout and stderr if ssh command failed', () async { + testUsingContext( + '`unforward` prints stdout and stderr if ssh command failed', () async { final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester'); processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/irrelevant', '-O', 'cancel', '-vvv', '-L', '0:127.0.0.1:1', 'id'], + command: [ + 'ssh', + '-F', + '/irrelevant', + '-O', + 'cancel', + '-vvv', + '-L', + '0:127.0.0.1:1', + 'id' + ], exitCode: 1, stdout: '', stderr: '', )); await expectLater( - () => device.portForwarder.unforward(ForwardedPort(/*hostPort=*/ 0, /*devicePort=*/ 1)), - throwsToolExit(message: 'Unforward command failed:\nstdout: \nstderr: '), + () => device.portForwarder + .unforward(ForwardedPort(/*hostPort=*/ 0, /*devicePort=*/ 1)), + throwsToolExit( + message: + 'Unforward command failed:\nstdout: \nstderr: '), ); }, overrides: { ProcessManager: () => processManager, @@ -647,26 +724,26 @@ void main() { }); }); - group('FuchsiaIsolateDiscoveryProtocol', () { - Future findUri(List views, String expectedIsolateName) async { + Future findUri( + List views, String expectedIsolateName) async { final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( requests: [ FakeVmServiceRequest( method: kListViewsMethod, jsonResponse: { 'views': [ - for (FlutterView view in views) - view.toJson(), + for (FlutterView view in views) view.toJson(), ], }, ), ], httpAddress: Uri.parse('example'), ); - final MockFuchsiaDevice fuchsiaDevice = MockFuchsiaDevice('123', const NoOpDevicePortForwarder(), false); + final MockFuchsiaDevice fuchsiaDevice = + MockFuchsiaDevice('123', const NoOpDevicePortForwarder(), false); final FuchsiaIsolateDiscoveryProtocol discoveryProtocol = - FuchsiaIsolateDiscoveryProtocol( + FuchsiaIsolateDiscoveryProtocol( fuchsiaDevice, expectedIsolateName, (Uri uri) async => fakeVmServiceHost.vmService, @@ -676,7 +753,8 @@ void main() { return discoveryProtocol.uri; } - testUsingContext('can find flutter view with matching isolate name', () async { + testUsingContext('can find flutter view with matching isolate name', + () async { const String expectedIsolateName = 'foobar'; final Uri uri = await findUri([ // no ui isolate. @@ -693,25 +771,29 @@ void main() { FlutterView( id: '3', uiIsolate: vm_service.Isolate.parse({ - ...fakeIsolate.toJson(), + ...fakeIsolate.toJson(), 'name': expectedIsolateName, }), ), ], expectedIsolateName); - expect(uri.toString(), 'http://${InternetAddress.loopbackIPv4.address}:0/'); + expect( + uri.toString(), 'http://${InternetAddress.loopbackIPv4.address}:0/'); }); - testUsingContext('can handle flutter view without matching isolate name', () async { + testUsingContext('can handle flutter view without matching isolate name', + () async { const String expectedIsolateName = 'foobar'; final Future uri = findUri([ // no ui isolate. FlutterView(id: '1', uiIsolate: fakeIsolate), // wrong name. - FlutterView(id: '2', uiIsolate: vm_service.Isolate.parse({ - ...fakeIsolate.toJson(), - 'name': 'wrong name', - })), + FlutterView( + id: '2', + uiIsolate: vm_service.Isolate.parse({ + ...fakeIsolate.toJson(), + 'name': 'wrong name', + })), ], expectedIsolateName); expect(uri, throwsException); @@ -738,28 +820,32 @@ void main() { platform: FakePlatform(), operatingSystemUtils: globals.os, ); - expect(artifacts.getArtifactPath( + expect( + artifacts.getArtifactPath( Artifact.fuchsiaFlutterRunner, platform: TargetPlatform.fuchsia_x64, mode: BuildMode.debug, ), contains('flutter_jit_runner'), ); - expect(artifacts.getArtifactPath( + expect( + artifacts.getArtifactPath( Artifact.fuchsiaFlutterRunner, platform: TargetPlatform.fuchsia_x64, mode: BuildMode.profile, ), contains('flutter_aot_runner'), ); - expect(artifacts.getArtifactPath( + expect( + artifacts.getArtifactPath( Artifact.fuchsiaFlutterRunner, platform: TargetPlatform.fuchsia_x64, mode: BuildMode.release, ), contains('flutter_aot_product_runner'), ); - expect(artifacts.getArtifactPath( + expect( + artifacts.getArtifactPath( Artifact.fuchsiaFlutterRunner, platform: TargetPlatform.fuchsia_x64, mode: BuildMode.jitRelease, @@ -773,7 +859,8 @@ void main() { FakeProcessManager processManager; setUp(() { - sshConfig = MemoryFileSystem.test().file('ssh_config')..writeAsStringSync('\n'); + sshConfig = MemoryFileSystem.test().file('ssh_config') + ..writeAsStringSync('\n'); processManager = FakeProcessManager.empty(); }); @@ -787,11 +874,15 @@ void main() { FuchsiaSdk: () => FakeFuchsiaSdk(), }); - testUsingContext('returns what we get from the device on success', () async { - processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/ssh_config', '123', 'cat /pkgfs/packages/build-info/0/data/version'], - stdout: 'version' - )); + testUsingContext('returns what we get from the device on success', + () async { + processManager.addCommand(const FakeCommand(command: [ + 'ssh', + '-F', + '/ssh_config', + '123', + 'cat /pkgfs/packages/build-info/0/data/version' + ], stdout: 'version')); final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); expect(await device.sdkNameAndVersion, equals('Fuchsia version')); @@ -803,7 +894,13 @@ void main() { testUsingContext('returns "Fuchsia" when device command fails', () async { processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/ssh_config', '123', 'cat /pkgfs/packages/build-info/0/data/version'], + command: [ + 'ssh', + '-F', + '/ssh_config', + '123', + 'cat /pkgfs/packages/build-info/0/data/version' + ], exitCode: 1, )); final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); @@ -815,9 +912,16 @@ void main() { FuchsiaSdk: () => FakeFuchsiaSdk(), }); - testUsingContext('returns "Fuchsia" when device gives an empty result', () async { + testUsingContext('returns "Fuchsia" when device gives an empty result', + () async { processManager.addCommand(const FakeCommand( - command: ['ssh', '-F', '/ssh_config', '123', 'cat /pkgfs/packages/build-info/0/data/version'], + command: [ + 'ssh', + '-F', + '/ssh_config', + '123', + 'cat /pkgfs/packages/build-info/0/data/version' + ], )); final FuchsiaDevice device = FuchsiaDevice('123', name: 'device'); @@ -855,7 +959,8 @@ class MockFuchsiaDevice extends Fake implements FuchsiaDevice { final DevicePortForwarder portForwarder; @override - Future get targetPlatform async => TargetPlatform.fuchsia_arm64; + Future get targetPlatform async => + TargetPlatform.fuchsia_arm64; @override String get name => 'fuchsia'; @@ -886,6 +991,16 @@ class FakeFuchsiaFfx implements FuchsiaFfx { Future resolve(String deviceName) async { return '192.168.42.10'; } + + @override + Future sessionShow() async { + return null; + } + + @override + Future sessionAdd(String url) async { + return false; + } } class FakeFuchsiaSdk extends Fake implements FuchsiaSdk { @@ -894,10 +1009,10 @@ class FakeFuchsiaSdk extends Fake implements FuchsiaSdk { FuchsiaKernelCompiler compiler, FuchsiaFfx ffx, String devices, - }) : fuchsiaPM = pm, - fuchsiaKernelCompiler = compiler, - fuchsiaFfx = ffx ?? FakeFuchsiaFfx(), - _devices = devices; + }) : fuchsiaPM = pm, + fuchsiaKernelCompiler = compiler, + fuchsiaFfx = ffx ?? FakeFuchsiaFfx(), + _devices = devices; @override final FuchsiaPM fuchsiaPM; @@ -916,7 +1031,8 @@ class FakeFuchsiaSdk extends Fake implements FuchsiaSdk { } } -class FakeDartDevelopmentService extends Fake implements DartDevelopmentService { +class FakeDartDevelopmentService extends Fake + implements DartDevelopmentService { @override Future startDartDevelopmentService( Uri observatoryUri, { diff --git a/packages/flutter_tools/test/integration.shard/analyze_suggestions_integration_test.dart b/packages/flutter_tools/test/integration.shard/analyze_suggestions_integration_test.dart index cae469f2447..ec8363881b7 100644 --- a/packages/flutter_tools/test/integration.shard/analyze_suggestions_integration_test.dart +++ b/packages/flutter_tools/test/integration.shard/analyze_suggestions_integration_test.dart @@ -43,14 +43,14 @@ void main() { ]); const String expected = '\n' - '┌────────────────────────────────────────────────────────────────────────────┐\n' - '│ General Info │\n' - '│ [✓] App Name: flutter_gallery │\n' - '│ [✓] Supported Platforms: android, ios, web, macos, linux, windows, fuchsia │\n' - '│ [✓] Is Flutter Package: yes │\n' - '│ [✓] Uses Material Design: yes │\n' - '│ [✓] Is Plugin: no │\n' - '└────────────────────────────────────────────────────────────────────────────┘\n'; + '┌───────────────────────────────────────────────────────────────────┐\n' + '│ General Info │\n' + '│ [✓] App Name: flutter_gallery │\n' + '│ [✓] Supported Platforms: android, ios, web, macos, linux, windows │\n' + '│ [✓] Is Flutter Package: yes │\n' + '│ [✓] Uses Material Design: yes │\n' + '│ [✓] Is Plugin: no │\n' + '└───────────────────────────────────────────────────────────────────┘\n'; expect(loggerTest.statusText, contains(expected)); }); diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index b94529aa775..d0d8ad21ae3 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -252,9 +252,6 @@ class FakeStdin extends Fake implements Stdin { @override bool echoMode = true; - @override - bool echoNewlineMode = true; - @override bool lineMode = true; diff --git a/packages/fuchsia_remote_debug_protocol/test/src/dart/dart_vm_test.dart b/packages/fuchsia_remote_debug_protocol/test/src/dart/dart_vm_test.dart index 0b49bd5c585..21bbb051308 100644 --- a/packages/fuchsia_remote_debug_protocol/test/src/dart/dart_vm_test.dart +++ b/packages/fuchsia_remote_debug_protocol/test/src/dart/dart_vm_test.dart @@ -25,7 +25,8 @@ void main() { } fuchsiaVmServiceConnectionFunction = fakeServiceFunction; - final DartVm vm = await DartVm.connect(Uri.parse('http://this.whatever/ws')); + final DartVm vm = + await DartVm.connect(Uri.parse('http://this.whatever/ws')); expect(vm, isNot(null)); await vm.stop(); expect(service.disposed, true); @@ -79,12 +80,14 @@ void main() { Uri uri, { Duration? timeout, }) { - fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponses); + fakeService.flutterListViews = + vms.Response.parse(flutterViewCannedResponses); return Future(() => fakeService); } fuchsiaVmServiceConnectionFunction = fakeVmConnectionFunction; - final DartVm vm = await DartVm.connect(Uri.parse('http://whatever.com/ws')); + final DartVm vm = + await DartVm.connect(Uri.parse('http://whatever.com/ws')); expect(vm, isNot(null)); final List views = await vm.getAllFlutterViews(); expect(views.length, 3); @@ -135,12 +138,14 @@ void main() { Uri uri, { Duration? timeout, }) { - fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponses); + fakeService.flutterListViews = + vms.Response.parse(flutterViewCannedResponses); return Future(() => fakeService); } fuchsiaVmServiceConnectionFunction = fakeVmConnectionFunction; - final DartVm vm = await DartVm.connect(Uri.parse('http://whatever.com/ws')); + final DartVm vm = + await DartVm.connect(Uri.parse('http://whatever.com/ws')); expect(vm, isNot(null)); final List views = await vm.getAllFlutterViews(); expect(views.length, 3); @@ -156,7 +161,8 @@ void main() { }); test('invalid flutter view missing ID', () async { - final Map flutterViewCannedResponseMissingId = { + final Map flutterViewCannedResponseMissingId = + { 'views': >[ // Valid flutter view. { @@ -182,12 +188,14 @@ void main() { Uri uri, { Duration? timeout, }) { - fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponseMissingId); + fakeService.flutterListViews = + vms.Response.parse(flutterViewCannedResponseMissingId); return Future(() => fakeService); } fuchsiaVmServiceConnectionFunction = fakeVmConnectionFunction; - final DartVm vm = await DartVm.connect(Uri.parse('http://whatever.com/ws')); + final DartVm vm = + await DartVm.connect(Uri.parse('http://whatever.com/ws')); expect(vm, isNot(null)); Future failingFunction() async { await vm.getAllFlutterViews(); @@ -217,7 +225,7 @@ void main() { 'type': '@Isolate', 'fixedId': 'true', 'id': 'isolates/3', - 'name': 'flutterBinary.cmx', + 'name': 'flutterBinary.cm', 'number': '3', })!, vms.IsolateRef.parse({ @@ -238,16 +246,20 @@ void main() { } fuchsiaVmServiceConnectionFunction = fakeVmConnectionFunction; - final DartVm vm = await DartVm.connect(Uri.parse('http://whatever.com/ws')); + final DartVm vm = + await DartVm.connect(Uri.parse('http://whatever.com/ws')); expect(vm, isNot(null)); - final List matchingFlutterIsolates = await vm.getMainIsolatesByPattern('flutterBinary.cmx'); + final List matchingFlutterIsolates = + await vm.getMainIsolatesByPattern('flutterBinary.cm'); expect(matchingFlutterIsolates.length, 1); - final List allIsolates = await vm.getMainIsolatesByPattern(''); + final List allIsolates = + await vm.getMainIsolatesByPattern(''); expect(allIsolates.length, 4); }); test('invalid flutter view missing ID', () async { - final Map flutterViewCannedResponseMissingIsolateName = { + final Map flutterViewCannedResponseMissingIsolateName = + { 'views': >[ // Missing isolate name. { @@ -267,12 +279,14 @@ void main() { Uri uri, { Duration? timeout, }) { - fakeService.flutterListViews = vms.Response.parse(flutterViewCannedResponseMissingIsolateName); + fakeService.flutterListViews = + vms.Response.parse(flutterViewCannedResponseMissingIsolateName); return Future(() => fakeService); } fuchsiaVmServiceConnectionFunction = fakeVmConnectionFunction; - final DartVm vm = await DartVm.connect(Uri.parse('http://whatever.com/ws')); + final DartVm vm = + await DartVm.connect(Uri.parse('http://whatever.com/ws')); expect(vm, isNot(null)); Future failingFunction() async { await vm.getAllFlutterViews(); @@ -298,7 +312,8 @@ class FakeVmService extends Fake implements vms.VmService { } @override - Future callMethod(String method, {String? isolateId, Map? args}) async { + Future callMethod(String method, + {String? isolateId, Map? args}) async { if (method == '_flutter.listViews') { return flutterListViews!; }