mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tools] [dap] Ensure DAP sends app.stop/app.detach during terminate (#108310)
* [flutter_tools] [dap] Ensure DAP sends app.stop/app.detach during terminate Fixes an issue where the flutter_tester device may not be cleaned up correctly if we just terminate the Flutter process. * Update integration test expectations * Revert accidental commit
This commit is contained in:
parent
925bee92e7
commit
5d31b07ed5
@ -400,6 +400,16 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
|
||||
if (isAttach) {
|
||||
await preventBreakingAndResume();
|
||||
}
|
||||
|
||||
// Send a request to stop/detach to give Flutter chance to do some cleanup.
|
||||
// It's possible the Flutter process will terminate before we process the
|
||||
// response, so accept either a response or the process exiting.
|
||||
final String method = isAttach ? 'app.detach' : 'app.stop';
|
||||
await Future.any<void>(<Future<void>>[
|
||||
sendFlutterRequest(method, <String, Object?>{'appId': _appId}),
|
||||
_process?.exitCode ?? Future<void>.value(),
|
||||
]);
|
||||
|
||||
terminatePids(ProcessSignal.sigterm);
|
||||
await _process?.exitCode;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:dds/dap.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
@ -96,6 +97,29 @@ void main() {
|
||||
// Ensure the VM's pid was not recorded.
|
||||
expect(adapter.pidsToTerminate, isNot(contains(123)));
|
||||
});
|
||||
|
||||
test('calls "app.stop" on terminateRequest', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
|
||||
final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments(
|
||||
cwd: '/project',
|
||||
program: 'foo.dart',
|
||||
);
|
||||
|
||||
await adapter.configurationDoneRequest(MockRequest(), null, () {});
|
||||
final Completer<void> launchCompleter = Completer<void>();
|
||||
await adapter.launchRequest(MockRequest(), args, launchCompleter.complete);
|
||||
await launchCompleter.future;
|
||||
|
||||
final Completer<void> terminateCompleter = Completer<void>();
|
||||
await adapter.terminateRequest(MockRequest(), TerminateArguments(restart: false), terminateCompleter.complete);
|
||||
await terminateCompleter.future;
|
||||
|
||||
expect(adapter.flutterRequests, contains('app.stop'));
|
||||
});
|
||||
});
|
||||
|
||||
group('attachRequest', () {
|
||||
@ -139,6 +163,28 @@ void main() {
|
||||
// Ensure the VM's pid was not recorded.
|
||||
expect(adapter.pidsToTerminate, isNot(contains(123)));
|
||||
});
|
||||
|
||||
test('calls "app.detach" on terminateRequest', () async {
|
||||
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
|
||||
fileSystem: MemoryFileSystem.test(style: fsStyle),
|
||||
platform: platform,
|
||||
);
|
||||
|
||||
final FlutterAttachRequestArguments args = FlutterAttachRequestArguments(
|
||||
cwd: '/project',
|
||||
);
|
||||
|
||||
await adapter.configurationDoneRequest(MockRequest(), null, () {});
|
||||
final Completer<void> attachCompleter = Completer<void>();
|
||||
await adapter.attachRequest(MockRequest(), args, attachCompleter.complete);
|
||||
await attachCompleter.future;
|
||||
|
||||
final Completer<void> terminateCompleter = Completer<void>();
|
||||
await adapter.terminateRequest(MockRequest(), TerminateArguments(restart: false), terminateCompleter.complete);
|
||||
await terminateCompleter.future;
|
||||
|
||||
expect(adapter.flutterRequests, contains('app.detach'));
|
||||
});
|
||||
});
|
||||
|
||||
group('--start-paused', () {
|
||||
|
@ -43,6 +43,7 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {
|
||||
late String executable;
|
||||
late List<String> processArgs;
|
||||
late Map<String, String>? env;
|
||||
final List<String> flutterRequests = <String>[];
|
||||
|
||||
@override
|
||||
Future<void> launchAsProcess({
|
||||
@ -59,6 +60,16 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {
|
||||
appStartedCompleter.complete();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Object?> sendFlutterRequest(
|
||||
String method,
|
||||
Map<String, Object?>? params, {
|
||||
bool failSilently = true,
|
||||
}) {
|
||||
flutterRequests.add(method);
|
||||
return super.sendFlutterRequest(method, params, failSilently: failSilently);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> get debuggerInitialized {
|
||||
// If we were mocking debug mode, then simulate the debugger initializing.
|
||||
|
@ -64,6 +64,7 @@ void main() {
|
||||
'Launching $relativeMainPath on Flutter test device in debug mode...',
|
||||
startsWith('Connecting to VM Service at'),
|
||||
'topLevelFunction',
|
||||
'Application finished.',
|
||||
'',
|
||||
startsWith('Exited'),
|
||||
]);
|
||||
@ -94,6 +95,7 @@ void main() {
|
||||
expectLines(output, <Object>[
|
||||
'Launching $relativeMainPath on Flutter test device in debug mode...',
|
||||
'topLevelFunction',
|
||||
'Application finished.',
|
||||
'',
|
||||
startsWith('Exited'),
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user