mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:17:55 +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
|
// 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.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -7,9 +7,10 @@ import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io' as io;
|
import 'dart:io' as io;
|
||||||
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
import 'package:vm_service/vm_service.dart';
|
import 'package:vm_service/vm_service.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'common/expect.dart';
|
||||||
import 'common/test_helper.dart';
|
import 'common/test_helper.dart';
|
||||||
|
|
||||||
Future setupFiles() async {
|
Future setupFiles() async {
|
||||||
|
@ -56,10 +57,11 @@ Future setupFiles() async {
|
||||||
final utilFile = io.File(writeTemp);
|
final utilFile = io.File(writeTemp);
|
||||||
await utilFile.writeAsString('foobar');
|
await utilFile.writeAsString('foobar');
|
||||||
final readTemp = io.File(writeTemp);
|
final readTemp = io.File(writeTemp);
|
||||||
await readTemp.readAsString();
|
final result = await readTemp.readAsString();
|
||||||
|
Expect.equals(result, 'foobar');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
closeDown();
|
closeDown();
|
||||||
rethrow;
|
throw e;
|
||||||
}
|
}
|
||||||
final result = jsonEncode({'type': 'foobar'});
|
final result = jsonEncode({'type': 'foobar'});
|
||||||
return Future.value(ServiceExtensionResponse.result(result));
|
return Future.value(ServiceExtensionResponse.result(result));
|
||||||
|
@ -69,22 +71,19 @@ Future setupFiles() async {
|
||||||
registerExtension('ext.dart.io.setup', setup);
|
registerExtension('ext.dart.io.setup', setup);
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileTests = <IsolateTest>[
|
final tests = <IsolateTest>[
|
||||||
(VmService service, IsolateRef isolate) async {
|
(VmService service, IsolateRef isolateRef) async {
|
||||||
final isolateId = isolate.id!;
|
final isolateId = isolateRef.id!;
|
||||||
await service.callServiceExtension(
|
|
||||||
'ext.dart.io.setup',
|
|
||||||
isolateId: isolate.id,
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
|
await service.callServiceExtension('ext.dart.io.setup',
|
||||||
|
isolateId: isolateId);
|
||||||
final result = await service.getOpenFiles(isolateId);
|
final result = await service.getOpenFiles(isolateId);
|
||||||
expect(result, isA<OpenFileList>());
|
expect(result.files.length, 2);
|
||||||
expect(result.files.length, equals(2));
|
|
||||||
final writing = await service.getOpenFileById(
|
final writing = await service.getOpenFileById(
|
||||||
isolateId,
|
isolateId,
|
||||||
result.files[0].id,
|
result.files[0].id,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(writing.readBytes, 0);
|
expect(writing.readBytes, 0);
|
||||||
expect(writing.readCount, 0);
|
expect(writing.readCount, 0);
|
||||||
expect(writing.writeCount, 3);
|
expect(writing.writeCount, 3);
|
||||||
|
@ -96,6 +95,7 @@ var fileTests = <IsolateTest>[
|
||||||
isolateId,
|
isolateId,
|
||||||
result.files[1].id,
|
result.files[1].id,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(reading.readBytes, 5);
|
expect(reading.readBytes, 5);
|
||||||
expect(reading.readCount, 5);
|
expect(reading.readCount, 5);
|
||||||
expect(reading.writeCount, 0);
|
expect(reading.writeCount, 0);
|
||||||
|
@ -105,15 +105,15 @@ var fileTests = <IsolateTest>[
|
||||||
} finally {
|
} finally {
|
||||||
await service.callServiceExtension(
|
await service.callServiceExtension(
|
||||||
'ext.dart.io.cleanup',
|
'ext.dart.io.cleanup',
|
||||||
isolateId: isolate.id,
|
isolateId: isolateId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
main([args = const <String>[]]) async => runIsolateTests(
|
void main([args = const <String>[]]) => runIsolateTests(
|
||||||
args,
|
args,
|
||||||
fileTests,
|
tests,
|
||||||
'file_service_test.dart',
|
'file_service_test.dart',
|
||||||
testeeBefore: setupFiles,
|
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
|
// 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.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:vm_service/vm_service.dart';
|
import 'package:vm_service/vm_service.dart';
|
||||||
|
|
||||||
import 'common/test_helper.dart';
|
import '../common/test_helper.dart';
|
||||||
|
|
||||||
class Foo {}
|
class Foo {}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
import 'package:vm_service/vm_service.dart';
|
import 'package:vm_service/vm_service.dart';
|
||||||
|
|
||||||
import 'common/test_helper.dart';
|
import '../common/test_helper.dart';
|
||||||
import 'common/service_test_common.dart';
|
import '../common/service_test_common.dart';
|
||||||
|
|
||||||
const int LINE_A = 18;
|
const int LINE_A = 18;
|
||||||
const int LINE_B = 21;
|
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
|
// 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.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:vm_service/src/vm_service.dart';
|
import 'package:vm_service/src/vm_service.dart';
|
||||||
import 'common/test_helper.dart';
|
import '../common/test_helper.dart';
|
||||||
|
|
||||||
class EchoResponse extends Response {
|
class EchoResponse extends Response {
|
||||||
static EchoResponse? parse(Map<String, dynamic>? json) =>
|
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:test/test.dart';
|
||||||
import 'package:vm_service/vm_service.dart';
|
import 'package:vm_service/vm_service.dart';
|
||||||
|
|
||||||
import 'common/test_helper.dart';
|
import '../common/test_helper.dart';
|
||||||
|
|
||||||
Future<Response> getImplementationFields(
|
Future<Response> getImplementationFields(
|
||||||
VmService service, String isolateId, String objectId) async {
|
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