Handle a WebSocketException that may be thrown when closing the WebKit inspection protocol connection to Chrome (#151997)

Noticed this happening on macOS when the tool tries to shut down Chrome after all tabs have already been closed.
This commit is contained in:
Jason Simmons 2024-07-19 10:58:26 -07:00 committed by GitHub
parent 7d5c1c04fb
commit 49a315284d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 17 deletions

View File

@ -507,20 +507,19 @@ class Chromium {
// Send a command to shut down the browser cleanly. // Send a command to shut down the browser cleanly.
Duration sigtermDelay = Duration.zero; Duration sigtermDelay = Duration.zero;
if (_hasValidChromeConnection) { if (_hasValidChromeConnection) {
ChromeTab? tab;
try { try {
tab = await chromeConnection.getTab( final ChromeTab? tab = await chromeConnection.getTab(
(_) => true, retryFor: const Duration(seconds: 1)); (_) => true, retryFor: const Duration(seconds: 1));
} on SocketException {
// Chrome is not responding to the debug protocol and probably has
// already been closed.
}
if (tab != null) { if (tab != null) {
final WipConnection wipConnection = await tab.connect(); final WipConnection wipConnection = await tab.connect();
await wipConnection.sendCommand('Browser.close'); await wipConnection.sendCommand('Browser.close');
await wipConnection.close(); await wipConnection.close();
sigtermDelay = const Duration(seconds: 1); sigtermDelay = const Duration(seconds: 1);
} }
} on IOException {
// Chrome is not responding to the debug protocol and probably has
// already been closed.
}
} }
chromeConnection.close(); chromeConnection.close();
_hasValidChromeConnection = false; _hasValidChromeConnection = false;

View File

@ -838,6 +838,23 @@ void main() {
chromeConnection.throwSocketExceptions = true; chromeConnection.throwSocketExceptions = true;
await chrome.close(); await chrome.close();
}); });
test('Chromium close handles a WebSocketException when closing the WipConnection', () async {
final BufferLogger logger = BufferLogger.test();
final FakeChromeConnectionWithTab chromeConnection = FakeChromeConnectionWithTab(throwWebSocketException: true);
final ChromiumLauncher chromiumLauncher = ChromiumLauncher(
fileSystem: fileSystem,
platform: platform,
processManager: processManager,
operatingSystemUtils: operatingSystemUtils,
browserFinder: findChromeExecutable,
logger: logger,
);
final FakeProcess process = FakeProcess();
final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger);
expect(await chromiumLauncher.connect(chrome, false), equals(chrome));
await chrome.close();
});
} }
/// Fake chrome connection that fails to get tabs a few times. /// Fake chrome connection that fails to get tabs a few times.
@ -877,8 +894,8 @@ typedef OnSendCommand = void Function(String);
/// Fake chrome connection that returns a tab. /// Fake chrome connection that returns a tab.
class FakeChromeConnectionWithTab extends Fake implements ChromeConnection { class FakeChromeConnectionWithTab extends Fake implements ChromeConnection {
FakeChromeConnectionWithTab({OnSendCommand? onSendCommand}) FakeChromeConnectionWithTab({OnSendCommand? onSendCommand, bool throwWebSocketException = false})
: _tab = FakeChromeTab(onSendCommand); : _tab = FakeChromeTab(onSendCommand, throwWebSocketException);
final FakeChromeTab _tab; final FakeChromeTab _tab;
bool throwSocketExceptions = false; bool throwSocketExceptions = false;
@ -904,20 +921,22 @@ class FakeChromeConnectionWithTab extends Fake implements ChromeConnection {
} }
class FakeChromeTab extends Fake implements ChromeTab { class FakeChromeTab extends Fake implements ChromeTab {
FakeChromeTab(this.onSendCommand); FakeChromeTab(this.onSendCommand, this.throwWebSocketException);
OnSendCommand? onSendCommand; final OnSendCommand? onSendCommand;
final bool throwWebSocketException;
@override @override
Future<WipConnection> connect({Function? onError}) async { Future<WipConnection> connect({Function? onError}) async {
return FakeWipConnection(onSendCommand); return FakeWipConnection(onSendCommand, throwWebSocketException);
} }
} }
class FakeWipConnection extends Fake implements WipConnection { class FakeWipConnection extends Fake implements WipConnection {
FakeWipConnection(this.onSendCommand); FakeWipConnection(this.onSendCommand, this.throwWebSocketException);
OnSendCommand? onSendCommand; final OnSendCommand? onSendCommand;
final bool throwWebSocketException;
@override @override
Future<WipResponse> sendCommand(String method, [Map<String, dynamic>? params]) async { Future<WipResponse> sendCommand(String method, [Map<String, dynamic>? params]) async {
@ -926,5 +945,9 @@ class FakeWipConnection extends Fake implements WipConnection {
} }
@override @override
Future<void> close() async {} Future<void> close() async {
if (throwWebSocketException) {
throw const io.WebSocketException('test');
}
}
} }