Catch StateError and output more useful error message when DDS fails to start (#72736)
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 aaaab19..e0606a8 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart
@@ -2683,6 +2683,7 @@ when(mockDevice.getLogReader(app: anyNamed('app'))).thenReturn(mockLogReader); when(mockDevice.dds).thenReturn(mockDds); when(mockDds.startDartDevelopmentService(any, any, any, any)).thenThrow(FakeDartDevelopmentServiceException()); + when(mockDds.uri).thenReturn(Uri.parse('http://localhost:1234')); when(mockDds.done).thenAnswer((_) => noopCompleter.future); final TestFlutterDevice flutterDevice = TestFlutterDevice( @@ -2703,6 +2704,36 @@ }) async => mockVMService, })); + testUsingContext('Failed DDS start outputs error message', () => testbed.run(() async { + // See https://github.com/flutter/flutter/issues/72385 for context. + fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]); + final MockDevice mockDevice = MockDevice(); + when(mockDevice.dds).thenReturn(DartDevelopmentService(logger: testLogger)); + ddsLauncherCallback = (Uri uri, {bool enableAuthCodes, bool ipv6, Uri serviceUri}) { + throw FakeDartDevelopmentServiceException(message: 'No URI'); + }; + final TestFlutterDevice flutterDevice = TestFlutterDevice( + mockDevice, + observatoryUris: Stream<Uri>.value(testUri), + ); + bool caught = false; + final Completer<void>done = Completer<void>(); + runZonedGuarded(() { + flutterDevice.connect(allowExistingDdsInstance: true).then((_) => done.complete()); + }, (Object e, StackTrace st) { + expect(e is StateError, true); + expect((e as StateError).message, contains('No URI')); + expect(testLogger.errorText, contains( + 'DDS has failed to start and there is not an existing DDS instance', + )); + done.complete(); + caught = true; + }); + await done.future; + if (!caught) { + fail('Expected a StateError to be thrown.'); + } + })); testUsingContext('nextPlatform moves through expected platforms', () { expect(nextPlatform('android', TestFeatureFlags()), 'iOS'); @@ -2726,11 +2757,14 @@ class MockResidentCompiler extends Mock implements ResidentCompiler {} class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceException { + FakeDartDevelopmentServiceException({this.message = defaultMessage}); + @override final int errorCode = dds.DartDevelopmentServiceException.existingDdsInstanceError; @override - final String message = 'A DDS instance is already connected at http://localhost:8181'; + final String message; + static const String defaultMessage = 'A DDS instance is already connected at http://localhost:8181'; } class TestFlutterDevice extends FlutterDevice {