Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: lib/src/runner/remote_listener.dart

Issue 1685363002: Add a platform plugin infrastructure. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
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.
4
5 import 'dart:async';
6 import 'dart:developer';
kevmoo 2016/02/11 19:57:50 unused import
nweiz 2016/02/11 21:29:18 Done.
7
8 import 'package:async/async.dart';
kevmoo 2016/02/11 19:57:50 unused import
nweiz 2016/02/11 21:29:18 Done.
9 import 'package:stream_channel/stream_channel.dart';
10
11 import '../backend/declarer.dart';
12 import '../backend/group.dart';
13 import '../backend/live_test.dart';
14 import '../backend/metadata.dart';
15 import '../backend/operating_system.dart';
16 import '../backend/suite.dart';
17 import '../backend/test.dart';
18 import '../backend/test_platform.dart';
19 import '../util/remote_exception.dart';
20 import '../utils.dart';
21
22 class RemoteListener {
23 /// The test suite to run.
24 final Suite _suite;
25
26 /// The zone to forward prints to, or `null` if prints shouldn't be forwarded.
27 final Zone _printZone;
28
29 /// Extracts metadata about all the tests in the function returned by
30 /// [getMain] and returns a channel that will send information about them.
31 ///
32 /// The main function is wrapped in a closure so that we can handle it being
33 /// undefined here rather than in the generated code.
34 ///
35 /// Once that's done, this starts listening for commands about which tests to
36 /// run.
37 ///
38 /// If [hidePrints] is `true` (the default), calls to `print()` within this
39 /// suite will not be forwarded to the parent zone's print handler. However,
40 /// the caller may want them to be forwarded in (for example) a browser
41 /// context where they'll be visible in the development console.
42 static StreamChannel start(AsyncFunction getMain(), {bool hidePrints: true}) {
43 // This has to be synchronous to work around sdk#25745. Otherwise, there'll
44 // be an asynchronous pause before a syntax error notification is sent,
45 // which will cause the send to fail entirely.
46 var controller = new StreamChannelController(
47 allowForeignErrors: false, sync: true);
48 var channel = new MultiChannel(controller.local);
49
50 var printZone = hidePrints ? null : Zone.current;
51 runZoned(() async {
52 var main;
53 try {
54 main = getMain();
55 } on NoSuchMethodError catch (_) {
56 _sendLoadException(channel, "No top-level main() function defined.");
57 return;
58 } catch (error, stackTrace) {
59 _sendError(channel, error, stackTrace);
60 return;
61 }
62
63 if (main is! Function) {
64 _sendLoadException(channel, "Top-level main getter is not a function.");
65 return;
66 } else if (main is! AsyncFunction) {
67 _sendLoadException(
68 channel, "Top-level main() function takes arguments.");
69 return;
70 }
71
72 var message = await channel.stream.first;
73 var metadata = new Metadata.deserialize(message['metadata']);
74 var declarer = new Declarer(metadata);
75 await declarer.declare(main);
76
77 var os = message['os'] == null
78 ? null
79 : OperatingSystem.find(message['os']);
80 var platform = TestPlatform.find(message['platform']);
81 var suite = new Suite(declarer.build(), platform: platform, os: os);
82 new RemoteListener._(suite, printZone)._listen(channel);
83 }, onError: (error, stackTrace) {
84 _sendError(channel, error, stackTrace);
85 }, zoneSpecification: new ZoneSpecification(print: (_, __, ___, line) {
86 if (printZone != null) printZone.print(line);
87 channel.sink.add({"type": "print", "line": line});
88 }));
89
90 return controller.foreign;
91 }
92
93
94 /// Sends a message over [channel] indicating that the tests failed to load.
95 ///
96 /// [message] should describe the failure.
97 static void _sendLoadException(StreamChannel channel, String message) {
98 channel.sink.add({"type": "loadException", "message": message});
99 }
100
101 /// Sends a message over [channel] indicating an error from user code.
102 static void _sendError(StreamChannel channel, error, StackTrace stackTrace) {
103 channel.sink.add({
104 "type": "error",
105 "error": RemoteException.serialize(error, stackTrace)
106 });
107 }
108
109 RemoteListener._(this._suite, this._printZone);
110
111 /// Send information about [_suite] across [channel] and start listening for
112 /// commands to run the tests.
113 void _listen(MultiChannel channel) {
114 channel.sink.add({
115 "type": "success",
116 "root": _serializeGroup(channel, _suite.group, [])
117 });
118 }
119
120 /// Serializes [group] into a JSON-safe map.
121 ///
122 /// [parents] lists the groups that contain [group].
123 Map _serializeGroup(MultiChannel channel, Group group,
124 Iterable<Group> parents) {
125 parents = parents.toList()..add(group);
126 return {
127 "type": "group",
128 "name": group.name,
129 "metadata": group.metadata.serialize(),
130 "setUpAll": _serializeTest(channel, group.setUpAll, parents),
131 "tearDownAll": _serializeTest(channel, group.tearDownAll, parents),
132 "entries": group.entries.map((entry) {
133 return entry is Group
134 ? _serializeGroup(channel, entry, parents)
135 : _serializeTest(channel, entry, parents);
136 }).toList()
137 };
138 }
139
140 /// Serializes [test] into a JSON-safe map.
141 ///
142 /// [groups] lists the groups that contain [test]. Returns `null` if [test]
143 /// is `null`.
144 Map _serializeTest(MultiChannel channel, Test test, Iterable<Group> groups) {
145 if (test == null) return null;
146
147 var testChannel = channel.virtualChannel();
148 testChannel.stream.listen((message) {
149 assert(message['command'] == 'run');
150 _runLiveTest(
151 test.load(_suite, groups: groups),
152 channel.virtualChannel(message['channel']));
153 });
154
155 return {
156 "type": "test",
157 "name": test.name,
158 "metadata": test.metadata.serialize(),
159 "channel": testChannel.id
160 };
161 }
162
163 /// Runs [liveTest] and sends the results across [channel].
164 void _runLiveTest(LiveTest liveTest, MultiChannel channel) {
165 channel.stream.listen((message) {
166 assert(message['command'] == 'close');
167 liveTest.close();
168 });
169
170 liveTest.onStateChange.listen((state) {
171 channel.sink.add({
172 "type": "state-change",
173 "status": state.status.name,
174 "result": state.result.name
175 });
176 });
177
178 liveTest.onError.listen((asyncError) {
179 channel.sink.add({
180 "type": "error",
181 "error": RemoteException.serialize(
182 asyncError.error, asyncError.stackTrace)
183 });
184 });
185
186 liveTest.onPrint.listen((line) {
187 if (_printZone != null) _printZone.print(line);
188 channel.sink.add({"type": "print", "line": line});
189 });
190
191 liveTest.run().then((_) => channel.sink.add({"type": "complete"}));
192 }
193 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698