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 |