[ package:vm_service ] Port some more Observatory service tests

Work towards https://github.com/dart-lang/sdk/issues/45037

Change-Id: I487a680a295bf29850793128d03ee36f1fa9c13b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322740
Reviewed-by: Derek Xu <derekx@google.com>
This commit is contained in:
Ben Konyi 2023-08-25 18:55:15 +00:00
parent 3180218123
commit a7847270f5
6 changed files with 460 additions and 72 deletions

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.
// VMOptions=--verbose_debug
import 'dart:developer';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE_A = 15;
/* LINE_A */ void testFunction(bool flag) {
if (flag) {
print("Yes");
} else {
print("No");
}
}
void testMain() {
debugger();
testFunction(true);
testFunction(false);
print("Done");
}
final tests = <IsolateTest>[
hasStoppedAtBreakpoint,
// Add breakpoint
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final function = rootLib.functions!.singleWhere(
(f) => f.name == 'testFunction',
);
final bpt = await service.addBreakpointAtEntry(isolateId, function.id!);
print(bpt);
},
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
resumeIsolate,
];
void main(args) => runIsolateTests(
args,
tests,
'break_on_function_test.dart',
testeeConcurrent: testMain,
);

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 'package:vm_service/vm_service.dart';
import 'common/test_helper.dart';
import 'common/service_test_common.dart';
const int LINE_A = 18;
const int LINE_B = 21;
const int LINE_C = 24;
const String file = "breakpoint_gc_test.dart";
int foo() => 42;
testeeMain() {
foo(); // static call
dynamic list = [1, 2, 3];
list.clear(); // instance call
print(list);
dynamic local = list; // debug step check = runtime call
return local;
}
Future<void> forceGC(VmService service, IsolateRef isolateRef) async {
await service.callMethod(
"_collectAllGarbage",
isolateId: isolateRef.id!,
);
}
final tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(file, LINE_A), // at `foo()`
setBreakpointAtUriAndLine(file, LINE_B), // at `list.clear()`
setBreakpointAtUriAndLine(file, LINE_C), // at `local = list`
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
forceGC, // Should not crash
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_B),
forceGC, // Should not crash
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_C),
forceGC, // Should not crash
resumeIsolate,
];
void main(List<String> args) => runIsolateTestsSynchronous(
args,
tests,
file,
testeeConcurrent: testeeMain,
pause_on_start: true,
);

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.
// ignore_for_file: dead_code
import 'common/test_helper.dart';
import 'common/service_test_common.dart';
const int LINE_A = 17;
const int LINE_B = 20;
const int LINE_C = 22;
const int LINE_D = 24;
void testMain() {
bool foo = false;
if (foo) {} // LINE_A
const bar = false;
if (bar) {} // LINE_B
while (foo) {} // LINE_C
while (bar) {} // LINE_D
}
final tests = [
hasPausedAtStart,
setBreakpointAtLine(LINE_A),
setBreakpointAtLine(LINE_B),
setBreakpointAtLine(LINE_C),
setBreakpointAtLine(LINE_D),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_B),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_C),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_D),
resumeIsolate,
];
void main(List<String> args) => runIsolateTests(
args,
tests,
'breakpoint_on_simple_conditions_test.dart',
testeeConcurrent: testMain,
pause_on_start: true,
);

View file

@ -0,0 +1,70 @@
// 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 Foo {
Foo();
Foo.named();
}
class Generic<T> {
Generic();
}
@pragma('vm:entry-point')
Function getNamedConstructorTearoff() => Foo.named;
@pragma('vm:entry-point')
Function getDefaultConstructorTearoff() => Foo.new;
@pragma('vm:entry-point')
Function getGenericConstructorTearoff() => Generic<int>.new;
Future<void> invokeConstructorTearoff(
VmService service,
IsolateRef isolateRef,
String name,
String expectedType,
) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final tearoff =
await service.invoke(isolateId, rootLib.id!, name, []) as InstanceRef;
final result =
await service.invoke(isolateId, tearoff.id!, 'call', []) as InstanceRef;
expect(result.classRef!.name, expectedType);
}
final tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) => invokeConstructorTearoff(
service,
isolateRef,
'getNamedConstructorTearoff',
'Foo',
),
(VmService service, IsolateRef isolateRef) => invokeConstructorTearoff(
service,
isolateRef,
'getDefaultConstructorTearoff',
'Foo',
),
(VmService service, IsolateRef isolateRef) => invokeConstructorTearoff(
service,
isolateRef,
'getGenericConstructorTearoff',
'Generic',
),
];
void main(List<String> args) => runIsolateTests(
args,
tests,
'constructor_tear_off_test.dart',
);

