mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 14:49:43 +00:00
Pull in a new version of unified_analytics and update server
Change-Id: I7f63b55fc6a74f2adfc97f00950ca0516bae68ca Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/310965 Reviewed-by: Elias Yishak <eliasyishak@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
758727dd12
commit
45572cf7dd
2
DEPS
2
DEPS
|
@ -179,7 +179,7 @@ vars = {
|
|||
"test_descriptor_rev": "be7ce0751d85abd1ef605d14d359f499e1ba8fe2",
|
||||
"test_process_rev": "5ff212250f6cc5f850b26295e7c8123bd5238ea3",
|
||||
"test_reflective_loader_rev": "40d61b16647cd61b02d806fea46362ef07e7c502",
|
||||
"tools_rev": "8d6e8b82e3eef8b2f5e3ec9bdd3dd1a2ad3e13f5",
|
||||
"tools_rev": "8db0aa1e8c418289b9a972529b0f47902c559550",
|
||||
"typed_data_rev": "8d29573ab6fd26a272dc846255eda66a01abae01",
|
||||
"usage_rev": "6ee09084596f9829371bb836f9d1ca05820f29ea",
|
||||
"vector_math_rev": "c14703830d47818a82ce8a9fcb70029e5e8e6a16",
|
||||
|
|
|
@ -35,6 +35,22 @@ class AnalyticsManager {
|
|||
/// development-time analytics account.
|
||||
static const bool sendExperimentalData = false;
|
||||
|
||||
static const addedKey = 'added';
|
||||
|
||||
static const removedKey = 'removed';
|
||||
|
||||
static const commandEnumKey = 'command';
|
||||
|
||||
static const openWorkspacePathsKey = 'openWorkspacePaths';
|
||||
|
||||
static const refactoringKindEnumKey = EDIT_REQUEST_GET_REFACTORING_KIND;
|
||||
|
||||
static const includedKey = ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS_INCLUDED;
|
||||
|
||||
static const excludedKey = ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS_EXCLUDED;
|
||||
|
||||
static const filesKey = ANALYSIS_REQUEST_SET_PRIORITY_FILES_FILES;
|
||||
|
||||
/// The object used to send analytics.
|
||||
final Analytics analytics;
|
||||
|
||||
|
@ -125,8 +141,8 @@ class AnalyticsManager {
|
|||
{required List<String> added, required List<String> removed}) {
|
||||
var requestData =
|
||||
getRequestData(Method.workspace_didChangeWorkspaceFolders.toString());
|
||||
requestData.addValue('added', added.length);
|
||||
requestData.addValue('removed', removed.length);
|
||||
requestData.addValue(addedKey, added.length);
|
||||
requestData.addValue(removedKey, removed.length);
|
||||
}
|
||||
|
||||
/// Record that the [contexts] have been created.
|
||||
|
@ -149,7 +165,7 @@ class AnalyticsManager {
|
|||
void executedCommand(String command) {
|
||||
var requestData =
|
||||
getRequestData(Method.workspace_executeCommand.toString());
|
||||
requestData.addEnumValue('command', command);
|
||||
requestData.addEnumValue(commandEnumKey, command);
|
||||
}
|
||||
|
||||
/// Return the request data for requests that have the given [method].
|
||||
|
@ -195,7 +211,7 @@ class AnalyticsManager {
|
|||
/// Record the number of [openWorkspacePaths].
|
||||
void initialized({required List<String> openWorkspacePaths}) {
|
||||
var requestData = getRequestData(Method.initialized.toString());
|
||||
requestData.addValue('openWorkspacePaths', openWorkspacePaths.length);
|
||||
requestData.addValue(openWorkspacePathsKey, openWorkspacePaths.length);
|
||||
}
|
||||
|
||||
Future<void> sendMemoryUsage(MemoryUsageEvent event) async {
|
||||
|
@ -205,19 +221,19 @@ class AnalyticsManager {
|
|||
assert((event.delta == null) == (event.period == null));
|
||||
|
||||
if (delta == null || seconds == null) {
|
||||
await analytics.sendEvent(eventName: DashEvent.memoryInfo, eventData: {
|
||||
'rss': event.rss,
|
||||
});
|
||||
await analytics.send(Event.memoryInfo(
|
||||
rss: event.rss,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
if (seconds == 0) seconds = 1;
|
||||
|
||||
await analytics.sendEvent(eventName: DashEvent.memoryInfo, eventData: {
|
||||
'rss': event.rss,
|
||||
'periodSec': seconds,
|
||||
'mbPerSec': delta / seconds,
|
||||
});
|
||||
await analytics.send(Event.memoryInfo(
|
||||
rss: event.rss,
|
||||
periodSec: seconds,
|
||||
mbPerSec: delta / seconds,
|
||||
));
|
||||
}
|
||||
|
||||
/// Record that the given [response] was sent to the client.
|
||||
|
@ -254,8 +270,7 @@ class AnalyticsManager {
|
|||
/// Record data from the given [params].
|
||||
void startedGetRefactoring(EditGetRefactoringParams params) {
|
||||
var requestData = getRequestData(EDIT_REQUEST_GET_REFACTORING);
|
||||
requestData.addEnumValue(
|
||||
EDIT_REQUEST_GET_REFACTORING_KIND, params.kind.name);
|
||||
requestData.addEnumValue(refactoringKindEnumKey, params.kind.name);
|
||||
}
|
||||
|
||||
/// Record that the server started working on the give [request] at the given
|
||||
|
@ -277,10 +292,8 @@ class AnalyticsManager {
|
|||
/// Record data from the given [params].
|
||||
void startedSetAnalysisRoots(AnalysisSetAnalysisRootsParams params) {
|
||||
var requestData = getRequestData(ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS);
|
||||
requestData.addValue(
|
||||
ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS_INCLUDED, params.included.length);
|
||||
requestData.addValue(
|
||||
ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS_EXCLUDED, params.excluded.length);
|
||||
requestData.addValue(includedKey, params.included.length);
|
||||
requestData.addValue(excludedKey, params.excluded.length);
|
||||
}
|
||||
|
||||
/// Record data from the given [params].
|
||||
|
@ -456,21 +469,20 @@ class AnalyticsManager {
|
|||
Future<void> _sendAnalysisData() async {
|
||||
var contextStructure = _contextStructure;
|
||||
if (contextStructure != null) {
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.contextStructure, eventData: {
|
||||
'numberOfContexts': contextStructure.numberOfContexts,
|
||||
'contextsWithoutFiles': contextStructure.contextsWithoutFiles,
|
||||
'contextsFromPackagesFiles': contextStructure.contextsFromPackagesFiles,
|
||||
'contextsFromOptionsFiles': contextStructure.contextsFromOptionsFiles,
|
||||
'contextsFromBothFiles': contextStructure.contextsFromBothFiles,
|
||||
'immediateFileCount': contextStructure.immediateFileCount,
|
||||
'immediateFileLineCount': contextStructure.immediateFileLineCount,
|
||||
'transitiveFileCount': contextStructure.transitiveFileCount,
|
||||
'transitiveFileLineCount': contextStructure.transitiveFileLineCount,
|
||||
'transitiveFileUniqueCount': contextStructure.transitiveFileUniqueCount,
|
||||
'transitiveFileUniqueLineCount':
|
||||
await analytics.send(Event.contextStructure(
|
||||
numberOfContexts: contextStructure.numberOfContexts,
|
||||
contextsWithoutFiles: contextStructure.contextsWithoutFiles,
|
||||
contextsFromPackagesFiles: contextStructure.contextsFromPackagesFiles,
|
||||
contextsFromOptionsFiles: contextStructure.contextsFromOptionsFiles,
|
||||
contextsFromBothFiles: contextStructure.contextsFromBothFiles,
|
||||
immediateFileCount: contextStructure.immediateFileCount,
|
||||
immediateFileLineCount: contextStructure.immediateFileLineCount,
|
||||
transitiveFileCount: contextStructure.transitiveFileCount,
|
||||
transitiveFileLineCount: contextStructure.transitiveFileLineCount,
|
||||
transitiveFileUniqueCount: contextStructure.transitiveFileUniqueCount,
|
||||
transitiveFileUniqueLineCount:
|
||||
contextStructure.transitiveFileUniqueLineCount,
|
||||
});
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,12 +490,14 @@ class AnalyticsManager {
|
|||
/// analysis options file.
|
||||
Future<void> _sendLintUsageCounts() async {
|
||||
if (_lintUsageCounts.isNotEmpty) {
|
||||
var lintUsageCounts = json.encode(_lintUsageCounts);
|
||||
var entries = _lintUsageCounts.entries.toList();
|
||||
_lintUsageCounts.clear();
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.lintUsageCounts, eventData: {
|
||||
'usageCounts': lintUsageCounts,
|
||||
});
|
||||
for (var entry in entries) {
|
||||
await analytics.send(Event.lintUsageCount(
|
||||
count: entry.value,
|
||||
name: entry.key,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,12 +507,11 @@ class AnalyticsManager {
|
|||
var completedNotifications = _completedNotifications.values.toList();
|
||||
_completedNotifications.clear();
|
||||
for (var data in completedNotifications) {
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.clientNotification, eventData: {
|
||||
'latency': data.latencyTimes.toAnalyticsString(),
|
||||
'method': data.method,
|
||||
'duration': data.handlingTimes.toAnalyticsString(),
|
||||
});
|
||||
await analytics.send(Event.clientNotification(
|
||||
latency: data.latencyTimes.toAnalyticsString(),
|
||||
method: data.method,
|
||||
duration: data.handlingTimes.toAnalyticsString(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -521,12 +534,11 @@ class AnalyticsManager {
|
|||
responseTimes.clear();
|
||||
for (var pluginEntry in entries) {
|
||||
for (var responseEntry in pluginEntry.value.entries) {
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.pluginRequest, eventData: {
|
||||
'pluginId': pluginEntry.key.safePluginId,
|
||||
'method': responseEntry.key,
|
||||
'duration': responseEntry.value.toAnalyticsString(),
|
||||
});
|
||||
await analytics.send(Event.pluginRequest(
|
||||
pluginId: pluginEntry.key.safePluginId,
|
||||
method: responseEntry.key,
|
||||
duration: responseEntry.value.toAnalyticsString(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -538,16 +550,33 @@ class AnalyticsManager {
|
|||
var completedRequests = _completedRequests.values.toList();
|
||||
_completedRequests.clear();
|
||||
for (var data in completedRequests) {
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.clientRequest, eventData: {
|
||||
'latency': data.latencyTimes.toAnalyticsString(),
|
||||
'method': data.method,
|
||||
'duration': data.responseTimes.toAnalyticsString(),
|
||||
for (var field in data.additionalPercentiles.entries)
|
||||
field.key: field.value.toAnalyticsString(),
|
||||
for (var field in data.additionalEnumCounts.entries)
|
||||
field.key: json.encode(field.value),
|
||||
});
|
||||
await analytics.send(Event.clientRequest(
|
||||
latency: data.latencyTimes.toAnalyticsString(),
|
||||
method: data.method,
|
||||
duration: data.responseTimes.toAnalyticsString(),
|
||||
added: data.additionalPercentiles[addedKey]?.toAnalyticsString(),
|
||||
excluded:
|
||||
data.additionalPercentiles[excludedKey]?.toAnalyticsString(),
|
||||
files: data.additionalPercentiles[filesKey]?.toAnalyticsString(),
|
||||
included:
|
||||
data.additionalPercentiles[includedKey]?.toAnalyticsString(),
|
||||
openWorkspacePaths: data.additionalPercentiles[openWorkspacePathsKey]
|
||||
?.toAnalyticsString(),
|
||||
removed: data.additionalPercentiles[removedKey]?.toAnalyticsString(),
|
||||
));
|
||||
var commandMap = data.additionalEnumCounts[commandEnumKey];
|
||||
if (commandMap != null) {
|
||||
for (var entry in commandMap.entries) {
|
||||
await analytics.send(Event.commandExecuted(
|
||||
count: entry.value,
|
||||
name: entry.key,
|
||||
));
|
||||
}
|
||||
}
|
||||
// TODO(brianwilkerson) We don't appear to have an event defined that we
|
||||
// can use to send analytics about how often old-style refactorings are
|
||||
// being invoked.
|
||||
// var refactoringMap = data.additionalEnumCounts[refactoringKindEnumKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,26 +585,33 @@ class AnalyticsManager {
|
|||
Future<void> _sendSessionData(SessionData sessionData) async {
|
||||
var endTime = DateTime.now().millisecondsSinceEpoch;
|
||||
var duration = endTime - sessionData.startTime.millisecondsSinceEpoch;
|
||||
await analytics.sendEvent(eventName: DashEvent.serverSession, eventData: {
|
||||
'flags': sessionData.commandLineArguments,
|
||||
'parameters': sessionData.initializeParams,
|
||||
'clientId': sessionData.clientId,
|
||||
'clientVersion': sessionData.clientVersion,
|
||||
'duration': duration.toString(),
|
||||
'plugins': _pluginData.usageCountData,
|
||||
});
|
||||
await analytics.send(Event.serverSession(
|
||||
flags: sessionData.commandLineArguments,
|
||||
parameters: sessionData.initializeParams,
|
||||
clientId: sessionData.clientId,
|
||||
clientVersion: sessionData.clientVersion,
|
||||
duration: duration,
|
||||
));
|
||||
for (var entry in _pluginData.usageCounts.entries) {
|
||||
await analytics.send(Event.pluginUse(
|
||||
count: _pluginData.recordCount,
|
||||
enabled: entry.value.toAnalyticsString(),
|
||||
pluginId: entry.key));
|
||||
}
|
||||
}
|
||||
|
||||
/// Send information about the number of times that the severity of a
|
||||
/// diagnostic is changed in an analysis options file.
|
||||
Future<void> _sendSeverityAdjustments() async {
|
||||
if (_severityAdjustments.isNotEmpty) {
|
||||
var severityAdjustments = json.encode(_severityAdjustments);
|
||||
var entries = _severityAdjustments.entries.toList();
|
||||
_severityAdjustments.clear();
|
||||
await analytics
|
||||
.sendEvent(eventName: DashEvent.severityAdjustments, eventData: {
|
||||
'adjustmentCounts': severityAdjustments,
|
||||
});
|
||||
for (var entry in entries) {
|
||||
await analytics.send(Event.severityAdjustment(
|
||||
adjustments: json.encode(entry.value),
|
||||
diagnostic: entry.key,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,9 +43,7 @@ class NoopAnalytics implements Analytics {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<Response>? sendEvent(
|
||||
{required DashEvent eventName,
|
||||
Map<String, Object?> eventData = const {}}) {
|
||||
Future<Response>? send(Event event) {
|
||||
// Ignored
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import 'package:linter/src/rules.dart';
|
|||
import 'package:path/path.dart' as path;
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
import 'package:unified_analytics/src/enums.dart';
|
||||
import 'package:unified_analytics/unified_analytics.dart';
|
||||
|
||||
void main() {
|
||||
|
@ -38,6 +39,9 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
|
||||
String get testPackageRootPath => testPackageRoot.path;
|
||||
|
||||
DateTime get _startUpTime => DateTime.fromMillisecondsSinceEpoch(
|
||||
DateTime.now().millisecondsSinceEpoch - 5);
|
||||
|
||||
Future<void> test_createAnalysisContexts_lints() async {
|
||||
_createAnalysisOptionsFile(lints: [
|
||||
'avoid_dynamic_calls',
|
||||
|
@ -50,9 +54,17 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
await manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.lintUsageCounts(eventData: {
|
||||
'usageCounts':
|
||||
'{"avoid_dynamic_calls":1,"await_only_futures":1,"unawaited_futures":1}',
|
||||
_ExpectedEvent.lintUsageCount(eventData: {
|
||||
'count': 1,
|
||||
'name': 'avoid_dynamic_calls',
|
||||
}),
|
||||
_ExpectedEvent.lintUsageCount(eventData: {
|
||||
'count': 1,
|
||||
'name': 'await_only_futures',
|
||||
}),
|
||||
_ExpectedEvent.lintUsageCount(eventData: {
|
||||
'count': 1,
|
||||
'name': 'unawaited_futures',
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
@ -68,9 +80,13 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
await manager.shutdown();
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(),
|
||||
_ExpectedEvent.severityAdjustments(eventData: {
|
||||
'adjustmentCounts':
|
||||
'{"AVOID_DYNAMIC_CALLS":{"ERROR":1},"AWAIT_ONLY_FUTURES":{"ignore":1}}',
|
||||
_ExpectedEvent.severityAdjustment(eventData: {
|
||||
'diagnostic': 'AVOID_DYNAMIC_CALLS',
|
||||
'adjustments': '{"ERROR":1}',
|
||||
}),
|
||||
_ExpectedEvent.severityAdjustment(eventData: {
|
||||
'diagnostic': 'AWAIT_ONLY_FUTURES',
|
||||
'adjustments': '{"ignore":1}',
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
@ -183,6 +199,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
]);
|
||||
}
|
||||
|
||||
@FailingTest(reason: 'We are currently unable to send refactoring events')
|
||||
Future<void> test_server_request_editGetRefactoring() async {
|
||||
_defaultStartup();
|
||||
var params =
|
||||
|
@ -282,7 +299,10 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
'latency': _IsPercentiles(),
|
||||
'method': Method.workspace_executeCommand.toString(),
|
||||
'duration': _IsPercentiles(),
|
||||
'command': '{"doIt":2}'
|
||||
}),
|
||||
_ExpectedEvent.commandExecuted(eventData: {
|
||||
'name': 'doIt',
|
||||
'count': 2,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
@ -296,7 +316,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
var arguments = ['a', 'b'];
|
||||
var clientId = 'clientId';
|
||||
manager.startUp(
|
||||
time: DateTime.now(),
|
||||
time: _startUpTime,
|
||||
arguments: arguments,
|
||||
clientId: clientId,
|
||||
clientVersion: null);
|
||||
|
@ -306,7 +326,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
'flags': arguments.join(','),
|
||||
'clientId': clientId,
|
||||
'clientVersion': '',
|
||||
'duration': _IsStringEncodedPositiveInt(),
|
||||
'duration': _IsPositiveInt(),
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
@ -318,10 +338,17 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
_pluginInfo('b'),
|
||||
]));
|
||||
await manager.shutdown();
|
||||
var counts = '{"count":1,"percentiles":[0,0,0,0,0]}';
|
||||
analytics.assertEvents([
|
||||
_ExpectedEvent.session(eventData: {
|
||||
'plugins': '{"recordCount":1,"rootCounts":{"a":$counts,"b":$counts}}'
|
||||
_ExpectedEvent.session(eventData: {}),
|
||||
_ExpectedEvent.pluginUse(eventData: {
|
||||
'count': 1,
|
||||
'pluginId': 'a',
|
||||
'enabled': _IsPercentiles(),
|
||||
}),
|
||||
_ExpectedEvent.pluginUse(eventData: {
|
||||
'count': 1,
|
||||
'pluginId': 'b',
|
||||
'enabled': _IsPercentiles(),
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
@ -331,7 +358,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
var clientId = 'clientId';
|
||||
var clientVersion = 'clientVersion';
|
||||
manager.startUp(
|
||||
time: DateTime.now(),
|
||||
time: _startUpTime,
|
||||
arguments: arguments,
|
||||
clientId: clientId,
|
||||
clientVersion: clientVersion);
|
||||
|
@ -341,8 +368,7 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
'flags': arguments.join(','),
|
||||
'clientId': clientId,
|
||||
'clientVersion': clientVersion,
|
||||
'': isNull,
|
||||
'duration': _IsStringEncodedPositiveInt(),
|
||||
'duration': _IsPositiveInt(),
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
@ -413,14 +439,6 @@ class AnalyticsManagerTest with ResourceProviderMixin {
|
|||
path.join('.pub-cache', 'pub.dev', name, 'tools', 'analyzer_plugin'));
|
||||
}
|
||||
|
||||
/// A record of an event that was reported to analytics.
|
||||
class _Event {
|
||||
final DashEvent eventName;
|
||||
final Map<String, Object?> eventData;
|
||||
|
||||
_Event(this.eventName, this.eventData);
|
||||
}
|
||||
|
||||
/// A record of an event that was reported to analytics.
|
||||
class _ExpectedEvent {
|
||||
final DashEvent eventName;
|
||||
|
@ -428,8 +446,11 @@ class _ExpectedEvent {
|
|||
|
||||
_ExpectedEvent(this.eventName, this.eventData);
|
||||
|
||||
_ExpectedEvent.lintUsageCounts({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.lintUsageCounts, eventData);
|
||||
_ExpectedEvent.commandExecuted({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.commandExecuted, eventData);
|
||||
|
||||
_ExpectedEvent.lintUsageCount({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.lintUsageCount, eventData);
|
||||
|
||||
_ExpectedEvent.notification({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.clientNotification, eventData);
|
||||
|
@ -437,18 +458,21 @@ class _ExpectedEvent {
|
|||
_ExpectedEvent.pluginRequest({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.pluginRequest, eventData);
|
||||
|
||||
_ExpectedEvent.pluginUse({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.pluginUse, eventData);
|
||||
|
||||
_ExpectedEvent.request({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.clientRequest, eventData);
|
||||
|
||||
_ExpectedEvent.session({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.serverSession, eventData);
|
||||
|
||||
_ExpectedEvent.severityAdjustments({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.severityAdjustments, eventData);
|
||||
_ExpectedEvent.severityAdjustment({Map<String, Object?>? eventData})
|
||||
: this(DashEvent.severityAdjustment, eventData);
|
||||
|
||||
/// Compare the expected event with the [actual] event, failing if the actual
|
||||
/// doesn't match the expected.
|
||||
void matches(_Event actual) {
|
||||
void matches(Event actual) {
|
||||
expect(actual.eventName, eventName);
|
||||
final actualData = actual.eventData;
|
||||
final expectedData = eventData;
|
||||
|
@ -456,6 +480,17 @@ class _ExpectedEvent {
|
|||
for (var expectedKey in expectedData.keys) {
|
||||
var actualValue = actualData[expectedKey];
|
||||
var expectedValue = expectedData[expectedKey];
|
||||
if (!(actualValue == expectedValue ||
|
||||
(expectedValue is Matcher &&
|
||||
expectedValue.matches(actualValue, {})))) {
|
||||
var buffer = StringBuffer();
|
||||
buffer.writeln('Incorrect event data.');
|
||||
buffer.writeln('Expected:');
|
||||
writeMap(buffer, expectedData);
|
||||
buffer.writeln('Actual:');
|
||||
writeMap(buffer, actualData);
|
||||
fail(buffer.toString());
|
||||
}
|
||||
expect(actualValue, expectedValue, reason: 'For key $expectedKey');
|
||||
}
|
||||
}
|
||||
|
@ -475,6 +510,15 @@ class _ExpectedEvent {
|
|||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
void writeMap(StringBuffer buffer, Map<String, Object?> map) {
|
||||
for (var entry in map.entries) {
|
||||
buffer.write(' ');
|
||||
buffer.write(entry.key);
|
||||
buffer.write(': ');
|
||||
buffer.writeln(entry.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A matcher for strings containing positive integer values.
|
||||
|
@ -506,30 +550,22 @@ class _IsPercentiles extends Matcher {
|
|||
}
|
||||
|
||||
/// A matcher for strings containing positive integer values.
|
||||
class _IsStringEncodedPositiveInt extends Matcher {
|
||||
const _IsStringEncodedPositiveInt();
|
||||
class _IsPositiveInt extends Matcher {
|
||||
const _IsPositiveInt();
|
||||
|
||||
@override
|
||||
Description describe(Description description) =>
|
||||
description.add('a string encoded positive integer');
|
||||
description.add('a positive integer');
|
||||
|
||||
@override
|
||||
bool matches(Object? item, Map<Object?, Object?> matchState) {
|
||||
if (item is! String) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
var value = int.parse(item);
|
||||
return value >= 0;
|
||||
} catch (exception) {
|
||||
return false;
|
||||
}
|
||||
return item is int && item >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// An implementation of [Analytics] specialized for testing.
|
||||
class _MockAnalytics implements NoopAnalytics {
|
||||
List<_Event> events = [];
|
||||
List<Event> events = [];
|
||||
|
||||
_MockAnalytics();
|
||||
|
||||
|
@ -568,11 +604,9 @@ class _MockAnalytics implements NoopAnalytics {
|
|||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
|
||||
@override
|
||||
Future<http.Response>? sendEvent(
|
||||
{required DashEvent eventName,
|
||||
Map<String, Object?> eventData = const {}}) {
|
||||
events.add(_Event(eventName, eventData));
|
||||
return null;
|
||||
Future<http.Response>? send(Event event) async {
|
||||
events.add(event);
|
||||
return http.Response('', 200);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue