[ 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:
Ben Konyi 2023-10-31 19:49:42 +00:00 committed by Commit Queue
parent b44987450e
commit 94f8809607
34 changed files with 2066 additions and 24 deletions

View 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;

View 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,
);

View file

@ -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,
);

View 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,
);

View file

@ -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',
);

View file

@ -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',
);

View 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',
);

View 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,
);

View file

@ -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,
);

View 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,
);

View 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,
);

View 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',
);

View 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,
);

View 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',
);

View file

@ -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');
}

View 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,
);

View 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,
);

View 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');
}
}

View 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.
import 'get_source_report_with_mixin_lib1.dart';
class Test1 with A {}

View 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.
import 'get_source_report_with_mixin_lib1.dart';
class Test2 with B {}

View 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,
);

View 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,
);

View 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,
);

View file

@ -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,
);

View 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',
);

View 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',
);

View file

@ -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 {}

View file

@ -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;

View file

@ -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) =>

View 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',
);

View file

@ -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 {

View file

@ -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,
);

View 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,
);

View 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',
);