View file

@ -1,9 +1,9 @@
// 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 'package:test/test.dart';
import 'common/test_helper.dart';
@ -55,95 +55,104 @@ void script() {
fullBlockWithChain = genFullBlockWithChain();
}
var tests = <IsolateTest>[
final tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final lib =
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final field = await service.getObject(
isolateId,
lib.variables!.singleWhere((v) => v.name == 'cleanBlock').id!,
) as Field;
final fieldRef =
rootLib.variables!.singleWhere((v) => v.name == 'cleanBlock');
final field = await service.getObject(isolateId, fieldRef.id!) as Field;
final block =
await service.getObject(isolateId, field.staticValue.id!) as Instance;
Instance block =
await service.getObject(isolateId, field.staticValue!.id!) as Instance;
expect(block.closureFunction, isNotNull);
expect(block.closureContext, isNull);
},
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final lib =
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final field = await service.getObject(
isolateId,
lib.variables!.singleWhere((v) => v.name == 'copyingBlock').id!,
) as Field;
Instance block =
await service.getObject(isolateId, field.staticValue!.id!) as Instance;
expect(block.closureContext, isNotNull);
expect(block.closureContext!.length, equals(1));
final ctxt = await service.getObject(isolateId, block.closureContext!.id!)
as Context;
expect(ctxt.variables!.single.value.kind, InstanceKind.kString);
expect(
ctxt.variables!.single.value.valueAsString,
'I could be copied into the block',
);
expect(ctxt.parent, isNull);
},
(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 field = await service.getObject(
isolateId,
lib.variables!.singleWhere((v) => v.name == 'fullBlock').id!,
) as Field;
Instance block =
await service.getObject(isolateId, field.staticValue!.id!) as Instance;
expect(block.closureContext, isNotNull);
expect(block.closureContext!.length, equals(1));
final ctxt = await service.getObject(isolateId, block.closureContext!.id!)
as Context;
expect(ctxt.variables!.single.value.kind, InstanceKind.kInt);
expect(ctxt.variables!.single.value.valueAsString, '43');
expect(ctxt.parent, isNull);
},
(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 field = await service.getObject(
isolateId,
lib.variables!.singleWhere((v) => v.name == 'fullBlockWithChain').id!,
) as Field;
final fieldRef =
rootLib.variables!.singleWhere((v) => v.name == 'copyingBlock');
final field = await service.getObject(isolateId, fieldRef.id!) as Field;
final block =
await service.getObject(isolateId, field.staticValue!.id!) as Instance;
await service.getObject(isolateId, field.staticValue.id!) as Instance;
expect(block.closureFunction, isNotNull);
expect(block.closureContext, isNotNull);
expect(block.closureContext!.length, equals(1));
final ctxt = await service.getObject(isolateId, block.closureContext!.id!)
as Context;
expect(ctxt.variables!.single.value.kind, InstanceKind.kInt);
expect(ctxt.variables!.single.value.valueAsString, '4201');
expect(ctxt.parent!.length, 1);
final outerCtxt =
await service.getObject(isolateId, ctxt.parent!.id!) as Context;
expect(outerCtxt.variables!.single.value.kind, InstanceKind.kInt);
expect(outerCtxt.variables!.single.value.valueAsString, '421');
final closureContext = block.closureContext!;
expect(closureContext.length, 1);
final ctxt =
await service.getObject(isolateId, closureContext.id!) as Context;
final value = ctxt.variables!.single.value as InstanceRef;
expect(value.kind, InstanceKind.kString);
expect(value.valueAsString, 'I could be copied into the block');
expect(ctxt.parent, isNull);
},
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final fieldRef =
rootLib.variables!.singleWhere((v) => v.name == 'fullBlock');
final field = await service.getObject(isolateId, fieldRef.id!) as Field;
final block =
await service.getObject(isolateId, field.staticValue.id!) as Instance;
expect(block.closureFunction, isNotNull);
expect(block.closureContext, isNotNull);
final closureContext = block.closureContext!;
expect(block.closureContext!.length, 1);
final ctxt =
await service.getObject(isolateId, closureContext.id!) as Context;
final value = ctxt.variables!.single.value as InstanceRef;
expect(value.kind, InstanceKind.kInt);
expect(value.valueAsString, '43');
expect(ctxt.parent, isNull);
},
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final fieldRef =
rootLib.variables!.singleWhere((v) => v.name == 'fullBlockWithChain');
final field = await service.getObject(isolateId, fieldRef.id!) as Field;
final block =
await service.getObject(isolateId, field.staticValue.id!) as Instance;
expect(block.closureFunction, isNotNull);
expect(block.closureContext, isNotNull);
final closureContext = block.closureContext!;
expect(block.closureContext!.length, 1);
final ctxt =
await service.getObject(isolateId, closureContext.id!) as Context;
final value = ctxt.variables!.single.value as InstanceRef;
expect(value.kind, InstanceKind.kInt);
expect(value.valueAsString, '4201');
final parent = ctxt.parent!;
expect(parent.length, 1);
final outerCtxt = await service.getObject(isolateId, parent.id!) as Context;
final outerValue = outerCtxt.variables!.single.value as InstanceRef;
expect(outerValue.kind, InstanceKind.kInt);
expect(outerValue.valueAsString, '421');
expect(outerCtxt.parent, isNull);
},
];
main(args) => runIsolateTests(
void main(List<String> args) => runIsolateTests(
args,
tests,
'contexts_test.dart',

View file

@ -0,0 +1,132 @@
// 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';
String leafFunction(void Function() f) {
f();
return "some constant";
}
void testFunction() {
debugger();
leafFunction(() {});
debugger();
}
bool allRangesCompiled(coverage) {
for (int i = 0; i < coverage['ranges'].length; i++) {
if (!coverage['ranges'][i]['compiled']) {
return false;
}
}
return true;
}
final tests = <IsolateTest>[
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final stack = await service.getStack(isolateId);
// Make sure we are in the right place.
final frames = stack.frames!;
expect(frames.length, greaterThanOrEqualTo(1));
expect(frames[0].function!.name, 'testFunction');
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final funcRef =
rootLib.functions!.singleWhere((f) => f.name == 'leafFunction');
final func = await service.getObject(isolateId, funcRef.id!) as Func;
final expectedRange = {
'scriptIndex': 0,
'startPos': 399,
'endPos': 473,
'compiled': true,
'coverage': {
'hits': [],
'misses': [399, 443]
}
};
final location = func.location!;
final report = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
scriptId: location.script!.id!,
tokenPos: location.tokenPos,
endTokenPos: location.endTokenPos,
forceCompile: true,
);
final ranges = report.ranges!;
final scripts = report.scripts!;
expect(ranges.length, 1);
expect(ranges[0].toJson(), expectedRange);
expect(scripts.length, 1);
expect(scripts[0].uri, endsWith('coverage_closure_call_test.dart'));
},
resumeIsolate,
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
final stack = await service.getStack(isolateId);
// Make sure we are in the right place.
final frames = stack.frames!;
expect(frames.length, greaterThanOrEqualTo(1));
expect(frames[0].function!.name, 'testFunction');
final rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final funcRef =
rootLib.functions!.singleWhere((f) => f.name == 'leafFunction');
final func = await service.getObject(isolateId, funcRef.id!) as Func;
final expectedRange = {
'scriptIndex': 0,
'startPos': 399,
'endPos': 473,
'compiled': true,
'coverage': {
'hits': [399, 443],
'misses': []
}
};
final location = func.location!;
final report = await service.getSourceReport(
isolateId,
[SourceReportKind.kCoverage],
scriptId: location.script!.id!,
tokenPos: location.tokenPos,
endTokenPos: location.endTokenPos,
forceCompile: true,
);
final ranges = report.ranges!;
final scripts = report.scripts!;
expect(ranges.length, 1);
expect(ranges[0].toJson(), expectedRange);
expect(scripts.length, 1);
expect(scripts[0].uri, endsWith('coverage_closure_call_test.dart'));
},
];
void main(List<String> args) => runIsolateTests(
args,
tests,
'coverage_closure_call_test.dart',
testeeConcurrent: testFunction,
);