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

Side by Side Diff: tests/fletch_tests/fletch_test_suite.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments 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) 2015, the Dartino 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.md file.
4
5 /// Helper program for running unit tests in warmed-up Dart VMs.
6 ///
7 /// This program listens for JSON encoded messages on stdin (one message per
8 /// line) and prints out messages in response (also in JSON, one per line).
9 ///
10 /// Messages are defined in 'message.dart'.
11 library fletch_tests.fletch_test_suite;
12
13 import 'dart:core' hide print;
14
15 import 'dart:io';
16
17 import 'dart:convert' show
18 JSON,
19 LineSplitter,
20 UTF8;
21
22 import 'dart:async' show
23 Completer,
24 Future,
25 Stream,
26 StreamIterator,
27 Zone,
28 ZoneSpecification;
29
30 import 'dart:isolate';
31
32 import 'package:fletchc/src/zone_helper.dart' show
33 runGuarded;
34
35 import 'package:fletchc/src/hub/hub_main.dart' show
36 IsolatePool,
37 ManagedIsolate;
38
39 import 'package:fletchc/src/worker/developer.dart' show
40 configFileUri;
41
42 import 'package:fletchc/src/console_print.dart' show
43 printToConsole;
44
45 import 'messages.dart' show
46 Info,
47 InternalErrorMessage,
48 ListTests,
49 ListTestsReply,
50 Message,
51 NamedMessage,
52 RunTest,
53 TestFailed,
54 TestPassed,
55 TestStdoutLine,
56 TimedOut,
57 messageTransformer;
58
59 import 'all_tests.dart' show
60 NoArgFuture,
61 TESTS;
62
63 // TODO(ahe): Should be: "@@@STEP_FAILURE@@@".
64 const String BUILDBOT_MARKER = "@@@STEP_WARNINGS@@@";
65
66 Map<String, NoArgFuture> expandedTests;
67
68 Sink<Message> messageSink;
69
70 main() async {
71 int port = const int.fromEnvironment("test.fletch_test_suite.port");
72 Socket socket = await Socket.connect(InternetAddress.LOOPBACK_IP_V4, port);
73 messageSink = new SocketSink(socket);
74 IsolatePool pool = new IsolatePool(isolateMain);
75 Set<ManagedIsolate> isolates = new Set<ManagedIsolate>();
76 Map<String, RunningTest> runningTests = <String, RunningTest>{};
77 try {
78 Stream<Message> messages = utf8Lines(socket).transform(messageTransformer);
79 await for (Message message in messages) {
80 if (message is TimedOut) {
81 handleTimeout(message, runningTests);
82 continue;
83 }
84 ManagedIsolate isolate = await pool.getIsolate();
85 isolates.add(isolate);
86 runInIsolate(
87 isolate.beginSession(), isolate, message, runningTests);
88 }
89 } catch (error, stackTrace) {
90 new InternalErrorMessage('$error', '$stackTrace').addTo(socket);
91 }
92 for (ManagedIsolate isolate in isolates) {
93 isolate.port.send(null);
94 }
95 await socket.close();
96 }
97
98 class RunningTest {
99 final cancelable;
100 final isolate;
101 RunningTest(this.cancelable, this.isolate);
102
103 void kill() {
104 cancelable.cancel();
105 isolate.kill();
106 }
107 }
108
109 void handleTimeout(TimedOut message, Map<String, RunningTest> runningTests) {
110 RunningTest test = runningTests.remove(message.name);
111 if (test != null) {
112 test.kill();
113 messageSink.add(message);
114 } else {
115 // This can happen for two reasons:
116 // 1. There's a bug, and test.dart will hang.
117 // 2. The test terminated just about the same time that test.dart decided
118 // it had timed out.
119 // Case 2 is unlikely, as tests aren't normally supposed to run for too
120 // long. Hopefully, case 1 is unlikely, but this message is helpful if
121 // test.dart hangs.
122 print("\nWarning: Unable to kill ${message.name}");
123 }
124 }
125
126 void runInIsolate(
127 ReceivePort port,
128 ManagedIsolate isolate,
129 Message message,
130 Map<String, RunningTest> runningTests) {
131 StreamIterator iterator = new StreamIterator(port);
132 String name = message is NamedMessage ? message.name : null;
133
134 if (name != null) {
135 runningTests[name] = new RunningTest(iterator, isolate);
136 }
137
138 // The rest of this function is executed without "await" as we want tests to
139 // run in parallel on multiple isolates.
140 new Future<Null>(() async {
141 bool hasNext = await iterator.moveNext();
142 if (!hasNext && name != null) {
143 // Timed out.
144 assert(runningTests[name] == null);
145 return null;
146 }
147 assert(hasNext);
148 SendPort sendPort = iterator.current;
149 sendPort.send(message);
150
151 hasNext = await iterator.moveNext();
152 if (!hasNext && name != null) {
153 // Timed out.
154 assert(runningTests[name] == null);
155 return null;
156 }
157 assert(hasNext);
158 do {
159 if (iterator.current == null) {
160 iterator.cancel();
161 continue;
162 }
163 messageSink.add(iterator.current);
164 } while (await iterator.moveNext());
165 runningTests.remove(name);
166 isolate.endSession();
167 }).catchError((error, stackTrace) {
168 messageSink.add(new InternalErrorMessage('$error', '$stackTrace'));
169 });
170 }
171
172 /* void */ isolateMain(SendPort port) async {
173 expandedTests = await expandTests(TESTS);
174 ReceivePort receivePort = new ReceivePort();
175 port.send(receivePort.sendPort);
176 port = null;
177 await for (SendPort port in receivePort) {
178 if (port == null) {
179 receivePort.close();
180 break;
181 }
182 ReceivePort clientPort = new ReceivePort();
183 port.send(clientPort.sendPort);
184 handleClient(port, clientPort);
185 }
186 }
187
188 Future<Null> handleClient(SendPort sendPort, ReceivePort receivePort) async {
189 messageSink = new PortSink(sendPort);
190 Message message = await receivePort.first;
191 Message reply;
192 if (message is RunTest) {
193 String name = message.name;
194 reply = await runTest(name, expandedTests[name]);
195 } else if (message is ListTests) {
196 reply = new ListTestsReply(expandedTests.keys.toList());
197 } else {
198 reply =
199 new InternalErrorMessage("Unhandled message: ${message.type}", null);
200 }
201 sendPort.send(reply);
202 sendPort.send(null); // Ask the main isolate to stop listening.
203 receivePort.close();
204 messageSink = null;
205 }
206
207 Future<Message> runTest(String name, NoArgFuture test) async {
208 Directory tmpdir;
209
210 printLineOnStdout(String line) {
211 if (messageSink != null) {
212 messageSink.add(new TestStdoutLine(name, line));
213 } else {
214 stdout.writeln(line);
215 }
216 }
217
218 Future setupGlobalStateForTesting() async {
219 tmpdir = await Directory.systemTemp.createTemp("fletch_test_home");
220 configFileUri = tmpdir.uri.resolve('.fletch');
221 printToConsole = printLineOnStdout;
222 }
223
224 Future resetGlobalStateAfterTesting() async {
225 try {
226 await tmpdir.delete(recursive: true);
227 } on FileSystemException catch (e) {
228 printToConsole('Error when deleting $tmpdir: $e');
229 }
230 printToConsole = Zone.ROOT.print;
231 }
232
233 if (test == null) {
234 throw "No such test: $name";
235 }
236 await setupGlobalStateForTesting();
237 try {
238 await runGuarded(
239 test,
240 printLineOnStdout: printLineOnStdout,
241 handleLateError: (error, StackTrace stackTrace) {
242 if (name == 'zone_helper/testAlwaysFails') {
243 // This test always report a late error (to ensure the framework
244 // handles it).
245 return;
246 }
247 print(
248 // Print one string to avoid interleaved messages.
249 "\n$BUILDBOT_MARKER\nLate error in test '$name':\n"
250 "$error\n$stackTrace");
251 });
252 } catch (error, stackTrace) {
253 return new TestFailed(name, '$error', '$stackTrace');
254 } finally {
255 await resetGlobalStateAfterTesting();
256 }
257 return new TestPassed(name);
258 }
259
260 Stream<String> utf8Lines(Stream<List<int>> stream) {
261 return stream.transform(UTF8.decoder).transform(new LineSplitter());
262 }
263
264 void print(object) {
265 if (messageSink != null) {
266 messageSink.add(new Info('$object'));
267 } else {
268 stdout.writeln('$object');
269 }
270 }
271
272 Future<Map<String, NoArgFuture>> expandTests(Map<String, NoArgFuture> tests) {
273 Map<String, NoArgFuture> result = <String, NoArgFuture>{};
274 var futures = [];
275 tests.forEach((String name, NoArgFuture f) {
276 if (name.endsWith("/*")) {
277 var future = f().then((Map<String, NoArgFuture> tests) {
278 tests.forEach((String name, NoArgFuture f) {
279 result[name] = f;
280 });
281 });
282 futures.add(future);
283 } else {
284 result[name] = f;
285 }
286 });
287 return Future.wait(futures).then((_) => result);
288 }
289
290 class SocketSink implements Sink<Message> {
291 final Socket socket;
292
293 SocketSink(this.socket);
294
295 void add(Message message) {
296 message.addTo(socket);
297 }
298
299 void close() {
300 throw "not supported";
301 }
302 }
303
304 class PortSink implements Sink<Message> {
305 final SendPort port;
306
307 PortSink(this.port);
308
309 void add(Message message) {
310 port.send(message);
311 }
312
313 void close() {
314 throw "not supported";
315 }
316 }
OLDNEW
« no previous file with comments | « tests/fletch_tests/file_with_compile_time_error.dart ('k') | tests/fletch_tests/fletch_tests.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698