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

Side by Side Diff: lib/src/executable.dart

Issue 1239613002: Factor out a Runner class from executable.dart. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Code review changes Created 5 years, 5 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
« no previous file with comments | « no previous file | lib/src/runner.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // TODO(nweiz): This is under lib so that it can be used by the unittest dummy 5 // TODO(nweiz): This is under lib so that it can be used by the unittest dummy
6 // package. Once that package is no longer being updated, move this back into 6 // package. Once that package is no longer being updated, move this back into
7 // bin. 7 // bin.
8 library test.executable; 8 library test.executable;
9 9
10 import 'dart:async';
11 import 'dart:io'; 10 import 'dart:io';
12 11
13 import 'package:async/async.dart';
14 import 'package:stack_trace/stack_trace.dart'; 12 import 'package:stack_trace/stack_trace.dart';
15 import 'package:yaml/yaml.dart'; 13 import 'package:yaml/yaml.dart';
16 14
17 import 'backend/metadata.dart'; 15 import 'runner.dart';
18 import 'runner/application_exception.dart'; 16 import 'runner/application_exception.dart';
19 import 'runner/configuration.dart'; 17 import 'runner/configuration.dart';
20 import 'runner/engine.dart';
21 import 'runner/load_exception.dart';
22 import 'runner/load_suite.dart';
23 import 'runner/loader.dart';
24 import 'runner/reporter/compact.dart';
25 import 'runner/reporter/expanded.dart';
26 import 'util/exit_codes.dart' as exit_codes; 18 import 'util/exit_codes.dart' as exit_codes;
27 import 'utils.dart'; 19 import 'utils.dart';
28 20
29 /// A merged stream of all signals that tell the test runner to shut down 21 /// A merged stream of all signals that tell the test runner to shut down
30 /// gracefully. 22 /// gracefully.
31 /// 23 ///
32 /// Signals will only be captured as long as this has an active subscription. 24 /// Signals will only be captured as long as this has an active subscription.
33 /// Otherwise, they'll be handled by Dart's default signal handler, which 25 /// Otherwise, they'll be handled by Dart's default signal handler, which
34 /// terminates the program immediately. 26 /// terminates the program immediately.
35 final _signals = Platform.isWindows 27 final _signals = Platform.isWindows
(...skipping 23 matching lines...) Expand all
59 if (transformers is! List) return false; 51 if (transformers is! List) return false;
60 52
61 return transformers.any((transformer) { 53 return transformers.any((transformer) {
62 if (transformer is String) return transformer == 'test/pub_serve'; 54 if (transformer is String) return transformer == 'test/pub_serve';
63 if (transformer is! Map) return false; 55 if (transformer is! Map) return false;
64 if (transformer.keys.length != 1) return false; 56 if (transformer.keys.length != 1) return false;
65 return transformer.keys.single == 'test/pub_serve'; 57 return transformer.keys.single == 'test/pub_serve';
66 }); 58 });
67 } 59 }
68 60
69 Configuration _configuration;
70
71 main(List<String> args) async { 61 main(List<String> args) async {
62 var configuration;
72 try { 63 try {
73 _configuration = new Configuration.parse(args); 64 configuration = new Configuration.parse(args);
74 } on FormatException catch (error) { 65 } on FormatException catch (error) {
75 _printUsage(error.message); 66 _printUsage(error.message);
76 exitCode = exit_codes.usage; 67 exitCode = exit_codes.usage;
77 return; 68 return;
78 } 69 }
79 70
80 if (_configuration.help) { 71 if (configuration.help) {
81 _printUsage(); 72 _printUsage();
82 return; 73 return;
83 } 74 }
84 75
85 if (_configuration.version) { 76 if (configuration.version) {
86 if (!_printVersion()) { 77 if (!_printVersion()) {
87 stderr.writeln("Couldn't find version number."); 78 stderr.writeln("Couldn't find version number.");
88 exitCode = exit_codes.data; 79 exitCode = exit_codes.data;
89 } 80 }
90 return; 81 return;
91 } 82 }
92 83
93 if (_configuration.pubServeUrl != null && !_usesTransformer) { 84 if (configuration.pubServeUrl != null && !_usesTransformer) {
94 stderr.write(''' 85 stderr.write('''
95 When using --pub-serve, you must include the "test/pub_serve" transformer in 86 When using --pub-serve, you must include the "test/pub_serve" transformer in
96 your pubspec: 87 your pubspec:
97 88
98 transformers: 89 transformers:
99 - test/pub_serve: 90 - test/pub_serve:
100 \$include: test/**_test.dart 91 \$include: test/**_test.dart
101 '''); 92 ''');
102 exitCode = exit_codes.data; 93 exitCode = exit_codes.data;
103 return; 94 return;
104 } 95 }
105 96
106 if (!_configuration.explicitPaths && 97 if (!configuration.explicitPaths &&
107 !new Directory(_configuration.paths.single).existsSync()) { 98 !new Directory(configuration.paths.single).existsSync()) {
108 _printUsage('No test files were passed and the default "test/" ' 99 _printUsage('No test files were passed and the default "test/" '
109 "directory doesn't exist."); 100 "directory doesn't exist.");
110 exitCode = exit_codes.data; 101 exitCode = exit_codes.data;
111 return; 102 return;
112 } 103 }
113 104
114 var metadata = new Metadata( 105 var runner = new Runner(configuration);
115 verboseTrace: _configuration.verboseTrace);
116 var loader = new Loader(_configuration.platforms,
117 pubServeUrl: _configuration.pubServeUrl,
118 packageRoot: _configuration.packageRoot,
119 color: _configuration.color,
120 metadata: metadata,
121 jsTrace: _configuration.jsTrace);
122 106
123 var closed = false;
124 var signalSubscription; 107 var signalSubscription;
125 signalSubscription = _signals.listen((_) { 108 close() async {
126 closed = true; 109 if (signalSubscription == null) return;
127 signalSubscription.cancel(); 110 signalSubscription.cancel();
128 loader.close(); 111 signalSubscription = null;
129 }); 112 await runner.close();
113 }
114
115 signalSubscription = _signals.listen((_) => close());
130 116
131 try { 117 try {
132 var engine = new Engine(concurrency: _configuration.concurrency); 118 exitCode = (await runner.run()) ? 0 : 1;
133
134 var watch = _configuration.reporter == "compact"
135 ? CompactReporter.watch
136 : ExpandedReporter.watch;
137
138 watch(
139 engine,
140 color: _configuration.color,
141 verboseTrace: _configuration.verboseTrace,
142 printPath: _configuration.paths.length > 1 ||
143 new Directory(_configuration.paths.single).existsSync(),
144 printPlatform: _configuration.platforms.length > 1);
145
146 // Override the signal handler to close [reporter]. [loader] will still be
147 // closed in the [whenComplete] below.
148 signalSubscription.onData((_) async {
149 closed = true;
150 signalSubscription.cancel();
151
152 // Wait a bit to print this message, since printing it eagerly looks weird
153 // if the tests then finish immediately.
154 var timer = new Timer(new Duration(seconds: 1), () {
155 // Print a blank line first to ensure that this doesn't interfere with
156 // the compact reporter's unfinished line.
157 print("");
158 print("Waiting for current test(s) to finish.");
159 print("Press Control-C again to terminate immediately.");
160 });
161
162 // Make sure we close the engine *before* the loader. Otherwise,
163 // LoadSuites provided by the loader may get into bad states.
164 await engine.close();
165 timer.cancel();
166 await loader.close();
167 });
168
169 try {
170 var results = await Future.wait([
171 _loadSuites(loader, engine),
172 engine.run()
173 ], eagerError: true);
174
175 if (closed) return;
176
177 // Explicitly check "== true" here because [engine.run] can return `null`
178 // if the engine was closed prematurely.
179 exitCode = results.last == true ? 0 : 1;
180 } finally {
181 signalSubscription.cancel();
182 await engine.close();
183 }
184
185 if (engine.passed.length == 0 && engine.failed.length == 0 &&
186 engine.skipped.length == 0 && _configuration.pattern != null) {
187 stderr.write('No tests match ');
188
189 if (_configuration.pattern is RegExp) {
190 var pattern = (_configuration.pattern as RegExp).pattern;
191 stderr.writeln('regular expression "$pattern".');
192 } else {
193 stderr.writeln('"${_configuration.pattern}".');
194 }
195 exitCode = exit_codes.data;
196 }
197 } on ApplicationException catch (error) { 119 } on ApplicationException catch (error) {
198 stderr.writeln(error.message); 120 stderr.writeln(error.message);
199 exitCode = exit_codes.data; 121 exitCode = exit_codes.data;
200 } catch (error, stackTrace) { 122 } catch (error, stackTrace) {
201 stderr.writeln(getErrorMessage(error)); 123 stderr.writeln(getErrorMessage(error));
202 stderr.writeln(new Trace.from(stackTrace).terse); 124 stderr.writeln(new Trace.from(stackTrace).terse);
203 stderr.writeln( 125 stderr.writeln(
204 "This is an unexpected error. Please file an issue at " 126 "This is an unexpected error. Please file an issue at "
205 "http://github.com/dart-lang/test\n" 127 "http://github.com/dart-lang/test\n"
206 "with the stack trace and instructions for reproducing the error."); 128 "with the stack trace and instructions for reproducing the error.");
207 exitCode = exit_codes.software; 129 exitCode = exit_codes.software;
208 } finally { 130 } finally {
209 signalSubscription.cancel(); 131 await close();
210 await loader.close();
211 } 132 }
212 } 133 }
213 134
214 /// Load the test suites in [_configuration.paths] that match
215 /// [_configuration.pattern] and pass them to [engine].
216 ///
217 /// This completes once all the tests have been added to the engine. It does not
218 /// run the engine.
219 Future _loadSuites(Loader loader, Engine engine) async {
220 var group = new FutureGroup();
221
222 mergeStreams(_configuration.paths.map((path) {
223 if (new Directory(path).existsSync()) return loader.loadDir(path);
224 if (new File(path).existsSync()) return loader.loadFile(path);
225
226 return new Stream.fromIterable([
227 new LoadSuite("loading $path", () =>
228 throw new LoadException(path, 'Does not exist.'))
229 ]);
230 })).listen((loadSuite) {
231 group.add(new Future.sync(() {
232 engine.suiteSink.add(loadSuite.changeSuite((suite) {
233 if (_configuration.pattern == null) return suite;
234 return suite.change(tests: suite.tests.where(
235 (test) => test.name.contains(_configuration.pattern)));
236 }));
237 }));
238 }, onError: (error, stackTrace) {
239 group.add(new Future.error(error, stackTrace));
240 }, onDone: group.close);
241
242 await group.future;
243
244 // Once we've loaded all the suites, notify the engine that no more will be
245 // coming.
246 engine.suiteSink.close();
247 }
248
249 /// Print usage information for this command. 135 /// Print usage information for this command.
250 /// 136 ///
251 /// If [error] is passed, it's used in place of the usage message and the whole 137 /// If [error] is passed, it's used in place of the usage message and the whole
252 /// thing is printed to stderr instead of stdout. 138 /// thing is printed to stderr instead of stdout.
253 void _printUsage([String error]) { 139 void _printUsage([String error]) {
254 var output = stdout; 140 var output = stdout;
255 141
256 var message = "Runs tests in this package."; 142 var message = "Runs tests in this package.";
257 if (error != null) { 143 if (error != null) {
258 message = error; 144 message = error;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 if (description is! Map) return false; 203 if (description is! Map) return false;
318 var path = description["path"]; 204 var path = description["path"];
319 if (path is! String) return false; 205 if (path is! String) return false;
320 206
321 print("$version (from $path)"); 207 print("$version (from $path)");
322 return true; 208 return true;
323 209
324 default: return false; 210 default: return false;
325 } 211 }
326 } 212 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/runner.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698