| Index: lib/src/runner/loader.dart
|
| diff --git a/lib/src/runner/loader.dart b/lib/src/runner/loader.dart
|
| index b7594db40536b4bc904c9b47078422a91d145e44..6e68ee20aa1ce8c96dec24a9df0be1f2d75fc512 100644
|
| --- a/lib/src/runner/loader.dart
|
| +++ b/lib/src/runner/loader.dart
|
| @@ -4,30 +4,25 @@
|
|
|
| import 'dart:async';
|
| import 'dart:io';
|
| -import 'dart:isolate';
|
|
|
| import 'package:analyzer/analyzer.dart' hide Configuration;
|
| import 'package:async/async.dart';
|
| import 'package:path/path.dart' as p;
|
| -import 'package:stack_trace/stack_trace.dart';
|
|
|
| import '../backend/group.dart';
|
| import '../backend/metadata.dart';
|
| -import '../backend/test.dart';
|
| import '../backend/test_platform.dart';
|
| -import '../util/dart.dart' as dart;
|
| import '../util/io.dart';
|
| -import '../util/remote_exception.dart';
|
| import '../utils.dart';
|
| import 'browser/server.dart';
|
| import 'configuration.dart';
|
| -import 'hack_load_vm_file_hook.dart';
|
| import 'load_exception.dart';
|
| import 'load_suite.dart';
|
| import 'parse_metadata.dart';
|
| +import 'plugin/environment.dart';
|
| +import 'plugin/platform.dart';
|
| import 'runner_suite.dart';
|
| -import 'vm/environment.dart';
|
| -import 'vm/isolate_test.dart';
|
| +import 'vm/platform.dart';
|
|
|
| /// A class for finding test files and loading them into a runnable form.
|
| class Loader {
|
| @@ -40,6 +35,11 @@ class Loader {
|
| /// All suites that have been created by the loader.
|
| final _suites = new Set<RunnerSuite>();
|
|
|
| + /// Plugins for loading test suites for various platforms.
|
| + ///
|
| + /// This includes the built-in [VMPlatform] plugin.
|
| + final _platformPlugins = <TestPlatform, PlatformPlugin>{};
|
| +
|
| /// The server that serves browser test pages.
|
| ///
|
| /// This is lazily initialized the first time it's accessed.
|
| @@ -58,7 +58,19 @@ class Loader {
|
| /// [root] is the root directory that will be served for browser tests. It
|
| /// defaults to the working directory.
|
| Loader(this._config, {String root})
|
| - : _root = root == null ? p.current : root;
|
| + : _root = root == null ? p.current : root {
|
| + registerPlatformPlugin(new VMPlatform(_config));
|
| + }
|
| +
|
| + /// Registers [plugin] as a plugin for the platforms it defines in
|
| + /// [PlatformPlugin.platforms].
|
| + ///
|
| + /// This overwrites previous plugins for those platforms.
|
| + void registerPlatformPlugin(PlatformPlugin plugin) {
|
| + for (var platform in plugin.platforms) {
|
| + _platformPlugins[platform] = plugin;
|
| + }
|
| + }
|
|
|
| /// Loads all test suites in [dir].
|
| ///
|
| @@ -119,17 +131,27 @@ class Loader {
|
| // Don't load a skipped suite.
|
| if (metadata.skip) {
|
| yield new LoadSuite.forSuite(new RunnerSuite(
|
| - const VMEnvironment(),
|
| + const PluginEnvironment(),
|
| new Group.root([], metadata: metadata),
|
| path: path, platform: platform));
|
| continue;
|
| }
|
|
|
| var name = (platform.isJS ? "compiling " : "loading ") + path;
|
| - yield new LoadSuite(name, () {
|
| - return platform == TestPlatform.vm
|
| - ? _loadVmFile(path, metadata)
|
| - : _loadBrowserFile(path, platform, metadata);
|
| + yield new LoadSuite(name, () async {
|
| + var plugin = _platformPlugins[platform];
|
| +
|
| + if (plugin != null) {
|
| + try {
|
| + return await plugin.load(path, platform, metadata);
|
| + } catch (error, stackTrace) {
|
| + if (error is LoadException) rethrow;
|
| + await new Future.error(new LoadException(path, error), stackTrace);
|
| + }
|
| + }
|
| +
|
| + assert(platform.isBrowser);
|
| + return _loadBrowserFile(path, platform, metadata);
|
| }, path: path, platform: platform);
|
| }
|
| }
|
| @@ -141,125 +163,6 @@ class Loader {
|
| Metadata metadata) async =>
|
| (await _browserServer).loadSuite(path, platform, metadata);
|
|
|
| - /// Load the test suite at [path] in VM isolate.
|
| - ///
|
| - /// [metadata] is the suite-level metadata for the test.
|
| - Future<RunnerSuite> _loadVmFile(String path, Metadata metadata) async {
|
| - if (loadVMFileHook != null) {
|
| - var suite = await loadVMFileHook(path, metadata, _config);
|
| - _suites.add(suite);
|
| - return suite;
|
| - }
|
| -
|
| - var receivePort = new ReceivePort();
|
| -
|
| - var isolate;
|
| - try {
|
| - if (_config.pubServeUrl != null) {
|
| - var url = _config.pubServeUrl.resolveUri(
|
| - p.toUri(p.relative(path, from: 'test') + '.vm_test.dart'));
|
| -
|
| - try {
|
| - isolate = await Isolate.spawnUri(url, [], {
|
| - 'reply': receivePort.sendPort,
|
| - 'metadata': metadata.serialize()
|
| - }, checked: true);
|
| - } on IsolateSpawnException catch (error) {
|
| - if (error.message.contains("OS Error: Connection refused") ||
|
| - error.message.contains("The remote computer refused")) {
|
| - throw new LoadException(path,
|
| - "Error getting $url: Connection refused\n"
|
| - 'Make sure "pub serve" is running.');
|
| - } else if (error.message.contains("404 Not Found")) {
|
| - throw new LoadException(path,
|
| - "Error getting $url: 404 Not Found\n"
|
| - 'Make sure "pub serve" is serving the test/ directory.');
|
| - }
|
| -
|
| - throw new LoadException(path, error);
|
| - }
|
| - } else {
|
| - isolate = await dart.runInIsolate('''
|
| -import "package:test/src/backend/metadata.dart";
|
| -import "package:test/src/runner/vm/isolate_listener.dart";
|
| -
|
| -import "${p.toUri(p.absolute(path))}" as test;
|
| -
|
| -void main(_, Map message) {
|
| - var sendPort = message['reply'];
|
| - var metadata = new Metadata.deserialize(message['metadata']);
|
| - IsolateListener.start(sendPort, metadata, () => test.main);
|
| -}
|
| -''', {
|
| - 'reply': receivePort.sendPort,
|
| - 'metadata': metadata.serialize()
|
| - }, packageRoot: p.toUri(_config.packageRoot), checked: true);
|
| - }
|
| - } catch (error, stackTrace) {
|
| - receivePort.close();
|
| - if (error is LoadException) rethrow;
|
| - await new Future.error(new LoadException(path, error), stackTrace);
|
| - }
|
| -
|
| - var completer = new Completer();
|
| -
|
| - var subscription = receivePort.listen((response) {
|
| - if (response["type"] == "print") {
|
| - print(response["line"]);
|
| - } else if (response["type"] == "loadException") {
|
| - isolate.kill();
|
| - completer.completeError(
|
| - new LoadException(path, response["message"]),
|
| - new Trace.current());
|
| - } else if (response["type"] == "error") {
|
| - isolate.kill();
|
| - var asyncError = RemoteException.deserialize(response["error"]);
|
| - completer.completeError(
|
| - new LoadException(path, asyncError.error),
|
| - asyncError.stackTrace);
|
| - } else {
|
| - assert(response["type"] == "success");
|
| - completer.complete(response["root"]);
|
| - }
|
| - });
|
| -
|
| - try {
|
| - var suite = new RunnerSuite(
|
| - const VMEnvironment(),
|
| - _deserializeGroup(await completer.future),
|
| - path: path,
|
| - platform: TestPlatform.vm,
|
| - os: currentOS,
|
| - onClose: isolate.kill);
|
| - _suites.add(suite);
|
| - return suite;
|
| - } finally {
|
| - subscription.cancel();
|
| - }
|
| - }
|
| -
|
| - /// Deserializes [group] into a concrete [Group] class.
|
| - Group _deserializeGroup(Map group) {
|
| - var metadata = new Metadata.deserialize(group['metadata']);
|
| - return new Group(group['name'], group['entries'].map((entry) {
|
| - if (entry['type'] == 'group') return _deserializeGroup(entry);
|
| - return _deserializeTest(entry);
|
| - }),
|
| - metadata: metadata,
|
| - setUpAll: _deserializeTest(group['setUpAll']),
|
| - tearDownAll: _deserializeTest(group['tearDownAll']));
|
| - }
|
| -
|
| - /// Deserializes [test] into a concrete [Test] class.
|
| - ///
|
| - /// Returns `null` if [test] is `null`.
|
| - Test _deserializeTest(Map test) {
|
| - if (test == null) return null;
|
| -
|
| - var metadata = new Metadata.deserialize(test['metadata']);
|
| - return new IsolateTest(test['name'], metadata, test['sendPort']);
|
| - }
|
| -
|
| /// Close all the browsers that the loader currently has open.
|
| ///
|
| /// Note that this doesn't close the loader itself. Browser tests can still be
|
|
|