dart-sdk/tests/dartdevc/developer_events_test.dart
Dan Field fe30c3f235 [vm] Expose whether extension stream has listeners, guard postEvent
This avoids json encoding that was otherwise happening even in product mode. JSON encoding shows up CPU profiling as taking significant time, particularly on low end devices.

TEST=runtime/observatory/tests/service/developer_extension_test.dart

Bug: https://github.com/dart-lang/sdk/issues/48860
Change-Id: I2cf4d949e85c0b23de01ec2033b04527d40c76fe
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/242081
Reviewed-by: Ben Konyi <bkonyi@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Dan Field <dnfield@google.com>
2022-04-26 07:53:43 +00:00

232 lines
7.2 KiB
Dart

// Copyright (c) 2021, 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.
@JS()
library developer_events_test;
import 'dart:developer'
show postEvent, registerExtension, ServiceExtensionResponse;
import 'dart:convert';
import 'package:js/js.dart';
import 'package:expect/minitest.dart';
@JS(r'$emitDebugEvent')
external set emitDebugEvent(void Function(String, String)? func);
@JS(r'$emitDebugEvent')
external void Function(String, String)? get emitDebugEvent;
@JS(r'$emitRegisterEvent')
external set emitRegisterEvent(void Function(String)? func);
@JS(r'$emitRegisterEvent')
external void Function(String)? get emitRegisterEvent;
@JS(r'console.warn')
external set consoleWarn(void Function(String) func);
@JS(r'console.warn')
external void Function(String) get consoleWarn;
@JS(r'console.debug')
external set consoleDebug(void Function(String) func);
@JS(r'console.debug')
external void Function(String) get consoleDebug;
@JS(r'$dwdsVersion')
external set dwdsVersion(String? s);
@JS(r'$dwdsVersion')
external String? get dwdsVersion;
class _TestDebugEvent {
final String kind;
final String eventData;
_TestDebugEvent(this.kind, this.eventData);
}
void main() {
testBackwardsCompatibility();
testWarningMessages();
testPostEvent();
testRegisterExtension();
}
/// Verify backwards compatibility for sending messages on the console.debug log
/// in the chrome browser when the hooks have not been set.
// TODO(nshahan) Remove testing of debug log after package:dwds removes support.
// https://github.com/dart-lang/webdev/issues/1342`
void testBackwardsCompatibility() {
var consoleDebugLog = <List>[];
var savedConsoleDebug = consoleDebug;
var savedDwdsVersion = dwdsVersion;
try {
// Patch our own console.debug function for testing.
consoleDebug = allowInterop((arg1, [arg2, arg3]) => consoleDebugLog.add([
arg1,
if (arg2 != null) arg2,
if (arg3 != null) arg3,
]));
// Provide a version to signal there is an attached debugger.
dwdsVersion = '1.0.0-for-test';
// All post and register events should go to the console debug log.
var data0 = {'key0': 'value0'};
postEvent('kind0', data0);
expect(consoleDebugLog.single[0], 'dart.developer.postEvent');
expect(consoleDebugLog.single[1], 'kind0');
expect(consoleDebugLog.single[2], jsonEncode(data0));
var testHandler = (String s, Map<String, String> m) async =>
ServiceExtensionResponse.result('test result');
registerExtension('ext.method0', testHandler);
expect(consoleDebugLog.length, 2);
expect(consoleDebugLog[1].first, 'dart.developer.registerExtension');
expect(consoleDebugLog[1].last, 'ext.method0');
var data1 = {'key1': 'value1'};
postEvent('kind1', data1);
expect(consoleDebugLog.length, 3);
expect(consoleDebugLog[2][0], 'dart.developer.postEvent');
expect(consoleDebugLog[2][1], 'kind1');
expect(consoleDebugLog[2][2], jsonEncode(data1));
registerExtension('ext.method1', testHandler);
expect(consoleDebugLog.length, 4);
expect(consoleDebugLog[3].first, 'dart.developer.registerExtension');
expect(consoleDebugLog[3].last, 'ext.method1');
} finally {
// Restore actual console.debug function.
consoleDebug = savedConsoleDebug;
dwdsVersion = savedDwdsVersion;
}
}
/// Verify that warning messages are printed on the first call of postEvent()
/// and registerExtension() when the hooks are undefined.
void testWarningMessages() {
final consoleWarnLog = <String>[];
var savedConsoleWarn = consoleWarn;
try {
// Patch our own console.warn function for testing.
consoleWarn = allowInterop((String s) => consoleWarnLog.add(s));
expect(consoleWarnLog.isEmpty, true);
var data0 = {'key0': 'value0'};
postEvent('kind0', data0);
// Nothing is listening, so this was a no-op.
expect(consoleWarnLog.isEmpty, true);
postEvent('kind0', data0);
var data1 = {'key1': 'value1'};
postEvent('kind1', data1);
// No warnings should be issued because postEvent is a no-op.
expect(consoleWarnLog.length, 0);
consoleWarnLog.clear();
var testHandler = (String s, Map<String, String> m) async =>
ServiceExtensionResponse.result('test result');
expect(consoleWarnLog.isEmpty, true);
registerExtension('ext.method0', testHandler);
// A warning message was issued about calling `registerExtension()` from
// dart:developer.
expect(
consoleWarnLog.single
.contains('registerExtension() from dart:developer'),
true);
registerExtension('ext.method1', testHandler);
registerExtension('ext.method2', testHandler);
// A warning is only issued on the first call of `registerExtension()`.
expect(consoleWarnLog.length, 1);
} finally {
// Restore actual console.warn function.
consoleWarn = savedConsoleWarn;
}
}
void testPostEvent() {
final debugEventLog = <_TestDebugEvent>[];
var savedEmitDebugEvent = emitDebugEvent;
var savedDwdsVersion = dwdsVersion;
try {
// Provide a test version of the $emitDebugEvent hook.
emitDebugEvent = allowInterop((String kind, String eventData) {
debugEventLog.add(_TestDebugEvent(kind, eventData));
});
// Provide a version to signal there is an attached debugger.
dwdsVersion = '1.0.0-for-test';
expect(debugEventLog.isEmpty, true);
var data0 = {'key0': 'value0'};
postEvent('kind0', data0);
expect(debugEventLog.single.kind, 'kind0');
expect(debugEventLog.single.eventData, jsonEncode(data0));
var data1 = {'key1': 'value1'};
var data2 = {'key2': 'value2'};
postEvent('kind1', data1);
postEvent('kind2', data2);
expect(debugEventLog.length, 3);
expect(debugEventLog[0].kind, 'kind0');
expect(debugEventLog[0].eventData, jsonEncode(data0));
expect(debugEventLog[1].kind, 'kind1');
expect(debugEventLog[1].eventData, jsonEncode(data1));
expect(debugEventLog[2].kind, 'kind2');
expect(debugEventLog[2].eventData, jsonEncode(data2));
} finally {
emitDebugEvent = savedEmitDebugEvent;
dwdsVersion = savedDwdsVersion;
}
}
void testRegisterExtension() {
final registerEventLog = <String>[];
var savedEmitRegisterEvent = emitRegisterEvent;
var savedDwdsVersion = dwdsVersion;
try {
// Provide a test version of the $emitRegisterEvent hook.
emitRegisterEvent = allowInterop((String eventData) {
registerEventLog.add(eventData);
});
// Provide a version to signal there is an attached debugger.
dwdsVersion = '1.0.0-for-test';
expect(registerEventLog.isEmpty, true);
var testHandler = (String s, Map<String, String> m) async =>
ServiceExtensionResponse.result('test result');
registerExtension('ext.method0', testHandler);
expect(registerEventLog.single, 'ext.method0');
registerExtension('ext.method1', testHandler);
registerExtension('ext.method2', testHandler);
expect(registerEventLog.length, 3);
expect(registerEventLog[0], 'ext.method0');
expect(registerEventLog[1], 'ext.method1');
expect(registerEventLog[2], 'ext.method2');
} finally {
emitRegisterEvent = savedEmitRegisterEvent;
dwdsVersion = savedDwdsVersion;
}
}