Chromium Code Reviews| 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 library test.runner.reporter.json; | 5 library test.runner.reporter.json; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 | 9 |
| 10 import '../../backend/live_test.dart'; | 10 import '../../backend/live_test.dart'; |
| 11 import '../../frontend/expect.dart'; | 11 import '../../frontend/expect.dart'; |
| 12 import '../../utils.dart'; | 12 import '../../utils.dart'; |
| 13 import '../engine.dart'; | 13 import '../engine.dart'; |
| 14 import '../load_suite.dart'; | |
|
kevmoo
2015/11/24 05:04:31
missing imports for Group and Metadata
nweiz
2015/11/24 05:07:11
Done.
| |
| 14 import '../reporter.dart'; | 15 import '../reporter.dart'; |
| 15 import '../version.dart'; | 16 import '../version.dart'; |
| 16 | 17 |
| 17 /// A reporter that prints machine-readable JSON-formatted test results. | 18 /// A reporter that prints machine-readable JSON-formatted test results. |
| 18 class JsonReporter implements Reporter { | 19 class JsonReporter implements Reporter { |
| 19 /// Whether to use verbose stack traces. | 20 /// Whether to use verbose stack traces. |
| 20 final bool _verboseTrace; | 21 final bool _verboseTrace; |
| 21 | 22 |
| 22 /// The engine used to run the tests. | 23 /// The engine used to run the tests. |
| 23 final Engine _engine; | 24 final Engine _engine; |
| 24 | 25 |
| 25 /// A stopwatch that tracks the duration of the full run. | 26 /// A stopwatch that tracks the duration of the full run. |
| 26 final _stopwatch = new Stopwatch(); | 27 final _stopwatch = new Stopwatch(); |
| 27 | 28 |
| 28 /// Whether we've started [_stopwatch]. | 29 /// Whether we've started [_stopwatch]. |
| 29 /// | 30 /// |
| 30 /// We can't just use `_stopwatch.isRunning` because the stopwatch is stopped | 31 /// We can't just use `_stopwatch.isRunning` because the stopwatch is stopped |
| 31 /// when the reporter is paused. | 32 /// when the reporter is paused. |
| 32 var _stopwatchStarted = false; | 33 var _stopwatchStarted = false; |
| 33 | 34 |
| 34 /// Whether the reporter is paused. | 35 /// Whether the reporter is paused. |
| 35 var _paused = false; | 36 var _paused = false; |
| 36 | 37 |
| 37 /// The set of all subscriptions to various streams. | 38 /// The set of all subscriptions to various streams. |
| 38 final _subscriptions = new Set<StreamSubscription>(); | 39 final _subscriptions = new Set<StreamSubscription>(); |
| 39 | 40 |
| 40 /// An expando that associates unique IDs with [LiveTest]s. | 41 /// An expando that associates unique IDs with [LiveTest]s. |
| 41 final _ids = new Map<LiveTest, int>(); | 42 final _liveTestIDs = new Map<LiveTest, int>(); |
| 43 | |
| 44 /// An expando that associates unique IDs with [Group]s. | |
| 45 final _groupIDs = new Map<Group, int>(); | |
| 42 | 46 |
| 43 /// The next ID to associate with a [LiveTest]. | 47 /// The next ID to associate with a [LiveTest]. |
| 44 var _nextID = 0; | 48 var _nextID = 0; |
| 45 | 49 |
| 46 /// Watches the tests run by [engine] and prints their results as JSON. | 50 /// Watches the tests run by [engine] and prints their results as JSON. |
| 47 /// | 51 /// |
| 48 /// If [verboseTrace] is `true`, this will print core library frames. | 52 /// If [verboseTrace] is `true`, this will print core library frames. |
| 49 static JsonReporter watch(Engine engine, {bool verboseTrace: false}) { | 53 static JsonReporter watch(Engine engine, {bool verboseTrace: false}) { |
| 50 return new JsonReporter._(engine, verboseTrace: verboseTrace); | 54 return new JsonReporter._(engine, verboseTrace: verboseTrace); |
| 51 } | 55 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 93 _subscriptions.clear(); | 97 _subscriptions.clear(); |
| 94 } | 98 } |
| 95 | 99 |
| 96 /// A callback called when the engine begins running [liveTest]. | 100 /// A callback called when the engine begins running [liveTest]. |
| 97 void _onTestStarted(LiveTest liveTest) { | 101 void _onTestStarted(LiveTest liveTest) { |
| 98 if (!_stopwatchStarted) { | 102 if (!_stopwatchStarted) { |
| 99 _stopwatchStarted = true; | 103 _stopwatchStarted = true; |
| 100 _stopwatch.start(); | 104 _stopwatch.start(); |
| 101 } | 105 } |
| 102 | 106 |
| 107 // Don't emit groups for load suites. They're always empty and they provide | |
| 108 // unnecessary clutter. | |
| 109 var groupIDs = liveTest.suite is LoadSuite | |
| 110 ? [] | |
| 111 : _idsForGroups(liveTest.groups); | |
| 112 | |
| 103 var id = _nextID++; | 113 var id = _nextID++; |
| 104 _ids[liveTest] = id; | 114 _liveTestIDs[liveTest] = id; |
| 105 _emit("testStart", { | 115 _emit("testStart", { |
| 106 "test": { | 116 "test": { |
| 107 "id": id, | 117 "id": id, |
| 108 "name": liveTest.test.name, | 118 "name": liveTest.test.name, |
| 109 "metadata": { | 119 "groupIDs": groupIDs, |
| 110 "skip": liveTest.test.metadata.skip, | 120 "metadata": _serializeMetadata(liveTest.test.metadata) |
| 111 "skipReason": liveTest.test.metadata.skipReason | |
| 112 } | |
| 113 } | 121 } |
| 114 }); | 122 }); |
| 115 | 123 |
| 116 /// Convert the future to a stream so that the subscription can be paused or | 124 /// Convert the future to a stream so that the subscription can be paused or |
| 117 /// canceled. | 125 /// canceled. |
| 118 _subscriptions.add(liveTest.onComplete.asStream().listen((_) => | 126 _subscriptions.add(liveTest.onComplete.asStream().listen((_) => |
| 119 _onComplete(liveTest))); | 127 _onComplete(liveTest))); |
| 120 | 128 |
| 121 _subscriptions.add(liveTest.onError.listen((error) => | 129 _subscriptions.add(liveTest.onError.listen((error) => |
| 122 _onError(liveTest, error.error, error.stackTrace))); | 130 _onError(liveTest, error.error, error.stackTrace))); |
| 123 | 131 |
| 124 _subscriptions.add(liveTest.onPrint.listen((line) { | 132 _subscriptions.add(liveTest.onPrint.listen((line) { |
| 125 _emit("print", { | 133 _emit("print", { |
| 126 "testID": id, | 134 "testID": id, |
| 127 "message": line | 135 "message": line |
| 128 }); | 136 }); |
| 129 })); | 137 })); |
| 130 } | 138 } |
| 131 | 139 |
| 140 /// Returns a list of the IDs for all the groups in [groups]. | |
| 141 /// | |
| 142 /// If a group doesn't have an ID yet, this assigns one and emits a new event | |
| 143 /// for that group. | |
| 144 List<int> _idsForGroups(Iterable<Group> groups) { | |
| 145 var parentID; | |
| 146 return groups.map((group) { | |
| 147 if (_groupIDs.containsKey(group)) { | |
| 148 parentID = _groupIDs[group]; | |
| 149 return parentID; | |
| 150 } | |
| 151 | |
| 152 var id = _nextID++; | |
| 153 _groupIDs[group] = id; | |
| 154 | |
| 155 _emit("group", { | |
| 156 "group": { | |
| 157 "id": id, | |
| 158 "parentID": parentID, | |
| 159 "name": group.name, | |
| 160 "metadata": _serializeMetadata(group.metadata) | |
| 161 } | |
| 162 }); | |
| 163 parentID = id; | |
| 164 return id; | |
| 165 }).toList(); | |
| 166 } | |
| 167 | |
| 168 /// Serializes [metadata] into a JSON-protocol-compatible map. | |
| 169 Map _serializeMetadata(Metadata metadata) => | |
| 170 {"skip": metadata.skip, "skipReason": metadata.skipReason}; | |
| 171 | |
| 132 /// A callback called when [liveTest] finishes running. | 172 /// A callback called when [liveTest] finishes running. |
| 133 void _onComplete(LiveTest liveTest) { | 173 void _onComplete(LiveTest liveTest) { |
| 134 _emit("testDone", { | 174 _emit("testDone", { |
| 135 "testID": _ids[liveTest], | 175 "testID": _liveTestIDs[liveTest], |
| 136 "result": liveTest.state.result.toString(), | 176 "result": liveTest.state.result.toString(), |
| 137 "hidden": !_engine.liveTests.contains(liveTest) | 177 "hidden": !_engine.liveTests.contains(liveTest) |
| 138 }); | 178 }); |
| 139 } | 179 } |
| 140 | 180 |
| 141 /// A callback called when [liveTest] throws [error]. | 181 /// A callback called when [liveTest] throws [error]. |
| 142 void _onError(LiveTest liveTest, error, StackTrace stackTrace) { | 182 void _onError(LiveTest liveTest, error, StackTrace stackTrace) { |
| 143 _emit("error", { | 183 _emit("error", { |
| 144 "testID": _ids[liveTest], | 184 "testID": _liveTestIDs[liveTest], |
| 145 "error": error.toString(), | 185 "error": error.toString(), |
| 146 "stackTrace": terseChain(stackTrace, verbose: _verboseTrace).toString(), | 186 "stackTrace": terseChain(stackTrace, verbose: _verboseTrace).toString(), |
| 147 "isFailure": error is TestFailure | 187 "isFailure": error is TestFailure |
| 148 }); | 188 }); |
| 149 } | 189 } |
| 150 | 190 |
| 151 /// A callback called when the engine is finished running tests. | 191 /// A callback called when the engine is finished running tests. |
| 152 /// | 192 /// |
| 153 /// [success] will be `true` if all tests passed, `false` if some tests | 193 /// [success] will be `true` if all tests passed, `false` if some tests |
| 154 /// failed, and `null` if the engine was closed prematurely. | 194 /// failed, and `null` if the engine was closed prematurely. |
| 155 void _onDone(bool success) { | 195 void _onDone(bool success) { |
| 156 cancel(); | 196 cancel(); |
| 157 _stopwatch.stop(); | 197 _stopwatch.stop(); |
| 158 | 198 |
| 159 _emit("done", {"success": success}); | 199 _emit("done", {"success": success}); |
| 160 } | 200 } |
| 161 | 201 |
| 162 /// Emits an event with the given type and attributes. | 202 /// Emits an event with the given type and attributes. |
| 163 void _emit(String type, Map attributes) { | 203 void _emit(String type, Map attributes) { |
| 164 attributes["type"] = type; | 204 attributes["type"] = type; |
| 165 attributes["time"] = _stopwatch.elapsed.inMilliseconds; | 205 attributes["time"] = _stopwatch.elapsed.inMilliseconds; |
| 166 print(JSON.encode(attributes)); | 206 print(JSON.encode(attributes)); |
| 167 } | 207 } |
| 168 } | 208 } |
| OLD | NEW |