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

Side by Side Diff: tools/testing/dart/test_runner.dart

Issue 9475038: test.dart: add support for compiling multiple scripts for a single test. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: '' Created 8 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | tools/testing/dart/test_suite.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 /** 5 /**
6 * Classes and methods for executing tests. 6 * Classes and methods for executing tests.
7 * 7 *
8 * This module includes: 8 * This module includes:
9 * - Managing parallel execution of tests, including timeout checks. 9 * - Managing parallel execution of tests, including timeout checks.
10 * - Evaluating the output of each test as pass/fail/crash/timeout. 10 * - Evaluating the output of each test as pass/fail/crash/timeout.
11 */ 11 */
12 #library("test_runner"); 12 #library("test_runner");
13 13
14 #import("dart:io"); 14 #import("dart:io");
15 #import("status_file_parser.dart"); 15 #import("status_file_parser.dart");
16 #import("test_progress.dart"); 16 #import("test_progress.dart");
17 #import("test_suite.dart"); 17 #import("test_suite.dart");
18 18
19 final int NO_TIMEOUT = 0; 19 final int NO_TIMEOUT = 0;
20 20
21 /** A command executed as a step in a test case. */
22 class Command {
23 /** Path to the executable of this command. */
24 String executable;
25
26 /** Command line arguments to the executable. */
27 List<String> arguments;
28
29 /** The actual command line that will be executed. */
30 String commandLine;
31
32 Command(this.executable, this.arguments) {
33 commandLine = "$executable ${Strings.join(arguments, ' ')}";
34 }
35 }
21 36
22 /** 37 /**
23 * TestCase contains all the information needed to run a test and evaluate 38 * TestCase contains all the information needed to run a test and evaluate
24 * its output. Running a test involves starting a separate process, with 39 * its output. Running a test involves starting a separate process, with
25 * the executable and arguments given by the TestCase, and recording its 40 * the executable and arguments given by the TestCase, and recording its
26 * stdout and stderr output streams, and its exit code. TestCase only 41 * stdout and stderr output streams, and its exit code. TestCase only
27 * contains static information about the test; actually running the test is 42 * contains static information about the test; actually running the test is
28 * performed by [ProcessQueue] using a [RunningProcess] object. 43 * performed by [ProcessQueue] using a [RunningProcess] object.
29 * 44 *
30 * The output information is stored in a [TestOutput] instance contained 45 * The output information is stored in a [TestOutput] instance contained
31 * in the TestCase. The TestOutput instance is responsible for evaluating 46 * in the TestCase. The TestOutput instance is responsible for evaluating
32 * if the test has passed, failed, crashed, or timed out, and the TestCase 47 * if the test has passed, failed, crashed, or timed out, and the TestCase
33 * has information about what the expected result of the test should be. 48 * has information about what the expected result of the test should be.
34 * 49 *
35 * The TestCase has a callback function, [completedHandler], that is run when 50 * The TestCase has a callback function, [completedHandler], that is run when
36 * the test is completed. 51 * the test is completed.
37 */ 52 */
38 class TestCase { 53 class TestCase {
39 String executablePath; 54 /**
40 List<String> arguments; 55 * A list of commands to execute. Most test cases have a single command. Frog
56 * tests have two commands, one to compilate the source and another to execute
57 * it. Some isolate tests might even have three, if they require compiling
58 * multiple sources that are run in isolation.
59 */
60 final List<Command> commands;
61
41 Map configuration; 62 Map configuration;
42 String commandLine;
43 String displayName; 63 String displayName;
44 TestOutput output; 64 TestOutput output;
45 bool isNegative; 65 bool isNegative;
46 Set<String> expectedOutcomes; 66 Set<String> expectedOutcomes;
47 Function completedHandler; 67 Function completedHandler;
48 68
49 TestCase(this.displayName, 69 TestCase(this.displayName,
50 this.executablePath, 70 this.commands,
51 this.arguments,
52 this.configuration, 71 this.configuration,
53 this.completedHandler, 72 this.completedHandler,
54 this.expectedOutcomes, 73 this.expectedOutcomes,
55 [this.isNegative = false]) { 74 [this.isNegative = false]) {
56 if (!isNegative) { 75 if (!isNegative) {
57 this.isNegative = displayName.contains("NegativeTest"); 76 this.isNegative = displayName.contains("NegativeTest");
58 } 77 }
59 commandLine = "$executablePath ${Strings.join(arguments, ' ')}";
60 78
61 // Special command handling. If a special command is specified 79 // Special command handling. If a special command is specified
62 // we have to completely rewrite the command that we are using. 80 // we have to completely rewrite the command that we are using.
63 // We generate a new command-line that is the special command 81 // We generate a new command-line that is the special command
64 // where we replace '@' with the original command. 82 // where we replace '@' with the original command.
65 var specialCommand = configuration['special-command']; 83 var specialCommand = configuration['special-command'];
66 if (!specialCommand.isEmpty()) { 84 if (!specialCommand.isEmpty()) {
67 Expect.isTrue(specialCommand.contains('@'), 85 Expect.isTrue(specialCommand.contains('@'),
68 "special-command must contain a '@' char"); 86 "special-command must contain a '@' char");
69 var specialCommandSplit = specialCommand.split('@'); 87 var specialCommandSplit = specialCommand.split('@');
70 var prefix = specialCommandSplit[0]; 88 var prefix = specialCommandSplit[0];
71 var suffix = specialCommandSplit[1]; 89 var suffix = specialCommandSplit[1];
72 commandLine = '$prefix $commandLine $suffix'; 90 List<Command> newCommands = [];
73 var newArguments = []; 91 for (Command c in commands) {
74 if (prefix.length > 0) { 92 var newExecutablePath;
75 var prefixSplit = prefix.split(' '); 93 var newArguments = [];
76 var newExecutablePath = prefixSplit[0]; 94
77 for (int i = 1; i < prefixSplit.length; i++) { 95 if (prefix.length > 0) {
78 var current = prefixSplit[i]; 96 var prefixSplit = prefix.split(' ');
79 if (!current.isEmpty()) newArguments.add(current); 97 newExecutablePath = prefixSplit[0];
98 for (int i = 1; i < prefixSplit.length; i++) {
99 var current = prefixSplit[i];
100 if (!current.isEmpty()) newArguments.add(current);
101 }
102 newArguments.add(c.executable);
80 } 103 }
81 newArguments.add(executablePath); 104 newArguments.addAll(arguments);
82 executablePath = newExecutablePath; 105 var suffixSplit = suffix.split(' ');
106 suffixSplit.forEach((e) {
107 if (!e.isEmpty()) newArguments.add(e);
108 });
109 final newCommand = new Command(newExecutablePath, newArguments);
110 newCommands.add(newCommand);
111 Expect.stringEquals('$prefix ${c.commandLine} $suffix',
112 newCommand.commandLine);
83 } 113 }
84 newArguments.addAll(arguments); 114 commands = newCommand;
85 var suffixSplit = suffix.split(' ');
86 suffixSplit.forEach((e) {
87 if (!e.isEmpty()) newArguments.add(e);
88 });
89 arguments = newArguments;
90 } 115 }
91 } 116 }
92 117
93 int get timeout() => configuration['timeout']; 118 int get timeout() => configuration['timeout'];
94 119
95 String get configurationString() { 120 String get configurationString() {
96 final component = configuration['component']; 121 final component = configuration['component'];
97 final mode = configuration['mode']; 122 final mode = configuration['mode'];
98 final arch = configuration['arch']; 123 final arch = configuration['arch'];
99 return "$component ${mode}_$arch"; 124 return "$component ${mode}_$arch";
100 } 125 }
101 126
102 List<String> get batchRunnerArguments() => ['-batch']; 127 List<String> get batchRunnerArguments() => ['-batch'];
103 List<String> get batchTestArguments() => arguments; 128 List<String> get batchTestArguments() => commands.last().arguments;
104 129
105 void completed() { completedHandler(this); } 130 void completed() { completedHandler(this); }
106 } 131 }
107 132
108 133
109 /** 134 /**
110 * BrowserTestCase has an extra compilation command that is run in a separate 135 * BrowserTestCase has an extra compilation command that is run in a separate
111 * process, before the regular test is run as in the base class [TestCase]. 136 * process, before the regular test is run as in the base class [TestCase].
112 * If the compilation command fails, then the rest of the test is not run. 137 * If the compilation command fails, then the rest of the test is not run.
113 */ 138 */
114 class BrowserTestCase extends TestCase { 139 class BrowserTestCase extends TestCase {
115 /** 140 /**
116 * The executable that is run in a new process in the compilation phase.
117 */
118 String compilerPath;
119 /**
120 * The arguments for the compilation command.
121 */
122 List<String> compilerArguments;
123 /**
124 * Indicates the number of potential retries remaining, to compensate for 141 * Indicates the number of potential retries remaining, to compensate for
125 * flaky browser tests. 142 * flaky browser tests.
126 */ 143 */
127 int numRetries; 144 int numRetries;
128 145
129 BrowserTestCase(displayName, 146 BrowserTestCase(displayName, commands, configuration, completedHandler,
130 this.compilerPath, 147 expectedOutcomes, [isNegative = false])
131 this.compilerArguments, 148 : super(displayName, commands, configuration, completedHandler,
132 executablePath, 149 expectedOutcomes, isNegative) {
133 arguments,
134 configuration,
135 completedHandler,
136 expectedOutcomes,
137 [isNegative = false]) : super(displayName,
138 executablePath,
139 arguments,
140 configuration,
141 completedHandler,
142 expectedOutcomes,
143 isNegative) {
144 if (compilerPath != null) {
145 commandLine = 'execution command: $commandLine';
146 String compilationCommand =
147 '$compilerPath ${Strings.join(compilerArguments, " ")}';
148 commandLine = 'compilation command: $compilationCommand\n$commandLine';
149 }
150 numRetries = 2; // Allow two retries to compensate for flaky browser tests. 150 numRetries = 2; // Allow two retries to compensate for flaky browser tests.
151 } 151 }
152 152
153 List<String> get batchRunnerArguments() => [arguments[0], '--batch']; 153 List<String> get _lastArguments() => command.last().arguments;
154
155 List<String> get batchRunnerArguments() => [_lastArguments[0], '--batch'];
156
154 List<String> get batchTestArguments() => 157 List<String> get batchTestArguments() =>
155 arguments.getRange(1, arguments.length - 1); 158 _lastArguments.getRange(1, _lastArguments.length - 1);
156 } 159 }
157 160
158 161
159 /** 162 /**
160 * TestOutput records the output of a completed test: the process's exit code, 163 * TestOutput records the output of a completed test: the process's exit code,
161 * the standard output and standard error, whether the process timed out, and 164 * the standard output and standard error, whether the process timed out, and
162 * the time the process took to run. It also contains a pointer to the 165 * the time the process took to run. It also contains a pointer to the
163 * [TestCase] this is the output of. 166 * [TestCase] this is the output of.
164 */ 167 */
165 class TestOutput { 168 class TestOutput {
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 Process process; 258 Process process;
256 TestCase testCase; 259 TestCase testCase;
257 bool timedOut = false; 260 bool timedOut = false;
258 Date startTime; 261 Date startTime;
259 Timer timeoutTimer; 262 Timer timeoutTimer;
260 List<String> stdout; 263 List<String> stdout;
261 List<String> stderr; 264 List<String> stderr;
262 List<Function> handlers; 265 List<Function> handlers;
263 bool allowRetries = false; 266 bool allowRetries = false;
264 267
268 /** Which command of [testCase.commands] is currently being executed. */
269 int currentStep;
270
265 RunningProcess(TestCase this.testCase, 271 RunningProcess(TestCase this.testCase,
266 [this.allowRetries, this.processQueue]); 272 [this.allowRetries, this.processQueue]);
267 273
268 void exitHandler(int exitCode) { 274 /**
275 * Called when all commands are executed. [exitCode] is 0 if all command
276 * succeded, otherwise it will have the exit code of the first failing
277 * command.
278 */
279 void testComplete(int exitCode) {
269 new TestOutput(testCase, exitCode, timedOut, stdout, 280 new TestOutput(testCase, exitCode, timedOut, stdout,
270 stderr, new Date.now().difference(startTime)); 281 stderr, new Date.now().difference(startTime));
271 process.close();
272 timeoutTimer.cancel(); 282 timeoutTimer.cancel();
273 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { 283 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) {
274 print(testCase.displayName); 284 print(testCase.displayName);
275 for (var line in testCase.output.stderr) print(line); 285 for (var line in testCase.output.stderr) print(line);
276 for (var line in testCase.output.stdout) print(line); 286 for (var line in testCase.output.stdout) print(line);
277 } 287 }
278 if (allowRetries != null && allowRetries 288 if (allowRetries != null && allowRetries
279 && testCase.configuration['component'] == 'webdriver' && 289 && testCase.configuration['component'] == 'webdriver' &&
280 testCase.output.unexpectedOutput && testCase.numRetries > 0) { 290 testCase.output.unexpectedOutput && testCase.numRetries > 0) {
281 // Selenium tests can be flaky. Try rerunning. 291 // Selenium tests can be flaky. Try rerunning.
282 testCase.output.requestRetry = true; 292 testCase.output.requestRetry = true;
283 } 293 }
284 if (testCase.output.requestRetry) { 294 if (testCase.output.requestRetry) {
285 testCase.output.requestRetry = false; 295 testCase.output.requestRetry = false;
286 this.timedOut = false; 296 this.timedOut = false;
287 testCase.dynamic.numRetries--; 297 testCase.dynamic.numRetries--;
288 print("Potential flake. " + 298 print("Potential flake. " +
289 "Re-running ${testCase.displayName} " + 299 "Re-running ${testCase.displayName} " +
290 "(${testCase.dynamic.numRetries} attempt(s) remains)"); 300 "(${testCase.dynamic.numRetries} attempt(s) remains)");
291 this.start(); 301 this.start();
292 } else { 302 } else {
293 testCase.completed(); 303 testCase.completed();
294 } 304 }
295 } 305 }
296 306
297 void compilerExitHandler(int exitCode) { 307 /**
298 if (exitCode != 0) { 308 * Process exit handler called at the end of every command. It internally
299 stderr.add('test.dart: Compilation step failed (exit code $exitCode)\n'); 309 * treats all but the last command as compilation steps. The last command is
300 exitHandler(exitCode); 310 * the actual test and its output is analyzed in [testComplete].
311 */
312 void stepExitHandler(int exitCode) {
313 process.close();
314 int totalSteps = testCase.commands.length;
315 String suffix =' (step $currentStep of $totalSteps)';
316 if (currentStep == totalSteps) { // done with test command
317 testComplete(exitCode);
318 } else if (exitCode != 0) {
319 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n');
320 testComplete(exitCode);
301 } else { 321 } else {
302 process.close(); 322 stderr.add('test.dart: Compilion finished $suffix\n');
303 stderr.add('test.dart: Compilation finished, starting execution\n'); 323 stdout.add('test.dart: Compilion finished $suffix\n');
304 stdout.add('test.dart: Compilation finished, starting execution\n'); 324 if (currentStep == totalSteps - 1
305 if (testCase.configuration['component'] == 'webdriver') { 325 && testCase.configuration['component'] == 'webdriver') {
306 // Note: processQueue will always be non-null for component == webdriver 326 // Note: processQueue will always be non-null for component == webdriver
307 // (It is only null for component == vm) 327 // (It is only null for component == vm)
308 processQueue._getBatchRunner(testCase).startTest(testCase); 328 processQueue._getBatchRunner(testCase).startTest(testCase);
309 } else { 329 } else {
310 runCommand(testCase.executablePath, testCase.arguments, exitHandler); 330 runCommand(testCase.commands[currentStep++], stepExitHandler);
311 } 331 }
312 } 332 }
313 } 333 }
314 334
315 Function makeReadHandler(StringInputStream source, List<String> destination) { 335 Function makeReadHandler(StringInputStream source, List<String> destination) {
316 return () { 336 return () {
317 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. 337 if (source.closed) return; // TODO(whesse): Remove when bug is fixed.
318 var line = source.readLine(); 338 var line = source.readLine();
319 while (null != line) { 339 while (null != line) {
320 destination.add(line); 340 destination.add(line);
321 line = source.readLine(); 341 line = source.readLine();
322 } 342 }
323 }; 343 };
324 } 344 }
325 345
326 void start() { 346 void start() {
327 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); 347 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP));
328 stdout = new List<String>(); 348 stdout = new List<String>();
329 stderr = new List<String>(); 349 stderr = new List<String>();
330 if (testCase is BrowserTestCase && testCase.dynamic.compilerPath != null) { 350 currentStep = 0;
331 runCommand(testCase.dynamic.compilerPath, 351 runCommand(testCase.commands[currentStep++], stepExitHandler);
332 testCase.dynamic.compilerArguments,
333 compilerExitHandler);
334 } else {
335 runCommand(testCase.executablePath, testCase.arguments, exitHandler);
336 }
337 } 352 }
338 353
339 void runCommand(String executable, 354 void runCommand(Command command,
340 List<String> arguments,
341 void exitHandler(int exitCode)) { 355 void exitHandler(int exitCode)) {
342 if (new Platform().operatingSystem() == 'windows') { 356 if (new Platform().operatingSystem() == 'windows') {
343 // Windows can't handle the first command if it is a .bat file or the like 357 // Windows can't handle the first command if it is a .bat file or the like
344 // with the slashes going the other direction. 358 // with the slashes going the other direction.
345 // TODO(efortuna): Remove this when fixed (Issue 1306). 359 // TODO(efortuna): Remove this when fixed (Issue 1306).
346 executable = executable.replaceAll('/', '\\'); 360 command.executable = command.executable.replaceAll('/', '\\');
347 } 361 }
348 process = new Process.start(executable, arguments); 362 process = new Process.start(command.executable, command.arguments);
349 process.exitHandler = exitHandler; 363 process.exitHandler = exitHandler;
350 startTime = new Date.now(); 364 startTime = new Date.now();
351 InputStream stdoutStream = process.stdout; 365 InputStream stdoutStream = process.stdout;
352 InputStream stderrStream = process.stderr; 366 InputStream stderrStream = process.stderr;
353 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream); 367 StringInputStream stdoutStringStream = new StringInputStream(stdoutStream);
354 StringInputStream stderrStringStream = new StringInputStream(stderrStream); 368 StringInputStream stderrStringStream = new StringInputStream(stderrStream);
355 stdoutStringStream.lineHandler = 369 stdoutStringStream.lineHandler =
356 makeReadHandler(stdoutStringStream, stdout); 370 makeReadHandler(stdoutStringStream, stdout);
357 stderrStringStream.lineHandler = 371 stderrStringStream.lineHandler =
358 makeReadHandler(stderrStringStream, stderr); 372 makeReadHandler(stderrStringStream, stderr);
(...skipping 16 matching lines...) Expand all
375 389
376 TestCase _currentTest; 390 TestCase _currentTest;
377 List<String> _testStdout; 391 List<String> _testStdout;
378 List<String> _testStderr; 392 List<String> _testStderr;
379 Date _startTime; 393 Date _startTime;
380 Timer _timer; 394 Timer _timer;
381 395
382 bool _isWebDriver; 396 bool _isWebDriver;
383 397
384 BatchRunnerProcess(TestCase testCase) { 398 BatchRunnerProcess(TestCase testCase) {
385 _executable = testCase.executablePath; 399 _executable = testCase.commands.last().executable;
386 _batchArguments = testCase.batchRunnerArguments; 400 _batchArguments = testCase.batchRunnerArguments;
387 _isWebDriver = testCase.configuration['component'] == 'webdriver'; 401 _isWebDriver = testCase.configuration['component'] == 'webdriver';
388 } 402 }
389 403
390 bool get active() => _currentTest != null; 404 bool get active() => _currentTest != null;
391 405
392 void startTest(TestCase testCase) { 406 void startTest(TestCase testCase) {
393 _currentTest = testCase; 407 _currentTest = testCase;
394 if (_process === null) { 408 if (_process === null) {
395 // Start process if not yet started. 409 // Start process if not yet started.
396 _executable = testCase.executablePath; 410 _executable = testCase.commands.last().executable;
397 _startProcess(() { 411 _startProcess(() {
398 doStartTest(testCase); 412 doStartTest(testCase);
399 }); 413 });
400 } else if (testCase.executablePath != _executable) { 414 } else if (testCase.commands.last().executable != _executable) {
401 // Restart this runner with the right executable for this test 415 // Restart this runner with the right executable for this test
402 // if needed. 416 // if needed.
403 _executable = testCase.executablePath; 417 _executable = testCase.commands.last().executable;
404 _batchArguments = testCase.batchRunnerArguments; 418 _batchArguments = testCase.batchRunnerArguments;
405 _process.exitHandler = (exitCode) { 419 _process.exitHandler = (exitCode) {
406 _process.close(); 420 _process.close();
407 _startProcess(() { 421 _startProcess(() {
408 doStartTest(testCase); 422 doStartTest(testCase);
409 }); 423 });
410 }; 424 };
411 _process.kill(); 425 _process.kill();
412 } else { 426 } else {
413 doStartTest(testCase); 427 doStartTest(testCase);
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 for (var runner in runners) { 739 for (var runner in runners) {
726 if (!runner.active) return runner; 740 if (!runner.active) return runner;
727 } 741 }
728 throw new Exception('Unable to find inactive batch runner.'); 742 throw new Exception('Unable to find inactive batch runner.');
729 } 743 }
730 744
731 void _tryRunTest() { 745 void _tryRunTest() {
732 _checkDone(); 746 _checkDone();
733 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) { 747 if (_numProcesses < _maxProcesses && !_tests.isEmpty()) {
734 TestCase test = _tests.removeFirst(); 748 TestCase test = _tests.removeFirst();
735 if (_verbose) print(test.commandLine); 749 if (_verbose) print(test.commands.last().commandLine);
736 if (_listTests) { 750 if (_listTests) {
737 final String tab = '\t'; 751 final String tab = '\t';
738 String outcomes = 752 String outcomes =
739 Strings.join(new List.from(test.expectedOutcomes), ','); 753 Strings.join(new List.from(test.expectedOutcomes), ',');
740 print(test.displayName + tab + outcomes + tab + test.isNegative + 754 print(test.displayName + tab + outcomes + tab + test.isNegative +
741 tab + Strings.join(test.arguments, tab)); 755 tab + Strings.join(test.commands.last().arguments, tab));
742 return; 756 return;
743 } 757 }
744 _progress.start(test); 758 _progress.start(test);
745 Function oldCallback = test.completedHandler; 759 Function oldCallback = test.completedHandler;
746 Function wrapper = (TestCase test_arg) { 760 Function wrapper = (TestCase test_arg) {
747 _numProcesses--; 761 _numProcesses--;
748 _progress.done(test_arg); 762 _progress.done(test_arg);
749 _tryRunTest(); 763 _tryRunTest();
750 oldCallback(test_arg); 764 oldCallback(test_arg);
751 }; 765 };
752 test.completedHandler = wrapper; 766 test.completedHandler = wrapper;
753 if (test.configuration['component'] == 'dartc' && 767 if (test.configuration['component'] == 'dartc' &&
754 test.displayName != 'dartc/junit_tests') { 768 test.displayName != 'dartc/junit_tests') {
755 _getBatchRunner(test).startTest(test); 769 _getBatchRunner(test).startTest(test);
756 } else { 770 } else {
757 // Once we've actually failed a test, technically, we wouldn't need to 771 // Once we've actually failed a test, technically, we wouldn't need to
758 // bother retrying any subsequent tests since the bot is already red. 772 // bother retrying any subsequent tests since the bot is already red.
759 // However, we continue to retry tests until we have actually failed 773 // However, we continue to retry tests until we have actually failed
760 // four tests (arbitrarily chosen) for more debugable output, so that 774 // four tests (arbitrarily chosen) for more debugable output, so that
761 // the developer doesn't waste his or her time trying to fix a bunch of 775 // the developer doesn't waste his or her time trying to fix a bunch of
762 // tests that appear to be broken but were actually just flakes that 776 // tests that appear to be broken but were actually just flakes that
763 // didn't get retried because there had already been one failure. 777 // didn't get retried because there had already been one failure.
764 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 778 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
765 new RunningProcess(test, allowRetry, this).start(); 779 new RunningProcess(test, allowRetry, this).start();
766 } 780 }
767 _numProcesses++; 781 _numProcesses++;
768 } 782 }
769 } 783 }
770 } 784 }
OLDNEW
« no previous file with comments | « tools/testing/dart/test_progress.dart ('k') | tools/testing/dart/test_suite.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698