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

Side by Side Diff: lib/src/runner/loader.dart

Issue 1704773002: Load web tests using the plugin infrastructure. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: 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
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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 file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:io'; 6 import 'dart:io';
7 7
8 import 'package:analyzer/analyzer.dart' hide Configuration; 8 import 'package:analyzer/analyzer.dart' hide Configuration;
9 import 'package:async/async.dart'; 9 import 'package:async/async.dart';
10 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
11 11
12 import '../backend/group.dart'; 12 import '../backend/group.dart';
13 import '../backend/metadata.dart'; 13 import '../backend/metadata.dart';
14 import '../backend/test_platform.dart'; 14 import '../backend/test_platform.dart';
15 import '../util/io.dart'; 15 import '../util/io.dart';
16 import '../utils.dart'; 16 import '../utils.dart';
17 import 'browser/server.dart'; 17 import 'browser/platform.dart';
18 import 'configuration.dart'; 18 import 'configuration.dart';
19 import 'load_exception.dart'; 19 import 'load_exception.dart';
20 import 'load_suite.dart'; 20 import 'load_suite.dart';
21 import 'parse_metadata.dart'; 21 import 'parse_metadata.dart';
22 import 'plugin/environment.dart'; 22 import 'plugin/environment.dart';
23 import 'plugin/platform.dart'; 23 import 'plugin/platform.dart';
24 import 'runner_suite.dart'; 24 import 'runner_suite.dart';
25 import 'vm/platform.dart'; 25 import 'vm/platform.dart';
26 26
27 /// A class for finding test files and loading them into a runnable form. 27 /// A class for finding test files and loading them into a runnable form.
28 class Loader { 28 class Loader {
29 /// The test runner configuration. 29 /// The test runner configuration.
30 final Configuration _config; 30 final Configuration _config;
31 31
32 /// The root directory that will be served for browser tests. 32 /// The root directory that will be served for browser tests.
33 final String _root; 33 final String _root;
34 34
35 /// All suites that have been created by the loader. 35 /// All suites that have been created by the loader.
36 final _suites = new Set<RunnerSuite>(); 36 final _suites = new Set<RunnerSuite>();
37 37
38 /// Plugins for loading test suites for various platforms. 38 /// Memoizers for platform plugins, indexed by the platforms they support.
39 final _platformPlugins = <TestPlatform, AsyncMemoizer<PlatformPlugin>>{};
40
41 /// The functions to use to load [_platformPlugins].
39 /// 42 ///
40 /// This includes the built-in [VMPlatform] plugin. 43 /// These are passed to the plugins' async memoizers when a plugin is needed.
41 final _platformPlugins = <TestPlatform, PlatformPlugin>{}; 44 final _platformCallbacks = <TestPlatform, AsyncFunction>{};
42
43 /// The server that serves browser test pages.
44 ///
45 /// This is lazily initialized the first time it's accessed.
46 Future<BrowserServer> get _browserServer {
47 return _browserServerMemo.runOnce(() {
48 return BrowserServer.start(_config, root: _root);
49 });
50 }
51 final _browserServerMemo = new AsyncMemoizer<BrowserServer>();
52
53 /// The memoizer for running [close] exactly once.
54 final _closeMemo = new AsyncMemoizer();
55 45
56 /// Creates a new loader that loads tests on platforms defined in [_config]. 46 /// Creates a new loader that loads tests on platforms defined in [_config].
57 /// 47 ///
58 /// [root] is the root directory that will be served for browser tests. It 48 /// [root] is the root directory that will be served for browser tests. It
59 /// defaults to the working directory. 49 /// defaults to the working directory.
60 Loader(this._config, {String root}) 50 Loader(this._config, {String root})
61 : _root = root == null ? p.current : root { 51 : _root = root == null ? p.current : root {
62 registerPlatformPlugin(new VMPlatform(_config)); 52 registerPlatformPlugin([TestPlatform.vm], () => new VMPlatform(_config));
53 registerPlatformPlugin([
54 TestPlatform.dartium,
55 TestPlatform.contentShell,
56 TestPlatform.chrome,
57 TestPlatform.phantomJS,
58 TestPlatform.firefox,
59 TestPlatform.safari,
60 TestPlatform.internetExplorer
61 ], () => BrowserPlatform.start(_config, root: root));
63 } 62 }
64 63
65 /// Registers [plugin] as a plugin for the platforms it defines in 64 /// Registers a [PlatformPlugin] for [platforms].
66 /// [PlatformPlugin.platforms]. 65 ///
66 /// When the runner first requests that a suite be loaded for one of the given
67 /// platforms, this will call [getPlugin] to load the platform plugin. It may
68 /// return either a [PlatformPlugin] or a [Future<PlatformPlugin>]. That
69 /// plugin is then preserved and used to load all suites for all matching
70 /// platforms.
67 /// 71 ///
68 /// This overwrites previous plugins for those platforms. 72 /// This overwrites previous plugins for those platforms.
69 void registerPlatformPlugin(PlatformPlugin plugin) { 73 void registerPlatformPlugin(Iterable<TestPlatform> platforms, getPlugin()) {
70 for (var platform in plugin.platforms) { 74 var memoizer = new AsyncMemoizer();
71 _platformPlugins[platform] = plugin; 75 for (var platform in platforms) {
76 _platformPlugins[platform] = memoizer;
77 _platformCallbacks[platform] = getPlugin;
72 } 78 }
73 } 79 }
74 80
75 /// Loads all test suites in [dir]. 81 /// Loads all test suites in [dir].
76 /// 82 ///
77 /// This will load tests from files that match the configuration's filename 83 /// This will load tests from files that match the configuration's filename
78 /// glob. Any tests that fail to load will be emitted as [LoadException]s. 84 /// glob. Any tests that fail to load will be emitted as [LoadException]s.
79 /// 85 ///
80 /// This emits [LoadSuite]s that must then be run to emit the actual 86 /// This emits [LoadSuite]s that must then be run to emit the actual
81 /// [RunnerSuite]s defined in the file. 87 /// [RunnerSuite]s defined in the file.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 if (metadata.skip) { 138 if (metadata.skip) {
133 yield new LoadSuite.forSuite(new RunnerSuite( 139 yield new LoadSuite.forSuite(new RunnerSuite(
134 const PluginEnvironment(), 140 const PluginEnvironment(),
135 new Group.root([], metadata: metadata), 141 new Group.root([], metadata: metadata),
136 path: path, platform: platform)); 142 path: path, platform: platform));
137 continue; 143 continue;
138 } 144 }
139 145
140 var name = (platform.isJS ? "compiling " : "loading ") + path; 146 var name = (platform.isJS ? "compiling " : "loading ") + path;
141 yield new LoadSuite(name, () async { 147 yield new LoadSuite(name, () async {
142 var plugin = _platformPlugins[platform]; 148 var memo = _platformPlugins[platform];
143 149
144 if (plugin != null) { 150 try {
145 try { 151 var plugin = await memo.runOnce(_platformCallbacks[platform]);
146 return await plugin.load(path, platform, metadata); 152 var suite = await plugin.load(path, platform, metadata);
147 } catch (error, stackTrace) { 153 _suites.add(suite);
148 if (error is LoadException) rethrow; 154 return suite;
149 await new Future.error(new LoadException(path, error), stackTrace); 155 } catch (error, stackTrace) {
150 } 156 if (error is LoadException) rethrow;
157 await new Future.error(new LoadException(path, error), stackTrace);
151 } 158 }
152
153 assert(platform.isBrowser);
154 return _loadBrowserFile(path, platform, metadata);
155 }, path: path, platform: platform); 159 }, path: path, platform: platform);
156 } 160 }
157 } 161 }
158 162
159 /// Load the test suite at [path] in [platform]. 163 Future closeEphemeral() async {
160 /// 164 await Future.wait(_platformPlugins.values.map((memo) async {
161 /// [metadata] is the suite-level metadata for the test. 165 if (!memo.hasRun) return;
162 Future<RunnerSuite> _loadBrowserFile(String path, TestPlatform platform, 166 await (await memo.future).closeEphemeral();
163 Metadata metadata) async => 167 }));
164 (await _browserServer).loadSuite(path, platform, metadata);
165
166 /// Close all the browsers that the loader currently has open.
167 ///
168 /// Note that this doesn't close the loader itself. Browser tests can still be
169 /// loaded, they'll just spawn new browsers.
170 Future closeBrowsers() async {
171 if (!_browserServerMemo.hasRun) return;
172 await (await _browserServer).closeBrowsers();
173 } 168 }
174 169
175 /// Closes the loader and releases all resources allocated by it. 170 /// Closes the loader and releases all resources allocated by it.
176 Future close() { 171 Future close() => _closeMemo.runOnce(() async {
177 return _closeMemo.runOnce(() async { 172 await Future.wait([
178 await Future.wait(_suites.map((suite) => suite.close())); 173 Future.wait(_platformPlugins.values.map((memo) async {
179 _suites.clear(); 174 if (!memo.hasRun) return;
175 await (await memo.future).close();
176 })),
177 Future.wait(_suites.map((suite) => suite.close()))
178 ]);
180 179
181 if (!_browserServerMemo.hasRun) return; 180 _platformPlugins.clear();
182 await (await _browserServer).close(); 181 _platformCallbacks.clear();
183 }); 182 _suites.clear();
184 } 183 });
184 final _closeMemo = new AsyncMemoizer();
185 } 185 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698