Index: lib/src/runner/loader.dart |
diff --git a/lib/src/runner/loader.dart b/lib/src/runner/loader.dart |
index 6e68ee20aa1ce8c96dec24a9df0be1f2d75fc512..cd0802666e59b36f289539a407987ae46b863ca4 100644 |
--- a/lib/src/runner/loader.dart |
+++ b/lib/src/runner/loader.dart |
@@ -14,7 +14,7 @@ import '../backend/metadata.dart'; |
import '../backend/test_platform.dart'; |
import '../util/io.dart'; |
import '../utils.dart'; |
-import 'browser/server.dart'; |
+import 'browser/platform.dart'; |
import 'configuration.dart'; |
import 'load_exception.dart'; |
import 'load_suite.dart'; |
@@ -35,23 +35,13 @@ 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>{}; |
+ /// Memoizers for platform plugins, indexed by the platforms they support. |
+ final _platformPlugins = <TestPlatform, AsyncMemoizer<PlatformPlugin>>{}; |
- /// The server that serves browser test pages. |
+ /// The functions to use to load [_platformPlugins]. |
/// |
- /// This is lazily initialized the first time it's accessed. |
- Future<BrowserServer> get _browserServer { |
- return _browserServerMemo.runOnce(() { |
- return BrowserServer.start(_config, root: _root); |
- }); |
- } |
- final _browserServerMemo = new AsyncMemoizer<BrowserServer>(); |
- |
- /// The memoizer for running [close] exactly once. |
- final _closeMemo = new AsyncMemoizer(); |
+ /// These are passed to the plugins' async memoizers when a plugin is needed. |
+ final _platformCallbacks = <TestPlatform, AsyncFunction>{}; |
/// Creates a new loader that loads tests on platforms defined in [_config]. |
/// |
@@ -59,16 +49,32 @@ class Loader { |
/// defaults to the working directory. |
Loader(this._config, {String root}) |
: _root = root == null ? p.current : root { |
- registerPlatformPlugin(new VMPlatform(_config)); |
+ registerPlatformPlugin([TestPlatform.vm], () => new VMPlatform(_config)); |
+ registerPlatformPlugin([ |
+ TestPlatform.dartium, |
+ TestPlatform.contentShell, |
+ TestPlatform.chrome, |
+ TestPlatform.phantomJS, |
+ TestPlatform.firefox, |
+ TestPlatform.safari, |
+ TestPlatform.internetExplorer |
+ ], () => BrowserPlatform.start(_config, root: root)); |
} |
- /// Registers [plugin] as a plugin for the platforms it defines in |
- /// [PlatformPlugin.platforms]. |
+ /// Registers a [PlatformPlugin] for [platforms]. |
+ /// |
+ /// When the runner first requests that a suite be loaded for one of the given |
+ /// platforms, this will call [getPlugin] to load the platform plugin. It may |
+ /// return either a [PlatformPlugin] or a [Future<PlatformPlugin>]. That |
+ /// plugin is then preserved and used to load all suites for all matching |
+ /// platforms. |
/// |
/// This overwrites previous plugins for those platforms. |
- void registerPlatformPlugin(PlatformPlugin plugin) { |
- for (var platform in plugin.platforms) { |
- _platformPlugins[platform] = plugin; |
+ void registerPlatformPlugin(Iterable<TestPlatform> platforms, getPlugin()) { |
+ var memoizer = new AsyncMemoizer(); |
+ for (var platform in platforms) { |
+ _platformPlugins[platform] = memoizer; |
+ _platformCallbacks[platform] = getPlugin; |
} |
} |
@@ -139,47 +145,41 @@ class Loader { |
var name = (platform.isJS ? "compiling " : "loading ") + path; |
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); |
- } |
+ var memo = _platformPlugins[platform]; |
+ |
+ try { |
+ var plugin = await memo.runOnce(_platformCallbacks[platform]); |
+ var suite = await plugin.load(path, platform, metadata); |
+ _suites.add(suite); |
+ return suite; |
+ } 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); |
} |
} |
- /// Load the test suite at [path] in [platform]. |
- /// |
- /// [metadata] is the suite-level metadata for the test. |
- Future<RunnerSuite> _loadBrowserFile(String path, TestPlatform platform, |
- Metadata metadata) async => |
- (await _browserServer).loadSuite(path, platform, metadata); |
- |
- /// Close all the browsers that the loader currently has open. |
- /// |
- /// Note that this doesn't close the loader itself. Browser tests can still be |
- /// loaded, they'll just spawn new browsers. |
- Future closeBrowsers() async { |
- if (!_browserServerMemo.hasRun) return; |
- await (await _browserServer).closeBrowsers(); |
+ Future closeEphemeral() async { |
+ await Future.wait(_platformPlugins.values.map((memo) async { |
+ if (!memo.hasRun) return; |
+ await (await memo.future).closeEphemeral(); |
+ })); |
} |
/// Closes the loader and releases all resources allocated by it. |
- Future close() { |
- return _closeMemo.runOnce(() async { |
- await Future.wait(_suites.map((suite) => suite.close())); |
- _suites.clear(); |
- |
- if (!_browserServerMemo.hasRun) return; |
- await (await _browserServer).close(); |
- }); |
- } |
+ Future close() => _closeMemo.runOnce(() async { |
+ await Future.wait([ |
+ Future.wait(_platformPlugins.values.map((memo) async { |
+ if (!memo.hasRun) return; |
+ await (await memo.future).close(); |
+ })), |
+ Future.wait(_suites.map((suite) => suite.close())) |
+ ]); |
+ |
+ _platformPlugins.clear(); |
+ _platformCallbacks.clear(); |
+ _suites.clear(); |
+ }); |
+ final _closeMemo = new AsyncMemoizer(); |
} |