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

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

Issue 1196413003: Add a LoadSuite class. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Created 5 years, 6 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 // 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'; 10 import 'dart:async';
11 import 'dart:io'; 11 import 'dart:io';
12 import 'dart:math' as math; 12 import 'dart:math' as math;
13 13
14 import 'package:args/args.dart'; 14 import 'package:args/args.dart';
15 import 'package:async/async.dart';
15 import 'package:stack_trace/stack_trace.dart'; 16 import 'package:stack_trace/stack_trace.dart';
16 import 'package:yaml/yaml.dart'; 17 import 'package:yaml/yaml.dart';
17 18
18 import 'backend/metadata.dart'; 19 import 'backend/metadata.dart';
19 import 'backend/test_platform.dart'; 20 import 'backend/test_platform.dart';
20 import 'runner/engine.dart'; 21 import 'runner/engine.dart';
21 import 'runner/application_exception.dart'; 22 import 'runner/application_exception.dart';
22 import 'runner/load_exception.dart'; 23 import 'runner/load_exception.dart';
23 import 'runner/load_exception_suite.dart'; 24 import 'runner/load_suite.dart';
24 import 'runner/loader.dart'; 25 import 'runner/loader.dart';
25 import 'runner/reporter/compact.dart'; 26 import 'runner/reporter/compact.dart';
26 import 'runner/reporter/expanded.dart'; 27 import 'runner/reporter/expanded.dart';
27 import 'util/exit_codes.dart' as exit_codes; 28 import 'util/exit_codes.dart' as exit_codes;
28 import 'util/io.dart'; 29 import 'util/io.dart';
29 import 'utils.dart'; 30 import 'utils.dart';
30 31
31 /// The argument parser used to parse the executable arguments. 32 /// The argument parser used to parse the executable arguments.
32 final _parser = new ArgParser(allowTrailingOptions: true); 33 final _parser = new ArgParser(allowTrailingOptions: true);
33 34
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 205
205 var metadata = new Metadata(verboseTrace: options["verbose-trace"]); 206 var metadata = new Metadata(verboseTrace: options["verbose-trace"]);
206 var platforms = options["platform"].map(TestPlatform.find); 207 var platforms = options["platform"].map(TestPlatform.find);
207 var loader = new Loader(platforms, 208 var loader = new Loader(platforms,
208 pubServeUrl: pubServeUrl, 209 pubServeUrl: pubServeUrl,
209 packageRoot: options["package-root"], 210 packageRoot: options["package-root"],
210 color: color, 211 color: color,
211 metadata: metadata, 212 metadata: metadata,
212 jsTrace: options["js-trace"]); 213 jsTrace: options["js-trace"]);
213 214
215 var closed = false;
214 var signalSubscription; 216 var signalSubscription;
215 signalSubscription = _signals.listen((_) { 217 signalSubscription = _signals.listen((_) {
218 closed = true;
216 signalSubscription.cancel(); 219 signalSubscription.cancel();
217 loader.close(); 220 loader.close();
218 }); 221 });
219 222
220 try { 223 try {
221 var engine = new Engine(concurrency: concurrency); 224 var engine = new Engine(concurrency: concurrency);
222 225
223 var watch = options["reporter"] == "compact" 226 var watch = options["reporter"] == "compact"
224 ? CompactReporter.watch 227 ? CompactReporter.watch
225 : ExpandedReporter.watch; 228 : ExpandedReporter.watch;
226 229
227 watch( 230 watch(
228 engine, 231 engine,
229 color: color, 232 color: color,
230 verboseTrace: options["verbose-trace"], 233 verboseTrace: options["verbose-trace"],
231 printPath: paths.length > 1 || 234 printPath: paths.length > 1 ||
232 new Directory(paths.single).existsSync(), 235 new Directory(paths.single).existsSync(),
233 printPlatform: platforms.length > 1); 236 printPlatform: platforms.length > 1);
234 237
235 // Override the signal handler to close [reporter]. [loader] will still be 238 // Override the signal handler to close [reporter]. [loader] will still be
236 // closed in the [whenComplete] below. 239 // closed in the [whenComplete] below.
237 signalSubscription.onData((_) async { 240 signalSubscription.onData((_) async {
241 closed = true;
238 signalSubscription.cancel(); 242 signalSubscription.cancel();
239 243
240 // Wait a bit to print this message, since printing it eagerly looks weird 244 // Wait a bit to print this message, since printing it eagerly looks weird
241 // if the tests then finish immediately. 245 // if the tests then finish immediately.
242 var timer = new Timer(new Duration(seconds: 1), () { 246 var timer = new Timer(new Duration(seconds: 1), () {
243 // Print a blank line first to ensure that this doesn't interfere with 247 // Print a blank line first to ensure that this doesn't interfere with
244 // the compact reporter's unfinished line. 248 // the compact reporter's unfinished line.
245 print(""); 249 print("");
246 print("Waiting for current test(s) to finish."); 250 print("Waiting for current test(s) to finish.");
247 print("Press Control-C again to terminate immediately."); 251 print("Press Control-C again to terminate immediately.");
248 }); 252 });
249 253
254 // Make sure we close the engine *before* the loader. Otherwise,
255 // LoadSuites provided by the loader may get into bad states.
250 await engine.close(); 256 await engine.close();
251 timer.cancel(); 257 timer.cancel();
252 await loader.close(); 258 await loader.close();
253 }); 259 });
254 260
255 try { 261 try {
256 var results = await Future.wait([ 262 var results = await Future.wait([
257 _loadSuites(paths, pattern, loader, engine), 263 _loadSuites(paths, pattern, loader, engine),
258 engine.run() 264 engine.run()
259 ], eagerError: true); 265 ], eagerError: true);
260 266
267 if (closed) return;
268
261 // Explicitly check "== true" here because [engine.run] can return `null` 269 // Explicitly check "== true" here because [engine.run] can return `null`
262 // if the engine was closed prematurely. 270 // if the engine was closed prematurely.
263 exitCode = results.last == true ? 0 : 1; 271 exitCode = results.last == true ? 0 : 1;
264 } finally { 272 } finally {
265 signalSubscription.cancel(); 273 signalSubscription.cancel();
266 await engine.close(); 274 await engine.close();
267 } 275 }
268 276
269 if (engine.passed.length == 0 && engine.failed.length == 0 && 277 if (engine.passed.length == 0 && engine.failed.length == 0 &&
270 engine.skipped.length == 0 && pattern != null) { 278 engine.skipped.length == 0 && pattern != null) {
(...skipping 23 matching lines...) Expand all
294 } 302 }
295 } 303 }
296 304
297 /// Load the test suites in [paths] that match [pattern] and pass them to 305 /// Load the test suites in [paths] that match [pattern] and pass them to
298 /// [engine]. 306 /// [engine].
299 /// 307 ///
300 /// This completes once all the tests have been added to the engine. It does not 308 /// This completes once all the tests have been added to the engine. It does not
301 /// run the engine. 309 /// run the engine.
302 Future _loadSuites(List<String> paths, Pattern pattern, Loader loader, 310 Future _loadSuites(List<String> paths, Pattern pattern, Loader loader,
303 Engine engine) async { 311 Engine engine) async {
304 var completer = new Completer(); 312 var group = new FutureGroup();
305 313
306 mergeStreams(paths.map((path) { 314 mergeStreams(paths.map((path) {
307 if (new Directory(path).existsSync()) return loader.loadDir(path); 315 if (new Directory(path).existsSync()) return loader.loadDir(path);
308 if (new File(path).existsSync()) return loader.loadFile(path); 316 if (new File(path).existsSync()) return loader.loadFile(path);
309 317
310 return new Stream.fromFuture(new Future.error( 318 return new Stream.fromIterable([
311 new LoadException(path, 'Does not exist.'), 319 new LoadSuite("loading $path", () =>
312 new Trace.current())); 320 throw new LoadException(path, 'Does not exist.'))
313 })).map((suite) { 321 ]);
314 if (pattern == null) return suite; 322 })).listen((loadSuite) {
315 return suite.change( 323 group.add(new Future.sync(() async {
316 tests: suite.tests.where((test) => test.name.contains(pattern))); 324 engine.suiteSink.add(loadSuite);
317 }).listen((suite) => engine.suiteSink.add(suite),
318 onError: (error, stackTrace) {
319 if (error is LoadException) {
320 engine.suiteSink.add(new LoadExceptionSuite(error, stackTrace));
321 } else if (!completer.isCompleted) {
322 completer.completeError(error, stackTrace);
323 }
324 }, onDone: () => completer.complete());
325 325
326 await completer.future; 326 var suite = await loadSuite.suite;
327 if (suite == null) return;
328 if (pattern != null) {
329 suite = suite.change(
330 tests: suite.tests.where((test) => test.name.contains(pattern)));
331 }
332
333 engine.suiteSink.add(suite);
334 }));
335 }, onError: (error, stackTrace) {
336 group.add(new Future.error(error, stackTrace));
337 }, onDone: group.close);
338
339 await group.future;
327 340
328 // Once we've loaded all the suites, notify the engine that no more will be 341 // Once we've loaded all the suites, notify the engine that no more will be
329 // coming. 342 // coming.
330 engine.suiteSink.close(); 343 engine.suiteSink.close();
331 } 344 }
332 345
333 /// Print usage information for this command. 346 /// Print usage information for this command.
334 /// 347 ///
335 /// If [error] is passed, it's used in place of the usage message and the whole 348 /// If [error] is passed, it's used in place of the usage message and the whole
336 /// thing is printed to stderr instead of stdout. 349 /// thing is printed to stderr instead of stdout.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 if (description is! Map) return false; 414 if (description is! Map) return false;
402 var path = description["path"]; 415 var path = description["path"];
403 if (path is! String) return false; 416 if (path is! String) return false;
404 417
405 print("$version (from $path)"); 418 print("$version (from $path)");
406 return true; 419 return true;
407 420
408 default: return false; 421 default: return false;
409 } 422 }
410 } 423 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698