| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:convert'; | 6 import 'dart:convert'; |
| 7 | 7 |
| 8 import '../../backend/group.dart'; | 8 import '../../backend/group.dart'; |
| 9 import '../../backend/live_test.dart'; | 9 import '../../backend/live_test.dart'; |
| 10 import '../../backend/metadata.dart'; | 10 import '../../backend/metadata.dart'; |
| 11 import '../../backend/suite.dart'; |
| 11 import '../../frontend/expect.dart'; | 12 import '../../frontend/expect.dart'; |
| 12 import '../../utils.dart'; | 13 import '../../utils.dart'; |
| 13 import '../engine.dart'; | 14 import '../engine.dart'; |
| 14 import '../load_suite.dart'; | 15 import '../load_suite.dart'; |
| 15 import '../reporter.dart'; | 16 import '../reporter.dart'; |
| 16 import '../version.dart'; | 17 import '../version.dart'; |
| 17 | 18 |
| 18 /// A reporter that prints machine-readable JSON-formatted test results. | 19 /// A reporter that prints machine-readable JSON-formatted test results. |
| 19 class JsonReporter implements Reporter { | 20 class JsonReporter implements Reporter { |
| 20 /// Whether to use verbose stack traces. | 21 /// Whether to use verbose stack traces. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 34 | 35 |
| 35 /// Whether the reporter is paused. | 36 /// Whether the reporter is paused. |
| 36 var _paused = false; | 37 var _paused = false; |
| 37 | 38 |
| 38 /// The set of all subscriptions to various streams. | 39 /// The set of all subscriptions to various streams. |
| 39 final _subscriptions = new Set<StreamSubscription>(); | 40 final _subscriptions = new Set<StreamSubscription>(); |
| 40 | 41 |
| 41 /// An expando that associates unique IDs with [LiveTest]s. | 42 /// An expando that associates unique IDs with [LiveTest]s. |
| 42 final _liveTestIDs = new Map<LiveTest, int>(); | 43 final _liveTestIDs = new Map<LiveTest, int>(); |
| 43 | 44 |
| 45 /// An expando that associates unique IDs with [Suite]s. |
| 46 final _suiteIDs = new Map<Suite, int>(); |
| 47 |
| 44 /// An expando that associates unique IDs with [Group]s. | 48 /// An expando that associates unique IDs with [Group]s. |
| 45 final _groupIDs = new Map<Group, int>(); | 49 final _groupIDs = new Map<Group, int>(); |
| 46 | 50 |
| 47 /// The next ID to associate with a [LiveTest]. | 51 /// The next ID to associate with a [LiveTest]. |
| 48 var _nextID = 0; | 52 var _nextID = 0; |
| 49 | 53 |
| 50 /// Watches the tests run by [engine] and prints their results as JSON. | 54 /// Watches the tests run by [engine] and prints their results as JSON. |
| 51 /// | 55 /// |
| 52 /// If [verboseTrace] is `true`, this will print core library frames. | 56 /// If [verboseTrace] is `true`, this will print core library frames. |
| 53 static JsonReporter watch(Engine engine, {bool verboseTrace: false}) { | 57 static JsonReporter watch(Engine engine, {bool verboseTrace: false}) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 _subscriptions.clear(); | 101 _subscriptions.clear(); |
| 98 } | 102 } |
| 99 | 103 |
| 100 /// A callback called when the engine begins running [liveTest]. | 104 /// A callback called when the engine begins running [liveTest]. |
| 101 void _onTestStarted(LiveTest liveTest) { | 105 void _onTestStarted(LiveTest liveTest) { |
| 102 if (!_stopwatchStarted) { | 106 if (!_stopwatchStarted) { |
| 103 _stopwatchStarted = true; | 107 _stopwatchStarted = true; |
| 104 _stopwatch.start(); | 108 _stopwatch.start(); |
| 105 } | 109 } |
| 106 | 110 |
| 111 var suiteID = _idForSuite(liveTest.suite); |
| 112 |
| 107 // Don't emit groups for load suites. They're always empty and they provide | 113 // Don't emit groups for load suites. They're always empty and they provide |
| 108 // unnecessary clutter. | 114 // unnecessary clutter. |
| 109 var groupIDs = liveTest.suite is LoadSuite | 115 var groupIDs = liveTest.suite is LoadSuite |
| 110 ? [] | 116 ? [] |
| 111 : _idsForGroups(liveTest.groups); | 117 : _idsForGroups(liveTest.groups, suiteID); |
| 112 | 118 |
| 113 var id = _nextID++; | 119 var id = _nextID++; |
| 114 _liveTestIDs[liveTest] = id; | 120 _liveTestIDs[liveTest] = id; |
| 115 _emit("testStart", { | 121 _emit("testStart", { |
| 116 "test": { | 122 "test": { |
| 117 "id": id, | 123 "id": id, |
| 118 "name": liveTest.test.name, | 124 "name": liveTest.test.name, |
| 125 "suiteID": suiteID, |
| 119 "groupIDs": groupIDs, | 126 "groupIDs": groupIDs, |
| 120 "metadata": _serializeMetadata(liveTest.test.metadata) | 127 "metadata": _serializeMetadata(liveTest.test.metadata) |
| 121 } | 128 } |
| 122 }); | 129 }); |
| 123 | 130 |
| 124 /// Convert the future to a stream so that the subscription can be paused or | 131 /// Convert the future to a stream so that the subscription can be paused or |
| 125 /// canceled. | 132 /// canceled. |
| 126 _subscriptions.add(liveTest.onComplete.asStream().listen((_) => | 133 _subscriptions.add(liveTest.onComplete.asStream().listen((_) => |
| 127 _onComplete(liveTest))); | 134 _onComplete(liveTest))); |
| 128 | 135 |
| 129 _subscriptions.add(liveTest.onError.listen((error) => | 136 _subscriptions.add(liveTest.onError.listen((error) => |
| 130 _onError(liveTest, error.error, error.stackTrace))); | 137 _onError(liveTest, error.error, error.stackTrace))); |
| 131 | 138 |
| 132 _subscriptions.add(liveTest.onPrint.listen((line) { | 139 _subscriptions.add(liveTest.onPrint.listen((line) { |
| 133 _emit("print", { | 140 _emit("print", { |
| 134 "testID": id, | 141 "testID": id, |
| 135 "message": line | 142 "message": line |
| 136 }); | 143 }); |
| 137 })); | 144 })); |
| 138 } | 145 } |
| 139 | 146 |
| 140 /// Returns a list of the IDs for all the groups in [groups]. | 147 /// Returns an ID for [suite]. |
| 148 /// |
| 149 /// If [suite] doesn't have an ID yet, this assigns one and emits a new event |
| 150 /// for that suite. |
| 151 int _idForSuite(Suite suite) { |
| 152 if (_suiteIDs.containsKey(suite)) return _suiteIDs[suite]; |
| 153 |
| 154 var id = _nextID++; |
| 155 _suiteIDs[suite] = id; |
| 156 |
| 157 // Give the load suite's suite the same ID, because it doesn't have any |
| 158 // different metadata. |
| 159 if (suite is LoadSuite) { |
| 160 suite.suite.then((runnerSuite) { |
| 161 if (runnerSuite != null) _suiteIDs[runnerSuite] = id; |
| 162 }); |
| 163 } |
| 164 |
| 165 _emit("suite", { |
| 166 "suite": { |
| 167 "id": id, |
| 168 "platform": suite.platform?.identifier, |
| 169 "path": suite.path |
| 170 } |
| 171 }); |
| 172 return id; |
| 173 } |
| 174 |
| 175 /// Returns a list of the IDs for all the groups in [groups], which are |
| 176 /// contained in the suite identified by [suiteID]. |
| 141 /// | 177 /// |
| 142 /// If a group doesn't have an ID yet, this assigns one and emits a new event | 178 /// If a group doesn't have an ID yet, this assigns one and emits a new event |
| 143 /// for that group. | 179 /// for that group. |
| 144 List<int> _idsForGroups(Iterable<Group> groups) { | 180 List<int> _idsForGroups(Iterable<Group> groups, int suiteID) { |
| 145 var parentID; | 181 var parentID; |
| 146 return groups.map((group) { | 182 return groups.map((group) { |
| 147 if (_groupIDs.containsKey(group)) { | 183 if (_groupIDs.containsKey(group)) { |
| 148 parentID = _groupIDs[group]; | 184 parentID = _groupIDs[group]; |
| 149 return parentID; | 185 return parentID; |
| 150 } | 186 } |
| 151 | 187 |
| 152 var id = _nextID++; | 188 var id = _nextID++; |
| 153 _groupIDs[group] = id; | 189 _groupIDs[group] = id; |
| 154 | 190 |
| 155 _emit("group", { | 191 _emit("group", { |
| 156 "group": { | 192 "group": { |
| 157 "id": id, | 193 "id": id, |
| 194 "suiteID": suiteID, |
| 158 "parentID": parentID, | 195 "parentID": parentID, |
| 159 "name": group.name, | 196 "name": group.name, |
| 160 "metadata": _serializeMetadata(group.metadata) | 197 "metadata": _serializeMetadata(group.metadata) |
| 161 } | 198 } |
| 162 }); | 199 }); |
| 163 parentID = id; | 200 parentID = id; |
| 164 return id; | 201 return id; |
| 165 }).toList(); | 202 }).toList(); |
| 166 } | 203 } |
| 167 | 204 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 _emit("done", {"success": success}); | 236 _emit("done", {"success": success}); |
| 200 } | 237 } |
| 201 | 238 |
| 202 /// Emits an event with the given type and attributes. | 239 /// Emits an event with the given type and attributes. |
| 203 void _emit(String type, Map attributes) { | 240 void _emit(String type, Map attributes) { |
| 204 attributes["type"] = type; | 241 attributes["type"] = type; |
| 205 attributes["time"] = _stopwatch.elapsed.inMilliseconds; | 242 attributes["time"] = _stopwatch.elapsed.inMilliseconds; |
| 206 print(JSON.encode(attributes)); | 243 print(JSON.encode(attributes)); |
| 207 } | 244 } |
| 208 } | 245 } |
| OLD | NEW |