From 8b3d93234d1df69c3db5428fa02bb6b39c671ed8 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 31 Oct 2023 19:54:28 +0000 Subject: [PATCH] [ package:vm_service ] Migrate Observatory HTTP service invocation tests Also adds READMEs to some test sub-directories. Change-Id: Ibf48654bcb43d7d52bd3bc0d2ab6afabc1ea3df6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333100 Commit-Queue: Ben Konyi Reviewed-by: Derek Xu --- pkg/vm_service/test/common/expect.dart | 16 ++--- .../test/http_invocations/README.md | 1 + .../http_auth_get_isolate_rpc_test.dart | 13 ++++ .../http_auth_get_vm_rpc_test.dart | 13 ++++ .../http_get_isolate_group_rpc_common.dart | 50 +++++++++++++++ .../http_get_isolate_group_rpc_test.dart | 13 ++++ .../http_get_isolate_rpc_common.dart | 64 +++++++++++++++++++ .../http_get_isolate_rpc_test.dart | 14 ++++ .../http_get_vm_rpc_common.dart | 45 +++++++++++++ .../http_get_vm_rpc_test.dart | 14 ++++ .../http_request_helpers.dart | 44 +++++++++++++ pkg/vm_service/test/private_rpcs/README.md | 3 + 12 files changed, 282 insertions(+), 8 deletions(-) create mode 100644 pkg/vm_service/test/http_invocations/README.md create mode 100644 pkg/vm_service/test/http_invocations/http_auth_get_isolate_rpc_test.dart create mode 100644 pkg/vm_service/test/http_invocations/http_auth_get_vm_rpc_test.dart create mode 100644 pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_common.dart create mode 100644 pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_test.dart create mode 100644 pkg/vm_service/test/http_invocations/http_get_isolate_rpc_common.dart create mode 100644 pkg/vm_service/test/http_invocations/http_get_isolate_rpc_test.dart create mode 100644 pkg/vm_service/test/http_invocations/http_get_vm_rpc_common.dart create mode 100644 pkg/vm_service/test/http_invocations/http_get_vm_rpc_test.dart create mode 100644 pkg/vm_service/test/http_invocations/http_request_helpers.dart create mode 100644 pkg/vm_service/test/private_rpcs/README.md diff --git a/pkg/vm_service/test/common/expect.dart b/pkg/vm_service/test/common/expect.dart index daba8d70c46..c38286c3034 100644 --- a/pkg/vm_service/test/common/expect.dart +++ b/pkg/vm_service/test/common/expect.dart @@ -108,46 +108,46 @@ class Expect { if (expected is String && actual is String) { String stringDifference = _stringDifference(expected, actual); if (stringDifference.isNotEmpty) { - _fail("Expect.equals($stringDifference$msg) fails."); + fail("Expect.equals($stringDifference$msg) fails."); } - _fail("Expect.equals(expected: <${_escapeString(expected)}>" + fail("Expect.equals(expected: <${_escapeString(expected)}>" ", actual: <${_escapeString(actual)}>$msg) fails."); } - _fail("Expect.equals(expected: <$expected>, actual: <$actual>$msg) fails."); + fail("Expect.equals(expected: <$expected>, actual: <$actual>$msg) fails."); } /// Checks whether the actual value is a bool and its value is true. static void isTrue(dynamic actual, [String reason = ""]) { if (_identical(actual, true)) return; String msg = _getMessage(reason); - _fail("Expect.isTrue($actual$msg) fails."); + fail("Expect.isTrue($actual$msg) fails."); } /// Checks whether the actual value is a bool and its value is false. static void isFalse(dynamic actual, [String reason = ""]) { if (_identical(actual, false)) return; String msg = _getMessage(reason); - _fail("Expect.isFalse($actual$msg) fails."); + fail("Expect.isFalse($actual$msg) fails."); } /// Checks whether [actual] is null. static void isNull(dynamic actual, [String reason = ""]) { if (null == actual) return; String msg = _getMessage(reason); - _fail("Expect.isNull(actual: <$actual>$msg) fails."); + fail("Expect.isNull(actual: <$actual>$msg) fails."); } /// Checks whether [actual] is not null. static void isNotNull(dynamic actual, [String reason = ""]) { if (null != actual) return; String msg = _getMessage(reason); - _fail("Expect.isNotNull(actual: <$actual>$msg) fails."); + fail("Expect.isNotNull(actual: <$actual>$msg) fails."); } static String _getMessage(String reason) => (reason.isEmpty) ? "" : ", '$reason'"; - static Never _fail(String message) { + static Never fail(String message) { throw ExpectException(message); } } diff --git a/pkg/vm_service/test/http_invocations/README.md b/pkg/vm_service/test/http_invocations/README.md new file mode 100644 index 00000000000..9b5cb58d5c8 --- /dev/null +++ b/pkg/vm_service/test/http_invocations/README.md @@ -0,0 +1 @@ +This directory contains tests that make VM service requests via HTTP rather than a web socket, only making use of `package:vm_service` to parse the response JSON. \ No newline at end of file diff --git a/pkg/vm_service/test/http_invocations/http_auth_get_isolate_rpc_test.dart b/pkg/vm_service/test/http_invocations/http_auth_get_isolate_rpc_test.dart new file mode 100644 index 00000000000..1af89ab105c --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_auth_get_isolate_rpc_test.dart @@ -0,0 +1,13 @@ +// 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 'http_get_isolate_rpc_common.dart'; +import '../common/test_helper.dart'; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'http_auth_get_isolate_rpc_test.dart', + testeeBefore: testeeBefore, + ); diff --git a/pkg/vm_service/test/http_invocations/http_auth_get_vm_rpc_test.dart b/pkg/vm_service/test/http_invocations/http_auth_get_vm_rpc_test.dart new file mode 100644 index 00000000000..177f5655b07 --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_auth_get_vm_rpc_test.dart @@ -0,0 +1,13 @@ +// 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 'http_get_vm_rpc_common.dart'; +import '../common/test_helper.dart'; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'http_auth_get_vm_rpc_test.dart', + testeeBefore: testeeBefore, + ); diff --git a/pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_common.dart b/pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_common.dart new file mode 100644 index 00000000000..f9c6cdbee0b --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_common.dart @@ -0,0 +1,50 @@ +// 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 'dart:developer'; + +import 'package:test/test.dart'; +import 'package:vm_service/vm_service.dart'; + +import '../common/expect.dart'; +import '../common/test_helper.dart'; +import 'http_request_helpers.dart'; + +Future getIsolateGroupId( + Uri serverUri, +) async { + final result = await makeHttpServiceRequest( + serverUri: serverUri, + method: 'getVM', + ); + return result['isolateGroups'][0]['id'] as String; +} + +Future testeeBefore() async { + final info = await Service.getInfo(); + final serverUri = info.serverUri!; + try { + final result = createServiceObject( + await makeHttpServiceRequest( + serverUri: serverUri, + method: 'getIsolateGroup', + params: {'isolateGroupId': await getIsolateGroupId(serverUri)}), + ['IsolateGroup'], + )! as IsolateGroup; + Expect.isTrue(result.id!.startsWith('isolateGroups/')); + Expect.isNotNull(result.number); + Expect.isFalse(result.isSystemIsolateGroup); + Expect.isTrue(result.isolates!.length > 0); + } catch (e) { + fail('invalid request: $e'); + } +} + +final tests = [ + (VmService service, IsolateRef isolate) async { + // Just getting here means that the testee enabled the service protocol + // web server. + } +]; diff --git a/pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_test.dart b/pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_test.dart new file mode 100644 index 00000000000..e5d96053d45 --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_get_isolate_group_rpc_test.dart @@ -0,0 +1,13 @@ +// 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 'http_get_isolate_group_rpc_common.dart'; +import '../common/test_helper.dart'; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'http_get_isolate_group_rpc_test.dart', + testeeBefore: testeeBefore, + ); diff --git a/pkg/vm_service/test/http_invocations/http_get_isolate_rpc_common.dart b/pkg/vm_service/test/http_invocations/http_get_isolate_rpc_common.dart new file mode 100644 index 00000000000..32370438486 --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_get_isolate_rpc_common.dart @@ -0,0 +1,64 @@ +// 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 'dart:developer'; + +import 'package:vm_service/vm_service.dart'; + +import '../common/expect.dart'; +import '../common/test_helper.dart'; +import 'http_request_helpers.dart'; + +Future getIsolateId(Uri serverUri) async { + final result = await makeHttpServiceRequest( + serverUri: serverUri, + method: 'getVM', + ); + return result['isolates'][0]['id'] as String; +} + +Future testeeBefore() async { + final info = await Service.getInfo(); + final serverUri = info.serverUri!; + + try { + // Build the request. + final params = { + 'isolateId': await getIsolateId(serverUri), + }; + + final result = createServiceObject( + await makeHttpServiceRequest( + serverUri: serverUri, + method: 'getIsolate', + params: params, + ), + ['Isolate'], + )! as Isolate; + Expect.isTrue(result.id!.startsWith('isolates/')); + Expect.isNotNull(result.number); + Expect.equals(result.json!['_originNumber'], result.number); + Expect.isTrue(result.startTime! > 0); + Expect.isTrue(result.livePorts! > 0); + Expect.isFalse(result.pauseOnExit); + Expect.isNotNull(result.pauseEvent); + Expect.isNull(result.error); + Expect.isNotNull(result.rootLib); + Expect.isTrue(result.libraries!.isNotEmpty); + Expect.isTrue(result.breakpoints!.isEmpty); + Expect.equals(result.json!['_heaps']['new']['type'], 'HeapSpace'); + Expect.equals(result.json!['_heaps']['old']['type'], 'HeapSpace'); + Expect.equals(result.json!['isolate_group']['type'], '@IsolateGroup'); + } catch (e) { + Expect.fail('invalid request: $e'); + } +} + +final tests = [ + (VmService service, IsolateRef isolateRef) async { + // Just getting here means that the testee enabled the service protocol + // web server. + } +]; diff --git a/pkg/vm_service/test/http_invocations/http_get_isolate_rpc_test.dart b/pkg/vm_service/test/http_invocations/http_get_isolate_rpc_test.dart new file mode 100644 index 00000000000..f4e344dce3e --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_get_isolate_rpc_test.dart @@ -0,0 +1,14 @@ +// 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 'http_get_isolate_rpc_common.dart'; +import '../common/test_helper.dart'; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'http_get_isolate_rpc_test.dart', + testeeBefore: testeeBefore, + useAuthToken: false, + ); diff --git a/pkg/vm_service/test/http_invocations/http_get_vm_rpc_common.dart b/pkg/vm_service/test/http_invocations/http_get_vm_rpc_common.dart new file mode 100644 index 00000000000..87dc021c77c --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_get_vm_rpc_common.dart @@ -0,0 +1,45 @@ +// 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 'dart:developer'; + +import 'package:vm_service/vm_service.dart'; + +import '../common/expect.dart'; +import '../common/test_helper.dart'; +import 'http_request_helpers.dart'; + +Future testeeBefore() async { + final info = await Service.getInfo(); + final serverUri = info.serverUri!; + + try { + final result = createServiceObject( + await makeHttpServiceRequest( + serverUri: serverUri, + method: 'getVM', + ), + ['VM'], + )! as VM; + Expect.equals(result.name, 'vm'); + Expect.isTrue(result.architectureBits! > 0); + Expect.isNotNull(result.targetCPU); + Expect.isNotNull(result.hostCPU); + Expect.isNotNull(result.version); + Expect.isNotNull(result.pid); + Expect.isTrue(result.startTime! > 0); + Expect.isTrue(result.isolates!.isNotEmpty); + Expect.isTrue(result.isolateGroups!.isNotEmpty); + } catch (e) { + Expect.fail('invalid request: $e'); + } +} + +final tests = [ + (VmService service, IsolateRef isolateRef) async { + // Just getting here means that the testee enabled the service protocol + // web server. + } +]; diff --git a/pkg/vm_service/test/http_invocations/http_get_vm_rpc_test.dart b/pkg/vm_service/test/http_invocations/http_get_vm_rpc_test.dart new file mode 100644 index 00000000000..5b4ba32c1b2 --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_get_vm_rpc_test.dart @@ -0,0 +1,14 @@ +// 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 'http_get_vm_rpc_common.dart'; +import '../common/test_helper.dart'; + +void main([args = const []]) => runIsolateTests( + args, + tests, + 'http_get_vm_rpc_test.dart', + testeeBefore: testeeBefore, + useAuthToken: false, + ); diff --git a/pkg/vm_service/test/http_invocations/http_request_helpers.dart b/pkg/vm_service/test/http_invocations/http_request_helpers.dart new file mode 100644 index 00000000000..440148c2a01 --- /dev/null +++ b/pkg/vm_service/test/http_invocations/http_request_helpers.dart @@ -0,0 +1,44 @@ +// 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:convert'; +import 'dart:io'; + +Uri buildRequestUri({ + required Uri serverUri, + required String method, + Map params = const {}, +}) { + final pathSegments = []..addAll(serverUri.pathSegments); + if (pathSegments.isNotEmpty) { + pathSegments[pathSegments.length - 1] = method; + } else { + pathSegments.add(method); + } + return serverUri.replace( + pathSegments: pathSegments, + queryParameters: params, + ); +} + +Future> makeHttpServiceRequest({ + required Uri serverUri, + required String method, + Map params = const {}, +}) async { + final requestUri = buildRequestUri( + serverUri: serverUri, + method: method, + params: params, + ); + final httpClient = HttpClient(); + final request = await httpClient.getUrl(requestUri); + final response = await request.close(); + final jsonResponse = await response + .cast>() + .transform(utf8.decoder) + .transform(json.decoder) + .first as Map; + return jsonResponse['result']; +} diff --git a/pkg/vm_service/test/private_rpcs/README.md b/pkg/vm_service/test/private_rpcs/README.md new file mode 100644 index 00000000000..013570e7a1c --- /dev/null +++ b/pkg/vm_service/test/private_rpcs/README.md @@ -0,0 +1,3 @@ +This directory contains tests for private VM service RPCs. + +**WARNING:** Functionality covered by these tests should not be relied on by clients not owned by the Dart and Flutter teams as private RPCs can and will be changed or removed without notice. \ No newline at end of file