Unpause and remove breakpoints when detaching from Flutter process with DAP (#101695)

This commit is contained in:
Danny Tuppeny 2022-04-11 21:15:37 +01:00 committed by GitHub
parent b086473769
commit 675b961573
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 6 deletions

View File

@ -205,6 +205,9 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
/// quickly and therefore may leave orphaned processes. /// quickly and therefore may leave orphaned processes.
@override @override
Future<void> disconnectImpl() async { Future<void> disconnectImpl() async {
if (isAttach) {
await preventBreakingAndResume();
}
terminatePids(ProcessSignal.sigkill); terminatePids(ProcessSignal.sigkill);
} }
@ -379,6 +382,9 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
/// Called by [terminateRequest] to request that we gracefully shut down the app being run (or in the case of an attach, disconnect). /// Called by [terminateRequest] to request that we gracefully shut down the app being run (or in the case of an attach, disconnect).
@override @override
Future<void> terminateImpl() async { Future<void> terminateImpl() async {
if (isAttach) {
await preventBreakingAndResume();
}
terminatePids(ProcessSignal.sigterm); terminatePids(ProcessSignal.sigterm);
await _process?.exitCode; await _process?.exitCode;
} }

View File

@ -380,13 +380,35 @@ void main() {
stoppedFuture, stoppedFuture,
dap.client.setBreakpoint(breakpointFilePath, breakpointLine), dap.client.setBreakpoint(breakpointFilePath, breakpointLine),
], eagerError: true); ], eagerError: true);
final int threadId = (await stoppedFuture).threadId!; });
// Remove the breakpoint and resume. testWithoutContext('resumes and removes breakpoints on detach', () async {
await dap.client.clearBreakpoints(breakpointFilePath); final Uri vmServiceUri = await testProcess.vmServiceUri;
await dap.client.continue_(threadId);
// Launch the app and wait for it to print "topLevelFunction".
await Future.wait(<Future<void>>[
dap.client.stdoutOutput.firstWhere((String output) => output.startsWith('topLevelFunction')),
dap.client.start(
launch: () => dap.client.attach(
cwd: project.dir.path,
toolArgs: <String>['-d', 'flutter-tester'],
vmServiceUri: vmServiceUri.toString(),
),
),
], eagerError: true);
// Set a breakpoint and expect to hit it.
final Future<StoppedEventBody> stoppedFuture = dap.client.stoppedEvents.firstWhere((StoppedEventBody e) => e.reason == 'breakpoint');
await Future.wait(<Future<void>>[
stoppedFuture,
dap.client.setBreakpoint(breakpointFilePath, breakpointLine),
], eagerError: true);
// Detach.
await dap.client.terminate(); await dap.client.terminate();
// Ensure we get additional output (confirming the process resumed).
await testProcess.output.first;
}); });
}); });
} }

View File

@ -63,6 +63,11 @@ class SimpleFlutterRunner {
unawaited(process.exitCode.then(_handleExitCode)); unawaited(process.exitCode.then(_handleExitCode));
} }
final StreamController<String> _output = StreamController<String>.broadcast();
/// A broadcast stream of any non-JSON output from the process.
Stream<String> get output => _output.stream;
void _handleExitCode(int code) { void _handleExitCode(int code) {
if (!_vmServiceUriCompleter.isCompleted) { if (!_vmServiceUriCompleter.isCompleted) {
_vmServiceUriCompleter.completeError('Flutter process ended without producing a VM Service URI'); _vmServiceUriCompleter.completeError('Flutter process ended without producing a VM Service URI');
@ -91,8 +96,9 @@ class SimpleFlutterRunner {
} }
} }
} on FormatException { } on FormatException {
// `flutter run` writes a lot of text to stdout so just ignore anything // `flutter run` writes a lot of text to stdout that isn't daemon messages
// that's not valid JSON. // (not valid JSON), so just pass that one for tests that may want it.
_output.add(outputLine);
} }
} }