[ package:vm_service ] Migrate Observatory service tests to package:vm_service (Pt 1)

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

TEST=pkg/vm_service/test/*

Change-Id: I20bfc03ae40bc41ee4d965a71f090ecf974e4e59
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/185522
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
Ben Konyi 2021-11-05 17:04:07 +00:00 committed by commit-bot@chromium.org
parent 9b7caf3b93
commit 76a74ba678
31 changed files with 1559 additions and 2 deletions

View file

@ -709,6 +709,11 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.12" "languageVersion": "2.12"
}, },
{
"name": "test_package",
"rootUri": "../pkg/vm_service/test/test_package",
"languageVersion": "2.12"
},
{ {
"name": "test_process", "name": "test_process",
"rootUri": "../third_party/pkg/test_process", "rootUri": "../third_party/pkg/test_process",

View file

@ -105,6 +105,7 @@ test:third_party/pkg/test/pkgs/test/lib
test_api:third_party/pkg/test/pkgs/test_api/lib test_api:third_party/pkg/test/pkgs/test_api/lib
test_core:third_party/pkg/test/pkgs/test_core/lib test_core:third_party/pkg/test/pkgs/test_core/lib
test_descriptor:third_party/pkg/test_descriptor/lib test_descriptor:third_party/pkg/test_descriptor/lib
test_package:pkg/vm_service/test/test_package
test_process:third_party/pkg/test_process/lib test_process:third_party/pkg/test_process/lib
test_reflective_loader:third_party/pkg/test_reflective_loader/lib test_reflective_loader:third_party/pkg/test_reflective_loader/lib
test_runner:pkg/test_runner/lib test_runner:pkg/test_runner/lib

View file

@ -21,3 +21,5 @@ dev_dependencies:
process: ^4.0.0 process: ^4.0.0
pub_semver: ^2.0.0-nullsafety.0 pub_semver: ^2.0.0-nullsafety.0
test: ^1.16.0-nullsafety.13 test: ^1.16.0-nullsafety.13
test_package:
path: 'test/test_package'

View file

@ -0,0 +1,178 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE_A = 24;
const int LINE_B = 26;
int value = 0;
int incValue(int amount) {
value += amount;
return amount;
}
Future testMain() async {
incValue(incValue(1)); // line A.
incValue(incValue(1)); // line B.
}
var tests = <IsolateTest>[
hasPausedAtStart,
// Test future breakpoints.
(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 rootLibId = rootLib.id!;
final scriptId = rootLib.scripts![0].id!;
final script = await service.getObject(isolateId, scriptId) as Script;
// Future breakpoint.
var futureBpt1 = await service.addBreakpoint(isolateId, scriptId, LINE_A);
expect(futureBpt1.breakpointNumber, 1);
expect(futureBpt1.resolved, isFalse);
expect(await futureBpt1.location!.line!, LINE_A);
expect(await futureBpt1.location!.column, null);
// Future breakpoint with specific column.
var futureBpt2 =
await service.addBreakpoint(isolateId, scriptId, LINE_A, column: 3);
expect(futureBpt2.breakpointNumber, 2);
expect(futureBpt2.resolved, isFalse);
expect(await futureBpt2.location!.line!, LINE_A);
expect(await futureBpt2.location!.column!, 3);
int resolvedCount = await resumeAndCountResolvedBreakpointsUntilPause(
service,
isolate,
);
// After resolution the breakpoints have assigned line & column.
expect(resolvedCount, 2);
// Refresh objects
futureBpt1 =
await service.getObject(isolateId, futureBpt1.id!) as Breakpoint;
futureBpt2 =
await service.getObject(isolateId, futureBpt2.id!) as Breakpoint;
expect(futureBpt1.resolved, isTrue);
expect(script.getLineNumberFromTokenPos(futureBpt1.location!.tokenPos!),
LINE_A);
expect(
script.getColumnNumberFromTokenPos(futureBpt1.location!.tokenPos!), 12);
expect(futureBpt2.resolved, isTrue);
expect(script.getLineNumberFromTokenPos(futureBpt2.location!.tokenPos!),
LINE_A);
expect(
script.getColumnNumberFromTokenPos(futureBpt2.location!.tokenPos!), 3);
// The first breakpoint hits before value is modified.
InstanceRef result =
await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
expect(result.valueAsString, '0');
await service.resume(isolateId);
await hasStoppedAtBreakpoint(service, isolate);
// The second breakpoint hits after value has been modified once.
result =
await service.evaluate(isolateId, rootLibId, 'value') as InstanceRef;
expect(result.valueAsString, '1');
// Remove the breakpoints.
expect((await service.removeBreakpoint(isolateId, futureBpt1.id!)).type,
'Success');
expect((await service.removeBreakpoint(isolateId, futureBpt2.id!)).type,
'Success');
},
// Test resolution of column breakpoints.
(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;
final scriptId = rootLib.scripts![0].id!;
final script = await service.getObject(isolateId, scriptId) as Script;
// Try all columns, including some columns that are too big.
for (int col = 1; col <= 50; col++) {
final bpt =
await service.addBreakpoint(isolateId, scriptId, LINE_A, column: col);
expect(bpt.resolved, isTrue);
int resolvedLine =
script.getLineNumberFromTokenPos(bpt.location!.tokenPos!)!;
int resolvedCol =
script.getColumnNumberFromTokenPos(bpt.location!.tokenPos!)!;
print('$LINE_A:${col} -> ${resolvedLine}:${resolvedCol}');
if (col <= 12) {
expect(resolvedLine, LINE_A);
expect(resolvedCol, 3);
} else if (col <= 36) {
expect(resolvedLine, LINE_A);
expect(resolvedCol, 12);
} else {
expect(resolvedLine, LINE_B);
expect(resolvedCol, 12);
}
expect(
(await service.removeBreakpoint(isolateId, bpt.id!)).type, 'Success');
}
// Make sure that a zero column is an error.
var caughtException = false;
try {
await service.addBreakpoint(isolateId, scriptId, 20, column: 0);
expect(false, isTrue, reason: 'Unreachable');
} on RPCError catch (e) {
caughtException = true;
expect(e.code, RPCError.kInvalidParams);
expect(e.details, "addBreakpoint: invalid 'column' parameter: 0");
}
expect(caughtException, isTrue);
},
];
Future<int> resumeAndCountResolvedBreakpointsUntilPause(
VmService service, Isolate isolate) async {
final completer = Completer<void>();
late StreamSubscription subscription;
int resolvedCount = 0;
subscription = service.onDebugEvent.listen((event) {
if (event.kind == EventKind.kBreakpointResolved) {
resolvedCount++;
} else if (event.kind == EventKind.kPauseBreakpoint) {
subscription.cancel();
service.streamCancel(EventStreams.kDebug);
completer.complete();
}
});
await service.streamListen(EventStreams.kDebug);
await service.resume(isolate.id!);
await completer.future;
return resolvedCount;
}
main(args) => runIsolateTests(
args,
tests,
'add_breakpoint_rpc_kernel_test.dart',
testeeConcurrent: testMain,
pause_on_start: true,
);

View file

@ -0,0 +1,43 @@
// Copyright (c) 2014, 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';
class Foo {}
// Prevent TFA from removing this static field to ensure the objects are kept
// alive, so the allocation stats will report them via the service api.
@pragma('vm:entry-point')
List<Foo>? foos;
void script() {
foos = [
Foo(),
Foo(),
Foo(),
];
}
var tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) async {
var profile = await service.callMethod('_getAllocationProfile',
isolateId: isolateRef.id!) as AllocationProfile;
print(profile.runtimeType);
var classHeapStats = profile.members!.singleWhere((stats) {
return stats.classRef!.name == 'Foo';
});
expect(classHeapStats.instancesCurrent, 3);
expect(classHeapStats.instancesAccumulated, 3);
},
];
main(args) => runIsolateTests(
args,
tests,
'allocations_test.dart',
testeeBefore: script,
);

View file

@ -0,0 +1,59 @@
// Copyright (c) 2018, 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 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE_A = 24;
const int LINE_B = 25;
const int LINE_C = 26;
foo() async {}
doAsync(stop) async {
// Flutter issue 18877:
// If a closure is defined in the context of an async method, stepping over
// an await causes the implicit breakpoint to be set for that closure instead
// of the async_op, resulting in the debugger falling through.
final baz = () => print('doAsync($stop) done!');
if (stop) debugger();
await foo(); // Line A.
await foo(); // Line B.
await foo(); // Line C.
baz();
return null;
}
testMain() {
// With two runs of doAsync floating around, async step should only cause
// us to stop in the run we started in.
doAsync(false);
doAsync(true);
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
stepOver, // foo()
stoppedAtLine(LINE_A),
asyncNext,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_B),
stepOver, // foo()
stoppedAtLine(LINE_B),
asyncNext,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_C),
resumeIsolate,
];
main(args) => runIsolateTests(
args,
tests,
'async_next_regression_18877_test.dart',
testeeConcurrent: testMain,
);

View file

@ -0,0 +1,64 @@
// Copyright (c) 2018, 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=--async-debugger --verbose-debug --lazy-async-stacks
import 'dart:developer';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const LINE_A = 28;
const LINE_B = 34;
const LINE_C = 38;
notCalled() async {
await null;
await null;
await null;
await null;
}
foobar() async {
await null;
debugger();
print('foobar'); // LINE_A.
}
helper() async {
await null;
print('helper');
await foobar(); // LINE_B.
}
testMain() async {
helper(); // LINE_C.
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
(VmService service, IsolateRef isolate) async {
final isolateId = isolate.id!;
// Verify awaiter stack trace is the current frame + the awaiter.
Stack stack = await service.getStack(isolateId);
expect(stack.awaiterFrames, isNotNull);
List<Frame> awaiterFrames = stack.awaiterFrames!;
expect(awaiterFrames.length, greaterThanOrEqualTo(2));
// Awaiter frame.
expect(awaiterFrames[0].function!.owner.name, 'foobar');
// Awaiter frame.
expect(awaiterFrames[1].function!.owner.name, 'helper');
},
];
main(args) => runIsolateTestsSynchronous(
args,
tests,
'awaiter_async_stack_contents_2_test.dart',
testeeConcurrent: testMain,
extraArgs: extraDebuggingArgs,
);

View file

@ -0,0 +1,72 @@
// Copyright (c) 2017, 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=--async-debugger --verbose-debug --lazy-async-stacks
import 'dart:developer';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const LINE_C = 22;
const LINE_A = 28;
const LINE_B = 34;
const LINE_D = 29;
foobar() async {
await null;
debugger();
print('foobar'); // LINE_C.
}
helper() async {
await null;
debugger();
print('helper'); // LINE_A.
await foobar(); // LINE_D
}
testMain() {
debugger();
helper(); // LINE_B.
}
var tests = <IsolateTest>[
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_B),
(VmService service, IsolateRef isolateRef) async {
Stack stack = await service.getStack(isolateRef.id!);
// No awaiter frames because we are in a completely synchronous stack.
expect(stack.awaiterFrames, isNull);
},
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_C),
(VmService service, IsolateRef isolateRef) async {
// Verify awaiter stack trace is the current frame + the awaiter.
Stack stack = await service.getStack(isolateRef.id!);
expect(stack.awaiterFrames, isNotNull);
List<Frame> awaiterFrames = stack.awaiterFrames!;
expect(awaiterFrames.length, greaterThanOrEqualTo(2));
// Awaiter frame.
expect(await awaiterFrames[0].function!.owner.name, 'foobar');
// Awaiter frame.
expect(await awaiterFrames[1].function!.owner.name, 'helper');
// "helper" is not await'ed.
},
];
main(args) => runIsolateTestsSynchronous(
args,
tests,
'awaiter_async_stack_contents_test.dart',
testeeConcurrent: testMain,
extraArgs: extraDebuggingArgs,
);

View file

@ -0,0 +1,79 @@
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE = 18;
// Issue: https://github.com/dart-lang/sdk/issues/36622
Future<void> testMain() async {
for (int i = 0; i < 2; i++) {
if (i > 0) {
break; // breakpoint here
}
await Future.delayed(Duration(seconds: 1));
}
}
var tests = <IsolateTest>[
hasPausedAtStart,
// Test future breakpoints.
(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 scriptId = rootLib.scripts![0].id!;
final script = await service.getObject(isolateId, scriptId) as Script;
// Future breakpoint.
var futureBpt = await service.addBreakpoint(isolateId, scriptId, LINE);
expect(futureBpt.breakpointNumber, 1);
expect(futureBpt.resolved, isFalse);
expect(await futureBpt.location!.line, LINE);
expect(await futureBpt.location!.column, null);
final completer = Completer<void>();
int resolvedCount = 0;
late StreamSubscription subscription;
subscription = service.onDebugEvent.listen((event) {
if (event.kind == EventKind.kBreakpointResolved) {
resolvedCount++;
} else if (event.kind == EventKind.kPauseBreakpoint) {
subscription.cancel();
service.streamCancel(EventStreams.kDebug);
completer.complete();
}
});
await service.streamListen(EventStreams.kDebug);
await service.resume(isolateId);
await hasStoppedAtBreakpoint(service, isolate);
// After resolution the breakpoints have assigned line & column.
expect(resolvedCount, 1);
futureBpt = await service.getObject(isolateId, futureBpt.id!) as Breakpoint;
expect(futureBpt.resolved, isTrue);
expect(
script.getLineNumberFromTokenPos(futureBpt.location!.tokenPos), LINE);
expect(script.getColumnNumberFromTokenPos(futureBpt.location!.tokenPos), 7);
// Remove the breakpoints.
expect((await service.removeBreakpoint(isolateId, futureBpt.id!)).type,
'Success');
},
];
main(args) => runIsolateTests(
args,
tests,
'breakpoint_async_break_test.dart',
testeeConcurrent: testMain,
pause_on_start: true,
);

View file

@ -0,0 +1,48 @@
// Copyright (c) 2019, 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:io' show Platform;
import 'package:path/path.dart' as path;
import 'package:test_package/has_part.dart' as has_part;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
// Chop off the file name.
String baseDirectory = path.dirname(Platform.script.path) + '/';
Uri baseUri = Platform.script.replace(path: baseDirectory);
Uri breakpointFile = baseUri.resolve('test_package/the_part.dart');
const String shortFile = "the_part.dart";
const int LINE = 87;
code() {
has_part.main();
}
List<String> stops = [];
List<String> expected = [
"$shortFile:${LINE + 0}:5", // on 'print'
"$shortFile:${LINE + 1}:3" // on class ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(breakpointFile.toString(), LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main([args = const <String>[]]) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_in_package_parts_class_file_uri_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2019, 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 breakpoint_in_parts_class;
import 'package:test_package/has_part.dart' as has_part;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE = 87;
const String breakpointFile = "package:test_package/the_part.dart";
const String shortFile = "the_part.dart";
code() {
has_part.main();
}
List<String> stops = [];
List<String> expected = [
"$shortFile:${LINE + 0}:5", // on 'print'
"$shortFile:${LINE + 1}:3" // on class ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(breakpointFile, LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_in_package_parts_class_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,91 @@
// Copyright (c) 2017, 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 breakpoint_in_parts_class;
void foo() {
print("lalala");
}
class Foo1 {
final foo;
Foo1(this.foo) {
print("hello from foo!");
}
}
class Foo2 {
final foo;
Foo2(this.foo) {
print("hello from foo!");
}
}
class Foo3 {
final foo;
Foo3(this.foo) {
print("hello from foo!");
}
}
class Foo4 {
final foo;
Foo4(this.foo) {
print("hello from foo!");
}
}
class Foo5 {
final foo;
Foo5(this.foo) {
print("hello from foo!");
}
}
class Foo6 {
final foo;
Foo6(this.foo) {
print("hello from foo!");
}
}
class Foo7 {
final foo;
Foo7(this.foo) {
print("hello from foo!");
}
}
class Foo8 {
final foo;
Foo8(this.foo) {
print("hello from foo!");
}
}
class Foo9 {
final foo;
Foo9(this.foo) {
print("hello from foo!");
}
}
class Foo10 {
final foo;
Foo10(this.foo) {
print("hello from foo!");
}
}
var foo2 = foo() as dynamic;

View file

@ -0,0 +1,43 @@
// Copyright (c) 2017, 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 breakpoint_in_parts_class;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
part 'breakpoint_in_parts_class_part.dart';
const int LINE = 87;
const String file = "breakpoint_in_parts_class_part.dart";
code() {
final foo = Foo10("Foo!");
print(foo);
}
List<String> stops = [];
List<String> expected = [
"$file:${LINE + 0}:5", // on 'print'
"$file:${LINE + 1}:3" // on class ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(file, LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_in_parts_class_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,83 @@
// Copyright (c) 2019, 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:test_package/has_part.dart' as test_pkg;
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const String file = 'package:test_package/has_part.dart';
// print() within fooz()
const int LINE_A = 15;
// print() within barz()
const int LINE_B = 11;
testMain() {
test_pkg.fooz();
}
var tests = <IsolateTest>[
hasPausedAtStart,
(VmService service, IsolateRef isolateRef) async {
// Mark 'package:observatory_test_package/has_part.dart' as not debuggable.
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
LibraryRef has_part_ref = isolate.libraries!.firstWhere(
(LibraryRef library) => library.uri == file,
);
Library has_part =
await service.getObject(isolateId, has_part_ref.id!) as Library;
expect(has_part.debuggable, true);
// SetBreakpoint before setting library to non-debuggable.
// Breakpoints are allowed to be set (before marking library as
// non-debuggable) but are not hit when running (after marking library
// as non-debuggable).
ScriptRef script = has_part.scripts!.firstWhere(
(ScriptRef script) => script.uri == file,
);
Breakpoint bpt = await service.addBreakpoint(isolateId, script.id!, LINE_A);
print("Breakpoint is $bpt");
expect(bpt, isNotNull);
// Set breakpoint and check later that this breakpoint won't be added if
// the library is non-debuggable.
bpt = await service.addBreakpoint(isolateId, script.id!, LINE_B);
print("Breakpoint is $bpt");
expect(bpt, isNotNull);
// Remove breakpoint.
final res = await service.removeBreakpoint(isolateId, bpt.id!);
expect(res.type, 'Success');
await service.setLibraryDebuggable(isolateId, has_part.id!, false);
has_part = await service.getObject(isolateId, has_part.id!) as Library;
expect(has_part.debuggable, false);
print('$has_part is debuggable: ${has_part.debuggable}');
// Breakpoints are not allowed to set on non-debuggable libraries.
try {
await service.addBreakpoint(isolateId, script.id!, LINE_B);
} on RPCError catch (e) {
// Cannot add breakpoint error code
expect(e.code, 102);
expect(e.details, contains("Cannot add breakpoint at line '11'"));
print("Set Breakpoint to non-debuggable library is not allowed");
}
},
resumeIsolate,
hasStoppedAtExit,
];
main(args) => runIsolateTests(
args,
tests,
'breakpoint_non_debuggable_library_test.dart',
testeeConcurrent: testMain,
pause_on_start: true,
pause_on_exit: true,
);

View file

@ -0,0 +1,56 @@
// Copyright (c) 2019, 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 breakpoint_in_parts_class;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE = 18;
const String file = "breakpoint_on_if_null_1_test.dart";
code() {
foo(42);
}
foo(dynamic args) {
if (args == null) {
print("was null");
}
if (args != null) {
print("was not null");
}
if (args == 42) {
print("was 42!");
}
}
List<String> stops = [];
List<String> expected = [
"$file:${LINE + 0}:12", // on '=='
"$file:${LINE + 3}:12", // on '!='
"$file:${LINE + 4}:5", // on 'print'
"$file:${LINE + 6}:12", // on '=='
"$file:${LINE + 7}:5", // on 'print'
"$file:${LINE + 9}:1", // on ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(file, LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_on_if_null_1_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,59 @@
// Copyright (c) 2019, 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 breakpoint_in_parts_class;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE = 21;
const String file = "breakpoint_on_if_null_2_test.dart";
dynamic compareWithMe = 43;
code() {
compareWithMe = null;
foo(42);
}
foo(dynamic args) {
if (args == compareWithMe) {
print("was null");
}
if (args != compareWithMe) {
print("was not null");
}
if (args == 42) {
print("was 42!");
}
}
List<String> stops = [];
List<String> expected = [
"$file:${LINE + 0}:12", // on '=='
"$file:${LINE + 3}:12", // on '!='
"$file:${LINE + 4}:5", // on 'print'
"$file:${LINE + 6}:12", // on '=='
"$file:${LINE + 7}:5", // on 'print'
"$file:${LINE + 9}:1", // on ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(file, LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_on_if_null_2_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,57 @@
// Copyright (c) 2019, 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 breakpoint_in_parts_class;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE = 17;
const String file = "breakpoint_on_if_null_3_test.dart";
code() {
foo(42);
}
foo(dynamic args) {
if (args == null) {
print("was null");
}
if (args != null) {
print("was not null");
}
if (args == 42) {
print("was 42!");
}
}
List<String> stops = [];
List<String> expected = [
"$file:${LINE + 0}:13", // on 'args'
"$file:${LINE + 1}:12", // on '=='
"$file:${LINE + 4}:12", // on '!='
"$file:${LINE + 5}:5", // on 'print'
"$file:${LINE + 7}:12", // on '=='
"$file:${LINE + 8}:5", // on 'print'
"$file:${LINE + 10}:1", // on ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(file, LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_on_if_null_3_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,60 @@
// Copyright (c) 2019, 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 breakpoint_in_parts_class;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE = 20;
const String file = "breakpoint_on_if_null_4_test.dart";
dynamic compareWithMe = 43;
code() {
compareWithMe = null;
foo(42);
}
foo(dynamic args) {
if (args == compareWithMe) {
print("was null");
}
if (args != compareWithMe) {
print("was not null");
}
if (args == 42) {
print("was 42!");
}
}
List<String> stops = [];
List<String> expected = [
"$file:${LINE + 0}:13", // on 'args'
"$file:${LINE + 1}:12", // on '=='
"$file:${LINE + 4}:12", // on '!='
"$file:${LINE + 5}:5", // on 'print'
"$file:${LINE + 7}:12", // on '=='
"$file:${LINE + 8}:5", // on 'print'
"$file:${LINE + 10}:1", // on ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(file, LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_on_if_null_4_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2019, 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 breakpoint_in_parts_class;
import 'package:test_package/has_part.dart' as has_part;
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE = 8;
const String breakpointFile = "package:test_package/the_part_2.dart";
const String shortFile = "the_part_2.dart";
code() {
has_part.bar();
}
List<String> stops = [];
List<String> expected = [
"$shortFile:${LINE + 0}:3", // on 'print'
"$shortFile:${LINE + 1}:1" // on class ending '}'
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(breakpointFile, LINE),
runStepThroughProgramRecordingStops(stops),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoint_partfile_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -0,0 +1,87 @@
// Copyright (c) 2016, 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
// TODO(bkonyi): consider deleting now that DBC is no more.
// This test was mostly interesting for DBC, which needed to patch two bytecodes
// to create a breakpoint for fast Smi ops.
import 'dart:developer';
import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const int LINE_A = 29;
const int LINE_B = 30;
const int LINE_C = 31;
class NotGeneric {}
testeeMain() {
final x = List<dynamic>.filled(1, null);
final y = 7;
debugger();
print("Statement");
x[0] = 3; // Line A.
x is NotGeneric; // Line B.
y & 4; // Line C.
}
final tests = <IsolateTest>[
hasStoppedAtBreakpoint,
// Add breakpoints.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final isolate = await service.getIsolate(isolateId);
Library rootLib =
await service.getObject(isolateId, isolate.rootLib!.id!) as Library;
final script =
await service.getObject(isolateId, rootLib.scripts![0].id!) as Script;
final scriptId = script.id!;
final bpt1 = await service.addBreakpoint(isolateId, scriptId, LINE_A);
print(bpt1);
expect(bpt1.resolved, isTrue);
expect(script.getLineNumberFromTokenPos(bpt1.location!.tokenPos),
equals(LINE_A));
final bpt2 = await service.addBreakpoint(isolateId, scriptId, LINE_B);
print(bpt2);
expect(bpt2.resolved, isTrue);
expect(script.getLineNumberFromTokenPos(bpt2.location!.tokenPos),
equals(LINE_B));
final bpt3 = await service.addBreakpoint(isolateId, scriptId, LINE_C);
print(bpt3);
expect(bpt3.resolved, isTrue);
expect(script.getLineNumberFromTokenPos(bpt3.location!.tokenPos),
equals(LINE_C));
},
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_B),
resumeIsolate,
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_C),
resumeIsolate,
];
main(args) => runIsolateTests(
args,
tests,
'breakpoint_two_args_checked_test.dart',
testeeConcurrent: testeeMain,
);

View file

@ -0,0 +1,7 @@
// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib3.dart";
class Test1 extends Object with Foo {}

View file

@ -0,0 +1,7 @@
// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib3.dart";
class Test2 extends Object with Foo {}

View file

@ -0,0 +1,15 @@
// Copyright (c) 2020, 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.
class Foo {
foo() {
print("I should be breakable!");
}
}
class Bar {
bar() {
print("I should be breakable too!");
}
}

View file

@ -0,0 +1,62 @@
// Copyright (c) 2020, 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 "breakpoints_with_mixin_lib1.dart";
import "breakpoints_with_mixin_lib2.dart";
import "breakpoints_with_mixin_lib3.dart";
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
const String testFilename = "breakpoints_with_mixin_test.dart";
const int testCodeLineStart = 17;
const String lib3Filename = "breakpoints_with_mixin_lib3.dart";
const int lib3Bp1 = 7;
const int lib3Bp2 = 13;
void code() {
Test1 test1 = Test1();
test1.foo();
Test2 test2 = Test2();
test2.foo();
Foo foo = Foo();
foo.foo();
Bar bar = Bar();
bar.bar();
test1.foo();
test2.foo();
foo.foo();
bar.bar();
}
List<String> stops = [];
List<String> expected = [
"$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 2}:9)",
"$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 4}:9)",
"$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 6}:7)",
"$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 8}:7)",
"$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 9}:9)",
"$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 10}:9)",
"$lib3Filename:$lib3Bp1:5 ($testFilename:${testCodeLineStart + 11}:7)",
"$lib3Filename:$lib3Bp2:5 ($testFilename:${testCodeLineStart + 12}:7)",
];
var tests = <IsolateTest>[
hasPausedAtStart,
setBreakpointAtUriAndLine(lib3Filename, lib3Bp1),
setBreakpointAtUriAndLine(lib3Filename, lib3Bp2),
resumeProgramRecordingStops(stops, true),
checkRecordedStops(stops, expected)
];
main(args) {
runIsolateTestsSynchronous(
args,
tests,
'breakpoints_with_mixin_test.dart',
testeeConcurrent: code,
pause_on_start: true,
pause_on_exit: true,
);
}

View file

@ -6,6 +6,7 @@ library service_test_common;
import 'dart:async'; import 'dart:async';
import 'package:path/path.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service.dart';
@ -131,6 +132,16 @@ IsolateTest setBreakpointAtLine(int line) {
}; };
} }
IsolateTest setBreakpointAtUriAndLine(String uri, int line) {
return (VmService service, IsolateRef isolateRef) async {
print("Setting breakpoint for line $line in $uri");
Breakpoint bpt =
await service.addBreakpointWithScriptUri(isolateRef.id!, uri, line);
print("Breakpoint is $bpt");
expect(bpt, isNotNull);
};
}
IsolateTest stoppedAtLine(int line) { IsolateTest stoppedAtLine(int line) {
return (VmService service, IsolateRef isolateRef) async { return (VmService service, IsolateRef isolateRef) async {
print("Checking we are at line $line"); print("Checking we are at line $line");
@ -221,3 +232,154 @@ Future<void> stepOut(VmService service, IsolateRef isolateRef) async {
await hasStoppedAtBreakpoint(service, isolateRef); await hasStoppedAtBreakpoint(service, isolateRef);
await _unsubscribeDebugStream(service); await _unsubscribeDebugStream(service);
} }
IsolateTest resumeProgramRecordingStops(
List<String> recordStops, bool includeCaller) {
return (VmService service, IsolateRef isolateRef) async {
final completer = Completer<void>();
late StreamSubscription subscription;
subscription = service.onDebugEvent.listen((event) async {
if (event.kind == EventKind.kPauseBreakpoint) {
final stack = await service.getStack(isolateRef.id!);
final frames = stack.frames!;
expect(frames.length, greaterThanOrEqualTo(2));
String brokeAt =
await _locationToString(service, isolateRef, frames[0]);
if (includeCaller) {
brokeAt =
'$brokeAt (${await _locationToString(service, isolateRef, frames[1])})';
}
recordStops.add(brokeAt);
await service.resume(isolateRef.id!);
} else if (event.kind == EventKind.kPauseExit) {
await subscription.cancel();
await service.streamCancel(EventStreams.kDebug);
completer.complete();
}
});
await service.streamListen(EventStreams.kDebug);
await service.resume(isolateRef.id!);
return completer.future;
};
}
Future<String> _locationToString(
VmService service,
IsolateRef isolateRef,
Frame frame,
) async {
final location = frame.location!;
Script script =
await service.getObject(isolateRef.id!, location.script!.id!) as Script;
final scriptName = basename(script.uri!);
final tokenPos = location.tokenPos!;
final line = script.getLineNumberFromTokenPos(tokenPos);
final column = script.getColumnNumberFromTokenPos(tokenPos);
return '$scriptName:$line:$column';
}
IsolateTest runStepThroughProgramRecordingStops(List<String> recordStops) {
return (VmService service, IsolateRef isolateRef) async {
final completer = Completer<void>();
late StreamSubscription subscription;
subscription = service.onDebugEvent.listen((event) async {
if (event.kind == EventKind.kPauseBreakpoint) {
final isolate = await service.getIsolate(isolateRef.id!);
final frame = isolate.pauseEvent!.topFrame!;
recordStops.add(await _locationToString(service, isolateRef, frame));
if (event.atAsyncSuspension ?? false) {
await service.resume(isolateRef.id!,
step: StepOption.kOverAsyncSuspension);
} else {
await service.resume(isolateRef.id!, step: StepOption.kOver);
}
} else if (event.kind == EventKind.kPauseExit) {
await subscription.cancel();
await service.streamCancel(EventStreams.kDebug);
completer.complete();
}
});
await service.streamListen(EventStreams.kDebug);
await service.resume(isolateRef.id!);
return completer.future;
};
}
IsolateTest checkRecordedStops(
List<String> recordStops, List<String> expectedStops,
{bool removeDuplicates = false,
bool debugPrint = false,
String? debugPrintFile,
int? debugPrintLine}) {
return (VmService service, IsolateRef isolate) async {
if (debugPrint) {
for (int i = 0; i < recordStops.length; i++) {
String line = recordStops[i];
String output = line;
int firstColon = line.indexOf(":");
int lastColon = line.lastIndexOf(":");
if (debugPrintFile != null &&
debugPrintLine != null &&
firstColon > 0 &&
lastColon > 0) {
int lineNumber = int.parse(line.substring(firstColon + 1, lastColon));
int relativeLineNumber = lineNumber - debugPrintLine;
var columnNumber = line.substring(lastColon + 1);
var file = line.substring(0, firstColon);
if (file == debugPrintFile) {
output = '\$file:\${LINE+$relativeLineNumber}:$columnNumber';
}
}
String comma = i == recordStops.length - 1 ? "" : ",";
print('"$output"$comma');
}
}
if (removeDuplicates) {
recordStops = removeAdjacentDuplicates(recordStops);
expectedStops = removeAdjacentDuplicates(expectedStops);
}
// Single stepping may record extra stops.
// Allow the extra ones as long as the expected ones are recorded.
int i = 0;
int j = 0;
while (i < recordStops.length && j < expectedStops.length) {
if (recordStops[i] != expectedStops[j]) {
// Check if recordStops[i] is an extra stop.
int k = i + 1;
while (k < recordStops.length && recordStops[k] != expectedStops[j]) {
k++;
}
if (k < recordStops.length) {
// Allow and ignore extra recorded stops from i to k-1.
i = k;
} else {
// This will report an error.
expect(recordStops[i], expectedStops[j]);
}
}
i++;
j++;
}
expect(recordStops.length >= expectedStops.length, true,
reason: "Expects at least ${expectedStops.length} breaks, "
"got ${recordStops.length}.");
};
}
List<String> removeAdjacentDuplicates(List<String> fromList) {
List<String> result = <String>[];
String? latestLine;
for (String s in fromList) {
if (s == latestLine) continue;
latestLine = s;
result.add(s);
}
return result;
}

View file

@ -277,6 +277,7 @@ class _ServiceTesterRunner {
vm = await vmServiceConnectUri(serviceWebsocketAddress); vm = await vmServiceConnectUri(serviceWebsocketAddress);
print('Done loading VM'); print('Done loading VM');
isolate = await getFirstIsolate(vm); isolate = await getFirstIsolate(vm);
print('Got first isolate');
}); });
}); });
@ -326,19 +327,24 @@ class _ServiceTesterRunner {
Completer<dynamic>? completer = Completer(); Completer<dynamic>? completer = Completer();
late StreamSubscription subscription; late StreamSubscription subscription;
subscription = service.onIsolateEvent.listen((Event event) async { subscription = service.onIsolateEvent.listen((Event event) async {
print('Isolate event: $event');
if (completer == null) { if (completer == null) {
await subscription.cancel(); await subscription.cancel();
return; return;
} }
if (event.kind == EventKind.kIsolateRunnable) { if (event.kind == EventKind.kIsolateRunnable) {
print(event.isolate!.name);
vm = await service.getVM(); vm = await service.getVM();
assert(vmIsolates.isNotEmpty); //assert(vmIsolates.isNotEmpty);
await subscription.cancel(); await subscription.cancel();
completer!.complete(vmIsolates.first); await service.streamCancel(EventStreams.kIsolate);
completer!.complete(event.isolate!);
completer = null; completer = null;
} }
}); });
await service.streamListen(EventStreams.kIsolate);
// The isolate may have started before we subscribed. // The isolate may have started before we subscribed.
vm = await service.getVM(); vm = await service.getVM();
if (vmIsolates.isNotEmpty) { if (vmIsolates.isNotEmpty) {

View file

@ -0,0 +1,22 @@
// Copyright (c) 2019, 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 has_part;
part 'the_part.dart';
part 'the_part_2.dart';
barz() {
print('in bar!');
}
fooz() {
print('in foo!');
bar();
}
main() {
Foo10 foo = Foo10("Foo!");
print(foo);
}

View file

@ -0,0 +1,4 @@
name: test_package
publish_to: none
environment:
sdk: '>=2.12.0-0 <3.0.0'

View file

@ -0,0 +1,91 @@
// Copyright (c) 2019, 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 has_part;
void foo() {
print("lalala");
}
class Foo1 {
final foo;
Foo1(this.foo) {
print("hello from foo!");
}
}
class Foo2 {
final foo;
Foo2(this.foo) {
print("hello from foo!");
}
}
class Foo3 {
final foo;
Foo3(this.foo) {
print("hello from foo!");
}
}
class Foo4 {
final foo;
Foo4(this.foo) {
print("hello from foo!");
}
}
class Foo5 {
final foo;
Foo5(this.foo) {
print("hello from foo!");
}
}
class Foo6 {
final foo;
Foo6(this.foo) {
print("hello from foo!");
}
}
class Foo7 {
final foo;
Foo7(this.foo) {
print("hello from foo!");
}
}
class Foo8 {
final foo;
Foo8(this.foo) {
print("hello from foo!");
}
}
class Foo9 {
final foo;
Foo9(this.foo) {
print("hello from foo!");
}
}
class Foo10 {
final foo;
Foo10(this.foo) {
print("hello from foo!");
}
}
var foo2 = foo() as dynamic;

View file

@ -0,0 +1,9 @@
// Copyright (c) 2019, 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 has_part;
void bar() {
print('Should break here');
}

View file

@ -56,6 +56,7 @@ void main(List<String> args) {
packageDirectory('runtime/observatory_2'), packageDirectory('runtime/observatory_2'),
packageDirectory( packageDirectory(
'runtime/observatory_2/tests/service_2/observatory_test_package_2'), 'runtime/observatory_2/tests/service_2/observatory_test_package_2'),
packageDirectory('pkg/vm_service/test/test_package'),
packageDirectory('sdk/lib/_internal/sdk_library_metadata'), packageDirectory('sdk/lib/_internal/sdk_library_metadata'),
packageDirectory('third_party/devtools/devtools_server'), packageDirectory('third_party/devtools/devtools_server'),
packageDirectory('third_party/devtools/devtools_shared'), packageDirectory('third_party/devtools/devtools_shared'),