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

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

Issue 11293278: 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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 * the test is completed. 65 * the test is completed.
66 */ 66 */
67 class TestCase { 67 class TestCase {
68 /** 68 /**
69 * A list of commands to execute. Most test cases have a single command. Frog 69 * A list of commands to execute. Most test cases have a single command. Frog
70 * tests have two commands, one to compilate the source and another to execute 70 * tests have two commands, one to compilate the source and another to execute
71 * it. Some isolate tests might even have three, if they require compiling 71 * it. Some isolate tests might even have three, if they require compiling
72 * multiple sources that are run in isolation. 72 * multiple sources that are run in isolation.
73 */ 73 */
74 List<Command> commands; 74 List<Command> commands;
75 Map<Command,CommandOutput> commandOutputs = new Map<Command,CommandOutput>();
ricow1 2012/11/14 16:59:53 space after ,
kustermann 2012/11/14 17:41:22 Done.
75 76
76 Map configuration; 77 Map configuration;
77 String displayName; 78 String displayName;
78 TestOutput output;
79 bool isNegative; 79 bool isNegative;
80 Set<String> expectedOutcomes; 80 Set<String> expectedOutcomes;
81 TestCaseEvent completedHandler; 81 TestCaseEvent completedHandler;
82 TestInformation info; 82 TestInformation info;
83 83
84 TestCase(this.displayName, 84 TestCase(this.displayName,
85 this.commands, 85 this.commands,
86 this.configuration, 86 this.configuration,
87 this.completedHandler, 87 this.completedHandler,
88 this.expectedOutcomes, 88 this.expectedOutcomes,
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 newCommands.add(newCommand); 137 newCommands.add(newCommand);
138 // If there are extra spaces inside the prefix or suffix, this fails. 138 // If there are extra spaces inside the prefix or suffix, this fails.
139 String expected = 139 String expected =
140 '$prefix ${c.executable} $suffix ${Strings.join(c.arguments, ' ')}'; 140 '$prefix ${c.executable} $suffix ${Strings.join(c.arguments, ' ')}';
141 Expect.stringEquals(expected.trim(), newCommand.commandLine); 141 Expect.stringEquals(expected.trim(), newCommand.commandLine);
142 } 142 }
143 commands = newCommands; 143 commands = newCommands;
144 } 144 }
145 } 145 }
146 146
147 CommandOutput get lastCommandOutput {
148 // Note: If commands = [cmd1, cmd2, cmd3] and cmd2 fails then
149 // commandOutputs contains only outputs for cmd1 and cmd2.
ricow1 2012/11/14 16:59:53 you could just do return commandOutputs[commands[c
kustermann 2012/11/14 17:41:22 Done.
150 var i = commands.length-1;
151 while (i>=0) {
ricow1 2012/11/14 16:59:53 spaces around >=
kustermann 2012/11/14 17:41:22 This code is now removed! On 2012/11/14 16:59:53,
152 if (commandOutputs.containsKey(commands[i])) {
153 return commandOutputs[commands[i]];
154 }
155 i--;
156 }
157 throw new Exception("CommandOutputs is empty, maybe no command was run?");
158 }
159
147 int get timeout { 160 int get timeout {
148 if (expectedOutcomes.contains(SLOW)) { 161 if (expectedOutcomes.contains(SLOW)) {
149 return configuration['timeout'] * SLOW_TIMEOUT_MULTIPLIER; 162 return configuration['timeout'] * SLOW_TIMEOUT_MULTIPLIER;
150 } else { 163 } else {
151 return configuration['timeout']; 164 return configuration['timeout'];
152 } 165 }
153 } 166 }
154 167
155 String get configurationString { 168 String get configurationString {
156 final compiler = configuration['compiler']; 169 final compiler = configuration['compiler'];
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 } 250 }
238 } 251 }
239 252
240 253
241 /** 254 /**
242 * TestOutput records the output of a completed test: the process's exit code, 255 * TestOutput records the output of a completed test: the process's exit code,
243 * the standard output and standard error, whether the process timed out, and 256 * the standard output and standard error, whether the process timed out, and
244 * the time the process took to run. It also contains a pointer to the 257 * the time the process took to run. It also contains a pointer to the
245 * [TestCase] this is the output of. 258 * [TestCase] this is the output of.
246 */ 259 */
247 abstract class TestOutput { 260 abstract class CommandOutput {
248 factory TestOutput.fromCase(TestCase testCase, 261 factory CommandOutput.fromCase(TestCase testCase,
249 int exitCode, 262 Command command,
250 bool incomplete, 263 int exitCode,
251 bool timedOut, 264 bool incomplete,
252 List<String> stdout, 265 bool timedOut,
253 List<String> stderr, 266 List<String> stdout,
254 Duration time) { 267 List<String> stderr,
255 return new TestOutputImpl.fromCase( 268 Duration time) {
256 testCase, exitCode, incomplete, timedOut, stdout, stderr, time); 269 return new CommandOutputImpl.fromCase(testCase,
270 command, exitCode, incomplete, timedOut, stdout, stderr, time);
ricow1 2012/11/14 16:59:53 one argument per line
kustermann 2012/11/14 17:41:22 Done.
257 } 271 }
258 272
259 bool get incomplete; 273 bool get incomplete;
260 274
261 String get result; 275 String get result;
262 276
263 bool get unexpectedOutput; 277 bool get unexpectedOutput;
264 278
265 bool get hasCrashed; 279 bool get hasCrashed;
266 280
267 bool get hasTimedOut; 281 bool get hasTimedOut;
268 282
269 bool get didFail; 283 bool get didFail;
270 284
271 bool requestRetry; 285 bool requestRetry;
272 286
273 Duration get time; 287 Duration get time;
274 288
275 int get exitCode; 289 int get exitCode;
276 290
277 List<String> get stdout; 291 List<String> get stdout;
278 292
279 List<String> get stderr; 293 List<String> get stderr;
280 294
281 List<String> get diagnostics; 295 List<String> get diagnostics;
282 } 296 }
283 297
284 class TestOutputImpl implements TestOutput { 298 class CommandOutputImpl implements CommandOutput {
285 TestCase testCase; 299 TestCase testCase;
286 int exitCode; 300 int exitCode;
287 301
288 /// Records if all commands were run, true if they weren't. 302 /// Records if all commands were run, true if they weren't.
289 final bool incomplete; 303 final bool incomplete;
290 304
291 bool timedOut; 305 bool timedOut;
292 bool failed = false; 306 bool failed = false;
293 List<String> stdout; 307 List<String> stdout;
294 List<String> stderr; 308 List<String> stderr;
295 Duration time; 309 Duration time;
296 List<String> diagnostics; 310 List<String> diagnostics;
297 311
298 /** 312 /**
299 * A flag to indicate we have already printed a warning about ignoring the VM 313 * 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. 314 * crash, to limit the amount of output produced per test.
301 */ 315 */
302 bool alreadyPrintedWarning = false; 316 bool alreadyPrintedWarning = false;
303 317
304 /** 318 /**
305 * Set to true if we encounter a condition in the output that indicates we 319 * Set to true if we encounter a condition in the output that indicates we
306 * need to rerun this test. 320 * need to rerun this test.
307 */ 321 */
308 bool requestRetry = false; 322 bool requestRetry = false;
309 323
310 // Don't call this constructor, call TestOutput.fromCase() to 324 // Don't call this constructor, call TestOutput.fromCase() to
311 // get a new TestOutput instance. 325 // get a new TestOutput instance.
312 TestOutputImpl(TestCase this.testCase, 326 CommandOutputImpl(TestCase this.testCase,
327 Command command,
ricow1 2012/11/14 16:59:53 indentation
kustermann 2012/11/14 17:41:22 Done.
313 int this.exitCode, 328 int this.exitCode,
314 bool this.incomplete, 329 bool this.incomplete,
315 bool this.timedOut, 330 bool this.timedOut,
316 List<String> this.stdout, 331 List<String> this.stdout,
317 List<String> this.stderr, 332 List<String> this.stderr,
318 Duration this.time) { 333 Duration this.time) {
319 testCase.output = this; 334 testCase.commandOutputs[command] = this;
320 diagnostics = []; 335 diagnostics = [];
321 } 336 }
322 factory TestOutputImpl.fromCase(TestCase testCase, 337 factory CommandOutputImpl.fromCase(TestCase testCase,
338 Command command,
ricow1 2012/11/14 16:59:53 indentation
kustermann 2012/11/14 17:41:22 Done.
323 int exitCode, 339 int exitCode,
324 bool incomplete, 340 bool incomplete,
325 bool timedOut, 341 bool timedOut,
326 List<String> stdout, 342 List<String> stdout,
327 List<String> stderr, 343 List<String> stderr,
328 Duration time) { 344 Duration time) {
329 if (testCase is BrowserTestCase) { 345 if (testCase is BrowserTestCase) {
330 return new BrowserTestOutputImpl(testCase, exitCode, incomplete, 346 return new BrowserCommandOutputImpl(testCase, command, exitCode,
347 incomplete, timedOut, stdout, stderr, time);
ricow1 2012/11/14 16:59:53 all or one per line
Bill Hesse 2012/11/14 17:07:34 These arguments should be all on one line or one o
kustermann 2012/11/14 17:41:22 Done.
kustermann 2012/11/14 17:41:22 Done.
348 } else if (testCase.configuration['compiler'] == 'dartc') {
349 return new AnalysisCommandOutputImpl(testCase, command, exitCode,
ricow1 2012/11/14 16:59:53 all or one per line
kustermann 2012/11/14 17:41:22 Done.
331 timedOut, stdout, stderr, time); 350 timedOut, stdout, stderr, time);
332 } else if (testCase.configuration['compiler'] == 'dartc') {
333 return new AnalysisTestOutputImpl(testCase, exitCode, timedOut,
334 stdout, stderr, time);
335 } 351 }
336 return new TestOutputImpl(testCase, exitCode, incomplete, timedOut, 352 return new CommandOutputImpl(testCase, command, exitCode, incomplete,
ricow1 2012/11/14 16:59:53 all or one per line
kustermann 2012/11/14 17:41:22 Done.
337 stdout, stderr, time); 353 timedOut, stdout, stderr, time);
338 } 354 }
339 355
340 String get result => 356 String get result =>
341 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); 357 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS));
342 358
343 bool get unexpectedOutput => !testCase.expectedOutcomes.contains(result); 359 bool get unexpectedOutput => !testCase.expectedOutcomes.contains(result);
344 360
345 bool get hasCrashed { 361 bool get hasCrashed {
346 // The Java dartc runner and dart2js exits with code 253 in case 362 // The Java dartc runner and dart2js exits with code 253 in case
347 // of unhandled exceptions. 363 // of unhandled exceptions.
(...skipping 19 matching lines...) Expand all
367 bool get hasFailed { 383 bool get hasFailed {
368 // Always fail if a runtime-error is expected and compilation failed. 384 // Always fail if a runtime-error is expected and compilation failed.
369 if (testCase.info != null && testCase.info.hasRuntimeError && incomplete) { 385 if (testCase.info != null && testCase.info.hasRuntimeError && incomplete) {
370 return true; 386 return true;
371 } 387 }
372 return testCase.isNegative ? !didFail : didFail; 388 return testCase.isNegative ? !didFail : didFail;
373 } 389 }
374 390
375 } 391 }
376 392
377 class BrowserTestOutputImpl extends TestOutputImpl { 393 class BrowserCommandOutputImpl extends CommandOutputImpl {
378 BrowserTestOutputImpl(testCase, exitCode, incomplete, 394 BrowserCommandOutputImpl(testCase, command, exitCode, incomplete,
379 timedOut, stdout, stderr, time) : 395 timedOut, stdout, stderr, time) :
ricow1 2012/11/14 16:59:53 indentation
kustermann 2012/11/14 17:41:22 Done.
380 super(testCase, exitCode, incomplete, timedOut, stdout, stderr, time); 396 super(testCase, command, exitCode, incomplete, timedOut, stdout, stderr,
397 time);
381 398
382 bool get didFail { 399 bool get didFail {
383 // Browser case: 400 // Browser case:
384 // If the browser test failed, it may have been because DumpRenderTree 401 // 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 402 // 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, 403 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS,
387 // so we have to do this check first. 404 // so we have to do this check first.
388 for (String line in super.stderr) { 405 for (String line in super.stderr) {
389 if (line.contains('Gtk-WARNING **: cannot open display: :99') || 406 if (line.contains('Gtk-WARNING **: cannot open display: :99') ||
390 line.contains('Failed to run command. return code=1')) { 407 line.contains('Failed to run command. return code=1')) {
(...skipping 22 matching lines...) Expand all
413 break; 430 break;
414 } 431 }
415 } 432 }
416 return true; 433 return true;
417 } 434 }
418 } 435 }
419 436
420 // The static analyzer does not actually execute code, so 437 // The static analyzer does not actually execute code, so
421 // the criteria for success now depend on the text sent 438 // the criteria for success now depend on the text sent
422 // to stderr. 439 // to stderr.
423 class AnalysisTestOutputImpl extends TestOutputImpl { 440 class AnalysisCommandOutputImpl extends CommandOutputImpl {
424 // An error line has 8 fields that look like: 441 // An error line has 8 fields that look like:
425 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source. 442 // ERROR|COMPILER|MISSING_SOURCE|file:/tmp/t.dart|15|1|24|Missing source.
426 final int ERROR_LEVEL = 0; 443 final int ERROR_LEVEL = 0;
427 final int ERROR_TYPE = 1; 444 final int ERROR_TYPE = 1;
428 final int FORMATTED_ERROR = 7; 445 final int FORMATTED_ERROR = 7;
429 446
430 bool alreadyComputed = false; 447 bool alreadyComputed = false;
431 bool failResult; 448 bool failResult;
432 AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : 449 AnalysisCommandOutputImpl(testCase, command, exitCode, timedOut, stdout,
433 super(testCase, exitCode, false, timedOut, stdout, stderr, time); 450 stderr, time) :
451 super(testCase, command, exitCode, false, timedOut, stdout, stderr, time);
434 452
435 bool get didFail { 453 bool get didFail {
436 if (!alreadyComputed) { 454 if (!alreadyComputed) {
437 failResult = _didFail(); 455 failResult = _didFail();
438 alreadyComputed = true; 456 alreadyComputed = true;
439 } 457 }
440 return failResult; 458 return failResult;
441 } 459 }
442 460
443 bool _didFail() { 461 bool _didFail() {
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 List<String> stderr; 618 List<String> stderr;
601 bool allowRetries; 619 bool allowRetries;
602 620
603 /** Which command of [testCase.commands] is currently being executed. */ 621 /** Which command of [testCase.commands] is currently being executed. */
604 int currentStep; 622 int currentStep;
605 623
606 RunningProcess(TestCase this.testCase, 624 RunningProcess(TestCase this.testCase,
607 [this.allowRetries = false, this.processQueue]); 625 [this.allowRetries = false, this.processQueue]);
608 626
609 /** 627 /**
610 * Called when all commands are executed. [exitCode] is 0 if all command 628 * Called when all commands are executed. [exitCode] is 0 if all command
Bill Hesse 2012/11/14 17:07:34 Is this comment still correct? Do we reach here a
kustermann 2012/11/14 17:41:22 I think so. In the commandComplete function below,
611 * succeded, otherwise it will have the exit code of the first failing 629 * succeded, otherwise it will have the exit code of the first failing
612 * command. 630 * command.
613 */ 631 */
614 void testComplete(int exitCode, bool incomplete) { 632 void testComplete(Command lastCommand, int exitCode, bool incomplete) {
615 new TestOutput.fromCase(testCase, exitCode, incomplete, timedOut, stdout, 633 var lastCmdOut = new CommandOutput.fromCase(testCase, lastCommand,
Bill Hesse 2012/11/14 17:07:34 lastCommandOutput, not lastCmdOut. Never abbrevia
kustermann 2012/11/14 17:41:22 Done.
616 stderr, new Date.now().difference(startTime)); 634 exitCode, incomplete, timedOut, stdout, stderr,
635 new Date.now().difference(startTime));
617 timeoutTimer.cancel(); 636 timeoutTimer.cancel();
618 if (testCase.output.unexpectedOutput 637 if (lastCmdOut.unexpectedOutput
619 && testCase.configuration['verbose'] != null 638 && testCase.configuration['verbose'] != null
620 && testCase.configuration['verbose']) { 639 && testCase.configuration['verbose']) {
621 print(testCase.displayName); 640 print(testCase.displayName);
622 for (var line in testCase.output.stderr) print(line); 641 for (var line in lastCmdOut.stderr) print(line);
623 for (var line in testCase.output.stdout) print(line); 642 for (var line in lastCmdOut.stdout) print(line);
624 } 643 }
625 if (allowRetries && testCase.usesWebDriver 644 if (allowRetries && testCase.usesWebDriver
626 && testCase.output.unexpectedOutput 645 && lastCmdOut.unexpectedOutput
627 && (testCase as BrowserTestCase).numRetries > 0) { 646 && (testCase as BrowserTestCase).numRetries > 0) {
628 // Selenium tests can be flaky. Try rerunning. 647 // Selenium tests can be flaky. Try rerunning.
629 testCase.output.requestRetry = true; 648 lastCmdOut.requestRetry = true;
630 } 649 }
631 if (testCase.output.requestRetry) { 650 if (lastCmdOut.requestRetry) {
632 testCase.output.requestRetry = false; 651 lastCmdOut.requestRetry = false;
633 this.timedOut = false; 652 this.timedOut = false;
634 (testCase as BrowserTestCase).numRetries--; 653 (testCase as BrowserTestCase).numRetries--;
635 print("Potential flake. Re-running ${testCase.displayName} " 654 print("Potential flake. Re-running ${testCase.displayName} "
636 "(${(testCase as BrowserTestCase).numRetries} attempt(s) remains)"); 655 "(${(testCase as BrowserTestCase).numRetries} attempt(s) remains)");
637 // When retrying we need to reset the timeout as well. 656 // When retrying we need to reset the timeout as well.
638 // Otherwise there will be no timeout handling for the retry. 657 // Otherwise there will be no timeout handling for the retry.
639 timeoutTimer = null; 658 timeoutTimer = null;
640 this.start(); 659 this.start();
641 } else { 660 } else {
642 testCase.completed(); 661 testCase.completed();
643 } 662 }
644 } 663 }
645 664
646 /** 665 /**
647 * Process exit handler called at the end of every command. It internally 666 * 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 667 * treats all but the last command as compilation steps. The last command is
649 * the actual test and its output is analyzed in [testComplete]. 668 * the actual test and its output is analyzed in [testComplete].
650 */ 669 */
651 void stepExitHandler(int exitCode) { 670 void commandComplete(Command cmd, int exitCode) {
Bill Hesse 2012/11/14 17:07:34 command
kustermann 2012/11/14 17:41:22 Done.
652 process = null; 671 process = null;
653 int totalSteps = testCase.commands.length; 672 int totalSteps = testCase.commands.length;
654 String suffix =' (step $currentStep of $totalSteps)'; 673 String suffix =' (step $currentStep of $totalSteps)';
655 if (timedOut) { 674 if (timedOut) {
656 // Non-webdriver test timed out before it could complete. Webdriver tests 675 // 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 676 // run their own timeouts by timing from the launch of the browser (which
658 // could be delayed). 677 // could be delayed).
659 testComplete(0, true); 678 testComplete(cmd, 0, true);
660 } else if (currentStep == totalSteps) { 679 } else if (currentStep == totalSteps) {
661 // Done with all test commands. 680 // Done with all test commands.
662 testComplete(exitCode, false); 681 testComplete(cmd, exitCode, false);
663 } else if (exitCode != 0) { 682 } else if (exitCode != 0) {
664 // One of the steps failed. 683 // One of the steps failed.
665 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n'); 684 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n');
666 testComplete(exitCode, true); 685 testComplete(cmd, exitCode, true);
667 } else { 686 } else {
668 // One compilation step successfully completed, move on to the 687 // One compilation step successfully completed, move on to the
669 // next step. 688 // next step.
670 stderr.add('test.dart: Compilation finished $suffix\n'); 689 stderr.add('test.dart: Compilation finished $suffix\n');
671 stdout.add('test.dart: Compilation finished $suffix\n'); 690 stdout.add('test.dart: Compilation finished $suffix\n');
672 if (currentStep == totalSteps - 1 && testCase.usesWebDriver && 691 if (currentStep == totalSteps - 1 && testCase.usesWebDriver &&
673 !testCase.configuration['noBatch']) { 692 !testCase.configuration['noBatch']) {
674 // Note: processQueue will always be non-null for runtime == ie9, ie10, 693 // Note: processQueue will always be non-null for runtime == ie9, ie10,
675 // ff, safari, chrome, opera. (It is only null for runtime == vm) 694 // ff, safari, chrome, opera. (It is only null for runtime == vm)
676 // This RunningProcess object is done, and hands over control to 695 // This RunningProcess object is done, and hands over control to
677 // BatchRunner.startTest(), which handles reporting, etc. 696 // BatchRunner.startTest(), which handles reporting, etc.
678 timeoutTimer.cancel(); 697 timeoutTimer.cancel();
679 processQueue._getBatchRunner(testCase).startTest(testCase); 698 processQueue._getBatchRunner(testCase).startTest(testCase);
680 } else { 699 } else {
681 runCommand(testCase.commands[currentStep++], stepExitHandler); 700 runCommand(testCase.commands[currentStep++], commandComplete);
682 } 701 }
683 } 702 }
684 } 703 }
685 704
686 VoidFunction makeReadHandler(StringInputStream source, 705 VoidFunction makeReadHandler(StringInputStream source,
687 List<String> destination) { 706 List<String> destination) {
688 void handler () { 707 void handler () {
689 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. 708 if (source.closed) return; // TODO(whesse): Remove when bug is fixed.
690 var line = source.readLine(); 709 var line = source.readLine();
691 while (null != line) { 710 while (null != line) {
692 destination.add(line); 711 destination.add(line);
693 line = source.readLine(); 712 line = source.readLine();
694 } 713 }
695 } 714 }
696 return handler; 715 return handler;
697 } 716 }
698 717
699 void start() { 718 void start() {
700 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); 719 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP));
701 stdout = new List<String>(); 720 stdout = new List<String>();
702 stderr = new List<String>(); 721 stderr = new List<String>();
703 currentStep = 0; 722 currentStep = 0;
704 startTime = new Date.now(); 723 startTime = new Date.now();
705 runCommand(testCase.commands[currentStep++], stepExitHandler); 724 runCommand(testCase.commands[currentStep++], commandComplete);
706 } 725 }
707 726
708 void runCommand(Command command, void exitHandler(int exitCode)) { 727 void runCommand(Command command, void cmdCompleteHandler(Command cmd,
Bill Hesse 2012/11/14 17:07:34 Can we leave the parameter names out of the argume
Bill Hesse 2012/11/14 17:07:34 commandCompleteHandler
kustermann 2012/11/14 17:41:22 Done.
kustermann 2012/11/14 17:41:22 Done.
728 int exitCode)) {
729 void processExitHandler(int returnCode) {
730 cmdCompleteHandler(command, returnCode);
731 }
732
709 Future processFuture = Process.start(command.executable, command.arguments); 733 Future processFuture = Process.start(command.executable, command.arguments);
710 processFuture.then((Process p) { 734 processFuture.then((Process p) {
711 process = p; 735 process = p;
712 process.onExit = exitHandler; 736 process.onExit = processExitHandler;
713 var stdoutStringStream = new StringInputStream(process.stdout); 737 var stdoutStringStream = new StringInputStream(process.stdout);
714 var stderrStringStream = new StringInputStream(process.stderr); 738 var stderrStringStream = new StringInputStream(process.stderr);
715 stdoutStringStream.onLine = 739 stdoutStringStream.onLine =
716 makeReadHandler(stdoutStringStream, stdout); 740 makeReadHandler(stdoutStringStream, stdout);
717 stderrStringStream.onLine = 741 stderrStringStream.onLine =
718 makeReadHandler(stderrStringStream, stderr); 742 makeReadHandler(stderrStringStream, stderr);
719 if (timeoutTimer == null) { 743 if (timeoutTimer == null) {
720 // Create one timeout timer when starting test case, remove it at end. 744 // Create one timeout timer when starting test case, remove it at end.
721 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler); 745 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler);
722 } 746 }
723 // If the timeout fired in between two commands, kill the just 747 // If the timeout fired in between two commands, kill the just
724 // started process immediately. 748 // started process immediately.
725 if (timedOut) safeKill(process); 749 if (timedOut) safeKill(process);
726 }); 750 });
727 processFuture.handleException((e) { 751 processFuture.handleException((e) {
728 print("Process error:"); 752 print("Process error:");
729 print(" Command: $command"); 753 print(" Command: $command");
730 print(" Error: $e"); 754 print(" Error: $e");
731 testComplete(-1, false); 755 testComplete(command, -1, false);
732 return true; 756 return true;
733 }); 757 });
734 } 758 }
735 759
736 void timeoutHandler(Timer unusedTimer) { 760 void timeoutHandler(Timer unusedTimer) {
737 timedOut = true; 761 timedOut = true;
738 safeKill(process); 762 safeKill(process);
739 } 763 }
740 764
741 void safeKill(Process p) { 765 void safeKill(Process p) {
(...skipping 10 matching lines...) Expand all
752 /** 776 /**
753 * This class holds a value, that can be changed. It is used when 777 * 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. 778 * closures need a shared value, that they can all change and read.
755 */ 779 */
756 class MutableValue<T> { 780 class MutableValue<T> {
757 MutableValue(T this.value); 781 MutableValue(T this.value);
758 T value; 782 T value;
759 } 783 }
760 784
761 class BatchRunnerProcess { 785 class BatchRunnerProcess {
786 Command _command;
762 String _executable; 787 String _executable;
763 List<String> _batchArguments; 788 List<String> _batchArguments;
764 789
765 Process _process; 790 Process _process;
766 StringInputStream _stdoutStream; 791 StringInputStream _stdoutStream;
767 StringInputStream _stderrStream; 792 StringInputStream _stderrStream;
768 793
769 TestCase _currentTest; 794 TestCase _currentTest;
770 List<String> _testStdout; 795 List<String> _testStdout;
771 List<String> _testStderr; 796 List<String> _testStderr;
772 String _status; 797 String _status;
773 bool _stdoutDrained = false; 798 bool _stdoutDrained = false;
774 bool _stderrDrained = false; 799 bool _stderrDrained = false;
775 MutableValue<bool> _ignoreStreams; 800 MutableValue<bool> _ignoreStreams;
776 Date _startTime; 801 Date _startTime;
777 Timer _timer; 802 Timer _timer;
778 803
779 bool _isWebDriver; 804 bool _isWebDriver;
780 805
781 BatchRunnerProcess(TestCase testCase) { 806 BatchRunnerProcess(TestCase testCase) {
807 _command = testCase.commands.last;
782 _executable = testCase.commands.last.executable; 808 _executable = testCase.commands.last.executable;
783 _batchArguments = testCase.batchRunnerArguments; 809 _batchArguments = testCase.batchRunnerArguments;
784 _isWebDriver = testCase.usesWebDriver; 810 _isWebDriver = testCase.usesWebDriver;
785 } 811 }
786 812
787 bool get active => _currentTest != null; 813 bool get active => _currentTest != null;
788 814
789 void startTest(TestCase testCase) { 815 void startTest(TestCase testCase) {
790 Expect.isNull(_currentTest); 816 Expect.isNull(_currentTest);
791 _currentTest = testCase; 817 _currentTest = testCase;
818 _command = testCase.commands.last;
792 if (_process === null) { 819 if (_process === null) {
793 // Start process if not yet started. 820 // Start process if not yet started.
794 _executable = testCase.commands.last.executable; 821 _executable = testCase.commands.last.executable;
795 _startProcess(() { 822 _startProcess(() {
796 doStartTest(testCase); 823 doStartTest(testCase);
797 }); 824 });
798 } else if (testCase.commands.last.executable != _executable) { 825 } else if (testCase.commands.last.executable != _executable) {
799 // Restart this runner with the right executable for this test 826 // Restart this runner with the right executable for this test
800 // if needed. 827 // if needed.
801 _executable = testCase.commands.last.executable; 828 _executable = testCase.commands.last.executable;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 } 889 }
863 890
864 void _reportResult() { 891 void _reportResult() {
865 if (!active) return; 892 if (!active) return;
866 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' 893 // _status == '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}'
867 894
868 var outcome = _status.split(" ")[2]; 895 var outcome = _status.split(" ")[2];
869 var exitCode = 0; 896 var exitCode = 0;
870 if (outcome == "CRASH") exitCode = -10; 897 if (outcome == "CRASH") exitCode = -10;
871 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; 898 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1;
872 new TestOutput.fromCase(_currentTest, exitCode, false, 899 new CommandOutput.fromCase(_currentTest, _command, exitCode, false,
873 (outcome == "TIMEOUT"), 900 (outcome == "TIMEOUT"),
874 _testStdout, _testStderr, 901 _testStdout, _testStderr,
875 new Date.now().difference(_startTime)); 902 new Date.now().difference(_startTime));
876 var test = _currentTest; 903 var test = _currentTest;
877 _currentTest = null; 904 _currentTest = null;
878 test.completed(); 905 test.completed();
879 } 906 }
880 907
881 void _stderrDone() { 908 void _stderrDone() {
882 _stderrDrained = true; 909 _stderrDrained = true;
(...skipping 447 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 1357 // 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 1358 // tests that appear to be broken but were actually just flakes that
1332 // didn't get retried because there had already been one failure. 1359 // didn't get retried because there had already been one failure.
1333 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 1360 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
1334 new RunningProcess(test, allowRetry, this).start(); 1361 new RunningProcess(test, allowRetry, this).start();
1335 } 1362 }
1336 _numProcesses++; 1363 _numProcesses++;
1337 } 1364 }
1338 } 1365 }
1339 } 1366 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698