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

Unified Diff: mojo/public/dart/third_party/test/lib/src/runner/browser/iframe_listener.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: mojo/public/dart/third_party/test/lib/src/runner/browser/iframe_listener.dart
diff --git a/mojo/public/dart/third_party/test/lib/src/runner/browser/iframe_listener.dart b/mojo/public/dart/third_party/test/lib/src/runner/browser/iframe_listener.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9da65771bfd5f7e96f57cf460e821a6db4112af9
--- /dev/null
+++ b/mojo/public/dart/third_party/test/lib/src/runner/browser/iframe_listener.dart
@@ -0,0 +1,182 @@
+// Copyright (c) 2015, the Dart 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 file.
+
+library test.runner.browser.iframe_listener;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:html' hide Metadata;
+
+import '../../backend/declarer.dart';
+import '../../backend/metadata.dart';
+import '../../backend/suite.dart';
+import '../../backend/test.dart';
+import '../../backend/test_platform.dart';
+import '../../util/multi_channel.dart';
+import '../../util/remote_exception.dart';
+import '../../utils.dart';
+
+/// A class that runs tests in a separate iframe.
+///
+/// This indirectly communicates with the test server. It uses `postMessage` to
+/// relay communication through the host page, which has a WebSocket connection
+/// to the test server.
+class IframeListener {
+ /// The test suite to run.
+ final Suite _suite;
+
+ /// Extracts metadata about all the tests in the function returned by
+ /// [getMain] and sends information about them over the `postMessage`
+ /// connection.
+ ///
+ /// The main function is wrapped in a closure so that we can handle it being
+ /// undefined here rather than in the generated code.
+ ///
+ /// Once that's done, this starts listening for commands about which tests to
+ /// run.
+ static Future start(Function getMain()) async {
+ var channel = _postMessageChannel();
+
+ var main;
+ try {
+ main = getMain();
+ } on NoSuchMethodError catch (_) {
+ _sendLoadException(channel, "No top-level main() function defined.");
+ return;
+ }
+
+ if (main is! Function) {
+ _sendLoadException(channel, "Top-level main getter is not a function.");
+ return;
+ } else if (main is! AsyncFunction) {
+ _sendLoadException(channel, "Top-level main() function takes arguments.");
+ return;
+ }
+
+ var declarer;
+ try {
+ declarer = new Declarer();
+ await runZoned(() => new Future.sync(main), zoneValues: {
+ #test.declarer: declarer
+ }, zoneSpecification: new ZoneSpecification(print: (_, __, ___, line) {
+ channel.sink.add({"type": "print", "line": line});
+ }));
+ } catch (error, stackTrace) {
+ channel.sink.add({
+ "type": "error",
+ "error": RemoteException.serialize(error, stackTrace)
+ });
+ return;
+ }
+
+ var url = Uri.parse(window.location.href);
+ var message = JSON.decode(Uri.decodeFull(url.fragment));
+ var metadata = new Metadata.deserialize(message['metadata']);
+ var browser = TestPlatform.find(message['browser']);
+
+ var suite = new Suite(
+ declarer.tests, platform: browser, metadata: metadata);
+ new IframeListener._(suite)._listen(channel);
+
+ return;
+ }
+
+ /// Constructs a [MultiChannel] wrapping the `postMessage` communication with
+ /// the host page.
+ ///
+ /// This [MultiChannel] corresponds to a [MultiChannel] in the server's
+ /// [IframeTest] class.
+ static MultiChannel _postMessageChannel() {
+ var inputController = new StreamController(sync: true);
+ var outputController = new StreamController(sync: true);
+
+ window.onMessage.listen((message) {
+ // A message on the Window can theoretically come from any website. It's
+ // very unlikely that a malicious site would care about hacking someone's
+ // unit tests, let alone be able to find the test server while it's
+ // running, but it's good practice to check the origin anyway.
+ if (message.origin != window.location.origin) return;
+ message.stopPropagation();
+ inputController.add(message.data);
+ });
+
+ outputController.stream.listen((data) {
+ // TODO(nweiz): Stop manually adding href here once issue 22554 is
+ // fixed.
+ window.parent.postMessage({
+ "href": window.location.href,
+ "data": data
+ }, window.location.origin);
+ });
+
+ return new MultiChannel(inputController.stream, outputController.sink);
+ }
+
+ /// Sends a message over [channel] indicating that the tests failed to load.
+ ///
+ /// [message] should describe the failure.
+ static void _sendLoadException(MultiChannel channel, String message) {
+ channel.sink.add({"type": "loadException", "message": message});
+ }
+
+ IframeListener._(this._suite);
+
+ /// Send information about [_suite] across [channel] and start listening for
+ /// commands to run the tests.
+ void _listen(MultiChannel channel) {
+ var tests = [];
+ for (var i = 0; i < _suite.tests.length; i++) {
+ var test = _suite.tests[i];
+ var testChannel = channel.virtualChannel();
+ tests.add({
+ "name": test.name,
+ "metadata": test.metadata.serialize(),
+ "channel": testChannel.id
+ });
+
+ testChannel.stream.listen((message) {
+ assert(message['command'] == 'run');
+ _runTest(test, channel.virtualChannel(message['channel']));
+ });
+ }
+
+ channel.sink.add({
+ "type": "success",
+ "tests": tests
+ });
+ }
+
+ /// Runs [test] and sends the results across [sendPort].
+ void _runTest(Test test, MultiChannel channel) {
+ var liveTest = test.load(_suite);
+
+ channel.stream.listen((message) {
+ assert(message['command'] == 'close');
+ liveTest.close();
+ });
+
+ liveTest.onStateChange.listen((state) {
+ channel.sink.add({
+ "type": "state-change",
+ "status": state.status.name,
+ "result": state.result.name
+ });
+ });
+
+ liveTest.onError.listen((asyncError) {
+ channel.sink.add({
+ "type": "error",
+ "error": RemoteException.serialize(
+ asyncError.error, asyncError.stackTrace)
+ });
+ });
+
+ liveTest.onPrint.listen((line) {
+ print(line);
+ channel.sink.add({"type": "print", "line": line});
+ });
+
+ liveTest.run().then((_) => channel.sink.add({"type": "complete"}));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698