| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:async'; |
| |
| import 'package:test/test.dart'; |
| import 'package:vm_service/vm_service.dart'; |
| import 'package:vm_service/vm_service_io.dart'; |
| |
| import 'common/service_test_common.dart'; |
| import 'common/test_helper.dart'; |
| |
| const serviceName = 'disappearService'; |
| const serviceAlias = 'serviceAlias'; |
| const paramKey = 'pkey'; |
| const paramValue = 'pvalue'; |
| const repetition = 5; |
| |
| final tests = <IsolateTest>[ |
| (VmService primaryClient, IsolateRef isolateRef) async { |
| final secondaryClient = await vmServiceConnectUri(primaryClient.wsUri!); |
| |
| final allRequestsReceivedCompleter = Completer<void>(); |
| final requests = <Map<String, dynamic>>[]; |
| |
| // Register the service. |
| final serviceMethodName = await registerServiceHelper( |
| primaryClient, |
| secondaryClient, |
| serviceName, |
| (params) async { |
| final completer = Completer<Map<String, dynamic>>(); |
| requests.add(params); |
| if (requests.length == repetition) { |
| allRequestsReceivedCompleter.complete(); |
| } |
| // We never complete this future as we want to see how the client |
| // handles the service disappearing while there are outstanding |
| // requests. |
| return await completer.future; |
| }, |
| ); |
| |
| // Invoke the service multiple times. |
| { |
| final results = <Future<Response>>[ |
| for (int i = 0; i < repetition; ++i) |
| primaryClient.callServiceExtension( |
| serviceMethodName, |
| args: { |
| paramKey + i.toString(): paramValue + i.toString(), |
| }, |
| ) |
| // We ignore these futures so that when they complete with an error |
| // without being awaited or do not have an error handler registered |
| // they won't cause an unhandled exception. |
| ..ignore(), |
| ]; |
| |
| // Wait for all of the requests to be received before processing. |
| await allRequestsReceivedCompleter.future; |
| |
| // Verify the request parameters as a sanity check. |
| for (final params in requests) { |
| final iteration = requests.indexOf(params); |
| final end = iteration.toString(); |
| |
| // check requests while they arrive |
| expect(params[paramKey + end], paramValue + end); |
| } |
| |
| // Disconnect the service client that registered the service extension. |
| await secondaryClient.dispose(); |
| |
| // Check that all of the outstanding requests complete with an RPC error. |
| for (final future in results) { |
| try { |
| await future; |
| fail('Service should have disappeared'); |
| } on RPCError catch (e) { |
| expect(e.code, RPCErrorKind.kServiceDisappeared.code); |
| expect(e.message, 'Service has disappeared'); |
| } |
| } |
| } |
| }, |
| ]; |
| |
| void main([args = const <String>[]]) => runIsolateTests( |
| args, |
| tests, |
| 'external_service_disappear_test.dart', |
| ); |