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

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

Issue 11348088: Changed: TestCase.output -> TestCase.commandOutputs[] (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month 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
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.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 } 49 }
50 50
51 /** 51 /**
52 * TestCase contains all the information needed to run a test and evaluate 52 * TestCase contains all the information needed to run a test and evaluate
53 * its output. Running a test involves starting a separate process, with 53 * its output. Running a test involves starting a separate process, with
54 * the executable and arguments given by the TestCase, and recording its 54 * the executable and arguments given by the TestCase, and recording its
55 * stdout and stderr output streams, and its exit code. TestCase only 55 * stdout and stderr output streams, and its exit code. TestCase only
56 * contains static information about the test; actually running the test is 56 * contains static information about the test; actually running the test is
57 * performed by [ProcessQueue] using a [RunningProcess] object. 57 * performed by [ProcessQueue] using a [RunningProcess] object.
58 * 58 *
59 * The output information is stored in a [TestOutput] instance contained 59 * The output information is stored in a [CommandOutput] instance contained
60 * in the TestCase. The TestOutput instance is responsible for evaluating 60 * in TestCase.commandOutputs. The last CommandOutput instance is responsible
61 * if the test has passed, failed, crashed, or timed out, and the TestCase 61 * for evaluating if the test has passed, failed, crashed, or timed out, and the
62 * has information about what the expected result of the test should be. 62 * TestCase has information about what the expected result of the test should
63 * be.
63 * 64 *
64 * The TestCase has a callback function, [completedHandler], that is run when 65 * The TestCase has a callback function, [completedHandler], that is run when
65 * the test is completed. 66 * the test is completed.
66 */ 67 */
67 class TestCase { 68 class TestCase {
68 /** 69 /**
69 * A list of commands to execute. Most test cases have a single command. Frog 70 * A list of commands to execute. Most test cases have a single command.
70 * tests have two commands, one to compilate the source and another to execute 71 * Dart2js tests have two commands, one to compile the source and another
71 * it. Some isolate tests might even have three, if they require compiling 72 * to execute it. Some isolate tests might even have three, if they require
72 * multiple sources that are run in isolation. 73 * compiling multiple sources that are run in isolation.
73 */ 74 */
74 List<Command> commands; 75 List<Command> commands;
76 Map<Command, CommandOutput> commandOutputs = new Map<Command,CommandOutput>();
75 77
76 Map configuration; 78 Map configuration;
77 String displayName; 79 String displayName;
78 TestOutput output;
79 bool isNegative; 80 bool isNegative;
80 Set<String> expectedOutcomes; 81 Set<String> expectedOutcomes;
81 TestCaseEvent completedHandler; 82 TestCaseEvent completedHandler;
82 TestInformation info; 83 TestInformation info;
83 84
84 TestCase(this.displayName, 85 TestCase(this.displayName,
85 this.commands, 86 this.commands,
86 this.configuration, 87 this.configuration,
87 this.completedHandler, 88 this.completedHandler,
88 this.expectedOutcomes, 89 this.expectedOutcomes,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 newCommands.add(newCommand); 138 newCommands.add(newCommand);
138 // If there are extra spaces inside the prefix or suffix, this fails. 139 // If there are extra spaces inside the prefix or suffix, this fails.
139 String expected = 140 String expected =
140 '$prefix ${c.executable} $suffix ${Strings.join(c.arguments, ' ')}'; 141 '$prefix ${c.executable} $suffix ${Strings.join(c.arguments, ' ')}';
141 Expect.stringEquals(expected.trim(), newCommand.commandLine); 142 Expect.stringEquals(expected.trim(), newCommand.commandLine);
142 } 143 }
143 commands = newCommands; 144 commands = newCommands;
144 } 145 }
145 } 146 }
146 147
148 CommandOutput get lastCommandOutput {
149 if (commandOutputs.length == 0) {
150 throw new Exception("CommandOutputs is empty, maybe no command was run? ("
151 "displayName: '$displayName', "
152 "configurationString: '$configurationString')");
153 }
154 return commandOutputs[commands[commandOutputs.length - 1]];
155 }
156
147 int get timeout { 157 int get timeout {
148 if (expectedOutcomes.contains(SLOW)) { 158 if (expectedOutcomes.contains(SLOW)) {
149 return configuration['timeout'] * SLOW_TIMEOUT_MULTIPLIER; 159 return configuration['timeout'] * SLOW_TIMEOUT_MULTIPLIER;
150 } else { 160 } else {
151 return configuration['timeout']; 161 return configuration['timeout'];
152 } 162 }
153 } 163 }
154 164
155 String get configurationString { 165 String get configurationString {
156 final compiler = configuration['compiler']; 166 final compiler = configuration['compiler'];
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 */ 242 */
233 void notifyObservers() { 243 void notifyObservers() {
234 for (BrowserTestCase testCase in observers) { 244 for (BrowserTestCase testCase in observers) {
235 testCase.waitingForOtherTest = false; 245 testCase.waitingForOtherTest = false;
236 } 246 }
237 } 247 }
238 } 248 }
239 249
240 250
241 /** 251 /**
242 * TestOutput records the output of a completed test: the process's exit code, 252 * CommandOutput records the output of a completed command: the process's exit
243 * the standard output and standard error, whether the process timed out, and 253 * code, the standard output and standard error, whether the process timed out,
244 * the time the process took to run. It also contains a pointer to the 254 * and the time the process took to run. It also contains a pointer to the
245 * [TestCase] this is the output of. 255 * [TestCase] this is the output of.
246 */ 256 */
247 abstract class TestOutput { 257 abstract class CommandOutput {
248 factory TestOutput.fromCase(TestCase testCase, 258 factory CommandOutput.fromCase(TestCase testCase,
249 int exitCode, 259 Command command,
250 bool incomplete, 260 int exitCode,
251 bool timedOut, 261 bool incomplete,
252 List<String> stdout, 262 bool timedOut,
253 List<String> stderr, 263 List<String> stdout,
254 Duration time) { 264 List<String> stderr,
255 return new TestOutputImpl.fromCase( 265 Duration time) {
256 testCase, exitCode, incomplete, timedOut, stdout, stderr, time); 266 return new CommandOutputImpl.fromCase(testCase,
267 command,
268 exitCode,
269 incomplete,
270 timedOut,
271 stdout,
272 stderr,
273 time);
257 } 274 }
258 275
259 bool get incomplete; 276 bool get incomplete;
260 277
261 String get result; 278 String get result;
262 279
263 bool get unexpectedOutput; 280 bool get unexpectedOutput;
264 281
265 bool get hasCrashed; 282 bool get hasCrashed;
266 283
267 bool get hasTimedOut; 284 bool get hasTimedOut;
268 285
269 bool get didFail; 286 bool get didFail;
270 287
271 bool requestRetry; 288 bool requestRetry;
272 289
273 Duration get time; 290 Duration get time;
274 291
275 int get exitCode; 292 int get exitCode;
276 293
277 List<String> get stdout; 294 List<String> get stdout;
278 295
279 List<String> get stderr; 296 List<String> get stderr;
280 297
281 List<String> get diagnostics; 298 List<String> get diagnostics;
282 } 299 }
283 300
284 class TestOutputImpl implements TestOutput { 301 class CommandOutputImpl implements CommandOutput {
285 TestCase testCase; 302 TestCase testCase;
286 int exitCode; 303 int exitCode;
287 304
288 /// Records if all commands were run, true if they weren't. 305 /// Records if all commands were run, true if they weren't.
289 final bool incomplete; 306 final bool incomplete;
290 307
291 bool timedOut; 308 bool timedOut;
292 bool failed = false; 309 bool failed = false;
293 List<String> stdout; 310 List<String> stdout;
294 List<String> stderr; 311 List<String> stderr;
295 Duration time; 312 Duration time;
296 List<String> diagnostics; 313 List<String> diagnostics;
297 314
298 /** 315 /**
299 * A flag to indicate we have already printed a warning about ignoring the VM 316 * A flag to indicate we have already printed a warning about ignoring the VM
300 * crash, to limit the amount of output produced per test. 317 * crash, to limit the amount of output produced per test.
301 */ 318 */
302 bool alreadyPrintedWarning = false; 319 bool alreadyPrintedWarning = false;
303 320
304 /** 321 /**
305 * Set to true if we encounter a condition in the output that indicates we 322 * Set to true if we encounter a condition in the output that indicates we
306 * need to rerun this test. 323 * need to rerun this test.
307 */ 324 */
308 bool requestRetry = false; 325 bool requestRetry = false;
309 326
310 // Don't call this constructor, call TestOutput.fromCase() to 327 // Don't call this constructor, call CommandOutput.fromCase() to
311 // get a new TestOutput instance. 328 // get a new TestOutput instance.
312 TestOutputImpl(TestCase this.testCase, 329 CommandOutputImpl(TestCase this.testCase,
313 int this.exitCode, 330 Command command,
314 bool this.incomplete, 331 int this.exitCode,
315 bool this.timedOut, 332 bool this.incomplete,
316 List<String> this.stdout, 333 bool this.timedOut,
317 List<String> this.stderr, 334 List<String> this.stdout,
318 Duration this.time) { 335 List<String> this.stderr,
319 testCase.output = this; 336 Duration this.time) {
337 testCase.commandOutputs[command] = this;
320 diagnostics = []; 338 diagnostics = [];
321 } 339 }
322 factory TestOutputImpl.fromCase(TestCase testCase, 340 factory CommandOutputImpl.fromCase(TestCase testCase,
323 int exitCode, 341 Command command,
324 bool incomplete, 342 int exitCode,
325 bool timedOut, 343 bool incomplete,
326 List<String> stdout, 344 bool timedOut,
327 List<String> stderr, 345 List<String> stdout,
328 Duration time) { 346 List<String> stderr,
347 Duration time) {
329 if (testCase is BrowserTestCase) { 348 if (testCase is BrowserTestCase) {
330 return new BrowserTestOutputImpl(testCase, exitCode, incomplete, 349 return new BrowserCommandOutputImpl(testCase,
331 timedOut, stdout, stderr, time); 350 command,
351 exitCode,
352 incomplete,
353 timedOut,
354 stdout,
355 stderr,
356 time);
332 } else if (testCase.configuration['compiler'] == 'dartc') { 357 } else if (testCase.configuration['compiler'] == 'dartc') {
333 return new AnalysisTestOutputImpl(testCase, exitCode, timedOut, 358 return new AnalysisCommandOutputImpl(testCase,
334 stdout, stderr, time); 359 command,
360 exitCode,
361 timedOut,
362 stdout,
363 stderr,
364 time);
335 } 365 }
336 return new TestOutputImpl(testCase, exitCode, incomplete, timedOut, 366 return new CommandOutputImpl(testCase,
337 stdout, stderr, time); 367 command,
368 exitCode,
369 incomplete,
370 timedOut,
371 stdout,
372 stderr,
373 time);
338 } 374 }
339 375
340 String get result => 376 String get result =>
341 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); 377 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS));
342 378
343 bool get unexpectedOutput => !testCase.expectedOutcomes.contains(result); 379 bool get unexpectedOutput => !testCase.expectedOutcomes.contains(result);
344 380
345 bool get hasCrashed { 381 bool get hasCrashed {
346 // The Java dartc runner and dart2js exits with code 253 in case 382 // The Java dartc runner and dart2js exits with code 253 in case
347 // of unhandled exceptions. 383 // of unhandled exceptions.
(...skipping 19 matching lines...) Expand all
367 bool get hasFailed { 403 bool get hasFailed {
368 // Always fail if a runtime-error is expected and compilation failed. 404 // Always fail if a runtime-error is expected and compilation failed.
369 if (testCase.info != null && testCase.info.hasRuntimeError && incomplete) { 405 if (testCase.info != null && testCase.info.hasRuntimeError && incomplete) {
370 return true; 406 return true;
371 } 407 }
372 return testCase.isNegative ? !didFail : didFail; 408 return testCase.isNegative ? !didFail : didFail;
373 } 409 }
374 410
375 } 411 }
376 412
377 class BrowserTestOutputImpl extends TestOutputImpl { 413 class BrowserCommandOutputImpl extends CommandOutputImpl {
378 BrowserTestOutputImpl(testCase, exitCode, incomplete, 414 BrowserCommandOutputImpl(
379 timedOut, stdout, stderr, time) : 415 testCase,
380 super(testCase, exitCode, incomplete, timedOut, stdout, stderr, time); 416 command,
417 exitCode,
418 incomplete,
419 timedOut,
420 stdout,
421 stderr,
422 time) :
423 super(testCase,
424 command,
425 exitCode,
426 incomplete,
427 timedOut,
428 stdout,
429 stderr,
430 time);
381 431
382 bool get didFail { 432 bool get didFail {
383 // Browser case: 433 // Browser case:
384 // If the browser test failed, it may have been because DumpRenderTree 434 // If the browser test failed, it may have been because DumpRenderTree
385 // and the virtual framebuffer X server didn't hook up, or DRT crashed with 435 // and the virtual framebuffer X server didn't hook up, or DRT crashed with
386 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, 436 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS,
387 // so we have to do this check first. 437 // so we have to do this check first.
388 for (String line in super.stderr) { 438 for (String line in super.stderr) {
389 if (line.contains('Gtk-WARNING **: cannot open display: :99') || 439 if (line.contains('Gtk-WARNING **: cannot open display: :99') ||
390 line.contains('Failed to run command. return code=1')) { 440 line.contains('Failed to run command. return code=1')) {
(...skipping 22 matching lines...) Expand all
413 break; 463 break;
414 } 464 }
415 } 465 }
416 return true; 466 return true;
417 } 467 }
418 } 468 }
419 469
420 // The static analyzer does not actually execute code, so 470 // The static analyzer does not actually execute code, so
421 // the criteria for success now depend on the text sent 471 // the criteria for success now depend on the text sent
422 // to stderr. 472 // to stderr.
423 class AnalysisTestOutputImpl extends TestOutputImpl { 473 class AnalysisCommandOutputImpl extends CommandOutputImpl {
424 // An error line has 8 fields that look like: 474 // An error line has 8 fields that look like:
425 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source. 475 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source.
426 final int ERROR_LEVEL = 0; 476 final int ERROR_LEVEL = 0;
427 final int ERROR_TYPE = 1; 477 final int ERROR_TYPE = 1;
428 final int FORMATTED_ERROR = 7; 478 final int FORMATTED_ERROR = 7;
429 479
430 bool alreadyComputed = false; 480 bool alreadyComputed = false;
431 bool failResult; 481 bool failResult;
432 AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : 482 AnalysisCommandOutputImpl(testCase,
433 super(testCase, exitCode, false, timedOut, stdout, stderr, time); 483 command,
484 exitCode,
485 timedOut,
486 stdout,
487 stderr,
488 time) :
489 super(testCase, command, exitCode, false, timedOut, stdout, stderr, time);
434 490
435 bool get didFail { 491 bool get didFail {
436 if (!alreadyComputed) { 492 if (!alreadyComputed) {
437 failResult = _didFail(); 493 failResult = _didFail();
438 alreadyComputed = true; 494 alreadyComputed = true;
439 } 495 }
440 return failResult; 496 return failResult;
441 } 497 }
442 498
443 bool _didFail() { 499 bool _didFail() {
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 } 632 }
577 result.add(field.toString()); 633 result.add(field.toString());
578 return result; 634 return result;
579 } 635 }
580 } 636 }
581 637
582 /** 638 /**
583 * A RunningProcess actually runs a test, getting the command lines from 639 * A RunningProcess actually runs a test, getting the command lines from
584 * its [TestCase], starting the test process (and first, a compilation 640 * its [TestCase], starting the test process (and first, a compilation
585 * process if the TestCase is a [BrowserTestCase]), creating a timeout 641 * process if the TestCase is a [BrowserTestCase]), creating a timeout
586 * timer, and recording the results in a new [TestOutput] object, which it 642 * timer, and recording the results in a new [CommandOutput] object, which it
587 * attaches to the TestCase. The lifetime of the RunningProcess is limited 643 * attaches to the TestCase. The lifetime of the RunningProcess is limited
588 * to the time it takes to start the process, run the process, and record 644 * to the time it takes to start the process, run the process, and record
589 * the result; there are no pointers to it, so it should be available to 645 * the result; there are no pointers to it, so it should be available to
590 * be garbage collected as soon as it is done. 646 * be garbage collected as soon as it is done.
591 */ 647 */
592 class RunningProcess { 648 class RunningProcess {
593 ProcessQueue processQueue; 649 ProcessQueue processQueue;
594 Process process; 650 Process process;
595 TestCase testCase; 651 TestCase testCase;
596 bool timedOut = false; 652 bool timedOut = false;
597 Date startTime; 653 Date startTime;
598 Timer timeoutTimer; 654 Timer timeoutTimer;
599 List<String> stdout; 655 List<String> stdout;
600 List<String> stderr; 656 List<String> stderr;
601 bool allowRetries; 657 bool allowRetries;
602 658
603 /** Which command of [testCase.commands] is currently being executed. */ 659 /** Which command of [testCase.commands] is currently being executed. */
604 int currentStep; 660 int currentStep;
605 661
606 RunningProcess(TestCase this.testCase, 662 RunningProcess(TestCase this.testCase,
607 [this.allowRetries = false, this.processQueue]); 663 [this.allowRetries = false, this.processQueue]);
608 664
609 /** 665 /**
610 * Called when all commands are executed. [exitCode] is 0 if all command 666 * Called when all commands are executed.
611 * succeded, otherwise it will have the exit code of the first failing
612 * command.
613 */ 667 */
614 void testComplete(int exitCode, bool incomplete) { 668 void testComplete(CommandOutput lastCommandOutput) {
615 new TestOutput.fromCase(testCase, exitCode, incomplete, timedOut, stdout,
616 stderr, new Date.now().difference(startTime));
617 timeoutTimer.cancel(); 669 timeoutTimer.cancel();
618 if (testCase.output.unexpectedOutput 670 if (lastCommandOutput.unexpectedOutput
619 && testCase.configuration['verbose'] != null 671 && testCase.configuration['verbose'] != null
620 && testCase.configuration['verbose']) { 672 && testCase.configuration['verbose']) {
621 print(testCase.displayName); 673 print(testCase.displayName);
622 for (var line in testCase.output.stderr) print(line); 674 for (var line in lastCommandOutput.stderr) print(line);
623 for (var line in testCase.output.stdout) print(line); 675 for (var line in lastCommandOutput.stdout) print(line);
624 } 676 }
625 if (allowRetries && testCase.usesWebDriver 677 if (allowRetries && testCase.usesWebDriver
626 && testCase.output.unexpectedOutput 678 && lastCommandOutput.unexpectedOutput
627 && (testCase as BrowserTestCase).numRetries > 0) { 679 && (testCase as BrowserTestCase).numRetries > 0) {
628 // Selenium tests can be flaky. Try rerunning. 680 // Selenium tests can be flaky. Try rerunning.
629 testCase.output.requestRetry = true; 681 lastCommandOutput.requestRetry = true;
630 } 682 }
631 if (testCase.output.requestRetry) { 683 if (lastCommandOutput.requestRetry) {
632 testCase.output.requestRetry = false; 684 lastCommandOutput.requestRetry = false;
633 this.timedOut = false; 685 this.timedOut = false;
634 (testCase as BrowserTestCase).numRetries--; 686 (testCase as BrowserTestCase).numRetries--;
635 print("Potential flake. Re-running ${testCase.displayName} " 687 print("Potential flake. Re-running ${testCase.displayName} "
636 "(${(testCase as BrowserTestCase).numRetries} attempt(s) remains)"); 688 "(${(testCase as BrowserTestCase).numRetries} attempt(s) remains)");
637 // When retrying we need to reset the timeout as well. 689 // When retrying we need to reset the timeout as well.
638 // Otherwise there will be no timeout handling for the retry. 690 // Otherwise there will be no timeout handling for the retry.
639 timeoutTimer = null; 691 timeoutTimer = null;
640 this.start(); 692 this.start();
641 } else { 693 } else {
642 testCase.completed(); 694 testCase.completed();
643 } 695 }
644 } 696 }
645 697
646 /** 698 /**
647 * Process exit handler called at the end of every command. It internally 699 * Process exit handler called at the end of every command. It internally
648 * treats all but the last command as compilation steps. The last command is 700 * treats all but the last command as compilation steps. The last command is
649 * the actual test and its output is analyzed in [testComplete]. 701 * the actual test and its output is analyzed in [testComplete].
650 */ 702 */
651 void stepExitHandler(int exitCode) { 703 void commandComplete(Command command, int exitCode) {
652 process = null; 704 process = null;
653 int totalSteps = testCase.commands.length; 705 int totalSteps = testCase.commands.length;
654 String suffix =' (step $currentStep of $totalSteps)'; 706 String suffix =' (step $currentStep of $totalSteps)';
655 if (timedOut) { 707 if (timedOut) {
656 // Non-webdriver test timed out before it could complete. Webdriver tests 708 // Non-webdriver test timed out before it could complete. Webdriver tests
657 // run their own timeouts by timing from the launch of the browser (which 709 // run their own timeouts by timing from the launch of the browser (which
658 // could be delayed). 710 // could be delayed).
659 testComplete(0, true); 711 testComplete(createCommandOutput(command, 0, true));
660 } else if (currentStep == totalSteps) { 712 } else if (currentStep == totalSteps) {
661 // Done with all test commands. 713 // Done with all test commands.
662 testComplete(exitCode, false); 714 testComplete(createCommandOutput(command, exitCode, false));
663 } else if (exitCode != 0) { 715 } else if (exitCode != 0) {
664 // One of the steps failed. 716 // One of the steps failed.
665 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n'); 717 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n');
666 testComplete(exitCode, true); 718 testComplete(createCommandOutput(command, exitCode, true));
667 } else { 719 } else {
720 createCommandOutput(command, exitCode, true);
668 // One compilation step successfully completed, move on to the 721 // One compilation step successfully completed, move on to the
669 // next step. 722 // next step.
670 stderr.add('test.dart: Compilation finished $suffix\n'); 723 stderr.add('test.dart: Compilation finished $suffix\n');
671 stdout.add('test.dart: Compilation finished $suffix\n'); 724 stdout.add('test.dart: Compilation finished $suffix\n');
672 if (currentStep == totalSteps - 1 && testCase.usesWebDriver && 725 if (currentStep == totalSteps - 1 && testCase.usesWebDriver &&
673 !testCase.configuration['noBatch']) { 726 !testCase.configuration['noBatch']) {
674 // Note: processQueue will always be non-null for runtime == ie9, ie10, 727 // Note: processQueue will always be non-null for runtime == ie9, ie10,
675 // ff, safari, chrome, opera. (It is only null for runtime == vm) 728 // ff, safari, chrome, opera. (It is only null for runtime == vm)
676 // This RunningProcess object is done, and hands over control to 729 // This RunningProcess object is done, and hands over control to
677 // BatchRunner.startTest(), which handles reporting, etc. 730 // BatchRunner.startTest(), which handles reporting, etc.
678 timeoutTimer.cancel(); 731 timeoutTimer.cancel();
679 processQueue._getBatchRunner(testCase).startTest(testCase); 732 processQueue._getBatchRunner(testCase).startTest(testCase);
680 } else { 733 } else {
681 runCommand(testCase.commands[currentStep++], stepExitHandler); 734 runCommand(testCase.commands[currentStep++], commandComplete);
682 } 735 }
683 } 736 }
684 } 737 }
685 738
739 /**
740 * Called for all executed commands.
741 */
742 CommandOutput createCommandOutput(Command command,
743 int exitCode,
744 bool incomplete) {
745 var commandOutput = new CommandOutput.fromCase(
746 testCase,
747 command,
748 exitCode,
749 incomplete,
750 timedOut,
751 stdout,
752 stderr,
753 new Date.now().difference(startTime));
754 resetLocalOutputInformation();
755 return commandOutput;
756 }
757
758 void resetLocalOutputInformation() {
759 stdout = new List<String>();
760 stderr = new List<String>();
761 }
762
686 VoidFunction makeReadHandler(StringInputStream source, 763 VoidFunction makeReadHandler(StringInputStream source,
687 List<String> destination) { 764 List<String> destination) {
688 void handler () { 765 void handler () {
689 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. 766 if (source.closed) return; // TODO(whesse): Remove when bug is fixed.
690 var line = source.readLine(); 767 var line = source.readLine();
691 while (null != line) { 768 while (null != line) {
692 destination.add(line); 769 destination.add(line);
693 line = source.readLine(); 770 line = source.readLine();
694 } 771 }
695 } 772 }
696 return handler; 773 return handler;
697 } 774 }
698 775
699 void start() { 776 void start() {
700 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); 777 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP));
701 stdout = new List<String>(); 778 resetLocalOutputInformation();
702 stderr = new List<String>();
703 currentStep = 0; 779 currentStep = 0;
704 startTime = new Date.now(); 780 startTime = new Date.now();
705 runCommand(testCase.commands[currentStep++], stepExitHandler); 781 runCommand(testCase.commands[currentStep++], commandComplete);
706 } 782 }
707 783
708 void runCommand(Command command, void exitHandler(int exitCode)) { 784 void runCommand(Command command, void commandCompleteHandler(Command, int)) {
785 void processExitHandler(int returnCode) {
786 commandCompleteHandler(command, returnCode);
787 }
788
709 Future processFuture = Process.start(command.executable, command.arguments); 789 Future processFuture = Process.start(command.executable, command.arguments);
710 processFuture.then((Process p) { 790 processFuture.then((Process p) {
711 process = p; 791 process = p;
712 process.onExit = exitHandler; 792 process.onExit = processExitHandler;
713 var stdoutStringStream = new StringInputStream(process.stdout); 793 var stdoutStringStream = new StringInputStream(process.stdout);
714 var stderrStringStream = new StringInputStream(process.stderr); 794 var stderrStringStream = new StringInputStream(process.stderr);
715 stdoutStringStream.onLine = 795 stdoutStringStream.onLine =
716 makeReadHandler(stdoutStringStream, stdout); 796 makeReadHandler(stdoutStringStream, stdout);
717 stderrStringStream.onLine = 797 stderrStringStream.onLine =
718 makeReadHandler(stderrStringStream, stderr); 798 makeReadHandler(stderrStringStream, stderr);
719 if (timeoutTimer == null) { 799 if (timeoutTimer == null) {
720 // Create one timeout timer when starting test case, remove it at end. 800 // Create one timeout timer when starting test case, remove it at end.
721 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler); 801 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler);
722 } 802 }
723 // If the timeout fired in between two commands, kill the just 803 // If the timeout fired in between two commands, kill the just
724 // started process immediately. 804 // started process immediately.
725 if (timedOut) safeKill(process); 805 if (timedOut) safeKill(process);
726 }); 806 });
727 processFuture.handleException((e) { 807 processFuture.handleException((e) {
728 print("Process error:"); 808 print("Process error:");
729 print(" Command: $command"); 809 print(" Command: $command");
730 print(" Error: $e"); 810 print(" Error: $e");
731 testComplete(-1, false); 811 testComplete(createCommandOutput(command, -1, false));
732 return true; 812 return true;
733 }); 813 });
734 } 814 }
735 815
736 void timeoutHandler(Timer unusedTimer) { 816 void timeoutHandler(Timer unusedTimer) {
737 timedOut = true; 817 timedOut = true;
738 safeKill(process); 818 safeKill(process);
739 } 819 }
740 820
741 void safeKill(Process p) { 821 void safeKill(Process p) {
(...skipping 10 matching lines...) Expand all
752 /** 832 /**
753 * This class holds a value, that can be changed. It is used when 833 * This class holds a value, that can be changed. It is used when
754 * closures need a shared value, that they can all change and read. 834 * closures need a shared value, that they can all change and read.
755 */ 835 */
756 class MutableValue<T> { 836 class MutableValue<T> {
757 MutableValue(T this.value); 837 MutableValue(T this.value);
758 T value; 838 T value;
759 } 839 }
760 840
761 class BatchRunnerProcess { 841 class BatchRunnerProcess {
842 Command _command;
762 String _executable; 843 String _executable;
763 List<String> _batchArguments; 844 List<String> _batchArguments;
764 845
765 Process _process; 846 Process _process;
766 StringInputStream _stdoutStream; 847 StringInputStream _stdoutStream;
767 StringInputStream _stderrStream; 848 StringInputStream _stderrStream;
768 849
769 TestCase _currentTest; 850 TestCase _currentTest;
770 List<String> _testStdout; 851 List<String> _testStdout;
771 List<String> _testStderr; 852 List<String> _testStderr;
772 String _status; 853 String _status;
773 bool _stdoutDrained = false; 854 bool _stdoutDrained = false;
774 bool _stderrDrained = false; 855 bool _stderrDrained = false;
775 MutableValue<bool> _ignoreStreams; 856 MutableValue<bool> _ignoreStreams;
776 Date _startTime; 857 Date _startTime;
777 Timer _timer; 858 Timer _timer;
778 859
779 bool _isWebDriver; 860 bool _isWebDriver;
780 861
781 BatchRunnerProcess(TestCase testCase) { 862 BatchRunnerProcess(TestCase testCase) {
863 _command = testCase.commands.last;
782 _executable = testCase.commands.last.executable; 864 _executable = testCase.commands.last.executable;
783 _batchArguments = testCase.batchRunnerArguments; 865 _batchArguments = testCase.batchRunnerArguments;
784 _isWebDriver = testCase.usesWebDriver; 866 _isWebDriver = testCase.usesWebDriver;
785 } 867 }
786 868
787 bool get active => _currentTest != null; 869 bool get active => _currentTest != null;
788 870
789 void startTest(TestCase testCase) { 871 void startTest(TestCase testCase) {
790 Expect.isNull(_currentTest); 872 Expect.isNull(_currentTest);
791 _currentTest = testCase; 873 _currentTest = testCase;
874 _command = testCase.commands.last;
792 if (_process == null) { 875 if (_process == null) {
793 // Start process if not yet started. 876 // Start process if not yet started.
794 _executable = testCase.commands.last.executable; 877 _executable = testCase.commands.last.executable;
795 _startProcess(() { 878 _startProcess(() {
796 doStartTest(testCase); 879 doStartTest(testCase);
797 }); 880 });
798 } else if (testCase.commands.last.executable != _executable) { 881 } else if (testCase.commands.last.executable != _executable) {
799 // Restart this runner with the right executable for this test 882 // Restart this runner with the right executable for this test
800 // if needed. 883 // if needed.
801 _executable = testCase.commands.last.executable; 884 _executable = testCase.commands.last.executable;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 } 945 }
863 946
864 void _reportResult() { 947 void _reportResult() {
865 if (!active) return; 948 if (!active) return;
866 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' 949 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
867 950
868 var outcome = _status.split(" ")[2]; 951 var outcome = _status.split(" ")[2];
869 var exitCode = 0; 952 var exitCode = 0;
870 if (outcome == "CRASH") exitCode = -10; 953 if (outcome == "CRASH") exitCode = -10;
871 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; 954 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
872 new TestOutput.fromCase(_currentTest, exitCode, false, 955 new CommandOutput.fromCase(_currentTest,
873 (outcome == "TIMEOUT"), 956 _command,
874 _testStdout, _testStderr, 957 exitCode,
875 new Date.now().difference(_startTime)); 958 false,
959 (outcome == "TIMEOUT"),
960 _testStdout,
961 _testStderr,
962 new Date.now().difference(_startTime));
876 var test = _currentTest; 963 var test = _currentTest;
877 _currentTest = null; 964 _currentTest = null;
878 test.completed(); 965 test.completed();
879 } 966 }
880 967
881 void _stderrDone() { 968 void _stderrDone() {
882 _stderrDrained = true; 969 _stderrDrained = true;
883 // Move on when both stdout and stderr has been drained. 970 // Move on when both stdout and stderr has been drained.
884 if (_stdoutDrained) _reportResult(); 971 if (_stdoutDrained) _reportResult();
885 } 972 }
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after
1330 // the developer doesn't waste his or her time trying to fix a bunch of 1417 // the developer doesn't waste his or her time trying to fix a bunch of
1331 // tests that appear to be broken but were actually just flakes that 1418 // tests that appear to be broken but were actually just flakes that
1332 // didn't get retried because there had already been one failure. 1419 // didn't get retried because there had already been one failure.
1333 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 1420 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
1334 new RunningProcess(test, allowRetry, this).start(); 1421 new RunningProcess(test, allowRetry, this).start();
1335 } 1422 }
1336 _numProcesses++; 1423 _numProcesses++;
1337 } 1424 }
1338 } 1425 }
1339 } 1426 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698