// Copyright 2022 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:devtools_shared/devtools_test_utils.dart'; import 'package:test/test.dart'; import 'utils/server_driver.dart'; late final DevToolsServerTestController testController; void main() { testController = DevToolsServerTestController(); setUp(() async { await testController.setUp(); }); tearDown(() async { await testController.tearDown(); }); for (final bool useVmService in [true, false]) { group('Server (${useVmService ? 'VM Service' : 'API'})', () { test('reuses DevTools instance if already connected to same VM', () async { // Register the VM. await testController.send( 'vm.register', {'uri': testController.appFixture.serviceUri.toString()}, ); // Send a request to launch DevTools in a browser. await testController.sendLaunchDevToolsRequest( useVmService: useVmService, ); { final serverResponse = await testController.waitForClients( requiredConnectionState: true, ); expect(serverResponse['clients'], hasLength(1)); } // Request again, allowing reuse, and server emits an event saying the // window was reused. final launchResponse = await testController.sendLaunchDevToolsRequest( useVmService: useVmService, reuseWindows: true, ); expect(launchResponse['reused'], isTrue); // Ensure there's still only one connection (eg. we didn't spawn a new one // we reused the existing one). final serverResponse = await testController.waitForClients(requiredConnectionState: true); expect(serverResponse['clients'], hasLength(1)); }, timeout: const Timeout.factor(20)); test('Server does not reuse DevTools instance if embedded', () async { // Register the VM. await testController.send( 'vm.register', {'uri': testController.appFixture.serviceUri.toString()}, ); // Spawn an embedded version of DevTools in a browser. final event = await testController.serverStartedEvent.future; final devToolsUri = 'http://${event['params']['host']}:${event['params']['port']}'; final launchUrl = '$devToolsUri/?embed=true&page=logging' '&uri=${Uri.encodeQueryComponent(testController.appFixture.serviceUri.toString())}'; final chrome = await Chrome.locate()!.start(url: launchUrl); try { { final serverResponse = await testController.waitForClients( requiredConnectionState: true, ); expect(serverResponse['clients'], hasLength(1)); } // Send a request to the server to launch and ensure it did // not reuse the existing connection. Launch it on a different page // so we can easily tell once this one has connected. final launchResponse = await testController.sendLaunchDevToolsRequest( useVmService: useVmService, reuseWindows: true, page: 'memory', ); expect(launchResponse['reused'], isFalse); // Ensure there's now two connections. final serverResponse = await testController.waitForClients( requiredConnectionState: true, requiredPage: 'memory', ); expect(serverResponse['clients'], hasLength(2)); } finally { chrome.kill(); } }, timeout: const Timeout.factor(20)); test('does not reuse if browser was terminated (unresponsive ping)', () async { // Register the VM. await testController.send( 'vm.register', {'uri': testController.appFixture.serviceUri.toString()}, ); // Spawn a DevTools in a browser. final event = await testController.serverStartedEvent.future; final devToolsUri = 'http://${event['params']['host']}:${event['params']['port']}'; final launchUrl = '$devToolsUri/?page=logging' '&uri=${Uri.encodeQueryComponent(testController.appFixture.serviceUri.toString())}'; final chrome = await Chrome.locate()!.start(url: launchUrl); try { { final serverResponse = await testController.waitForClients( requiredConnectionState: true, ); expect(serverResponse['clients'], hasLength(1)); } // Terminate the browser to prevent it responding to future pings. chrome.kill(); // Send a request to the server to launch and ensure it did // not reuse the existing connection. Launch it on a different page // so we can easily tell once this one has connected. final launchResponse = await testController.sendLaunchDevToolsRequest( useVmService: useVmService, reuseWindows: true, page: 'memory', ); expect(launchResponse['reused'], isFalse); // Ensure there's now two connections. final serverResponse = await testController.waitForClients( requiredConnectionState: true, requiredPage: 'memory', ); expect(serverResponse['clients'], hasLength(2)); } finally { chrome.kill(); } }, timeout: const Timeout.factor(20)); test('reuses DevTools instance if not connected to a VM', () async { // Register the VM. await testController.send( 'vm.register', {'uri': testController.appFixture.serviceUri.toString()}, ); // Send a request to launch DevTools in a browser. await testController.sendLaunchDevToolsRequest( useVmService: useVmService, ); // Wait for the DevTools to inform server that it's connected. await testController.waitForClients(requiredConnectionState: true); // Terminate the VM. await testController.appFixture.teardown(); // Ensure the client is marked as disconnected. await testController.waitForClients(requiredConnectionState: false); // Start up a new app. await testController.startApp(); await testController.send( 'vm.register', {'uri': testController.appFixture.serviceUri.toString()}, ); // Send a new request to launch. await testController.sendLaunchDevToolsRequest( useVmService: useVmService, reuseWindows: true, notify: true, ); // Ensure we now have a single connected client. final serverResponse = await testController.waitForClients(requiredConnectionState: true); expect(serverResponse['clients'], hasLength(1)); expect(serverResponse['clients'][0]['hasConnection'], isTrue); expect( serverResponse['clients'][0]['vmServiceUri'], testController.appFixture.serviceUri.toString(), ); }, timeout: const Timeout.factor(20)); }); } }