diff --git a/packages/flutter_tools/lib/src/resident_devtools_handler.dart b/packages/flutter_tools/lib/src/resident_devtools_handler.dart index abb248bd4ef..6c9310eb7ca 100644 --- a/packages/flutter_tools/lib/src/resident_devtools_handler.dart +++ b/packages/flutter_tools/lib/src/resident_devtools_handler.dart @@ -13,10 +13,27 @@ import 'base/logger.dart'; import 'resident_runner.dart'; import 'vmservice.dart'; +typedef ResidentDevtoolsHandlerFactory = ResidentDevtoolsHandler Function(DevtoolsLauncher, ResidentRunner, Logger); + +ResidentDevtoolsHandler createDefaultHandler(DevtoolsLauncher launcher, ResidentRunner runner, Logger logger) { + return FlutterResidentDevtoolsHandler(launcher, runner, logger); +} + /// Helper class to manage the life-cycle of devtools and its interaction with /// the resident runner. -class ResidentDevtoolsHandler { - ResidentDevtoolsHandler(this._devToolsLauncher, this._residentRunner, this._logger); +abstract class ResidentDevtoolsHandler { + /// The current devtools server, or null if one is not running. + DevToolsServerAddress get activeDevToolsServer; + + Future hotRestart(List flutterDevices); + + Future serveAndAnnounceDevTools({Uri devToolsServerAddress, List flutterDevices}); + + Future shutdown(); +} + +class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { + FlutterResidentDevtoolsHandler(this._devToolsLauncher, this._residentRunner, this._logger); final DevtoolsLauncher _devToolsLauncher; final ResidentRunner _residentRunner; @@ -24,10 +41,11 @@ class ResidentDevtoolsHandler { bool _shutdown = false; bool _served = false; - /// The current devtools server, or null if one is not running. + @override DevToolsServerAddress get activeDevToolsServer => _devToolsLauncher?.activeDevToolsServer; // This must be guaranteed not to return a Future that fails. + @override Future serveAndAnnounceDevTools({ Uri devToolsServerAddress, @required List flutterDevices, @@ -48,12 +66,16 @@ class ResidentDevtoolsHandler { // report their URLs yet. Do so now. _residentRunner.printDebuggerList(includeObservatory: false); } - await maybeCallDevToolsUriServiceExtension( + await _waitForExtensions(flutterDevices); + await _maybeCallDevToolsUriServiceExtension( + flutterDevices, + ); + await _callConnectedVmServiceUriExtension( flutterDevices, ); } - Future maybeCallDevToolsUriServiceExtension( + Future _maybeCallDevToolsUriServiceExtension( List flutterDevices, ) async { if (_devToolsLauncher?.activeDevToolsServer == null) { @@ -69,7 +91,6 @@ class ResidentDevtoolsHandler { Future _callDevToolsUriExtension( FlutterDevice device, ) async { - await waitForExtension(device.vmService, 'ext.flutter.activeDevToolsServerAddress'); try { await _invokeRpcOnFirstView( 'ext.flutter.activeDevToolsServerAddress', @@ -86,7 +107,15 @@ class ResidentDevtoolsHandler { } } - Future callConnectedVmServiceUriExtension(List flutterDevices) async { + Future _waitForExtensions(List flutterDevices) async { + await Future.wait(>[ + for (final FlutterDevice device in flutterDevices) + if (device.vmService != null) + waitForExtension(device.vmService, 'ext.flutter.connectedVmServiceUri'), + ]); + } + + Future _callConnectedVmServiceUriExtension(List flutterDevices) async { await Future.wait(>[ for (final FlutterDevice device in flutterDevices) if (device.vmService != null) @@ -95,24 +124,24 @@ class ResidentDevtoolsHandler { } Future _callConnectedVmServiceExtension(FlutterDevice device) async { - if (device.vmService.httpAddress != null || device.vmService.wsAddress != null) { - final Uri uri = device.vmService.httpAddress ?? device.vmService.wsAddress; - await waitForExtension(device.vmService, 'ext.flutter.connectedVmServiceUri'); - try { - await _invokeRpcOnFirstView( - 'ext.flutter.connectedVmServiceUri', - device: device, - params: { - 'value': uri.toString(), - }, - ); - } on Exception catch (e) { - _logger.printError(e.toString()); - _logger.printError( - 'Failed to set vm service URI: ${e.toString()}. Deep links to DevTools' - ' will not show in Flutter errors.', - ); - } + final Uri uri = device.vmService.httpAddress ?? device.vmService.wsAddress; + if (uri == null) { + return; + } + try { + await _invokeRpcOnFirstView( + 'ext.flutter.connectedVmServiceUri', + device: device, + params: { + 'value': uri.toString(), + }, + ); + } on Exception catch (e) { + _logger.printError(e.toString()); + _logger.printError( + 'Failed to set vm service URI: ${e.toString()}. Deep links to DevTools' + ' will not show in Flutter errors.', + ); } } @@ -121,6 +150,9 @@ class ResidentDevtoolsHandler { @required Map params, }) async { final List views = await device.vmService.getFlutterViews(); + if (views.isEmpty) { + return; + } await device.vmService .invokeFlutterExtensionRpcRaw( method, @@ -130,13 +162,16 @@ class ResidentDevtoolsHandler { ); } + @override Future hotRestart(List flutterDevices) async { + await _waitForExtensions(flutterDevices); await Future.wait(>[ - maybeCallDevToolsUriServiceExtension(flutterDevices), - callConnectedVmServiceUriExtension(flutterDevices), + _maybeCallDevToolsUriServiceExtension(flutterDevices), + _callConnectedVmServiceUriExtension(flutterDevices), ]); } + @override Future shutdown() async { if (_devToolsLauncher == null || _shutdown || !_served) { return; @@ -176,3 +211,29 @@ Future waitForExtension(vm_service.VmService vmService, String extension) } await completer.future; } + +@visibleForTesting +NoOpDevtoolsHandler createNoOpHandler(DevtoolsLauncher launcher, ResidentRunner runner, Logger logger) { + return NoOpDevtoolsHandler(); +} + +@visibleForTesting +class NoOpDevtoolsHandler implements ResidentDevtoolsHandler { + @override + DevToolsServerAddress get activeDevToolsServer => null; + + @override + Future hotRestart(List flutterDevices) async { + return; + } + + @override + Future serveAndAnnounceDevTools({Uri devToolsServerAddress, List flutterDevices}) async { + return; + } + + @override + Future shutdown() async { + return; + } +} diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 58edfe96fed..e6b8a6e2144 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -758,6 +758,7 @@ abstract class ResidentRunner { this.hotMode = true, String dillOutputPath, this.machine = false, + ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler, }) : mainPath = globals.fs.path.absolute(target), packagesFilePath = debuggingOptions.buildInfo.packagesPath, projectRootPath = projectRootPath ?? globals.fs.currentDirectory.path, @@ -775,7 +776,7 @@ abstract class ResidentRunner { if (!artifactDirectory.existsSync()) { artifactDirectory.createSync(recursive: true); } - _residentDevtoolsHandler = ResidentDevtoolsHandler(DevtoolsLauncher.instance, this, globals.logger); + _residentDevtoolsHandler = devtoolsHandler(DevtoolsLauncher.instance, this, globals.logger); } @protected diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart index 222068a8f41..fdcddb93c44 100644 --- a/packages/flutter_tools/lib/src/run_cold.dart +++ b/packages/flutter_tools/lib/src/run_cold.dart @@ -13,6 +13,7 @@ import 'base/file_system.dart'; import 'build_info.dart'; import 'device.dart'; import 'globals.dart' as globals; +import 'resident_devtools_handler.dart'; import 'resident_runner.dart'; import 'tracing.dart'; import 'vmservice.dart'; @@ -28,6 +29,7 @@ class ColdRunner extends ResidentRunner { bool ipv6 = false, bool stayResident = true, bool machine = false, + ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler, }) : super( devices, target: target, @@ -36,6 +38,7 @@ class ColdRunner extends ResidentRunner { stayResident: stayResident, ipv6: ipv6, machine: machine, + devtoolsHandler: devtoolsHandler, ); final bool traceStartup; @@ -73,14 +76,6 @@ class ColdRunner extends ResidentRunner { return 1; } - if (enableDevTools) { - // The method below is guaranteed never to return a failing future. - unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools( - devToolsServerAddress: debuggingOptions.devToolsServerAddress, - flutterDevices: flutterDevices, - )); - } - // Connect to observatory. if (debuggingEnabled) { try { @@ -92,6 +87,14 @@ class ColdRunner extends ResidentRunner { } } + if (enableDevTools && debuggingEnabled) { + // The method below is guaranteed never to return a failing future. + unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools( + devToolsServerAddress: debuggingOptions.devToolsServerAddress, + flutterDevices: flutterDevices, + )); + } + if (flutterDevices.first.observatoryUris != null) { // For now, only support one debugger connection. connectionInfoCompleter?.complete(DebugConnectionInfo( @@ -125,12 +128,6 @@ class ColdRunner extends ResidentRunner { appFinished(); } - if (debuggingEnabled) { - unawaited(residentDevtoolsHandler.callConnectedVmServiceUriExtension( - flutterDevices, - )); - } - appStartedCompleter?.complete(); writeVmServiceFile(); @@ -160,14 +157,6 @@ class ColdRunner extends ResidentRunner { return 2; } - if (enableDevTools) { - // The method below is guaranteed never to return a failing future. - unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools( - devToolsServerAddress: debuggingOptions.devToolsServerAddress, - flutterDevices: flutterDevices, - )); - } - for (final FlutterDevice device in flutterDevices) { await device.initLogReader(); } @@ -178,9 +167,13 @@ class ColdRunner extends ResidentRunner { } } - unawaited(residentDevtoolsHandler.callConnectedVmServiceUriExtension( - flutterDevices, - )); + if (enableDevTools && debuggingEnabled) { + // The method below is guaranteed never to return a failing future. + unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools( + devToolsServerAddress: debuggingOptions.devToolsServerAddress, + flutterDevices: flutterDevices, + )); + } appStartedCompleter?.complete(); if (stayResident) { diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index aa590d9735b..7d6b7142d31 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -5,10 +5,11 @@ // @dart = 2.8 import 'dart:async'; -import 'package:package_config/package_config.dart'; -import 'package:vm_service/vm_service.dart' as vm_service; + import 'package:meta/meta.dart'; +import 'package:package_config/package_config.dart'; import 'package:pool/pool.dart'; +import 'package:vm_service/vm_service.dart' as vm_service; import 'base/common.dart'; import 'base/context.dart'; @@ -26,6 +27,7 @@ import 'device.dart'; import 'features.dart'; import 'globals.dart' as globals; import 'reporting/reporting.dart'; +import 'resident_devtools_handler.dart'; import 'resident_runner.dart'; import 'vmservice.dart'; @@ -78,6 +80,7 @@ class HotRunner extends ResidentRunner { bool stayResident = true, bool ipv6 = false, bool machine = false, + ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler, }) : super( devices, target: target, @@ -88,6 +91,7 @@ class HotRunner extends ResidentRunner { dillOutputPath: dillOutputPath, ipv6: ipv6, machine: machine, + devtoolsHandler: devtoolsHandler, ); final bool benchmarkMode; @@ -222,10 +226,6 @@ class HotRunner extends ResidentRunner { return 3; } - unawaited(residentDevtoolsHandler.callConnectedVmServiceUriExtension( - flutterDevices, - )); - final Stopwatch initialUpdateDevFSsTimer = Stopwatch()..start(); final UpdateFSReport devfsResult = await _updateDevFS(fullRestart: true); _addBenchmarkData( diff --git a/packages/flutter_tools/test/general.shard/hot_test.dart b/packages/flutter_tools/test/general.shard/hot_test.dart index b6850611b8f..89e43f4132f 100644 --- a/packages/flutter_tools/test/general.shard/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/hot_test.dart @@ -7,6 +7,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/resident_devtools_handler.dart'; import 'package:vm_service/vm_service.dart' as vm_service; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/io.dart'; @@ -187,6 +188,7 @@ void main() { devices, debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ).restart(fullRestart: true); // Expect hot restart failed. expect(result.isOk, false); @@ -219,6 +221,7 @@ void main() { devices, debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ).restart(fullRestart: true); // Expect hot restart failed. expect(result.isOk, false); @@ -322,6 +325,7 @@ void main() { devices, debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); final OperationResult result = await hotRunner.restart(fullRestart: true); // Expect hot restart was successful. @@ -351,6 +355,7 @@ void main() { devices, debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ).restart(fullRestart: true); expect(result.isOk, false); expect(result.message, 'setupHotRestart failed'); @@ -417,6 +422,7 @@ void main() { devices, debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); final OperationResult result = await hotRunner.restart(fullRestart: true); // Expect hot restart successful. diff --git a/packages/flutter_tools/test/general.shard/resident_devtools_handler_test.dart b/packages/flutter_tools/test/general.shard/resident_devtools_handler_test.dart index 0ea507d7fd9..bcd34e26c97 100644 --- a/packages/flutter_tools/test/general.shard/resident_devtools_handler_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_devtools_handler_test.dart @@ -6,6 +6,7 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/devtools_launcher.dart'; +import 'package:flutter_tools/src/vmservice.dart'; import 'package:vm_service/vm_service.dart' as vm_service; import 'package:flutter_tools/src/base/logger.dart'; @@ -16,6 +17,31 @@ import 'package:test/fake.dart'; import '../src/common.dart'; import '../src/context.dart'; + final vm_service.Isolate isolate = vm_service.Isolate( + id: '1', + pauseEvent: vm_service.Event( + kind: vm_service.EventKind.kResume, + timestamp: 0 + ), + breakpoints: [], + exceptionPauseMode: null, + libraries: [ + vm_service.LibraryRef( + id: '1', + uri: 'file:///hello_world/main.dart', + name: '', + ), + ], + livePorts: 0, + name: 'test', + number: '1', + pauseOnExit: false, + runnable: true, + startTime: 0, + isSystemIsolate: false, + isolateFlags: [], + extensionRPCs: ['foo'] +); final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate( id: '1', @@ -58,9 +84,23 @@ final vm_service.VM fakeVM = vm_service.VM( systemIsolates: [], ); +final FlutterView fakeFlutterView = FlutterView( + id: 'a', + uiIsolate: fakeUnpausedIsolate, +); + +final FakeVmServiceRequest listViews = FakeVmServiceRequest( + method: kListViewsMethod, + jsonResponse: { + 'views': [ + fakeFlutterView.toJson(), + ], + }, +); + void main() { testWithoutContext('Does not serve devtools if launcher is null', () async { - final ResidentDevtoolsHandler handler = ResidentDevtoolsHandler( + final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler( null, FakeResidentRunner(), BufferLogger.test(), @@ -72,7 +112,7 @@ void main() { }); testWithoutContext('Does not serve devtools if ResidentRunner does not support the service protocol', () async { - final ResidentDevtoolsHandler handler = ResidentDevtoolsHandler( + final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler( FakeDevtoolsLauncher(), FakeResidentRunner()..supportsServiceProtocol = false, BufferLogger.test(), @@ -91,7 +131,7 @@ void main() { platform: FakePlatform(), persistentToolState: null, ); - final ResidentDevtoolsHandler handler = ResidentDevtoolsHandler( + final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler( // Uses real devtools instance which should be a no-op if // URI is already set. launcher, @@ -108,8 +148,8 @@ void main() { expect(handler.activeDevToolsServer.port, 8181); }); - testWithoutContext('can serveAndAnnounceDevTools with attached device does not fail on null vm service', () async { - final ResidentDevtoolsHandler handler = ResidentDevtoolsHandler( + testWithoutContext('serveAndAnnounceDevTools with attached device does not fail on null vm service', () async { + final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler( FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080), FakeResidentRunner(), BufferLogger.test(), @@ -123,33 +163,63 @@ void main() { ); }); - testWithoutContext('wait for extension handles an immediate extension', () { - final vm_service.Isolate isolate = vm_service.Isolate( - id: '1', - pauseEvent: vm_service.Event( - kind: vm_service.EventKind.kResume, - timestamp: 0 - ), - breakpoints: [], - exceptionPauseMode: null, - libraries: [ - vm_service.LibraryRef( - id: '1', - uri: 'file:///hello_world/main.dart', - name: '', - ), - ], - livePorts: 0, - name: 'test', - number: '1', - pauseOnExit: false, - runnable: true, - startTime: 0, - isSystemIsolate: false, - isolateFlags: [], - extensionRPCs: ['foo'] + testWithoutContext('serveAndAnnounceDevTools with invokes devtools and vm_service setter', () async { + final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler( + FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080), + FakeResidentRunner(), + BufferLogger.test(), ); + final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: [ + const FakeVmServiceRequest( + method: 'streamListen', + args: { + 'streamId': 'Extension', + } + ), + FakeVmServiceRequest(method: 'getVM', jsonResponse: fakeVM.toJson()), + FakeVmServiceRequest( + method: 'getIsolate', + jsonResponse: isolate.toJson(), + args: { + 'isolateId': '1', + }, + ), + FakeVmServiceStreamResponse( + streamId: 'Extension', + event: vm_service.Event( + timestamp: 0, + extensionKind: 'Flutter.FrameworkInitialization', + kind: 'test', + ), + ), + listViews, + const FakeVmServiceRequest( + method: 'ext.flutter.activeDevToolsServerAddress', + args: { + 'isolateId': '1', + 'value': 'http://localhost:8080', + }, + ), + listViews, + const FakeVmServiceRequest( + method: 'ext.flutter.connectedVmServiceUri', + args: { + 'isolateId': '1', + 'value': 'http://localhost:1234', + }, + ), + ]); + final FakeFlutterDevice device = FakeFlutterDevice() + ..vmService = fakeVmServiceHost.vmService; + setHttpAddress(Uri.parse('http://localhost:1234'), fakeVmServiceHost.vmService); + + await handler.serveAndAnnounceDevTools( + flutterDevices: [device], + ); + }); + + testWithoutContext('wait for extension handles an immediate extension', () { final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(requests: [ const FakeVmServiceRequest( method: 'streamListen', diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 311e1cc3121..a317042141d 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -10,6 +10,7 @@ import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/base/dds.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/resident_devtools_handler.dart'; import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -132,11 +133,6 @@ const FakeVmServiceRequest setAssetBundlePath = FakeVmServiceRequest( } ); -const FakeVmServiceRequest listenToExtensionStream = FakeVmServiceRequest( - method: 'streamListen', - args: {'streamId': 'Extension'}, -); - final Uri testUri = Uri.parse('foo://bar'); void main() { @@ -163,6 +159,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); }); mockFlutterDevice = MockFlutterDevice(); @@ -261,6 +258,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.generator).thenReturn(residentCompiler); when(residentCompiler.recompile( @@ -305,6 +303,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.generator).thenReturn(residentCompiler); when(residentCompiler.recompile( @@ -340,6 +339,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.runCold( coldRunner: anyNamed('coldRunner'), @@ -365,6 +365,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.runCold( coldRunner: anyNamed('coldRunner'), @@ -395,6 +396,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.generator).thenReturn(residentCompiler); when(residentCompiler.recompile( @@ -477,6 +479,7 @@ void main() { startPaused: true, ), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); final Completer futureConnectionInfo = Completer.sync(); final Completer futureAppStart = Completer.sync(); @@ -639,6 +642,7 @@ void main() { '--enable-experiment=non-nullable', ], )), + devtoolsHandler: createNoOpHandler, ); final Completer futureConnectionInfo = Completer.sync(); final Completer futureAppStart = Completer.sync(); @@ -709,6 +713,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); final Completer futureConnectionInfo = Completer.sync(); final Completer futureAppStart = Completer.sync(); @@ -1029,6 +1034,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockDevFS.update( mainUri: anyNamed('mainUri'), @@ -1402,6 +1408,7 @@ void main() { debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), dillOutputPath: globals.fs.path.join('foobar', 'app.dill'), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(otherRunner.artifactDirectory.path, contains('foobar')); })); @@ -1511,6 +1518,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); residentRunner.printHelp(details: true); @@ -1587,59 +1595,6 @@ void main() { ) })); - testUsingContext('ResidentRunner invokes DevToolsLauncher when attaching and shutting down DevTools', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: [ - listViews, - listViews, - setAssetBundlePath, - ]); - final Future result = residentRunner.attach(enableDevTools: true); - expect(await result, 0); - - // Verify DevTools was served. - verify(mockDevtoolsLauncher.serve()).called(1); - - // Shutdown - await residentRunner.residentDevtoolsHandler.shutdown(); - verify(mockDevtoolsLauncher.close()).called(1); - }), overrides: { - DevtoolsLauncher: () => mockDevtoolsLauncher, - }); - - testUsingContext('ResidentRunner invokes DevtoolsLauncher when attaching and shutting down - cold mode', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: [ - listViews, - listViews, - setAssetBundlePath, - ]); - residentRunner = ColdRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile, vmserviceOutFile: 'foo'), - target: 'main.dart', - ); - when(mockFlutterDevice.runCold( - coldRunner: anyNamed('coldRunner'), - route: anyNamed('route'), - )).thenAnswer((Invocation invocation) async { - return 0; - }); - - final Future result = residentRunner.attach(enableDevTools: true); - expect(await result, 0); - - // Verify DevTools was served. - verify(mockDevtoolsLauncher.serve()).called(1); - - // Shutdown - await residentRunner.residentDevtoolsHandler.shutdown(); - verify(mockDevtoolsLauncher.close()).called(1); - }), overrides: { - DevtoolsLauncher: () => mockDevtoolsLauncher, - }); - testUsingContext('ResidentRunner ignores DevToolsLauncher when attaching with enableDevTools: false', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, @@ -1668,6 +1623,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile, vmserviceOutFile: 'foo'), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.runCold( coldRunner: anyNamed('coldRunner'), @@ -1685,40 +1641,6 @@ void main() { DevtoolsLauncher: () => mockDevtoolsLauncher, }); - testUsingContext('ResidentRunner invokes DevtoolsLauncher when running and shutting down - cold mode', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: [ - listViews, - listViews, - setAssetBundlePath, - ]); - residentRunner = ColdRunner( - [ - mockFlutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile, vmserviceOutFile: 'foo'), - target: 'main.dart', - ); - when(mockFlutterDevice.runCold( - coldRunner: anyNamed('coldRunner'), - route: anyNamed('route'), - )).thenAnswer((Invocation invocation) async { - return 0; - }); - - final Future result = residentRunner.run(enableDevTools: true); - expect(await result, 0); - - // Verify DevTools was served. - verify(mockDevtoolsLauncher.serve()).called(1); - - // Shutdown - await residentRunner.residentDevtoolsHandler.shutdown(); - verify(mockDevtoolsLauncher.close()).called(1); - }), overrides: { - DevtoolsLauncher: () => mockDevtoolsLauncher, - }); - testUsingContext('ResidentRunner can take screenshot on debug device', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, @@ -1751,6 +1673,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); await residentRunner.screenshot(mockFlutterDevice); @@ -1856,6 +1779,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); await residentRunner.screenshot(mockFlutterDevice); @@ -1994,6 +1918,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugDumpApp(), false); @@ -2016,6 +1941,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugDumpRenderTree(), false); @@ -2038,6 +1964,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugDumpLayerTree(), false); @@ -2060,6 +1987,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugDumpSemanticsTreeInTraversalOrder(), false); @@ -2082,6 +2010,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugDumpSemanticsTreeInInverseHitTestOrder(), false); @@ -2104,6 +2033,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugToggleDebugPaintSizeEnabled(), false); @@ -2126,6 +2056,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugToggleBrightness(), false); @@ -2171,6 +2102,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugToggleInvertOversizedImages(), false); @@ -2186,6 +2118,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugToggleInvertOversizedImages(), false); @@ -2231,6 +2164,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugToggleDebugCheckElevationsEnabled(), false); @@ -2253,6 +2187,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugTogglePerformanceOverlayOverride(), false); @@ -2276,6 +2211,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugToggleWidgetInspector(), false); @@ -2298,6 +2234,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); expect(await residentRunner.debugToggleProfileWidgetBuilds(), false); @@ -2307,19 +2244,7 @@ void main() { testUsingContext('HotRunner writes vm service file when providing debugging option', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, - listenToExtensionStream, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), listViews, - FakeVmServiceRequest( - method: 'getIsolate', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedIsolate.toJson(), - ), setAssetBundlePath, ]); setWsAddress(testUri, fakeVmServiceHost.vmService); @@ -2331,6 +2256,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, vmserviceOutFile: 'foo'), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.runHot( hotRunner: anyNamed('hotRunner'), @@ -2340,6 +2266,7 @@ void main() { }); await residentRunner.run(enableDevTools: true); + expect(fakeVmServiceHost.hasRemainingExpectations, false); expect(await globals.fs.file('foo').readAsString(), testUri.toString()); }), overrides: { DevtoolsLauncher: () => mockDevtoolsLauncher, @@ -2348,19 +2275,7 @@ void main() { testUsingContext('HotRunner copies compiled app.dill to cache during startup', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, - listenToExtensionStream, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), listViews, - FakeVmServiceRequest( - method: 'getIsolate', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedIsolate.toJson(), - ), setAssetBundlePath, ]); setWsAddress(testUri, fakeVmServiceHost.vmService); @@ -2372,6 +2287,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); residentRunner.artifactDirectory.childFile('app.dill').writeAsStringSync('ABC'); when(mockFlutterDevice.runHot( @@ -2390,19 +2306,7 @@ void main() { testUsingContext('HotRunner copies compiled app.dill to cache during startup with dart defines', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, - listenToExtensionStream, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), listViews, - FakeVmServiceRequest( - method: 'getIsolate', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedIsolate.toJson(), - ), setAssetBundlePath, ]); setWsAddress(testUri, fakeVmServiceHost.vmService); @@ -2421,6 +2325,7 @@ void main() { ) ), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); residentRunner.artifactDirectory.childFile('app.dill').writeAsStringSync('ABC'); when(mockFlutterDevice.runHot( @@ -2440,19 +2345,7 @@ void main() { testUsingContext('HotRunner copies compiled app.dill to cache during startup with null safety', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, - listenToExtensionStream, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), listViews, - FakeVmServiceRequest( - method: 'getIsolate', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedIsolate.toJson(), - ), setAssetBundlePath, ]); setWsAddress(testUri, fakeVmServiceHost.vmService); @@ -2471,6 +2364,7 @@ void main() { ) ), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); residentRunner.artifactDirectory.childFile('app.dill').writeAsStringSync('ABC'); when(mockFlutterDevice.runHot( @@ -2490,19 +2384,7 @@ void main() { testUsingContext('HotRunner does not copy app.dill if a dillOutputPath is given', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, - listenToExtensionStream, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), listViews, - FakeVmServiceRequest( - method: 'getIsolate', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedIsolate.toJson(), - ), setAssetBundlePath, ]); setWsAddress(testUri, fakeVmServiceHost.vmService); @@ -2515,6 +2397,7 @@ void main() { dillOutputPath: 'test', debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); residentRunner.artifactDirectory.childFile('app.dill').writeAsStringSync('ABC'); when(mockFlutterDevice.runHot( @@ -2533,19 +2416,7 @@ void main() { testUsingContext('HotRunner copies compiled app.dill to cache during startup with --track-widget-creation', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, - listenToExtensionStream, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), listViews, - FakeVmServiceRequest( - method: 'getIsolate', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedIsolate.toJson(), - ), setAssetBundlePath, ]); setWsAddress(testUri, fakeVmServiceHost.vmService); @@ -2562,6 +2433,7 @@ void main() { trackWidgetCreation: true, )), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); residentRunner.artifactDirectory.childFile('app.dill').writeAsStringSync('ABC'); when(mockFlutterDevice.runHot( @@ -2591,6 +2463,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.runHot( hotRunner: anyNamed('hotRunner'), @@ -2619,6 +2492,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, vmserviceOutFile: 'foo'), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.runHot( hotRunner: anyNamed('hotRunner'), @@ -2640,18 +2514,6 @@ void main() { testUsingContext('ColdRunner writes vm service file when providing debugging option', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, - listenToExtensionStream, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), - FakeVmServiceRequest( - method: 'getIsolate', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedIsolate.toJson(), - ), ]); globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); setWsAddress(testUri, fakeVmServiceHost.vmService); @@ -2662,6 +2524,7 @@ void main() { stayResident: false, debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile, vmserviceOutFile: 'foo'), target: 'main.dart', + devtoolsHandler: createNoOpHandler, ); when(mockFlutterDevice.runCold( coldRunner: anyNamed('coldRunner'), @@ -2670,10 +2533,6 @@ void main() { return 0; }); await residentRunner.run(enableDevTools: true); - // Await a short delay so that we don't try to exit before all the expected - // VM service requests have been fired. - // TODO(ianh): remove this delay, it's almost certainly going to cause flakes - await Future.delayed(const Duration(milliseconds: 200)); expect(await globals.fs.file('foo').readAsString(), testUri.toString()); expect(fakeVmServiceHost.hasRemainingExpectations, false);