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

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

Issue 1056733002: Run test tearDowns and clean up temporary directories when a signal is caught. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Code review changes Created 5 years, 8 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 | « lib/src/backend/live_test_controller.dart ('k') | lib/src/frontend/expect.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'; 10 import 'dart:async';
11 import 'dart:io'; 11 import 'dart:io';
12 import 'dart:isolate'; 12 import 'dart:isolate';
13 13
14 import 'package:args/args.dart'; 14 import 'package:args/args.dart';
15 import 'package:stack_trace/stack_trace.dart'; 15 import 'package:stack_trace/stack_trace.dart';
16 16
17 import 'backend/test_platform.dart'; 17 import 'backend/test_platform.dart';
18 import 'runner/reporter/compact.dart'; 18 import 'runner/reporter/compact.dart';
19 import 'runner/load_exception.dart'; 19 import 'runner/load_exception.dart';
20 import 'runner/loader.dart'; 20 import 'runner/loader.dart';
21 import 'util/exit_codes.dart' as exit_codes; 21 import 'util/exit_codes.dart' as exit_codes;
22 import 'util/io.dart'; 22 import 'util/io.dart';
23 import 'utils.dart'; 23 import 'utils.dart';
24 24
25 /// The argument parser used to parse the executable arguments. 25 /// The argument parser used to parse the executable arguments.
26 final _parser = new ArgParser(allowTrailingOptions: true); 26 final _parser = new ArgParser(allowTrailingOptions: true);
27 27
28 /// A merged stream of all signals that tell the test runner to shut down
29 /// gracefully.
30 ///
31 /// Signals will only be captured as long as this has an active subscription.
32 /// Otherwise, they'll be handled by Dart's default signal handler, which
33 /// terminates the program immediately.
34 final _signals = mergeStreams([
35 ProcessSignal.SIGTERM.watch(), ProcessSignal.SIGINT.watch()
36 ]);
37
28 void main(List<String> args) { 38 void main(List<String> args) {
29 _parser.addFlag("help", abbr: "h", negatable: false, 39 _parser.addFlag("help", abbr: "h", negatable: false,
30 help: "Shows this usage information."); 40 help: "Shows this usage information.");
31 _parser.addOption("package-root", hide: true); 41 _parser.addOption("package-root", hide: true);
32 _parser.addOption("name", 42 _parser.addOption("name",
33 abbr: 'n', 43 abbr: 'n',
34 help: 'A substring of the name of the test to run.\n' 44 help: 'A substring of the name of the test to run.\n'
35 'Regular expression syntax is supported.'); 45 'Regular expression syntax is supported.');
36 _parser.addOption("plain-name", 46 _parser.addOption("plain-name",
37 abbr: 'N', 47 abbr: 'N',
(...skipping 20 matching lines...) Expand all
58 _printUsage(); 68 _printUsage();
59 return; 69 return;
60 } 70 }
61 71
62 var color = options["color"]; 72 var color = options["color"];
63 if (color == null) color = canUseSpecialChars; 73 if (color == null) color = canUseSpecialChars;
64 74
65 var platforms = options["platform"].map(TestPlatform.find); 75 var platforms = options["platform"].map(TestPlatform.find);
66 var loader = new Loader(platforms, 76 var loader = new Loader(platforms,
67 packageRoot: options["package-root"], color: color); 77 packageRoot: options["package-root"], color: color);
78
79 var signalSubscription;
80 var closed = false;
81 signalSubscription = _signals.listen((_) {
82 signalSubscription.cancel();
83 closed = true;
84 loader.close();
85 });
86
68 new Future.sync(() { 87 new Future.sync(() {
69 var paths = options.rest; 88 var paths = options.rest;
70 if (paths.isEmpty) { 89 if (paths.isEmpty) {
71 if (!new Directory("test").existsSync()) { 90 if (!new Directory("test").existsSync()) {
72 throw new LoadException("test", 91 throw new LoadException("test",
73 "No test files were passed and the default directory doesn't " 92 "No test files were passed and the default directory doesn't "
74 "exist."); 93 "exist.");
75 } 94 }
76 paths = ["test"]; 95 paths = ["test"];
77 } 96 }
78 97
79 return Future.wait(paths.map((path) { 98 return Future.wait(paths.map((path) {
80 if (new Directory(path).existsSync()) return loader.loadDir(path); 99 if (new Directory(path).existsSync()) return loader.loadDir(path);
81 if (new File(path).existsSync()) return loader.loadFile(path); 100 if (new File(path).existsSync()) return loader.loadFile(path);
82 throw new LoadException(path, 'Does not exist.'); 101 throw new LoadException(path, 'Does not exist.');
83 })); 102 }));
84 }).then((suites) { 103 }).then((suites) {
104 if (closed) return null;
85 suites = flatten(suites); 105 suites = flatten(suites);
86 106
87 var pattern; 107 var pattern;
88 if (options["name"] != null) { 108 if (options["name"] != null) {
89 if (options["plain-name"] != null) { 109 if (options["plain-name"] != null) {
90 _printUsage("--name and --plain-name may not both be passed."); 110 _printUsage("--name and --plain-name may not both be passed.");
91 exitCode = exit_codes.data; 111 exitCode = exit_codes.data;
92 return null; 112 return null;
93 } 113 }
94 pattern = new RegExp(options["name"]); 114 pattern = new RegExp(options["name"]);
(...skipping 14 matching lines...) Expand all
109 stderr.write('regular expression "${pattern.pattern}".'); 129 stderr.write('regular expression "${pattern.pattern}".');
110 } else { 130 } else {
111 stderr.writeln('"$pattern".'); 131 stderr.writeln('"$pattern".');
112 } 132 }
113 exitCode = exit_codes.data; 133 exitCode = exit_codes.data;
114 return null; 134 return null;
115 } 135 }
116 } 136 }
117 137
118 var reporter = new CompactReporter(flatten(suites), color: color); 138 var reporter = new CompactReporter(flatten(suites), color: color);
139
140 // Override the signal handler to close [reporter]. [loader] will still be
141 // closed in the [whenComplete] below.
142 signalSubscription.onData((_) {
143 signalSubscription.cancel();
144 closed = true;
145
146 // Wait a bit to print this message, since printing it eagerly looks weird
147 // if the tests then finish immediately.
148 var timer = new Timer(new Duration(seconds: 1), () {
149 print("Waiting for current test to finish.");
150 print("Press Control-C again to terminate immediately.");
151 });
152
153 reporter.close().then((_) => timer.cancel());
154 });
155
119 return reporter.run().then((success) { 156 return reporter.run().then((success) {
120 exitCode = success ? 0 : 1; 157 exitCode = success ? 0 : 1;
121 }).whenComplete(() => reporter.close()); 158 }).whenComplete(() {
122 }).catchError((error, stackTrace) { 159 signalSubscription.cancel();
160 return reporter.close();
161 });
162 }).whenComplete(signalSubscription.cancel).catchError((error, stackTrace) {
123 if (error is LoadException) { 163 if (error is LoadException) {
124 stderr.writeln(error.toString(color: color)); 164 stderr.writeln(error.toString(color: color));
125 165
126 // Only print stack traces for load errors that come from the user's 166 // Only print stack traces for load errors that come from the user's
127 if (error.innerError is! IOException && 167 if (error.innerError is! IOException &&
128 error.innerError is! IsolateSpawnException && 168 error.innerError is! IsolateSpawnException &&
129 error.innerError is! FormatException && 169 error.innerError is! FormatException &&
130 error.innerError is! String) { 170 error.innerError is! String) {
131 stderr.write(terseChain(stackTrace)); 171 stderr.write(terseChain(stackTrace));
132 } 172 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 output = stderr; 205 output = stderr;
166 } 206 }
167 207
168 output.write("""$message 208 output.write("""$message
169 209
170 Usage: pub run test:test [files or directories...] 210 Usage: pub run test:test [files or directories...]
171 211
172 ${_parser.usage} 212 ${_parser.usage}
173 """); 213 """);
174 } 214 }
OLDNEW
« no previous file with comments | « lib/src/backend/live_test_controller.dart ('k') | lib/src/frontend/expect.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698