| // 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:developer' as dev; |
| |
| import 'package:test/test.dart'; |
| import 'package:vm_service/vm_service.dart'; |
| |
| import 'common/service_test_common.dart'; |
| import 'common/test_helper.dart'; |
| |
| // AUTOGENERATED START |
| // |
| // Update these constants by running: |
| // |
| // dart pkg/vm_service/test/update_line_numbers.dart <test.dart> |
| // |
| const LINE_A = 26; |
| const LINE_B = 28; |
| // AUTOGENERATED END |
| |
| void primeDartTimeline() { |
| while (true) { |
| dev.Timeline.startSync('apple'); // LINE_A |
| dev.Timeline.finishSync(); |
| dev.debugger(); // LINE_B |
| } |
| } |
| |
| bool isDart(TimelineEvent event) => event.json!['cat'] == 'Dart'; |
| bool isMetaData(TimelineEvent event) => event.json!['ph'] == 'M'; |
| bool isNotMetaData(TimelineEvent event) => !isMetaData(event); |
| bool isNotDartAndMetaData(TimelineEvent event) => |
| !isDart(event) && !isMetaData(event); |
| |
| List<TimelineEvent> filterEvents( |
| List<TimelineEvent> events, |
| bool Function(TimelineEvent) filter, |
| ) { |
| return events.where(filter).toList(); |
| } |
| |
| int dartEventCount = 0; |
| |
| final tests = <IsolateTest>[ |
| hasStoppedAtBreakpoint, |
| stoppedAtLine(LINE_B), |
| (VmService service, IsolateRef isolateRef) async { |
| // Get the flags. |
| final flags = await service.getVMTimelineFlags(); |
| // Confirm that 'Dart' is available. |
| expect(flags.availableStreams!.contains('Dart'), true); |
| // Confirm that nothing is being recorded. |
| expect(flags.recordedStreams, isEmpty); |
| }, |
| (VmService service, IsolateRef isolateRef) async { |
| // Get the timeline. |
| final timeline = await service.getVMTimeline(); |
| // Confirm that it has no non-meta data events. |
| expect(filterEvents(timeline.traceEvents!, isNotMetaData), isEmpty); |
| }, |
| (VmService service, IsolateRef isolateRef) async { |
| final completer = Completer<void>(); |
| late final StreamSubscription sub; |
| sub = service.onTimelineEvent.listen((event) async { |
| expect(event.kind, EventKind.kTimelineStreamSubscriptionsUpdate); |
| expect(event.updatedStreams!.length, 1); |
| expect(event.updatedStreams!.first, 'Dart'); |
| await service.streamCancel(EventStreams.kTimeline); |
| await sub.cancel(); |
| completer.complete(); |
| }); |
| await service.streamListen(EventStreams.kTimeline); |
| |
| // Enable the Dart category. |
| await service.setVMTimelineFlags(['Dart']); |
| await completer.future; |
| }, |
| (VmService service, IsolateRef isolateRef) async { |
| // Get the flags. |
| final flags = await service.getVMTimelineFlags(); |
| // Confirm that only Dart is being recorded. |
| expect(flags.recordedStreams!.length, 1); |
| expect(flags.recordedStreams!.contains('Dart'), true); |
| }, |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| // TODO: this is a bug in the debugger and we shouldn't actually be stopping |
| // at LINE_A. This should be removed once <issue here> is fixed. |
| stoppedAtLine(LINE_A), |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| stoppedAtLine(LINE_B), |
| (VmService service, IsolateRef isolateRef) async { |
| // Get the timeline. |
| final timeline = await service.getVMTimeline(); |
| final traceEvents = timeline.traceEvents!; |
| // Confirm that Dart events are added. |
| expect(filterEvents(traceEvents, isDart), isNotEmpty); |
| // Confirm that zero non-Dart events are added. |
| expect(filterEvents(traceEvents, isNotDartAndMetaData), isEmpty); |
| }, |
| (VmService service, IsolateRef isolateRef) async { |
| final completer = Completer<void>(); |
| late final StreamSubscription sub; |
| sub = service.onTimelineEvent.listen((event) async { |
| expect(event.kind, EventKind.kTimelineStreamSubscriptionsUpdate); |
| expect(event.updatedStreams!.length, 0); |
| await service.streamCancel(EventStreams.kTimeline); |
| await sub.cancel(); |
| completer.complete(); |
| }); |
| await service.streamListen(EventStreams.kTimeline); |
| |
| // Disable the Dart category. |
| await service.setVMTimelineFlags([]); |
| await completer.future; |
| |
| // Grab the timeline and remember the number of Dart events. |
| final timeline = await service.getVMTimeline(); |
| dartEventCount = filterEvents(timeline.traceEvents!, isDart).length; |
| }, |
| (VmService service, IsolateRef isolateRef) async { |
| // Get the flags. |
| final flags = await service.getVMTimelineFlags(); |
| // Confirm that nothing is being recorded. |
| expect(flags.recordedStreams, isEmpty); |
| }, |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| // TODO: this is a bug in the debugger and we shouldn't actually be stopping |
| // at LINE_A. This should be removed once <issue here> is fixed. |
| stoppedAtLine(LINE_A), |
| resumeIsolate, |
| hasStoppedAtBreakpoint, |
| stoppedAtLine(LINE_B), |
| (VmService service, IsolateRef isolateRef) async { |
| // Grab the timeline and verify that we haven't added any new Dart events. |
| final timeline = await service.getVMTimeline(); |
| final traceEvents = timeline.traceEvents!; |
| final updatedCount = filterEvents(traceEvents, isDart).length; |
| expect(updatedCount, dartEventCount); |
| |
| // Confirm that zero non-Dart events are added. |
| expect(filterEvents(traceEvents, isNotDartAndMetaData), isEmpty); |
| }, |
| ]; |
| |
| void main([args = const <String>[]]) => runIsolateTests( |
| args, |
| tests, |
| 'vm_timeline_flags_test.dart', |
| testeeConcurrent: primeDartTimeline, |
| ); |