mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
[ package:vm_service ] Migrate more Observatory tests
Change-Id: I2d653fcc98087feaff79fa1adb2e4293085e959c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/332642 Reviewed-by: Derek Xu <derekx@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
b44987450e
commit
94f8809607
7
pkg/vm_service/test/field_script_other.dart
Normal file
7
pkg/vm_service/test/field_script_other.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// 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.
|
||||
|
||||
part of field_script_test;
|
||||
|
||||
var otherField = 42;
|
62
pkg/vm_service/test/field_script_test.dart
Normal file
62
pkg/vm_service/test/field_script_test.dart
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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.
|
||||
|
||||
library field_script_test;
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
|
||||
part 'field_script_other.dart';
|
||||
|
||||
code() {
|
||||
print(otherField);
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasPausedAtStart,
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final isolate = await service.getIsolate(isolateId);
|
||||
final lib = await service.getObject(
|
||||
isolateId,
|
||||
isolate.rootLib!.id!,
|
||||
) as Library;
|
||||
|
||||
final fields = lib.variables!;
|
||||
expect(fields.length, 2);
|
||||
for (final fieldRef in fields) {
|
||||
final field = await service.getObject(isolateId, fieldRef.id!) as Field;
|
||||
final location = field.location!;
|
||||
if (field.name == 'tests') {
|
||||
expect(
|
||||
location.script!.uri!.endsWith('field_script_test.dart'),
|
||||
true,
|
||||
);
|
||||
expect(location.line, 19);
|
||||
expect(location.column, 7);
|
||||
} else if (field.name == 'otherField') {
|
||||
expect(
|
||||
location.script!.uri!.endsWith('field_script_other.dart'),
|
||||
true,
|
||||
);
|
||||
expect(location.line, 7);
|
||||
expect(location.column, 5);
|
||||
} else {
|
||||
fail('Unexpected field: ${field.name}');
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTestsSynchronous(
|
||||
args,
|
||||
tests,
|
||||
'field_script_test.dart',
|
||||
testeeConcurrent: code,
|
||||
pause_on_start: true,
|
||||
pause_on_exit: true,
|
||||
);
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||
// 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.
|
||||
|
||||
|
@ -7,9 +7,10 @@ import 'dart:convert';
|
|||
import 'dart:developer';
|
||||
import 'dart:io' as io;
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/expect.dart';
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
Future setupFiles() async {
|
||||
|
@ -56,10 +57,11 @@ Future setupFiles() async {
|
|||
final utilFile = io.File(writeTemp);
|
||||
await utilFile.writeAsString('foobar');
|
||||
final readTemp = io.File(writeTemp);
|
||||
await readTemp.readAsString();
|
||||
final result = await readTemp.readAsString();
|
||||
Expect.equals(result, 'foobar');
|
||||
} catch (e) {
|
||||
closeDown();
|
||||
rethrow;
|
||||
throw e;
|
||||
}
|
||||
final result = jsonEncode({'type': 'foobar'});
|
||||
return Future.value(ServiceExtensionResponse.result(result));
|
||||
|
@ -69,22 +71,19 @@ Future setupFiles() async {
|
|||
registerExtension('ext.dart.io.setup', setup);
|
||||
}
|
||||
|
||||
var fileTests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolate) async {
|
||||
final isolateId = isolate.id!;
|
||||
await service.callServiceExtension(
|
||||
'ext.dart.io.setup',
|
||||
isolateId: isolate.id,
|
||||
);
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
try {
|
||||
await service.callServiceExtension('ext.dart.io.setup',
|
||||
isolateId: isolateId);
|
||||
final result = await service.getOpenFiles(isolateId);
|
||||
expect(result, isA<OpenFileList>());
|
||||
expect(result.files.length, equals(2));
|
||||
expect(result.files.length, 2);
|
||||
|
||||
final writing = await service.getOpenFileById(
|
||||
isolateId,
|
||||
result.files[0].id,
|
||||
);
|
||||
|
||||
expect(writing.readBytes, 0);
|
||||
expect(writing.readCount, 0);
|
||||
expect(writing.writeCount, 3);
|
||||
|
@ -96,6 +95,7 @@ var fileTests = <IsolateTest>[
|
|||
isolateId,
|
||||
result.files[1].id,
|
||||
);
|
||||
|
||||
expect(reading.readBytes, 5);
|
||||
expect(reading.readCount, 5);
|
||||
expect(reading.writeCount, 0);
|
||||
|
@ -105,15 +105,15 @@ var fileTests = <IsolateTest>[
|
|||
} finally {
|
||||
await service.callServiceExtension(
|
||||
'ext.dart.io.cleanup',
|
||||
isolateId: isolate.id,
|
||||
isolateId: isolateId,
|
||||
);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
main([args = const <String>[]]) async => runIsolateTests(
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
fileTests,
|
||||
tests,
|
||||
'file_service_test.dart',
|
||||
testeeBefore: setupFiles,
|
||||
);
|
||||
|
|
45
pkg/vm_service/test/gc_test.dart
Normal file
45
pkg/vm_service/test/gc_test.dart
Normal file
|
@ -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 'package:vm_service/vm_service.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
void script() {
|
||||
var grow;
|
||||
grow = (int iterations, int size, Duration duration) {
|
||||
if (iterations <= 0) {
|
||||
return;
|
||||
}
|
||||
List<int>.filled(size, 0);
|
||||
Timer(duration, () => grow(iterations - 1, size, duration));
|
||||
};
|
||||
grow(100, 1 << 24, new Duration(seconds: 1));
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
Completer completer = Completer();
|
||||
// Expect at least this many GC events.
|
||||
int gcCountdown = 3;
|
||||
late final StreamSubscription sub;
|
||||
sub = service.onGCEvent.listen((stream) {
|
||||
if (--gcCountdown == 0) {
|
||||
sub.cancel();
|
||||
completer.complete();
|
||||
}
|
||||
});
|
||||
await service.streamListen(EventStreams.kGC);
|
||||
return completer.future;
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'gc_test.dart',
|
||||
testeeConcurrent: script,
|
||||
);
|
|
@ -0,0 +1,82 @@
|
|||
// 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:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
void verifyMember(ClassHeapStats member) {
|
||||
expect(member.json!.containsKey('_new'), false);
|
||||
expect(member.json!.containsKey('_old'), false);
|
||||
expect(member.json!.containsKey('_promotedInstances'), false);
|
||||
expect(member.json!.containsKey('_promotedBytes'), false);
|
||||
expect(member.instancesAccumulated, greaterThanOrEqualTo(0));
|
||||
expect(member.instancesCurrent, greaterThanOrEqualTo(0));
|
||||
expect(member.bytesCurrent, greaterThanOrEqualTo(0));
|
||||
expect(member.accumulatedSize, greaterThanOrEqualTo(0));
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
var result = await service.getAllocationProfile(isolateId);
|
||||
expect(result.dateLastAccumulatorReset, isNull);
|
||||
expect(result.dateLastServiceGC, isNull);
|
||||
expect(result.json!.containsKey('_heaps'), false);
|
||||
var members = result.members!;
|
||||
expect(members, isNotEmpty);
|
||||
|
||||
var member = members.first;
|
||||
verifyMember(member);
|
||||
|
||||
// reset.
|
||||
result = await service.getAllocationProfile(isolateId, reset: true);
|
||||
final firstReset = result.dateLastAccumulatorReset!;
|
||||
expect(result.dateLastServiceGC, isNull);
|
||||
expect(result.json!.containsKey('_heaps'), false);
|
||||
|
||||
members = result.members!;
|
||||
expect(members, isNotEmpty);
|
||||
|
||||
member = members.first;
|
||||
verifyMember(member);
|
||||
|
||||
// Create an artificial delay to ensure there's a difference between the
|
||||
// reset times.
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
result = await service.getAllocationProfile(isolateId, reset: true);
|
||||
final secondReset = result.dateLastAccumulatorReset!;
|
||||
expect(secondReset, isNot(firstReset));
|
||||
|
||||
// gc.
|
||||
result = await service.getAllocationProfile(isolateId, gc: true);
|
||||
expect(result.dateLastAccumulatorReset, secondReset);
|
||||
final firstGC = result.dateLastServiceGC!;
|
||||
expect(result.json!.containsKey('_heaps'), false);
|
||||
|
||||
members = result.members!;
|
||||
expect(members, isNotEmpty);
|
||||
|
||||
member = members.first;
|
||||
verifyMember(member);
|
||||
|
||||
// Create an artificial delay to ensure there's a difference between the
|
||||
// GC times.
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
result = await service.getAllocationProfile(isolateId, gc: true);
|
||||
final secondGC = result.dateLastServiceGC!;
|
||||
expect(secondGC, isNot(firstGC));
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_allocation_profile_public_rpc_test.dart',
|
||||
);
|
|
@ -0,0 +1,49 @@
|
|||
// 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 'package:test/test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
|
||||
Future<void> getInstancesAndExecuteExpression(ClassHeapStats member) async {
|
||||
final objectId = member.classRef!.id!;
|
||||
final result = await service.getInstancesAsList(isolateId, objectId);
|
||||
// This has previously caused an exception like
|
||||
// "RPCError(evaluate: Unexpected exception:
|
||||
// FormatException: Unexpected character (at offset 329)"
|
||||
try {
|
||||
await service.evaluate(isolateId, result.id!, 'this');
|
||||
} on RPCError catch (e) {
|
||||
expect(e.code, RPCErrorKind.kExpressionCompilationError.code);
|
||||
expect(
|
||||
e.details,
|
||||
contains('Cannot evaluate against a VM-internal object'),
|
||||
);
|
||||
return;
|
||||
}
|
||||
fail('Expected exception');
|
||||
}
|
||||
|
||||
final result = await service.getAllocationProfile(isolateId);
|
||||
final members = result.members!;
|
||||
for (final member in members) {
|
||||
final name = member.classRef!.name!;
|
||||
if (name == 'Library') {
|
||||
await getInstancesAndExecuteExpression(member);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_instances_as_array_rpc_expression_evaluation_on_internal_test.dart',
|
||||
);
|
77
pkg/vm_service/test/get_instances_as_array_rpc_test.dart
Normal file
77
pkg/vm_service/test/get_instances_as_array_rpc_test.dart
Normal file
|
@ -0,0 +1,77 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
class Class {}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
class Subclass extends Class {}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
class Implementor implements Class {}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
var aClass;
|
||||
@pragma('vm:entry-point')
|
||||
var aSubclass;
|
||||
@pragma('vm:entry-point')
|
||||
var anImplementor;
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void allocate() {
|
||||
aClass = Class();
|
||||
aSubclass = Subclass();
|
||||
anImplementor = Implementor();
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final isolate = await service.getIsolate(isolateId);
|
||||
final rootLibId = isolate.rootLib!.id!;
|
||||
final rootLib = await service.getObject(isolateId, rootLibId) as Library;
|
||||
|
||||
Future<void> invoke(String selector) => service.invoke(
|
||||
isolateId,
|
||||
rootLibId,
|
||||
selector,
|
||||
const <String>[],
|
||||
);
|
||||
|
||||
Future<int> instanceCount(String className,
|
||||
{bool includeSubclasses = false,
|
||||
bool includeImplementors = false}) async {
|
||||
final objectId =
|
||||
rootLib.classes!.singleWhere((cls) => cls.name == className).id!;
|
||||
final result = await service.getInstancesAsList(
|
||||
isolateId,
|
||||
objectId,
|
||||
includeImplementers: includeImplementors,
|
||||
includeSubclasses: includeSubclasses,
|
||||
);
|
||||
return result.length!;
|
||||
}
|
||||
|
||||
expect(await instanceCount('Class'), 0);
|
||||
expect(await instanceCount('Class', includeSubclasses: true), 0);
|
||||
expect(await instanceCount('Class', includeImplementors: true), 0);
|
||||
|
||||
await invoke('allocate');
|
||||
|
||||
expect(await instanceCount('Class'), 1);
|
||||
expect(await instanceCount('Class', includeSubclasses: true), 2);
|
||||
expect(await instanceCount('Class', includeImplementors: true), 3);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_instances_as_array_rpc_test.dart',
|
||||
);
|
30
pkg/vm_service/test/get_isolate_after_async_error_test.dart
Normal file
30
pkg/vm_service/test/get_isolate_after_async_error_test.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
|
||||
Future<Never> doThrow() async {
|
||||
throw 'oh no';
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtExit,
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolate = await service.getIsolate(isolateRef.id!);
|
||||
expect(isolate.error, isNotNull);
|
||||
expect(isolate.error!.message!.contains('oh no'), true);
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_isolate_after_async_error_test.dart',
|
||||
pause_on_exit: true,
|
||||
testeeConcurrent: doThrow,
|
||||
);
|
|
@ -0,0 +1,35 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
|
||||
// Non tailable recursive function that should trigger a Stack Overflow.
|
||||
num factorialGrowth([num n = 1]) {
|
||||
return factorialGrowth(n + 1) * n;
|
||||
}
|
||||
|
||||
void nonTailableRecursion() {
|
||||
factorialGrowth();
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtExit,
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolate = await service.getIsolate(isolateRef.id!);
|
||||
expect(isolate.error, isNotNull);
|
||||
expect(isolate.error!.message!.contains('Stack Overflow'), true);
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_isolate_after_stack_overflow_error_test.dart',
|
||||
pause_on_exit: true,
|
||||
testeeConcurrent: nonTailableRecursion,
|
||||
);
|
30
pkg/vm_service/test/get_isolate_after_sync_error_test.dart
Normal file
30
pkg/vm_service/test/get_isolate_after_sync_error_test.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
|
||||
void doThrow() {
|
||||
throw 'oh no';
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtExit,
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolate = await service.getIsolate(isolateRef.id!);
|
||||
expect(isolate.error, isNotNull);
|
||||
expect(isolate.error!.message!.contains('oh no'), true);
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_isolate_after_async_error_test.dart',
|
||||
pause_on_exit: true,
|
||||
testeeConcurrent: doThrow,
|
||||
);
|
54
pkg/vm_service/test/get_ports_public_rpc_test.dart
Normal file
54
pkg/vm_service/test/get_ports_public_rpc_test.dart
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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:isolate' hide Isolate;
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
late final RawReceivePort port1;
|
||||
late final RawReceivePort port2;
|
||||
late final RawReceivePort port3;
|
||||
|
||||
void warmup() {
|
||||
port1 = RawReceivePort(null, 'port1');
|
||||
port2 = RawReceivePort((_) {});
|
||||
port3 = RawReceivePort((_) {}, 'port3');
|
||||
port3.close();
|
||||
RawReceivePort((_) {}, 'port4');
|
||||
}
|
||||
|
||||
int countNameMatches(List<InstanceRef> ports, String name) {
|
||||
int matches = 0;
|
||||
for (final port in ports) {
|
||||
if (port.debugName == name) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final result = await service.getPorts(isolateId);
|
||||
final ports = result.ports!;
|
||||
// There are at least three ports: the three created in warm up that
|
||||
// weren't closed. Some OSes will have other ports open but we do not try
|
||||
// and test for these.
|
||||
expect(ports.length, greaterThanOrEqualTo(3));
|
||||
expect(countNameMatches(ports, 'port1'), 1);
|
||||
expect(countNameMatches(ports, 'port3'), 0);
|
||||
expect(countNameMatches(ports, 'port4'), 1);
|
||||
expect(countNameMatches(ports, ''), greaterThanOrEqualTo(1));
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_ports_public_rpc_test.dart',
|
||||
testeeBefore: warmup,
|
||||
);
|
30
pkg/vm_service/test/get_process_memory_usage_rpc_test.dart
Normal file
30
pkg/vm_service/test/get_process_memory_usage_rpc_test.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
final tests = <VMTest>[
|
||||
(VmService service) async {
|
||||
final result = await service.getProcessMemoryUsage();
|
||||
void checkProcessMemoryItem(ProcessMemoryItem item) {
|
||||
expect(item.name, isNotNull);
|
||||
expect(item.description, isNotNull);
|
||||
expect(item.size, greaterThanOrEqualTo(0));
|
||||
for (final child in item.children!) {
|
||||
checkProcessMemoryItem(child);
|
||||
}
|
||||
}
|
||||
|
||||
checkProcessMemoryItem(result.root!);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runVMTests(
|
||||
args,
|
||||
tests,
|
||||
'get_process_memory_usage_rpc_test.dart',
|
||||
);
|
255
pkg/vm_service/test/get_retaining_path_rpc_test.dart
Normal file
255
pkg/vm_service/test/get_retaining_path_rpc_test.dart
Normal file
|
@ -0,0 +1,255 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
class _TestClass {
|
||||
_TestClass();
|
||||
// Make sure these fields are not removed by the tree shaker.
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
dynamic x;
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
dynamic y;
|
||||
}
|
||||
|
||||
_TestClass? target1 = _TestClass();
|
||||
_TestClass? target2 = _TestClass();
|
||||
_TestClass? target3 = _TestClass();
|
||||
_TestClass? target4 = _TestClass();
|
||||
_TestClass? target5 = _TestClass();
|
||||
_TestClass? target6 = _TestClass();
|
||||
_TestClass? target7 = _TestClass();
|
||||
_TestClass? target8 = _TestClass();
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
Expando<_TestClass> expando = Expando<_TestClass>();
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass globalObject = _TestClass();
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
dynamic globalList = List<dynamic>.filled(100, null);
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
dynamic globalMap1 = Map();
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
dynamic globalMap2 = Map();
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass weakReachable = _TestClass();
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass weakUnreachable = _TestClass();
|
||||
|
||||
void warmup() {
|
||||
globalObject.x = target1;
|
||||
globalObject.y = target2;
|
||||
globalList[12] = target3;
|
||||
globalMap1['key'] = target4;
|
||||
globalMap2[target5] = 'value';
|
||||
|
||||
// The weak reference will be traced first in DFS, but the retaining path
|
||||
// include the strong reference.
|
||||
weakReachable.x = WeakReference<_TestClass>(target7!);
|
||||
weakReachable.y = target7;
|
||||
|
||||
weakUnreachable.x = WeakReference<_TestClass>(target8!);
|
||||
weakUnreachable.y = null;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
getGlobalObject() => globalObject;
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeTarget1() {
|
||||
var tmp = target1;
|
||||
target1 = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeTarget2() {
|
||||
var tmp = target2;
|
||||
target2 = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeTarget3() {
|
||||
var tmp = target3;
|
||||
target3 = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeTarget4() {
|
||||
var tmp = target4;
|
||||
target4 = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeTarget5() {
|
||||
var tmp = target5;
|
||||
target5 = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeExpandoTarget() {
|
||||
var tmp = target6;
|
||||
target6 = null;
|
||||
var tmp2 = _TestClass();
|
||||
expando[tmp!] = tmp2;
|
||||
return tmp2;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeWeakReachableTarget() {
|
||||
var tmp = target7;
|
||||
target7 = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
_TestClass? takeWeakUnreachableTarget() {
|
||||
var tmp = target8;
|
||||
target8 = null;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
bool getTrue() => true;
|
||||
|
||||
Future<InstanceRef> invoke(String selector) async {
|
||||
return await rootService.invoke(
|
||||
isolateId,
|
||||
isolate.rootLib!.id!,
|
||||
selector,
|
||||
[],
|
||||
) as InstanceRef;
|
||||
}
|
||||
|
||||
late final VmService rootService;
|
||||
late final Isolate isolate;
|
||||
late final String isolateId;
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
// Initialization
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
isolateId = isolateRef.id!;
|
||||
rootService = service;
|
||||
isolate = await service.getIsolate(isolateId);
|
||||
},
|
||||
// simple path
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final obj = await invoke('getGlobalObject');
|
||||
final result = await service.getRetainingPath(isolateId, obj.id!, 100);
|
||||
expect(result.gcRootType, 'user global');
|
||||
expect(result.elements!.length, 2);
|
||||
expect((result.elements![1].value! as FieldRef).name, 'globalObject');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('takeTarget1');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
expect(result.gcRootType, 'user global');
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 3);
|
||||
expect(elements[1].parentField, 'x');
|
||||
expect((elements[2].value as FieldRef).name, 'globalObject');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('takeTarget2');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
expect(result.gcRootType, 'user global');
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 3);
|
||||
expect(elements[1].parentField, 'y');
|
||||
expect((elements[2].value as FieldRef).name, 'globalObject');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('takeTarget3');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
expect(result.gcRootType, 'user global');
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 3);
|
||||
expect(elements[1].parentListIndex, 12);
|
||||
expect((elements[2].value as FieldRef).name, 'globalList');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('takeTarget4');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
expect(result.gcRootType, 'user global');
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 3);
|
||||
expect((elements[1].parentMapKey as InstanceRef).valueAsString, 'key');
|
||||
expect((elements[2].value as FieldRef).name, 'globalMap1');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('takeTarget5');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
expect(result.gcRootType, 'user global');
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 3);
|
||||
expect(
|
||||
(elements[1].parentMapKey as InstanceRef).classRef!.name,
|
||||
'_TestClass',
|
||||
);
|
||||
expect((elements[2].value as FieldRef).name, 'globalMap2');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
// Regression test for https://github.com/dart-lang/sdk/issues/44016
|
||||
final target = await invoke('takeExpandoTarget');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 5);
|
||||
expect(
|
||||
(elements[1].parentMapKey as InstanceRef).classRef!.name,
|
||||
'_TestClass',
|
||||
);
|
||||
expect(elements[2].parentListIndex, isNotNull);
|
||||
expect((elements[4].value as FieldRef).name, 'expando');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('takeWeakReachableTarget');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
expect(result.gcRootType, 'user global');
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 3);
|
||||
expect(elements[1].parentField, 'y');
|
||||
expect((elements[2].value as FieldRef).name, 'weakReachable');
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('takeWeakUnreachableTarget');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 0);
|
||||
},
|
||||
|
||||
// object store
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('getTrue');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
expect(
|
||||
result.gcRootType == 'isolate_object store' ||
|
||||
result.gcRootType == 'class table',
|
||||
true,
|
||||
);
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 0);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) async => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_retaining_path_rpc_test.dart',
|
||||
testeeBefore: warmup,
|
||||
);
|
52
pkg/vm_service/test/get_scripts_rpc_test.dart
Normal file
52
pkg/vm_service/test/get_scripts_rpc_test.dart
Normal file
|
@ -0,0 +1,52 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final results = await service.getScripts(isolateId);
|
||||
expect(results.scripts!.length, isPositive);
|
||||
},
|
||||
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = 'badid';
|
||||
bool caughtException = false;
|
||||
try {
|
||||
await service.getScripts(isolateId);
|
||||
fail('Unreachable');
|
||||
} on RPCError catch (e) {
|
||||
caughtException = true;
|
||||
expect(e.code, RPCErrorKind.kInvalidParams.code);
|
||||
expect(e.details, "getScripts: invalid 'isolateId' parameter: badid");
|
||||
}
|
||||
expect(caughtException, true);
|
||||
},
|
||||
|
||||
// Plausible isolate id, not found.
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = 'isolates/9999999999';
|
||||
bool caughtException = false;
|
||||
try {
|
||||
await service.getScripts(isolateId);
|
||||
fail('Unreachable');
|
||||
} on SentinelException catch (e) {
|
||||
caughtException = true;
|
||||
expect(e.callingMethod, 'getScripts');
|
||||
expect(e.sentinel.kind, SentinelKind.kCollected);
|
||||
expect(e.sentinel.valueAsString, '<collected>');
|
||||
}
|
||||
expect(caughtException, true);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_scripts_rpc_test.dart',
|
||||
);
|
|
@ -0,0 +1,12 @@
|
|||
// 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 'get_source_report_const_coverage_test.dart';
|
||||
|
||||
void testFunction() {
|
||||
const namedFoo = Foo.named3();
|
||||
const namedFoo2 = Foo.named3();
|
||||
const namedIdentical = identical(namedFoo, namedFoo2);
|
||||
print('namedIdentical: $namedIdentical');
|
||||
}
|
137
pkg/vm_service/test/get_source_report_const_coverage_test.dart
Normal file
137
pkg/vm_service/test/get_source_report_const_coverage_test.dart
Normal file
|
@ -0,0 +1,137 @@
|
|||
// 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:developer';
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
|
||||
import 'get_source_report_const_coverage_lib.dart' as lib;
|
||||
|
||||
const filename = 'get_source_report_const_coverage_test';
|
||||
const expectedLinesHit = <int>{24, 26, 30};
|
||||
const expectedLinesNotHit = <int>{28};
|
||||
|
||||
const LINE_A = 45;
|
||||
|
||||
class Foo {
|
||||
final int x;
|
||||
// Expect this constructor to be coverage by coverage.
|
||||
const Foo([int? x]) : this.x = x ?? 42;
|
||||
// Expect this constructor to be coverage by coverage too.
|
||||
const Foo.named1([int? x]) : this.x = x ?? 42;
|
||||
// Expect this constructor to *NOT* be coverage by coverage.
|
||||
const Foo.named2([int? x]) : this.x = x ?? 42;
|
||||
// Expect this constructor to be coverage by coverage too (from lib).
|
||||
const Foo.named3([int? x]) : this.x = x ?? 42;
|
||||
}
|
||||
|
||||
void testFunction() {
|
||||
const foo = Foo();
|
||||
const foo2 = Foo();
|
||||
const fooIdentical = identical(foo, foo2);
|
||||
print(fooIdentical);
|
||||
|
||||
const namedFoo = Foo.named1();
|
||||
const namedFoo2 = Foo.named1();
|
||||
// ignore: unused_local_variable
|
||||
const namedIdentical = identical(namedFoo, namedFoo2);
|
||||
print(fooIdentical);
|
||||
|
||||
debugger(); // LINE_A
|
||||
|
||||
// That this is called after (or at all) is not relevent for the code
|
||||
// coverage of constants.
|
||||
lib.testFunction();
|
||||
|
||||
print('Done');
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtBreakpoint,
|
||||
stoppedAtLine(LINE_A),
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final isolate = await service.getIsolate(isolateId);
|
||||
final rootLibId = isolate.rootLib!.id!;
|
||||
final rootLib = await service.getObject(isolateId, rootLibId) as Library;
|
||||
Script? foundScript;
|
||||
for (ScriptRef script in rootLib.scripts!) {
|
||||
if (script.uri!.contains(filename)) {
|
||||
foundScript = await service.getObject(isolateId, script.id!) as Script;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundScript == null) {
|
||||
fail('Failed to find script');
|
||||
}
|
||||
|
||||
Set<int> hits;
|
||||
{
|
||||
// Get report for everything; then collect for this library.
|
||||
final coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
);
|
||||
hits = getHitsFor(coverage, filename);
|
||||
final lines = <int>{};
|
||||
for (int hit in hits) {
|
||||
// We expect every hit to be translatable to line
|
||||
// (i.e. tokenToLine to return non-null).
|
||||
final line = foundScript.getLineNumberFromTokenPos(hit);
|
||||
lines.add(line!);
|
||||
}
|
||||
print('Token position hits: $hits --- line hits: $lines');
|
||||
expect(lines.intersection(expectedLinesHit), expectedLinesHit);
|
||||
expect(lines.intersection(expectedLinesNotHit), isEmpty);
|
||||
}
|
||||
{
|
||||
// Now get report for the this file only.
|
||||
final coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
scriptId: foundScript.id!,
|
||||
);
|
||||
final localHits = getHitsFor(coverage, filename);
|
||||
expect(localHits.length, hits.length);
|
||||
expect(hits.toList()..sort(), localHits.toList()..sort());
|
||||
print(localHits);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
Set<int> getHitsFor(SourceReport coverage, String uriContains) {
|
||||
final scripts = coverage.scripts!;
|
||||
final scriptIdsWanted = <int>{};
|
||||
for (int i = 0; i < scripts.length; i++) {
|
||||
final script = scripts[i];
|
||||
final scriptUri = script.uri!;
|
||||
if (scriptUri.contains(uriContains)) {
|
||||
scriptIdsWanted.add(i);
|
||||
}
|
||||
}
|
||||
final ranges = coverage.ranges!;
|
||||
final hits = <int>{};
|
||||
for (final range in ranges) {
|
||||
if (scriptIdsWanted.contains(range.scriptIndex!)) {
|
||||
if (range.coverage != null) {
|
||||
for (int hit in range.coverage!.hits!) {
|
||||
hits.add(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_source_report_const_coverage_test.dart',
|
||||
testeeConcurrent: testFunction,
|
||||
);
|
213
pkg/vm_service/test/get_source_report_test.dart
Normal file
213
pkg/vm_service/test/get_source_report_test.dart
Normal file
|
@ -0,0 +1,213 @@
|
|||
// 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:developer';
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
|
||||
const LINE_A = 25;
|
||||
const LINE_B = 46;
|
||||
|
||||
int globalVar = 100;
|
||||
|
||||
class MyClass {
|
||||
static void myFunction(int value) {
|
||||
if (value < 0) {
|
||||
print('negative');
|
||||
} else {
|
||||
print('positive');
|
||||
}
|
||||
debugger(); // LINE_A
|
||||
}
|
||||
|
||||
static void otherFunction(int value) {
|
||||
if (value < 0) {
|
||||
print('otherFunction <');
|
||||
} else {
|
||||
print('otherFunction >=');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testFunction() {
|
||||
MyClass.otherFunction(-100);
|
||||
MyClass.myFunction(10000);
|
||||
}
|
||||
|
||||
class MyConstClass {
|
||||
const MyConstClass();
|
||||
static const MyConstClass instance = null ?? const MyConstClass();
|
||||
|
||||
void foo() {
|
||||
debugger(); // LINE_B
|
||||
}
|
||||
}
|
||||
|
||||
void testFunction2() {
|
||||
MyConstClass.instance.foo();
|
||||
}
|
||||
|
||||
bool allRangesCompiled(SourceReport coverage) {
|
||||
for (final range in coverage.ranges!) {
|
||||
if (!range.compiled!) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtBreakpoint,
|
||||
stoppedAtLine(LINE_A),
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final stack = await service.getStack(isolateId);
|
||||
final func = stack.frames!.first.function!;
|
||||
final scriptId = func.location!.script!.id!;
|
||||
|
||||
final expectedRange = SourceReportRange(
|
||||
scriptIndex: 0,
|
||||
startPos: 478,
|
||||
endPos: 632,
|
||||
compiled: true,
|
||||
coverage: SourceReportCoverage(
|
||||
hits: const [478, 528, 579, 608],
|
||||
misses: [541],
|
||||
),
|
||||
);
|
||||
|
||||
// Full script
|
||||
var coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
scriptId: scriptId,
|
||||
);
|
||||
|
||||
var ranges = coverage.ranges!;
|
||||
expect(ranges.length, greaterThanOrEqualTo(10));
|
||||
// TODO(bkonyi): implement operator== properly.
|
||||
expect(ranges[0].toJson(), expectedRange.toJson());
|
||||
|
||||
var scripts = coverage.scripts!;
|
||||
expect(coverage.scripts!.length, 1);
|
||||
expect(scripts[0].uri!, endsWith('get_source_report_test.dart'));
|
||||
expect(allRangesCompiled(coverage), false);
|
||||
|
||||
// Force compilation.
|
||||
coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
scriptId: scriptId,
|
||||
forceCompile: true,
|
||||
);
|
||||
ranges = coverage.ranges!;
|
||||
expect(ranges.length, greaterThanOrEqualTo(10));
|
||||
expect(allRangesCompiled(coverage), isTrue);
|
||||
|
||||
// One function
|
||||
coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
scriptId: scriptId,
|
||||
tokenPos: func.location!.tokenPos!,
|
||||
endTokenPos: func.location!.endTokenPos!,
|
||||
);
|
||||
ranges = coverage.ranges!;
|
||||
scripts = coverage.scripts!;
|
||||
expect(ranges.length, 1);
|
||||
// TODO(bkonyi): implement operator== properly.
|
||||
expect(ranges[0].toJson(), expectedRange.toJson());
|
||||
expect(scripts.length, 1);
|
||||
expect(scripts[0].uri!, endsWith('get_source_report_test.dart'));
|
||||
|
||||
// Full isolate
|
||||
coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
);
|
||||
ranges = coverage.ranges!;
|
||||
scripts = coverage.scripts!;
|
||||
expect(ranges.length, greaterThan(1));
|
||||
expect(scripts.length, greaterThan(1));
|
||||
|
||||
// Full isolate
|
||||
coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
forceCompile: true,
|
||||
);
|
||||
ranges = coverage.ranges!;
|
||||
scripts = coverage.scripts!;
|
||||
expect(ranges.length, greaterThan(1));
|
||||
expect(scripts.length, greaterThan(1));
|
||||
|
||||
// Multiple reports (make sure enum list parameter parsing works).
|
||||
coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[
|
||||
SourceReportKind.kCoverage,
|
||||
SourceReportKind.kPossibleBreakpoints,
|
||||
'_CallSites',
|
||||
],
|
||||
scriptId: scriptId,
|
||||
tokenPos: func.location!.tokenPos!,
|
||||
endTokenPos: func.location!.endTokenPos!,
|
||||
);
|
||||
ranges = coverage.ranges!;
|
||||
expect(ranges.length, 1);
|
||||
final range = ranges[0];
|
||||
expect(coverage.json!['ranges'][0].containsKey('callSites'), true);
|
||||
expect(range.coverage, isNotNull);
|
||||
expect(range.possibleBreakpoints, isNotNull);
|
||||
|
||||
// missing scriptId with tokenPos.
|
||||
bool caughtException = false;
|
||||
try {
|
||||
await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
tokenPos: func.location!.tokenPos!,
|
||||
);
|
||||
fail('Unreachable');
|
||||
} on RPCError catch (e) {
|
||||
caughtException = true;
|
||||
expect(e.code, RPCErrorKind.kInvalidParams.code);
|
||||
expect(
|
||||
e.details,
|
||||
"getSourceReport: the 'tokenPos' parameter requires the "
|
||||
"\'scriptId\' parameter");
|
||||
}
|
||||
expect(caughtException, true);
|
||||
|
||||
// missing scriptId with endTokenPos.
|
||||
caughtException = false;
|
||||
try {
|
||||
await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
endTokenPos: func.location!.endTokenPos!,
|
||||
);
|
||||
fail('Unreachable');
|
||||
} on RPCError catch (e) {
|
||||
caughtException = true;
|
||||
expect(e.code, RPCErrorKind.kInvalidParams.code);
|
||||
expect(
|
||||
e.details,
|
||||
"getSourceReport: the 'endTokenPos' parameter requires the "
|
||||
"\'scriptId\' parameter");
|
||||
}
|
||||
expect(caughtException, true);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_source_report_test.dart',
|
||||
testeeConcurrent: testFunction,
|
||||
);
|
15
pkg/vm_service/test/get_source_report_with_mixin_lib1.dart
Normal file
15
pkg/vm_service/test/get_source_report_with_mixin_lib1.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
// 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.
|
||||
|
||||
mixin A {
|
||||
void foo() {
|
||||
print('foo');
|
||||
}
|
||||
}
|
||||
|
||||
mixin B {
|
||||
void bar() {
|
||||
print('bar');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
// 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 'get_source_report_with_mixin_lib1.dart';
|
||||
|
||||
class Test1 with A {}
|
|
@ -0,0 +1,7 @@
|
|||
// 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 'get_source_report_with_mixin_lib1.dart';
|
||||
|
||||
class Test2 with B {}
|
103
pkg/vm_service/test/get_source_report_with_mixin_test.dart
Normal file
103
pkg/vm_service/test/get_source_report_with_mixin_test.dart
Normal file
|
@ -0,0 +1,103 @@
|
|||
// 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:developer';
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
|
||||
import 'get_source_report_with_mixin_lib2.dart';
|
||||
import 'get_source_report_with_mixin_lib3.dart';
|
||||
|
||||
const LINE_A = 26;
|
||||
|
||||
const lib1Filename = 'get_source_report_with_mixin_lib1';
|
||||
const lib3Filename = 'get_source_report_with_mixin_lib3';
|
||||
|
||||
void testFunction() {
|
||||
final Test1 test1 = new Test1();
|
||||
test1.foo();
|
||||
final Test2 test2 = new Test2();
|
||||
test2.bar();
|
||||
debugger(); // LINE_A
|
||||
print('done');
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtBreakpoint,
|
||||
stoppedAtLine(LINE_A),
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final scripts = await service.getScripts(isolateId);
|
||||
ScriptRef? foundScript;
|
||||
for (ScriptRef script in scripts.scripts!) {
|
||||
if (script.uri!.contains(lib1Filename)) {
|
||||
foundScript = script;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundScript == null) {
|
||||
fail('Failed to find script');
|
||||
}
|
||||
|
||||
Set<int> hits;
|
||||
{
|
||||
// Get report for everything; then collect for lib1.
|
||||
final coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
);
|
||||
hits = getHitsForLib1(coverage, lib1Filename);
|
||||
expect(hits.length, greaterThanOrEqualTo(2));
|
||||
print(hits);
|
||||
}
|
||||
{
|
||||
// Now get report for the lib1 only.
|
||||
final coverage = await service.getSourceReport(
|
||||
isolateId,
|
||||
[SourceReportKind.kCoverage],
|
||||
scriptId: foundScript.id!,
|
||||
);
|
||||
final localHits = getHitsForLib1(coverage, lib1Filename);
|
||||
expect(localHits.length, hits.length);
|
||||
expect(hits.toList()..sort(), localHits.toList()..sort());
|
||||
print(localHits);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
Set<int> getHitsForLib1(SourceReport coverage, String uriContains) {
|
||||
final scripts = coverage.scripts!;
|
||||
final scriptIdsWanted = <int>{};
|
||||
for (int i = 0; i < scripts.length; i++) {
|
||||
final script = scripts[i];
|
||||
final scriptUri = script.uri!;
|
||||
if (scriptUri.contains(uriContains)) {
|
||||
scriptIdsWanted.add(i);
|
||||
}
|
||||
}
|
||||
final ranges = coverage.ranges!;
|
||||
final hits = <int>{};
|
||||
for (final range in ranges) {
|
||||
if (scriptIdsWanted.contains(range.scriptIndex!)) {
|
||||
if (range.coverage != null) {
|
||||
for (final hit in range.coverage!.hits!) {
|
||||
hits.add(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_source_report_with_mixin_test.dart',
|
||||
testeeConcurrent: testFunction,
|
||||
);
|
134
pkg/vm_service/test/get_stack_limit_rpc_test.dart
Normal file
134
pkg/vm_service/test/get_stack_limit_rpc_test.dart
Normal file
|
@ -0,0 +1,134 @@
|
|||
// 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:developer';
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/service_test_common.dart';
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
Future<void> bar(int depth) async {
|
||||
if (depth == 21) {
|
||||
debugger();
|
||||
return;
|
||||
}
|
||||
await foo(depth + 1);
|
||||
}
|
||||
|
||||
Future<void> foo(int depth) async {
|
||||
if (depth == 10) {
|
||||
// Yield once to force the rest to run async.
|
||||
await 0;
|
||||
}
|
||||
await bar(depth + 1);
|
||||
}
|
||||
|
||||
Future<void> testMain() async {
|
||||
await foo(0);
|
||||
}
|
||||
|
||||
void verifyStack(List<Frame> frames, List<String> expectedNames) {
|
||||
for (int i = 0; i < frames.length && i < expectedNames.length; ++i) {
|
||||
expect(frames[i].function!.name, expectedNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtBreakpoint,
|
||||
// Get stack
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
var stack = await service.getStack(isolateId);
|
||||
|
||||
// Sanity check.
|
||||
var frames = stack.frames!;
|
||||
var asyncFrames = stack.asyncCausalFrames!;
|
||||
expect(frames.length, greaterThanOrEqualTo(12));
|
||||
expect(asyncFrames.length, greaterThan(frames.length));
|
||||
expect(stack.truncated, false);
|
||||
verifyStack(frames, [
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo'
|
||||
]);
|
||||
|
||||
final fullStackLength = frames.length;
|
||||
|
||||
// Try a limit > actual stack depth and expect to get the full stack with
|
||||
// truncated async stacks.
|
||||
stack = await service.getStack(isolateId, limit: fullStackLength + 1);
|
||||
frames = stack.frames!;
|
||||
asyncFrames = stack.asyncCausalFrames!;
|
||||
|
||||
expect(frames.length, fullStackLength);
|
||||
expect(asyncFrames.length, fullStackLength + 1);
|
||||
expect(stack.truncated, true);
|
||||
verifyStack(frames, [
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo'
|
||||
]);
|
||||
|
||||
// Try a limit < actual stack depth and expect to get a stack of depth
|
||||
// 'limit'.
|
||||
stack = await service.getStack(isolateId, limit: 10);
|
||||
frames = stack.frames!;
|
||||
asyncFrames = stack.asyncCausalFrames!;
|
||||
|
||||
expect(frames.length, 10);
|
||||
expect(asyncFrames.length, 10);
|
||||
expect(stack.truncated, true);
|
||||
verifyStack(frames, [
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
'bar',
|
||||
'foo',
|
||||
]);
|
||||
},
|
||||
// Invalid limit
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
bool caughtException = false;
|
||||
try {
|
||||
await service.getStack(isolateRef.id!, limit: -1);
|
||||
fail('Invalid parameter of -1 successful');
|
||||
} on RPCError {
|
||||
// Expected.
|
||||
caughtException = true;
|
||||
}
|
||||
expect(caughtException, true);
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_stack_limit_rpc_test.dart',
|
||||
testeeConcurrent: testMain,
|
||||
);
|
98
pkg/vm_service/test/get_stack_rpc_test.dart
Normal file
98
pkg/vm_service/test/get_stack_rpc_test.dart
Normal file
|
@ -0,0 +1,98 @@
|
|||
// 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:isolate';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/service_test_common.dart';
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
const LINE_A = 25;
|
||||
|
||||
int counter = 0;
|
||||
final port = RawReceivePort(msgHandler);
|
||||
|
||||
// This name is used in a test below.
|
||||
void msgHandler(_) {}
|
||||
|
||||
void periodicTask(_) {
|
||||
port.sendPort.send(34);
|
||||
debugger(message: 'fo', when: true);
|
||||
counter++;
|
||||
if (counter % 300 == 0) {
|
||||
print('counter = $counter');
|
||||
}
|
||||
}
|
||||
|
||||
void startTimer() {
|
||||
new Timer.periodic(const Duration(milliseconds: 10), periodicTask);
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasStoppedAtBreakpoint,
|
||||
stoppedAtLine(LINE_A),
|
||||
// Get stack
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final stack = await service.getStack(isolateId);
|
||||
|
||||
// Sanity check.
|
||||
final frames = stack.frames!;
|
||||
expect(frames.length, greaterThanOrEqualTo(1));
|
||||
final scriptId = frames[0].location!.script!.id!;
|
||||
final script = await service.getObject(isolateId, scriptId) as Script;
|
||||
expect(
|
||||
script.getLineNumberFromTokenPos(frames[0].location!.tokenPos!),
|
||||
LINE_A,
|
||||
);
|
||||
|
||||
// Iterate over frames.
|
||||
int frameDepth = 0;
|
||||
for (var frame in frames) {
|
||||
print('checking frame $frameDepth');
|
||||
expect(frame.index, equals(frameDepth++));
|
||||
expect(frame.code, isNotNull);
|
||||
expect(frame.function, isNotNull);
|
||||
expect(frame.location, isNotNull);
|
||||
}
|
||||
|
||||
// Sanity check.
|
||||
final messages = stack.messages!;
|
||||
expect(messages.length, greaterThanOrEqualTo(1));
|
||||
|
||||
// Iterate over messages.
|
||||
int messageDepth = 0;
|
||||
// objectId of message to be handled by msgHandler.
|
||||
var msgHandlerObjectId;
|
||||
for (final message in messages) {
|
||||
print('checking message $messageDepth');
|
||||
expect(message.index, messageDepth++);
|
||||
expect(message.size, greaterThanOrEqualTo(0));
|
||||
expect(message.handler, isNotNull);
|
||||
expect(message.location, isNotNull);
|
||||
if (message.handler!.name!.contains('msgHandler')) {
|
||||
msgHandlerObjectId = message.messageObjectId;
|
||||
}
|
||||
}
|
||||
expect(msgHandlerObjectId, isNotNull);
|
||||
|
||||
// Get object.
|
||||
final object = await service.getObject(
|
||||
isolateId,
|
||||
msgHandlerObjectId,
|
||||
) as Instance;
|
||||
expect(object.valueAsString, '34');
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_stack_rpc_test.dart',
|
||||
testeeBefore: startTimer,
|
||||
);
|
|
@ -0,0 +1,80 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
class _TestConst {
|
||||
const _TestConst();
|
||||
}
|
||||
|
||||
_TopLevelClosure() {}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
var x;
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
var fn;
|
||||
|
||||
void warmup() {
|
||||
x = const _TestConst();
|
||||
fn = _TopLevelClosure;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
getX() => x;
|
||||
|
||||
@pragma("vm:entry-point") // Prevent obfuscation
|
||||
getFn() => fn;
|
||||
|
||||
Future<InstanceRef> invoke(String selector) async {
|
||||
return await rootService.invoke(
|
||||
isolateId,
|
||||
isolate.rootLib!.id!,
|
||||
selector,
|
||||
[],
|
||||
) as InstanceRef;
|
||||
}
|
||||
|
||||
late final VmService rootService;
|
||||
late final Isolate isolate;
|
||||
late final String isolateId;
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
isolateId = isolateRef.id!;
|
||||
rootService = service;
|
||||
isolate = await service.getIsolate(isolateId);
|
||||
},
|
||||
// Expect a simple path through variable x instead of long path filled
|
||||
// with VM objects
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('getX');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 2);
|
||||
expect((elements[0].value as InstanceRef).classRef!.name, '_TestConst');
|
||||
expect((elements[1].value as FieldRef).name, 'x');
|
||||
},
|
||||
|
||||
// Expect a simple path through variable fn instead of long path filled
|
||||
// with VM objects
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final target = await invoke('getFn');
|
||||
final result = await service.getRetainingPath(isolateId, target.id!, 100);
|
||||
final elements = result.elements!;
|
||||
expect(elements.length, 2);
|
||||
expect((elements[0].value as InstanceRef).classRef!.name, '_Closure');
|
||||
expect((elements[1].value as FieldRef).name, 'fn');
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_user_level_retaining_path_rpc_test.dart',
|
||||
testeeBefore: warmup,
|
||||
);
|
38
pkg/vm_service/test/get_vm_rpc_test.dart
Normal file
38
pkg/vm_service/test/get_vm_rpc_test.dart
Normal file
|
@ -0,0 +1,38 @@
|
|||
// 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.
|
||||
// VMOptions=--vm-name=Walter
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
final tests = <VMTest>[
|
||||
(VmService service) async {
|
||||
final vm = await service.getVM();
|
||||
expect(vm.name, equals('Walter'));
|
||||
expect(vm.architectureBits, isPositive);
|
||||
expect(vm.targetCPU, isA<String>());
|
||||
expect(vm.hostCPU, isA<String>());
|
||||
expect(vm.operatingSystem, Platform.operatingSystem);
|
||||
expect(vm.version, isA<String>());
|
||||
expect(vm.pid, isA<int>());
|
||||
expect(vm.startTime, isPositive);
|
||||
final isolates = vm.isolates!;
|
||||
expect(isolates.length, isPositive);
|
||||
expect(isolates[0].id, startsWith('isolates/'));
|
||||
expect(isolates[0].isolateGroupId, startsWith('isolateGroups/'));
|
||||
final isolateGroups = vm.isolateGroups!;
|
||||
expect(isolateGroups.length, isPositive);
|
||||
expect(isolateGroups[0].id, startsWith('isolateGroups/'));
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runVMTests(
|
||||
args,
|
||||
tests,
|
||||
'get_vm_rpc_test.dart',
|
||||
);
|
21
pkg/vm_service/test/get_vm_timeline_micros_rpc_test.dart
Normal file
21
pkg/vm_service/test/get_vm_timeline_micros_rpc_test.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
final tests = <VMTest>[
|
||||
(VmService service) async {
|
||||
final result = await service.getVMTimelineMicros();
|
||||
expect(result.timestamp, isPositive);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runVMTests(
|
||||
args,
|
||||
tests,
|
||||
'get_vm_timeline_micros_rpc_test.dart',
|
||||
);
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// 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 'package:test/test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import '../common/test_helper.dart';
|
||||
|
||||
class Foo {}
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
import '../common/test_helper.dart';
|
||||
import '../common/service_test_common.dart';
|
||||
|
||||
const int LINE_A = 18;
|
||||
const int LINE_B = 21;
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
||||
// 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/src/vm_service.dart';
|
||||
import 'common/test_helper.dart';
|
||||
import '../common/test_helper.dart';
|
||||
|
||||
class EchoResponse extends Response {
|
||||
static EchoResponse? parse(Map<String, dynamic>? json) =>
|
137
pkg/vm_service/test/private_rpcs/get_heap_map_rpc_test.dart
Normal file
137
pkg/vm_service/test/private_rpcs/get_heap_map_rpc_test.dart
Normal file
|
@ -0,0 +1,137 @@
|
|||
// 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 'package:vm_service/src/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../common/test_helper.dart';
|
||||
|
||||
class Page {
|
||||
Page.fromJson(Map<String, dynamic> json)
|
||||
: objectStart = json['objectStart'],
|
||||
objects = json['objects'].cast<int>();
|
||||
|
||||
final String objectStart;
|
||||
final List<int> objects;
|
||||
}
|
||||
|
||||
class HeapMap extends Response {
|
||||
static HeapMap? parse(Map<String, dynamic>? json) =>
|
||||
json == null ? null : HeapMap._fromJson(json);
|
||||
|
||||
HeapMap._fromJson(Map<String, dynamic> json)
|
||||
: freeClassId = json['freeClassId'],
|
||||
unitSizeBytes = json['unitSizeBytes'],
|
||||
pageSizeBytes = json['pageSizeBytes'],
|
||||
classList = ClassList.parse(json['classList'])!,
|
||||
pages = json['pages'].map<Page>((e) => Page.fromJson(e)).toList();
|
||||
|
||||
@override
|
||||
String get type => 'HeapMap';
|
||||
|
||||
final int freeClassId;
|
||||
final int unitSizeBytes;
|
||||
final int pageSizeBytes;
|
||||
final ClassList classList;
|
||||
final List<Page> pages;
|
||||
}
|
||||
|
||||
enum GCType {
|
||||
none,
|
||||
scavenge,
|
||||
markSweep,
|
||||
markCompact;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
switch (this) {
|
||||
case GCType.none:
|
||||
return '';
|
||||
case GCType.scavenge:
|
||||
return 'scavenge';
|
||||
case GCType.markCompact:
|
||||
return 'mark-compact';
|
||||
case GCType.markSweep:
|
||||
return 'mark-sweep';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension on VmService {
|
||||
Future<HeapMap> getHeapMap(String isolateId,
|
||||
{GCType gc = GCType.none}) async =>
|
||||
await callMethod('_getHeapMap', isolateId: isolateId, args: {
|
||||
if (gc != GCType.none) 'gc': gc.toString(),
|
||||
}) as HeapMap;
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
// Setup
|
||||
addTypeFactory('HeapMap', HeapMap.parse);
|
||||
},
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final result = await service.getHeapMap(isolateId);
|
||||
expect(result.freeClassId, isPositive);
|
||||
expect(result.unitSizeBytes, isPositive);
|
||||
expect(result.pageSizeBytes, isPositive);
|
||||
expect(result.classList.classes, isNotNull);
|
||||
expect(result.pages, isNotEmpty);
|
||||
expect(result.pages[0].objectStart, isNotEmpty);
|
||||
expect(result.pages[0].objects, isNotEmpty);
|
||||
expect(result.pages[0].objects[0], isPositive);
|
||||
},
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final result = await service.getHeapMap(
|
||||
isolateId,
|
||||
gc: GCType.markCompact,
|
||||
);
|
||||
expect(result.freeClassId, isPositive);
|
||||
expect(result.unitSizeBytes, isPositive);
|
||||
expect(result.pageSizeBytes, isPositive);
|
||||
expect(result.classList.classes, isNotNull);
|
||||
expect(result.pages, isNotEmpty);
|
||||
expect(result.pages[0].objectStart, isNotEmpty);
|
||||
expect(result.pages[0].objects, isNotEmpty);
|
||||
expect(result.pages[0].objects[0], isPositive);
|
||||
},
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final result = await service.getHeapMap(
|
||||
isolateId,
|
||||
gc: GCType.markSweep,
|
||||
);
|
||||
expect(result.freeClassId, isPositive);
|
||||
expect(result.unitSizeBytes, isPositive);
|
||||
expect(result.pageSizeBytes, isPositive);
|
||||
expect(result.classList.classes, isNotNull);
|
||||
expect(result.pages, isNotEmpty);
|
||||
expect(result.pages[0].objectStart, isNotEmpty);
|
||||
expect(result.pages[0].objects, isNotEmpty);
|
||||
expect(result.pages[0].objects[0], isPositive);
|
||||
},
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final result = await service.getHeapMap(
|
||||
isolateId,
|
||||
gc: GCType.scavenge,
|
||||
);
|
||||
expect(result.freeClassId, isPositive);
|
||||
expect(result.unitSizeBytes, isPositive);
|
||||
expect(result.pageSizeBytes, isPositive);
|
||||
expect(result.classList.classes, isNotNull);
|
||||
expect(result.pages, isNotEmpty);
|
||||
expect(result.pages[0].objectStart, isNotEmpty);
|
||||
expect(result.pages[0].objects, isNotEmpty);
|
||||
expect(result.pages[0].objects[0], isPositive);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_heap_map_rpc_test.dart',
|
||||
);
|
|
@ -5,7 +5,7 @@
|
|||
import 'package:test/test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
import '../common/test_helper.dart';
|
||||
|
||||
Future<Response> getImplementationFields(
|
||||
VmService service, String isolateId, String objectId) async {
|
|
@ -0,0 +1,67 @@
|
|||
// 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 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../common/test_helper.dart';
|
||||
|
||||
void testeeMain() {}
|
||||
|
||||
// Pulled from DevTools.
|
||||
class ObjectStore {
|
||||
const ObjectStore({
|
||||
required this.fields,
|
||||
});
|
||||
|
||||
static ObjectStore? parse(Map<String, dynamic>? json) {
|
||||
if (json?['type'] != '_ObjectStore') {
|
||||
return null;
|
||||
}
|
||||
final rawFields = json!['fields']! as Map<String, dynamic>;
|
||||
return ObjectStore(
|
||||
fields: rawFields.map((key, value) {
|
||||
return MapEntry(
|
||||
key,
|
||||
createServiceObject(value, ['InstanceRef']) as ObjRef,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
final Map<String, ObjRef> fields;
|
||||
}
|
||||
|
||||
extension on VmService {
|
||||
Future<ObjectStore> getObjectStore(String isolateId) async {
|
||||
final result = await callMethod('_getObjectStore', isolateId: isolateId);
|
||||
return ObjectStore.parse(result.json!)!;
|
||||
}
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
// Get object_store.
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final objectStore = await service.getObjectStore(isolateId);
|
||||
|
||||
// Sanity check.
|
||||
expect(objectStore.fields, isNotEmpty);
|
||||
|
||||
// Checking Closures.
|
||||
final entry = objectStore.fields.keys.singleWhere(
|
||||
(e) => e == 'closure_functions_',
|
||||
);
|
||||
expect(entry, isNotNull);
|
||||
final value = objectStore.fields[entry]! as InstanceRef;
|
||||
expect(value.kind, InstanceKind.kList);
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTestsSynchronous(
|
||||
args,
|
||||
tests,
|
||||
'get_object_store_rpc_test.dart',
|
||||
testeeBefore: testeeMain,
|
||||
);
|
61
pkg/vm_service/test/private_rpcs/get_ports_rpc_test.dart
Normal file
61
pkg/vm_service/test/private_rpcs/get_ports_rpc_test.dart
Normal file
|
@ -0,0 +1,61 @@
|
|||
// 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:isolate' hide Isolate;
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../common/test_helper.dart';
|
||||
|
||||
late final RawReceivePort port1;
|
||||
late final RawReceivePort port2;
|
||||
|
||||
void warmup() {
|
||||
port1 = RawReceivePort(null);
|
||||
port2 = RawReceivePort((_) {});
|
||||
}
|
||||
|
||||
int countHandlerMatches(
|
||||
List<Map<String, dynamic>> ports,
|
||||
bool Function(InstanceRef) matcher,
|
||||
) {
|
||||
int matches = 0;
|
||||
for (final port in ports) {
|
||||
if (matcher(InstanceRef.parse(port['handler'])!)) {
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool nullMatcher(InstanceRef handler) {
|
||||
return handler.kind == InstanceKind.kNull;
|
||||
}
|
||||
|
||||
bool closureMatcher(InstanceRef handler) {
|
||||
return handler.kind == InstanceKind.kClosure;
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final result =
|
||||
(await service.callMethod('_getPorts', isolateId: isolateId)).json!;
|
||||
expect(result['type'], equals('_Ports'));
|
||||
expect(result['ports'], isList);
|
||||
final ports = result['ports'].cast<Map<String, dynamic>>();
|
||||
// There are at least two ports: the two created in warm up. Some OSes
|
||||
// will have other ports open but we do not try and test for these.
|
||||
expect(ports.length, greaterThanOrEqualTo(2));
|
||||
expect(countHandlerMatches(ports, nullMatcher), greaterThanOrEqualTo(1));
|
||||
expect(countHandlerMatches(ports, closureMatcher), greaterThanOrEqualTo(1));
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_ports_rpc_test.dart',
|
||||
testeeBefore: warmup,
|
||||
);
|
104
pkg/vm_service/test/private_rpcs/get_retained_size_rpc_test.dart
Normal file
104
pkg/vm_service/test/private_rpcs/get_retained_size_rpc_test.dart
Normal file
|
@ -0,0 +1,104 @@
|
|||
// 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:typed_data';
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../common/test_helper.dart';
|
||||
|
||||
const MB = 1 << 20;
|
||||
|
||||
class _TestClass {
|
||||
_TestClass(this.x, this.y);
|
||||
// Make sure these fields are not removed by the tree shaker.
|
||||
@pragma("vm:entry-point")
|
||||
var x;
|
||||
@pragma("vm:entry-point")
|
||||
var y;
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
var myVar;
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
invoke1() => myVar = new _TestClass(null, null);
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
invoke2() => myVar = new _TestClass(new _TestClass(null, null), null);
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
invoke3() => myVar = new _TestClass(new WeakReference(new Uint8List(MB)), null);
|
||||
|
||||
extension on VmService {
|
||||
Future<InstanceRef> getRetainedSize(
|
||||
String isolateId,
|
||||
String targetId,
|
||||
) async {
|
||||
return await callMethod('_getRetainedSize', isolateId: isolateId, args: {
|
||||
'targetId': targetId,
|
||||
}) as InstanceRef;
|
||||
}
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
final isolateId = isolateRef.id!;
|
||||
final isolate = await service.getIsolate(isolateId);
|
||||
final rootLibId = isolate.rootLib!.id!;
|
||||
|
||||
// One instance of _TestClass retained.
|
||||
var evalResult = await service.invoke(
|
||||
isolateId,
|
||||
rootLibId,
|
||||
'invoke1',
|
||||
[],
|
||||
) as InstanceRef;
|
||||
var result = await service.getRetainedSize(isolateId, evalResult.id!);
|
||||
expect(result.kind, InstanceKind.kInt);
|
||||
final value1 = int.parse(result.valueAsString!);
|
||||
expect(value1, isPositive);
|
||||
|
||||
// Two instances of _TestClass retained.
|
||||
evalResult = await service.invoke(
|
||||
isolateId,
|
||||
rootLibId,
|
||||
'invoke2',
|
||||
[],
|
||||
) as InstanceRef;
|
||||
result = await service.getRetainedSize(isolateId, evalResult.id!);
|
||||
expect(result.kind, InstanceKind.kInt);
|
||||
final value2 = int.parse(result.valueAsString!);
|
||||
expect(value2, isPositive);
|
||||
|
||||
// Size has doubled.
|
||||
expect(value2, 2 * value1);
|
||||
|
||||
// Get the retained size for class _TestClass.
|
||||
result = await service.getRetainedSize(isolateId, evalResult.classRef!.id!);
|
||||
expect(result.kind, InstanceKind.kInt);
|
||||
final value3 = int.parse(result.valueAsString!);
|
||||
expect(value3, isPositive);
|
||||
expect(value3, value2);
|
||||
|
||||
// Target of WeakReference not retained.
|
||||
evalResult = await service.invoke(
|
||||
isolateId,
|
||||
rootLibId,
|
||||
'invoke3',
|
||||
[],
|
||||
) as InstanceRef;
|
||||
result = await service.getRetainedSize(isolateId, evalResult.id!);
|
||||
expect(result.kind, InstanceKind.kInt);
|
||||
final value4 = int.parse(result.valueAsString!);
|
||||
expect(value4, lessThan(MB));
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'get_retained_size_rpc_test.dart',
|
||||
);
|
Loading…
Reference in a new issue