mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:07:06 +00:00
[ package:vm_service ] Migrate some more tests from service/
Change-Id: I009b9ae97fb5eaeebc4bddb3813d83562302d0ec Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349560 Reviewed-by: Derek Xu <derekx@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
83aca6c5c2
commit
8338fc2eac
28
pkg/vm_service/test/custom_stream_listen_test.dart
Normal file
28
pkg/vm_service/test/custom_stream_listen_test.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2024, 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 = <VMTest>[
|
||||
// Ensure the VM service throws an exception when encountering a custom
|
||||
// stream.
|
||||
(VmService service) async {
|
||||
try {
|
||||
await service.streamListen('Foo');
|
||||
fail('Successfully listened to a custom stream, which requires DDS');
|
||||
} on RPCError catch (_) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runVMTests(
|
||||
args,
|
||||
tests,
|
||||
'custom_stream_listen_test.dart',
|
||||
extraArgs: ['--no-dds'],
|
||||
);
|
19
pkg/vm_service/test/get_supported_protocols_common.dart
Normal file
19
pkg/vm_service/test/get_supported_protocols_common.dart
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2024, 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';
|
||||
|
||||
VMTest expectedProtocolTest(List<String> expectedProtocols) =>
|
||||
(VmService service) async {
|
||||
final protocols = (await service.getSupportedProtocols()).protocols!;
|
||||
expect(protocols.length, expectedProtocols.length);
|
||||
for (final protocol in protocols) {
|
||||
expect(expectedProtocols.contains(protocol.protocolName), true);
|
||||
expect(protocol.minor, greaterThan(0));
|
||||
expect(protocol.major, greaterThan(0));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2024, 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 'common/test_helper.dart';
|
||||
import 'get_supported_protocols_common.dart';
|
||||
|
||||
final tests = <VMTest>[
|
||||
expectedProtocolTest(<String>[
|
||||
'VM Service',
|
||||
'DDS',
|
||||
]),
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runVMTests(
|
||||
args,
|
||||
tests,
|
||||
'get_supported_protocols_with_dds_test.dart',
|
||||
);
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2024, 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 'common/test_helper.dart';
|
||||
import 'get_supported_protocols_common.dart';
|
||||
|
||||
final tests = <VMTest>[
|
||||
expectedProtocolTest(<String>[
|
||||
'VM Service',
|
||||
]),
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runVMTests(
|
||||
args,
|
||||
tests,
|
||||
'get_supported_protocols_with_dds_test.dart',
|
||||
extraArgs: ['--no-dds'],
|
||||
);
|
231
pkg/vm_service/test/get_vm_timeline_rpc_test.dart
Normal file
231
pkg/vm_service/test/get_vm_timeline_rpc_test.dart
Normal file
|
@ -0,0 +1,231 @@
|
|||
// Copyright (c) 2024, 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' as dev;
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
void primeTimeline() {
|
||||
dev.Timeline.startSync('apple');
|
||||
dev.Timeline.instantSync('ISYNC', arguments: {'fruit': 'banana'});
|
||||
dev.Timeline.finishSync();
|
||||
final parentTask = dev.TimelineTask.withTaskId(42);
|
||||
final task = dev.TimelineTask(parent: parentTask, filterKey: 'testFilter');
|
||||
task.start('TASK1', arguments: {'task1-start-key': 'task1-start-value'});
|
||||
task.instant(
|
||||
'ITASK',
|
||||
arguments: {'task1-instant-key': 'task1-instant-value'},
|
||||
);
|
||||
task.finish(arguments: {'task1-finish-key': 'task1-finish-value'});
|
||||
|
||||
final flow = dev.Flow.begin(id: 123);
|
||||
dev.Timeline.startSync('peach', flow: flow);
|
||||
dev.Timeline.finishSync();
|
||||
dev.Timeline.startSync('watermelon', flow: dev.Flow.step(flow.id));
|
||||
dev.Timeline.finishSync();
|
||||
dev.Timeline.startSync('pear', flow: dev.Flow.end(flow.id));
|
||||
dev.Timeline.finishSync();
|
||||
}
|
||||
|
||||
List<TimelineEvent> filterForDartEvents(List<TimelineEvent> events) {
|
||||
return events.where((event) => event.json!['cat'] == 'Dart').toList();
|
||||
}
|
||||
|
||||
bool mapContains(Map<String, dynamic> map, Map submap) {
|
||||
for (final key in submap.keys) {
|
||||
if (map[key] != submap[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eventsContains(
|
||||
List<TimelineEvent> events,
|
||||
String phase,
|
||||
String name, [
|
||||
Map? arguments,
|
||||
]) {
|
||||
for (final timelineEvent in events) {
|
||||
final event = timelineEvent.json!;
|
||||
if ((event['ph'] == phase) && (event['name'] == name)) {
|
||||
if (arguments == null) {
|
||||
return true;
|
||||
} else if (mapContains(event['args'], arguments)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int timeOrigin(List<TimelineEvent> events) {
|
||||
if (events.isEmpty) {
|
||||
return 0;
|
||||
}
|
||||
int smallest = events.first.json!['ts'];
|
||||
for (final timelineEvent in events) {
|
||||
final event = timelineEvent.json!;
|
||||
if (event['ts'] < smallest) {
|
||||
smallest = event['ts'];
|
||||
}
|
||||
}
|
||||
return smallest;
|
||||
}
|
||||
|
||||
int timeDuration(List<TimelineEvent> events, int timeOrigin) {
|
||||
if (events.isEmpty) {
|
||||
return 0;
|
||||
}
|
||||
int biggestDuration = events.first.json!['ts'] - timeOrigin;
|
||||
for (final timelineEvent in events) {
|
||||
final event = timelineEvent.json!;
|
||||
final duration = event['ts'] - timeOrigin;
|
||||
if (duration > biggestDuration) {
|
||||
biggestDuration = duration;
|
||||
}
|
||||
}
|
||||
return biggestDuration;
|
||||
}
|
||||
|
||||
void allEventsHaveIsolateNumber(List<TimelineEvent> events) {
|
||||
for (final timelineEvent in events) {
|
||||
final event = timelineEvent.json!;
|
||||
if (event['ph'] == 'M') {
|
||||
// Skip meta-data events.
|
||||
continue;
|
||||
}
|
||||
if (event['name'] == 'Runnable' && event['ph'] == 'i') {
|
||||
// Skip Runnable events which don't have an isolate.
|
||||
continue;
|
||||
}
|
||||
if (event['cat'] == 'VM') {
|
||||
// Skip VM category events which don't have an isolate.
|
||||
continue;
|
||||
}
|
||||
if (event['cat'] == 'API') {
|
||||
// Skip API category events which sometimes don't have an isolate.
|
||||
continue;
|
||||
}
|
||||
if (event['cat'] == 'Embedder' &&
|
||||
(event['name'] == 'DFE::ReadScript' ||
|
||||
event['name'] == 'CreateIsolateGroupAndSetupHelper' ||
|
||||
event['name'] == 'CreateAndSetupDartDevIsolate')) {
|
||||
continue;
|
||||
}
|
||||
final arguments = event['args'];
|
||||
expect(arguments, isA<Map>());
|
||||
expect(arguments['isolateGroupId'], isA<String>());
|
||||
if (!const ['GC', 'Compiler', 'CompilerVerbose'].contains(event['cat']) &&
|
||||
!const [
|
||||
'FinishTopLevelClassLoading',
|
||||
'FinishClassLoading',
|
||||
'ProcessPendingClasses',
|
||||
].contains(event['name'])) {
|
||||
expect(arguments['isolateId'], isA<String>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final tests = <VMTest>[
|
||||
(VmService service) async {
|
||||
var timeline = await service.getVMTimeline();
|
||||
var traceEvents = timeline.traceEvents!;
|
||||
final int numEvents = traceEvents.length;
|
||||
final dartEvents = filterForDartEvents(traceEvents);
|
||||
expect(dartEvents.length, greaterThanOrEqualTo(11));
|
||||
allEventsHaveIsolateNumber(dartEvents);
|
||||
allEventsHaveIsolateNumber(traceEvents);
|
||||
expect(
|
||||
eventsContains(dartEvents, 'i', 'ISYNC', {'fruit': 'banana'}),
|
||||
isTrue,
|
||||
);
|
||||
expect(eventsContains(dartEvents, 'B', 'apple'), isTrue);
|
||||
expect(eventsContains(dartEvents, 'E', 'apple'), isTrue);
|
||||
expect(
|
||||
eventsContains(
|
||||
dartEvents,
|
||||
'b',
|
||||
'TASK1',
|
||||
{
|
||||
'filterKey': 'testFilter',
|
||||
'task1-start-key': 'task1-start-value',
|
||||
'parentId': 42.toRadixString(16),
|
||||
},
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(
|
||||
eventsContains(
|
||||
dartEvents,
|
||||
'e',
|
||||
'TASK1',
|
||||
{
|
||||
'filterKey': 'testFilter',
|
||||
'task1-finish-key': 'task1-finish-value',
|
||||
},
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(
|
||||
eventsContains(
|
||||
dartEvents,
|
||||
'n',
|
||||
'ITASK',
|
||||
{
|
||||
'filterKey': 'testFilter',
|
||||
'task1-instant-key': 'task1-instant-value',
|
||||
},
|
||||
),
|
||||
isTrue,
|
||||
);
|
||||
expect(eventsContains(dartEvents, 'q', 'ITASK'), isFalse);
|
||||
expect(eventsContains(dartEvents, 'B', 'peach'), isTrue);
|
||||
expect(eventsContains(dartEvents, 'E', 'peach'), isTrue);
|
||||
expect(eventsContains(dartEvents, 'B', 'watermelon'), isTrue);
|
||||
expect(eventsContains(dartEvents, 'E', 'watermelon'), isTrue);
|
||||
expect(eventsContains(dartEvents, 'B', 'pear'), isTrue);
|
||||
expect(eventsContains(dartEvents, 'E', 'pear'), isTrue);
|
||||
expect(eventsContains(dartEvents, 's', '123'), isTrue);
|
||||
expect(eventsContains(dartEvents, 't', '123'), isTrue);
|
||||
expect(eventsContains(dartEvents, 'f', '123'), isTrue);
|
||||
// Calculate the time Window of Dart events.
|
||||
final origin = timeOrigin(dartEvents);
|
||||
final extent = timeDuration(dartEvents, origin);
|
||||
// Query for the timeline with the time window for Dart events.
|
||||
timeline = await service.getVMTimeline(
|
||||
timeOriginMicros: origin,
|
||||
timeExtentMicros: extent,
|
||||
);
|
||||
traceEvents = timeline.traceEvents!;
|
||||
// Verify that we received fewer events than before.
|
||||
expect(traceEvents.length, lessThan(numEvents));
|
||||
// Verify that we have the same number of Dart events.
|
||||
final dartEvents2 = filterForDartEvents(traceEvents);
|
||||
expect(dartEvents2.length, dartEvents.length);
|
||||
},
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) {
|
||||
// NOTE: the original service test compiled the target program to kernel
|
||||
// first, with the following comment providing an explanation:
|
||||
//
|
||||
// We first compile the testee to kernel and run the subprocess on the kernel
|
||||
// file. That avoids cases where the testee has to run a lot of code in the
|
||||
// kernel-isolate (e.g. due to ia32's kernel-service not being app-jit
|
||||
// trained). We do that because otherwise the --complete-timeline will
|
||||
// collect a lot of data, possibly leading to OOMs or timeouts.
|
||||
//
|
||||
// If this test times out on ia32, we may need to do the same.
|
||||
runVMTests(
|
||||
args,
|
||||
tests,
|
||||
'get_vm_timeline_rpc_test.dart',
|
||||
testeeBefore: primeTimeline,
|
||||
extraArgs: ['--complete-timeline'],
|
||||
);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2024, 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' as isolate;
|
||||
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'common/service_test_common.dart';
|
||||
import 'common/test_helper.dart';
|
||||
|
||||
void child(message) {
|
||||
print('Child got initial message');
|
||||
message.send(null);
|
||||
}
|
||||
|
||||
void testMain() {
|
||||
final port = isolate.RawReceivePort();
|
||||
port.handler = (message) {
|
||||
print('Parent got response');
|
||||
port.close();
|
||||
};
|
||||
|
||||
isolate.Isolate.spawn(child, port.sendPort);
|
||||
}
|
||||
|
||||
final tests = <IsolateTest>[
|
||||
hasPausedAtStart,
|
||||
(VmService service, IsolateRef isolateRef) async {
|
||||
// Disabling these flags will result in any new isolates spawned not
|
||||
// pausing on start or exit. However, existing isolates will maintain their
|
||||
// existing flags and the main isolate should pause at exit.
|
||||
await service.setFlag('pause_isolates_on_start', 'false');
|
||||
await service.setFlag('pause_isolates_on_exit', 'false');
|
||||
},
|
||||
resumeIsolate,
|
||||
// When the main isolate is resumed, we expect the child isolate to spawn and
|
||||
// immediately exit after sending a message to the main isolate. The main
|
||||
// isolate will only exit when `port` is closed after the message sent by the
|
||||
// child is received.
|
||||
hasStoppedAtExit,
|
||||
];
|
||||
|
||||
void main([args = const <String>[]]) => runIsolateTests(
|
||||
args,
|
||||
tests,
|
||||
'pause_on_start_and_exit_with_child_test.dart',
|
||||
testeeConcurrent: testMain,
|
||||
pauseOnStart: true,
|
||||
pauseOnExit: true,
|
||||
extraArgs: [
|
||||
'--trace-service',
|
||||
'--trace-service-verbose',
|
||||
],
|
||||
);
|
Loading…
Reference in a new issue