Unverified Commit 675b9615 authored by Danny Tuppeny's avatar Danny Tuppeny Committed by GitHub

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

parent b0864737
......@@ -205,6 +205,9 @@ class FlutterDebugAdapter extends DartDebugAdapter<FlutterLaunchRequestArguments
/// quickly and therefore may leave orphaned processes.
@override
Future<void> disconnectImpl() async {
if (isAttach) {
await preventBreakingAndResume();
}
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).
@override
Future<void> terminateImpl() async {
if (isAttach) {
await preventBreakingAndResume();
}
terminatePids(ProcessSignal.sigterm);
await _process?.exitCode;
}
......
......@@ -380,13 +380,35 @@ void main() {
stoppedFuture,
dap.client.setBreakpoint(breakpointFilePath, breakpointLine),
], eagerError: true);
final int threadId = (await stoppedFuture).threadId!;
});
testWithoutContext('resumes and removes breakpoints on detach', () async {
final Uri vmServiceUri = await testProcess.vmServiceUri;
// 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);
// Remove the breakpoint and resume.
await dap.client.clearBreakpoints(breakpointFilePath);
await dap.client.continue_(threadId);
// 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();
// Ensure we get additional output (confirming the process resumed).
await testProcess.output.first;
});
});
}
......
......@@ -63,6 +63,11 @@ class SimpleFlutterRunner {
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) {
if (!_vmServiceUriCompleter.isCompleted) {
_vmServiceUriCompleter.completeError('Flutter process ended without producing a VM Service URI');
......@@ -91,8 +96,9 @@ class SimpleFlutterRunner {
}
}
} on FormatException {
// `flutter run` writes a lot of text to stdout so just ignore anything
// that's not valid JSON.
// `flutter run` writes a lot of text to stdout that isn't daemon messages
// (not valid JSON), so just pass that one for tests that may want it.
_output.add(outputLine);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment