Index: tests/fletch_tests/fletch_test_suite.dart |
diff --git a/tests/fletch_tests/fletch_test_suite.dart b/tests/fletch_tests/fletch_test_suite.dart |
deleted file mode 100644 |
index ed341fc7d6240be8b5b8bb9e4d24b6d50a3d2e4e..0000000000000000000000000000000000000000 |
--- a/tests/fletch_tests/fletch_test_suite.dart |
+++ /dev/null |
@@ -1,316 +0,0 @@ |
-// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE.md file. |
- |
-/// Helper program for running unit tests in warmed-up Dart VMs. |
-/// |
-/// This program listens for JSON encoded messages on stdin (one message per |
-/// line) and prints out messages in response (also in JSON, one per line). |
-/// |
-/// Messages are defined in 'message.dart'. |
-library fletch_tests.fletch_test_suite; |
- |
-import 'dart:core' hide print; |
- |
-import 'dart:io'; |
- |
-import 'dart:convert' show |
- JSON, |
- LineSplitter, |
- UTF8; |
- |
-import 'dart:async' show |
- Completer, |
- Future, |
- Stream, |
- StreamIterator, |
- Zone, |
- ZoneSpecification; |
- |
-import 'dart:isolate'; |
- |
-import 'package:fletchc/src/zone_helper.dart' show |
- runGuarded; |
- |
-import 'package:fletchc/src/hub/hub_main.dart' show |
- IsolatePool, |
- ManagedIsolate; |
- |
-import 'package:fletchc/src/worker/developer.dart' show |
- configFileUri; |
- |
-import 'package:fletchc/src/console_print.dart' show |
- printToConsole; |
- |
-import 'messages.dart' show |
- Info, |
- InternalErrorMessage, |
- ListTests, |
- ListTestsReply, |
- Message, |
- NamedMessage, |
- RunTest, |
- TestFailed, |
- TestPassed, |
- TestStdoutLine, |
- TimedOut, |
- messageTransformer; |
- |
-import 'all_tests.dart' show |
- NoArgFuture, |
- TESTS; |
- |
-// TODO(ahe): Should be: "@@@STEP_FAILURE@@@". |
-const String BUILDBOT_MARKER = "@@@STEP_WARNINGS@@@"; |
- |
-Map<String, NoArgFuture> expandedTests; |
- |
-Sink<Message> messageSink; |
- |
-main() async { |
- int port = const int.fromEnvironment("test.fletch_test_suite.port"); |
- Socket socket = await Socket.connect(InternetAddress.LOOPBACK_IP_V4, port); |
- messageSink = new SocketSink(socket); |
- IsolatePool pool = new IsolatePool(isolateMain); |
- Set<ManagedIsolate> isolates = new Set<ManagedIsolate>(); |
- Map<String, RunningTest> runningTests = <String, RunningTest>{}; |
- try { |
- Stream<Message> messages = utf8Lines(socket).transform(messageTransformer); |
- await for (Message message in messages) { |
- if (message is TimedOut) { |
- handleTimeout(message, runningTests); |
- continue; |
- } |
- ManagedIsolate isolate = await pool.getIsolate(); |
- isolates.add(isolate); |
- runInIsolate( |
- isolate.beginSession(), isolate, message, runningTests); |
- } |
- } catch (error, stackTrace) { |
- new InternalErrorMessage('$error', '$stackTrace').addTo(socket); |
- } |
- for (ManagedIsolate isolate in isolates) { |
- isolate.port.send(null); |
- } |
- await socket.close(); |
-} |
- |
-class RunningTest { |
- final cancelable; |
- final isolate; |
- RunningTest(this.cancelable, this.isolate); |
- |
- void kill() { |
- cancelable.cancel(); |
- isolate.kill(); |
- } |
-} |
- |
-void handleTimeout(TimedOut message, Map<String, RunningTest> runningTests) { |
- RunningTest test = runningTests.remove(message.name); |
- if (test != null) { |
- test.kill(); |
- messageSink.add(message); |
- } else { |
- // This can happen for two reasons: |
- // 1. There's a bug, and test.dart will hang. |
- // 2. The test terminated just about the same time that test.dart decided |
- // it had timed out. |
- // Case 2 is unlikely, as tests aren't normally supposed to run for too |
- // long. Hopefully, case 1 is unlikely, but this message is helpful if |
- // test.dart hangs. |
- print("\nWarning: Unable to kill ${message.name}"); |
- } |
-} |
- |
-void runInIsolate( |
- ReceivePort port, |
- ManagedIsolate isolate, |
- Message message, |
- Map<String, RunningTest> runningTests) { |
- StreamIterator iterator = new StreamIterator(port); |
- String name = message is NamedMessage ? message.name : null; |
- |
- if (name != null) { |
- runningTests[name] = new RunningTest(iterator, isolate); |
- } |
- |
- // The rest of this function is executed without "await" as we want tests to |
- // run in parallel on multiple isolates. |
- new Future<Null>(() async { |
- bool hasNext = await iterator.moveNext(); |
- if (!hasNext && name != null) { |
- // Timed out. |
- assert(runningTests[name] == null); |
- return null; |
- } |
- assert(hasNext); |
- SendPort sendPort = iterator.current; |
- sendPort.send(message); |
- |
- hasNext = await iterator.moveNext(); |
- if (!hasNext && name != null) { |
- // Timed out. |
- assert(runningTests[name] == null); |
- return null; |
- } |
- assert(hasNext); |
- do { |
- if (iterator.current == null) { |
- iterator.cancel(); |
- continue; |
- } |
- messageSink.add(iterator.current); |
- } while (await iterator.moveNext()); |
- runningTests.remove(name); |
- isolate.endSession(); |
- }).catchError((error, stackTrace) { |
- messageSink.add(new InternalErrorMessage('$error', '$stackTrace')); |
- }); |
-} |
- |
-/* void */ isolateMain(SendPort port) async { |
- expandedTests = await expandTests(TESTS); |
- ReceivePort receivePort = new ReceivePort(); |
- port.send(receivePort.sendPort); |
- port = null; |
- await for (SendPort port in receivePort) { |
- if (port == null) { |
- receivePort.close(); |
- break; |
- } |
- ReceivePort clientPort = new ReceivePort(); |
- port.send(clientPort.sendPort); |
- handleClient(port, clientPort); |
- } |
-} |
- |
-Future<Null> handleClient(SendPort sendPort, ReceivePort receivePort) async { |
- messageSink = new PortSink(sendPort); |
- Message message = await receivePort.first; |
- Message reply; |
- if (message is RunTest) { |
- String name = message.name; |
- reply = await runTest(name, expandedTests[name]); |
- } else if (message is ListTests) { |
- reply = new ListTestsReply(expandedTests.keys.toList()); |
- } else { |
- reply = |
- new InternalErrorMessage("Unhandled message: ${message.type}", null); |
- } |
- sendPort.send(reply); |
- sendPort.send(null); // Ask the main isolate to stop listening. |
- receivePort.close(); |
- messageSink = null; |
-} |
- |
-Future<Message> runTest(String name, NoArgFuture test) async { |
- Directory tmpdir; |
- |
- printLineOnStdout(String line) { |
- if (messageSink != null) { |
- messageSink.add(new TestStdoutLine(name, line)); |
- } else { |
- stdout.writeln(line); |
- } |
- } |
- |
- Future setupGlobalStateForTesting() async { |
- tmpdir = await Directory.systemTemp.createTemp("fletch_test_home"); |
- configFileUri = tmpdir.uri.resolve('.fletch'); |
- printToConsole = printLineOnStdout; |
- } |
- |
- Future resetGlobalStateAfterTesting() async { |
- try { |
- await tmpdir.delete(recursive: true); |
- } on FileSystemException catch (e) { |
- printToConsole('Error when deleting $tmpdir: $e'); |
- } |
- printToConsole = Zone.ROOT.print; |
- } |
- |
- if (test == null) { |
- throw "No such test: $name"; |
- } |
- await setupGlobalStateForTesting(); |
- try { |
- await runGuarded( |
- test, |
- printLineOnStdout: printLineOnStdout, |
- handleLateError: (error, StackTrace stackTrace) { |
- if (name == 'zone_helper/testAlwaysFails') { |
- // This test always report a late error (to ensure the framework |
- // handles it). |
- return; |
- } |
- print( |
- // Print one string to avoid interleaved messages. |
- "\n$BUILDBOT_MARKER\nLate error in test '$name':\n" |
- "$error\n$stackTrace"); |
- }); |
- } catch (error, stackTrace) { |
- return new TestFailed(name, '$error', '$stackTrace'); |
- } finally { |
- await resetGlobalStateAfterTesting(); |
- } |
- return new TestPassed(name); |
-} |
- |
-Stream<String> utf8Lines(Stream<List<int>> stream) { |
- return stream.transform(UTF8.decoder).transform(new LineSplitter()); |
-} |
- |
-void print(object) { |
- if (messageSink != null) { |
- messageSink.add(new Info('$object')); |
- } else { |
- stdout.writeln('$object'); |
- } |
-} |
- |
-Future<Map<String, NoArgFuture>> expandTests(Map<String, NoArgFuture> tests) { |
- Map<String, NoArgFuture> result = <String, NoArgFuture>{}; |
- var futures = []; |
- tests.forEach((String name, NoArgFuture f) { |
- if (name.endsWith("/*")) { |
- var future = f().then((Map<String, NoArgFuture> tests) { |
- tests.forEach((String name, NoArgFuture f) { |
- result[name] = f; |
- }); |
- }); |
- futures.add(future); |
- } else { |
- result[name] = f; |
- } |
- }); |
- return Future.wait(futures).then((_) => result); |
-} |
- |
-class SocketSink implements Sink<Message> { |
- final Socket socket; |
- |
- SocketSink(this.socket); |
- |
- void add(Message message) { |
- message.addTo(socket); |
- } |
- |
- void close() { |
- throw "not supported"; |
- } |
-} |
- |
-class PortSink implements Sink<Message> { |
- final SendPort port; |
- |
- PortSink(this.port); |
- |
- void add(Message message) { |
- port.send(message); |
- } |
- |
- void close() { |
- throw "not supported"; |
- } |
-} |