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

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

Issue 11591017: Revert "Call DumpRenderTree directly from test.dart instead of using the drt-trampoline.py indirect… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years 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 "dart:isolate"; 15 import "dart:isolate";
16 import "dart:uri"; 16 import "dart:uri";
17 import "status_file_parser.dart"; 17 import "status_file_parser.dart";
18 import "test_progress.dart"; 18 import "test_progress.dart";
19 import "test_suite.dart"; 19 import "test_suite.dart";
20 20
21 const int NO_TIMEOUT = 0; 21 const int NO_TIMEOUT = 0;
22 const int SLOW_TIMEOUT_MULTIPLIER = 4; 22 const int SLOW_TIMEOUT_MULTIPLIER = 4;
23 23
24 typedef void TestCaseEvent(TestCase testCase); 24 typedef void TestCaseEvent(TestCase testCase);
25 typedef void ExitCodeEvent(int exitCode); 25 typedef void ExitCodeEvent(int exitCode);
26 typedef void EnqueueMoreWork(ProcessQueue queue); 26 typedef void EnqueueMoreWork(ProcessQueue queue);
27 27
28
29 /**
30 * [areByteArraysEqual] compares a range of bytes from [buffer1] with a
31 * range of bytes from [buffer2].
32 *
33 * Returns [true] if the [count] bytes in [buffer1] (starting at
34 * [offset1]) match the [count] bytes in [buffer2] (starting at
35 * [offset2]).
36 * Otherwise [false] is returned.
37 */
38 bool areByteArraysEqual(List<int> buffer1, int offset1,
39 List<int> buffer2, int offset2,
40 int count) {
41 if ((offset1 + count) > buffer1.length ||
42 (offset2 + count) > buffer2.length) {
43 return false;
44 }
45
46 for (var i = 0; i < count; i++) {
47 if (buffer1[offset1 + i] != buffer2[offset2 + i]) {
48 return false;
49 }
50 }
51 return true;
52 }
53
54 /**
55 * [findBytes] searches for [pattern] in [data] beginning at [startPos].
56 *
57 * Returns [true] if [pattern] was found in [data].
58 * Otherwise [false] is returned.
59 */
60 int findBytes(List<int> data, List<int> pattern, [int startPos=0]) {
61 // TODO(kustermann): Use one of the fast string-matching algorithms!
62 for (int i=startPos; i < (data.length-pattern.length); i++) {
63 bool found = true;
64 for (int j=0; j<pattern.length; j++) {
65 if (data[i+j] != pattern[j]) {
66 found = false;
67 }
68 }
69 if (found) {
70 return i;
71 }
72 }
73 return -1;
74 }
75
76
77 /** A command executed as a step in a test case. */ 28 /** A command executed as a step in a test case. */
78 class Command { 29 class Command {
79 /** Path to the executable of this command. */ 30 /** Path to the executable of this command. */
80 String executable; 31 String executable;
81 32
82 /** Command line arguments to the executable. */ 33 /** Command line arguments to the executable. */
83 List<String> arguments; 34 List<String> arguments;
84
85 /** Environment for the command */
86 Map<String,String> environment;
87 35
88 /** The actual command line that will be executed. */ 36 /** The actual command line that will be executed. */
89 String commandLine; 37 String commandLine;
90 38
91 Command(this.executable, this.arguments, [this.environment = null]) { 39 Command(this.executable, this.arguments) {
92 if (Platform.operatingSystem == 'windows') { 40 if (Platform.operatingSystem == 'windows') {
93 // Windows can't handle the first command if it is a .bat file or the like 41 // Windows can't handle the first command if it is a .bat file or the like
94 // with the slashes going the other direction. 42 // with the slashes going the other direction.
95 // TODO(efortuna): Remove this when fixed (Issue 1306). 43 // TODO(efortuna): Remove this when fixed (Issue 1306).
96 executable = executable.replaceAll('/', '\\'); 44 executable = executable.replaceAll('/', '\\');
97 } 45 }
98 commandLine = "$executable ${Strings.join(arguments, ' ')}"; 46 commandLine = "$executable ${Strings.join(arguments, ' ')}";
99 } 47 }
100 48
101 String toString() => commandLine; 49 String toString() => commandLine;
102 50
103 Future<bool> get outputIsUpToDate => new Future.immediate(false); 51 Future<bool> get outputIsUpToDate => new Future.immediate(false);
104 Path get expectedOutputFile => null;
105 bool get isPixelTest => false;
106 } 52 }
107 53
108 class CompilationCommand extends Command { 54 class CompilationCommand extends Command {
109 String _outputFile; 55 String _outputFile;
110 bool _neverSkipCompilation; 56 bool _neverSkipCompilation;
111 List<Uri> _bootstrapDependencies; 57 List<Uri> _bootstrapDependencies;
112 58
113 CompilationCommand(this._outputFile, 59 CompilationCommand(this._outputFile,
114 this._neverSkipCompilation, 60 this._neverSkipCompilation,
115 this._bootstrapDependencies, 61 this._bootstrapDependencies,
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 } 98 }
153 } 99 }
154 return true; 100 return true;
155 } 101 }
156 } 102 }
157 return false; 103 return false;
158 }); 104 });
159 } 105 }
160 } 106 }
161 107
162 class DumpRenderTreeCommand extends Command {
163 /**
164 * If [expectedOutputPath] is set, the output of DumpRenderTree is compared
165 * with the content of [expectedOutputPath].
166 * This is used for example for pixel tests, where [expectedOutputPath] points
167 * to a *png file.
168 */
169 Path expectedOutputPath;
170
171 DumpRenderTreeCommand(String executable,
172 String htmlFile,
173 List<String> options,
174 List<String> dartFlags,
175 Uri packageRootUri,
176 Path this.expectedOutputPath)
177 : super(executable,
178 _getArguments(options, htmlFile),
179 _getEnvironment(dartFlags, packageRootUri));
180
181 static Map _getEnvironment(List<String> dartFlags, Uri packageRootUri) {
182 var needDartFlags = dartFlags != null && dartFlags.length > 0;
183 var needDartPackageRoot = packageRootUri != null;
184
185 var env = null;
186 if (needDartFlags || needDartPackageRoot) {
187 var env = new Map.from(Platform.environment);
188 if (needDartFlags) {
189 env['DART_FLAGS'] = Strings.join(dartFlags, " ");
190 }
191 if (needDartPackageRoot) {
192 env['DART_PACKAGE_ROOT'] = packageRootUri.toString();
193 }
194 }
195
196 return env;
197 }
198
199 static List<String> _getArguments(List<String> options, String htmlFile) {
200 var arguments = new List.from(options);
201 arguments.add(htmlFile);
202 return arguments;
203 }
204
205 Path get expectedOutputFile => expectedOutputPath;
206 bool get isPixelTest => (expectedOutputFile != null &&
207 expectedOutputFile.filename.endsWith(".png"));
208 }
209
210
211 /** 108 /**
212 * TestCase contains all the information needed to run a test and evaluate 109 * TestCase contains all the information needed to run a test and evaluate
213 * its output. Running a test involves starting a separate process, with 110 * its output. Running a test involves starting a separate process, with
214 * the executable and arguments given by the TestCase, and recording its 111 * the executable and arguments given by the TestCase, and recording its
215 * stdout and stderr output streams, and its exit code. TestCase only 112 * stdout and stderr output streams, and its exit code. TestCase only
216 * contains static information about the test; actually running the test is 113 * contains static information about the test; actually running the test is
217 * performed by [ProcessQueue] using a [RunningProcess] object. 114 * performed by [ProcessQueue] using a [RunningProcess] object.
218 * 115 *
219 * The output information is stored in a [CommandOutput] instance contained 116 * The output information is stored in a [CommandOutput] instance contained
220 * in TestCase.commandOutputs. The last CommandOutput instance is responsible 117 * in TestCase.commandOutputs. The last CommandOutput instance is responsible
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 * code, the standard output and standard error, whether the process timed out, 310 * code, the standard output and standard error, whether the process timed out,
414 * and the time the process took to run. It also contains a pointer to the 311 * and the time the process took to run. It also contains a pointer to the
415 * [TestCase] this is the output of. 312 * [TestCase] this is the output of.
416 */ 313 */
417 abstract class CommandOutput { 314 abstract class CommandOutput {
418 factory CommandOutput.fromCase(TestCase testCase, 315 factory CommandOutput.fromCase(TestCase testCase,
419 Command command, 316 Command command,
420 int exitCode, 317 int exitCode,
421 bool incomplete, 318 bool incomplete,
422 bool timedOut, 319 bool timedOut,
423 List<int> stdout, 320 List<String> stdout,
424 List<int> stderr, 321 List<String> stderr,
425 Duration time, 322 Duration time,
426 bool compilationSkipped) { 323 bool compilationSkipped) {
427 return new CommandOutputImpl.fromCase(testCase, 324 return new CommandOutputImpl.fromCase(testCase,
428 command, 325 command,
429 exitCode, 326 exitCode,
430 incomplete, 327 incomplete,
431 timedOut, 328 timedOut,
432 stdout, 329 stdout,
433 stderr, 330 stderr,
434 time, 331 time,
435 compilationSkipped); 332 compilationSkipped);
436 } 333 }
437 334
438 Command get command;
439
440 bool get incomplete; 335 bool get incomplete;
441 336
442 String get result; 337 String get result;
443 338
444 bool get unexpectedOutput; 339 bool get unexpectedOutput;
445 340
446 bool get hasCrashed; 341 bool get hasCrashed;
447 342
448 bool get hasTimedOut; 343 bool get hasTimedOut;
449 344
450 bool get didFail; 345 bool get didFail;
451 346
452 bool requestRetry; 347 bool requestRetry;
453 348
454 Duration get time; 349 Duration get time;
455 350
456 int get exitCode; 351 int get exitCode;
457 352
458 List<int> get stdout; 353 List<String> get stdout;
459 354
460 List<int> get stderr; 355 List<String> get stderr;
461 356
462 List<String> get diagnostics; 357 List<String> get diagnostics;
463 358
464 bool get compilationSkipped; 359 bool get compilationSkipped;
465 } 360 }
466 361
467 class CommandOutputImpl implements CommandOutput { 362 class CommandOutputImpl implements CommandOutput {
468 Command command;
469 TestCase testCase; 363 TestCase testCase;
470 int exitCode; 364 int exitCode;
471 365
472 /// Records if all commands were run, true if they weren't. 366 /// Records if all commands were run, true if they weren't.
473 final bool incomplete; 367 final bool incomplete;
474 368
475 bool timedOut; 369 bool timedOut;
476 bool failed = false; 370 bool failed = false;
477 List<int> stdout; 371 List<String> stdout;
478 List<int> stderr; 372 List<String> stderr;
479 Duration time; 373 Duration time;
480 List<String> diagnostics; 374 List<String> diagnostics;
481 bool compilationSkipped; 375 bool compilationSkipped;
482 376
483 /** 377 /**
484 * A flag to indicate we have already printed a warning about ignoring the VM 378 * A flag to indicate we have already printed a warning about ignoring the VM
485 * crash, to limit the amount of output produced per test. 379 * crash, to limit the amount of output produced per test.
486 */ 380 */
487 bool alreadyPrintedWarning = false; 381 bool alreadyPrintedWarning = false;
488 382
489 /** 383 /**
490 * Set to true if we encounter a condition in the output that indicates we 384 * Set to true if we encounter a condition in the output that indicates we
491 * need to rerun this test. 385 * need to rerun this test.
492 */ 386 */
493 bool requestRetry = false; 387 bool requestRetry = false;
494 388
495 // Don't call this constructor, call CommandOutput.fromCase() to 389 // Don't call this constructor, call CommandOutput.fromCase() to
496 // get a new TestOutput instance. 390 // get a new TestOutput instance.
497 CommandOutputImpl(TestCase this.testCase, 391 CommandOutputImpl(TestCase this.testCase,
498 Command this.command, 392 Command command,
499 int this.exitCode, 393 int this.exitCode,
500 bool this.incomplete, 394 bool this.incomplete,
501 bool this.timedOut, 395 bool this.timedOut,
502 List<int> this.stdout, 396 List<String> this.stdout,
503 List<int> this.stderr, 397 List<String> this.stderr,
504 Duration this.time, 398 Duration this.time,
505 bool this.compilationSkipped) { 399 bool this.compilationSkipped) {
506 testCase.commandOutputs[command] = this; 400 testCase.commandOutputs[command] = this;
507 diagnostics = []; 401 diagnostics = [];
508 } 402 }
509 factory CommandOutputImpl.fromCase(TestCase testCase, 403 factory CommandOutputImpl.fromCase(TestCase testCase,
510 Command command, 404 Command command,
511 int exitCode, 405 int exitCode,
512 bool incomplete, 406 bool incomplete,
513 bool timedOut, 407 bool timedOut,
514 List<int> stdout, 408 List<String> stdout,
515 List<int> stderr, 409 List<String> stderr,
516 Duration time, 410 Duration time,
517 bool compilationSkipped) { 411 bool compilationSkipped) {
518 if (testCase is BrowserTestCase) { 412 if (testCase is BrowserTestCase) {
519 return new BrowserCommandOutputImpl(testCase, 413 return new BrowserCommandOutputImpl(testCase,
520 command, 414 command,
521 exitCode, 415 exitCode,
522 incomplete, 416 incomplete,
523 timedOut, 417 timedOut,
524 stdout, 418 stdout,
525 stderr, 419 stderr,
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 command, 492 command,
599 exitCode, 493 exitCode,
600 incomplete, 494 incomplete,
601 timedOut, 495 timedOut,
602 stdout, 496 stdout,
603 stderr, 497 stderr,
604 time, 498 time,
605 compilationSkipped); 499 compilationSkipped);
606 500
607 bool get didFail { 501 bool get didFail {
608 if (_failedBecauseOfMissingXDisplay) {
609 return true;
610 }
611
612 if (command.expectedOutputFile != null) {
613 // We are either doing a pixel test or a layout test with DumpRenderTree
614 return _failedBecauseOfUnexpectedDRTOutput;
615 }
616 return _browserTestFailure;
617 }
618
619 bool get _failedBecauseOfMissingXDisplay {
620 // Browser case: 502 // Browser case:
621 // If the browser test failed, it may have been because DumpRenderTree 503 // If the browser test failed, it may have been because DumpRenderTree
622 // and the virtual framebuffer X server didn't hook up, or DRT crashed with 504 // and the virtual framebuffer X server didn't hook up, or DRT crashed with
623 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, 505 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS,
624 // so we have to do this check first. 506 // so we have to do this check first.
625 var stderrLines = new String.fromCharCodes(super.stderr).split("\n"); 507 for (String line in super.stderr) {
626 for (String line in stderrLines) {
627 if (line.contains('Gtk-WARNING **: cannot open display: :99') || 508 if (line.contains('Gtk-WARNING **: cannot open display: :99') ||
628 line.contains('Failed to run command. return code=1')) { 509 line.contains('Failed to run command. return code=1')) {
629 // If we get the X server error, or DRT crashes with a core dump, retry 510 // If we get the X server error, or DRT crashes with a core dump, retry
630 // the test. 511 // the test.
631 if ((testCase as BrowserTestCase).numRetries > 0) { 512 if ((testCase as BrowserTestCase).numRetries > 0) {
632 requestRetry = true; 513 requestRetry = true;
633 } 514 }
634 return true; 515 return true;
635 } 516 }
636 } 517 }
637 return false;
638 }
639 518
640 bool get _failedBecauseOfUnexpectedDRTOutput {
641 /*
642 * The output of DumpRenderTree is different for pixel tests than for
643 * layout tests.
644 *
645 * On a pixel test, the DRT output has the following format
646 * ......
647 * ......
648 * Content-Length: ...\n
649 * <*png data>
650 * #EOF\n
651 * So we need to get the byte-range of the png data first, before
652 * comparing it with the content of the expected output file.
653 *
654 * On a layout tests, the DRT output is directly compared with the
655 * content of the expected output.
656 */
657 var stdout = testCase.commandOutputs[command].stdout;
658 var file = new File.fromPath(command.expectedOutputFile);
659 if (file.existsSync()) {
660 var bytesContentLength = "Content-Length:".charCodes;
661 var bytesNewLine = "\n".charCodes;
662 var bytesEOF = "#EOF\n".charCodes;
663
664 var expectedContent = file.readAsBytesSync();
665 if (command.isPixelTest) {
666 var startOfContentLength = findBytes(stdout, bytesContentLength);
667 if (startOfContentLength >= 0) {
668 var newLineAfterContentLength = findBytes(stdout,
669 bytesNewLine,
670 startOfContentLength);
671 if (newLineAfterContentLength > 0) {
672 var startPosition = newLineAfterContentLength +
673 bytesNewLine.length;
674 var endPosition = stdout.length - bytesEOF.length;
675
676 return !areByteArraysEqual(expectedContent,
677 0,
678 stdout,
679 startPosition,
680 endPosition - startPosition);
681 }
682 }
683 return true;
684 } else {
685 return !areByteArraysEqual(expectedContent, 0,
686 stdout, 0,
687 stdout.length);
688 }
689 }
690 return true;
691 }
692
693 bool get _browserTestFailure {
694 // Browser tests fail unless stdout contains 519 // Browser tests fail unless stdout contains
695 // 'Content-Type: text/plain' followed by 'PASS'. 520 // 'Content-Type: text/plain' followed by 'PASS'.
696 bool has_content_type = false; 521 bool has_content_type = false;
697 var stdoutLines = new String.fromCharCodes(super.stdout).split("\n"); 522 for (String line in super.stdout) {
698 for (String line in stdoutLines) {
699 switch (line) { 523 switch (line) {
700 case 'Content-Type: text/plain': 524 case 'Content-Type: text/plain':
701 has_content_type = true; 525 has_content_type = true;
702 break; 526 break;
527
703 case 'PASS': 528 case 'PASS':
704 if (has_content_type) { 529 if (has_content_type) {
705 return (exitCode != 0 && !hasCrashed); 530 return (exitCode != 0 && !hasCrashed);
706 } 531 }
707 break; 532 break;
708 } 533 }
709 } 534 }
710 return true; 535 return true;
711 } 536 }
712 } 537 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 return failResult; 575 return failResult;
751 } 576 }
752 577
753 bool _didFail() { 578 bool _didFail() {
754 if (hasCrashed) return false; 579 if (hasCrashed) return false;
755 580
756 List<String> errors = []; 581 List<String> errors = [];
757 List<String> staticWarnings = []; 582 List<String> staticWarnings = [];
758 583
759 // Read the returned list of errors and stuff them away. 584 // Read the returned list of errors and stuff them away.
760 var stderrLines = new String.fromCharCodes(super.stderr).split("\n"); 585 for (String line in super.stderr) {
761 for (String line in stderrLines) {
762 if (line.length == 0) continue; 586 if (line.length == 0) continue;
763 List<String> fields = splitMachineError(line); 587 List<String> fields = splitMachineError(line);
764 if (fields[ERROR_LEVEL] == 'ERROR') { 588 if (fields[ERROR_LEVEL] == 'ERROR') {
765 errors.add(fields[FORMATTED_ERROR]); 589 errors.add(fields[FORMATTED_ERROR]);
766 } else if (fields[ERROR_LEVEL] == 'WARNING') { 590 } else if (fields[ERROR_LEVEL] == 'WARNING') {
767 // We only care about testing Static type warnings 591 // We only care about testing Static type warnings
768 // ignore all others 592 // ignore all others
769 if (fields[ERROR_TYPE] == 'STATIC_TYPE') { 593 if (fields[ERROR_TYPE] == 'STATIC_TYPE') {
770 staticWarnings.add(fields[FORMATTED_ERROR]); 594 staticWarnings.add(fields[FORMATTED_ERROR]);
771 } 595 }
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 * the result; there are no pointers to it, so it should be available to 724 * the result; there are no pointers to it, so it should be available to
901 * be garbage collected as soon as it is done. 725 * be garbage collected as soon as it is done.
902 */ 726 */
903 class RunningProcess { 727 class RunningProcess {
904 ProcessQueue processQueue; 728 ProcessQueue processQueue;
905 Process process; 729 Process process;
906 TestCase testCase; 730 TestCase testCase;
907 bool timedOut = false; 731 bool timedOut = false;
908 Date startTime; 732 Date startTime;
909 Timer timeoutTimer; 733 Timer timeoutTimer;
910 List<int> stdout; 734 List<String> stdout;
911 List<int> stderr; 735 List<String> stderr;
912 List<String> notifications;
913 bool compilationSkipped; 736 bool compilationSkipped;
914 bool allowRetries; 737 bool allowRetries;
915 738
916 /** Which command of [testCase.commands] is currently being executed. */ 739 /** Which command of [testCase.commands] is currently being executed. */
917 int currentStep; 740 int currentStep;
918 741
919 RunningProcess(TestCase this.testCase, 742 RunningProcess(TestCase this.testCase,
920 [this.allowRetries = false, this.processQueue]); 743 [this.allowRetries = false, this.processQueue]);
921 744
922 /** 745 /**
923 * Called when all commands are executed. 746 * Called when all commands are executed.
924 */ 747 */
925 void testComplete(CommandOutput lastCommandOutput) { 748 void testComplete(CommandOutput lastCommandOutput) {
926 var command = lastCommandOutput.command;
927
928 if (timeoutTimer != null) { 749 if (timeoutTimer != null) {
929 timeoutTimer.cancel(); 750 timeoutTimer.cancel();
930 } 751 }
931 if (lastCommandOutput.unexpectedOutput 752 if (lastCommandOutput.unexpectedOutput
932 && testCase.configuration['verbose'] != null 753 && testCase.configuration['verbose'] != null
933 && testCase.configuration['verbose']) { 754 && testCase.configuration['verbose']) {
934 print(testCase.displayName); 755 print(testCase.displayName);
935 756 for (var line in lastCommandOutput.stderr) print(line);
936 print(new String.fromCharCodes(lastCommandOutput.stderr)); 757 for (var line in lastCommandOutput.stdout) print(line);
937 if (!lastCommandOutput.command.isPixelTest) {
938 print(new String.fromCharCodes(lastCommandOutput.stdout));
939 } else {
940 print("DRT pixel test failed! stdout is not printed because it "
941 "contains binary data!");
942 }
943 print('');
944 if (notifications.length > 0) {
945 print("Notifications:");
946 for (var line in notifications) {
947 print(notifications);
948 }
949 print('');
950 }
951 } 758 }
952 if (allowRetries && testCase.usesWebDriver 759 if (allowRetries && testCase.usesWebDriver
953 && lastCommandOutput.unexpectedOutput 760 && lastCommandOutput.unexpectedOutput
954 && (testCase as BrowserTestCase).numRetries > 0) { 761 && (testCase as BrowserTestCase).numRetries > 0) {
955 // Selenium tests can be flaky. Try rerunning. 762 // Selenium tests can be flaky. Try rerunning.
956 lastCommandOutput.requestRetry = true; 763 lastCommandOutput.requestRetry = true;
957 } 764 }
958 if (lastCommandOutput.requestRetry) { 765 if (lastCommandOutput.requestRetry) {
959 lastCommandOutput.requestRetry = false; 766 lastCommandOutput.requestRetry = false;
960 this.timedOut = false; 767 this.timedOut = false;
(...skipping 21 matching lines...) Expand all
982 if (timedOut) { 789 if (timedOut) {
983 // Non-webdriver test timed out before it could complete. Webdriver tests 790 // Non-webdriver test timed out before it could complete. Webdriver tests
984 // run their own timeouts by timing from the launch of the browser (which 791 // run their own timeouts by timing from the launch of the browser (which
985 // could be delayed). 792 // could be delayed).
986 testComplete(createCommandOutput(command, 0, true)); 793 testComplete(createCommandOutput(command, 0, true));
987 } else if (currentStep == totalSteps) { 794 } else if (currentStep == totalSteps) {
988 // Done with all test commands. 795 // Done with all test commands.
989 testComplete(createCommandOutput(command, exitCode, false)); 796 testComplete(createCommandOutput(command, exitCode, false));
990 } else if (exitCode != 0) { 797 } else if (exitCode != 0) {
991 // One of the steps failed. 798 // One of the steps failed.
992 notifications.add('test.dart: Compilation failed$suffix, ' 799 stderr.add('test.dart: Compilation failed$suffix, exit code $exitCode\n');
993 'exit code $exitCode\n');
994 testComplete(createCommandOutput(command, exitCode, true)); 800 testComplete(createCommandOutput(command, exitCode, true));
995 } else { 801 } else {
996 createCommandOutput(command, exitCode, true); 802 createCommandOutput(command, exitCode, true);
997 // One compilation step successfully completed, move on to the 803 // One compilation step successfully completed, move on to the
998 // next step. 804 // next step.
999 notifications.add('test.dart: Compilation finished $suffix\n\n'); 805 stderr.add('test.dart: Compilation finished $suffix\n');
806 stdout.add('test.dart: Compilation finished $suffix\n');
1000 if (currentStep == totalSteps - 1 && testCase.usesWebDriver && 807 if (currentStep == totalSteps - 1 && testCase.usesWebDriver &&
1001 !testCase.configuration['noBatch']) { 808 !testCase.configuration['noBatch']) {
1002 // Note: processQueue will always be non-null for runtime == ie9, ie10, 809 // Note: processQueue will always be non-null for runtime == ie9, ie10,
1003 // ff, safari, chrome, opera. (It is only null for runtime == vm) 810 // ff, safari, chrome, opera. (It is only null for runtime == vm)
1004 // This RunningProcess object is done, and hands over control to 811 // This RunningProcess object is done, and hands over control to
1005 // BatchRunner.startTest(), which handles reporting, etc. 812 // BatchRunner.startTest(), which handles reporting, etc.
1006 if (timeoutTimer != null) { 813 if (timeoutTimer != null) {
1007 timeoutTimer.cancel(); 814 timeoutTimer.cancel();
1008 } 815 }
1009 processQueue._getBatchRunner(testCase).startTest(testCase); 816 processQueue._getBatchRunner(testCase).startTest(testCase);
(...skipping 17 matching lines...) Expand all
1027 timedOut, 834 timedOut,
1028 stdout, 835 stdout,
1029 stderr, 836 stderr,
1030 new Date.now().difference(startTime), 837 new Date.now().difference(startTime),
1031 compilationSkipped); 838 compilationSkipped);
1032 resetLocalOutputInformation(); 839 resetLocalOutputInformation();
1033 return commandOutput; 840 return commandOutput;
1034 } 841 }
1035 842
1036 void resetLocalOutputInformation() { 843 void resetLocalOutputInformation() {
1037 stdout = new List<int>(); 844 stdout = new List<String>();
1038 stderr = new List<int>(); 845 stderr = new List<String>();
1039 notifications = new List<String>();
1040 compilationSkipped = false; 846 compilationSkipped = false;
1041 } 847 }
1042 848
1043 void drainStream(InputStream source, List<int> destination) { 849 VoidFunction makeReadHandler(StringInputStream source,
1044 void onDataHandler () { 850 List<String> destination) {
1045 if (source.closed) { 851 void handler () {
1046 return; // TODO(whesse): Remove when bug is fixed. 852 if (source.closed) return; // TODO(whesse): Remove when bug is fixed.
1047 } 853 var line = source.readLine();
1048 var data = source.read(); 854 while (null != line) {
1049 while (data != null) { 855 destination.add(line);
1050 destination.addAll(data); 856 line = source.readLine();
1051 data = source.read();
1052 } 857 }
1053 } 858 }
1054 source.onData = onDataHandler; 859 return handler;
1055 source.onClosed = onDataHandler;
1056 } 860 }
1057 861
1058 void start() { 862 void start() {
1059 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP)); 863 Expect.isFalse(testCase.expectedOutcomes.contains(SKIP));
1060 resetLocalOutputInformation(); 864 resetLocalOutputInformation();
1061 currentStep = 0; 865 currentStep = 0;
1062 startTime = new Date.now(); 866 startTime = new Date.now();
1063 runCommand(testCase.commands[currentStep++], commandComplete); 867 runCommand(testCase.commands[currentStep++], commandComplete);
1064 } 868 }
1065 869
1066 void runCommand(Command command, void commandCompleteHandler(Command, int)) { 870 void runCommand(Command command, void commandCompleteHandler(Command, int)) {
1067 void processExitHandler(int returnCode) { 871 void processExitHandler(int returnCode) {
1068 commandCompleteHandler(command, returnCode); 872 commandCompleteHandler(command, returnCode);
1069 } 873 }
1070 874
1071 command.outputIsUpToDate.then((bool isUpToDate) { 875 command.outputIsUpToDate.then((bool isUpToDate) {
1072 if (isUpToDate) { 876 if (isUpToDate) {
1073 notifications.add("Skipped compilation because the old output is " 877 stdout.add("Skipped compilation because the old output is "
1074 "still up to date!"); 878 "still up to date!");
1075 compilationSkipped = true; 879 compilationSkipped = true;
1076 commandComplete(command, 0); 880 commandComplete(command, 0);
1077 } else { 881 } else {
1078 ProcessOptions options = new ProcessOptions(); 882 ProcessOptions options = new ProcessOptions();
1079 if (command.environment != null) { 883 options.environment =
1080 options.environment = 884 new Map<String, String>.from(Platform.environment);
1081 new Map<String, String>.from(command.environment);
1082 } else {
1083 options.environment =
1084 new Map<String, String>.from(Platform.environment);
1085 }
1086
1087 options.environment['DART_CONFIGURATION'] = 885 options.environment['DART_CONFIGURATION'] =
1088 TestUtils.configurationDir(testCase.configuration); 886 TestUtils.configurationDir(testCase.configuration);
1089 Future processFuture = Process.start(command.executable, 887 Future processFuture = Process.start(command.executable,
1090 command.arguments, 888 command.arguments,
1091 options); 889 options);
1092 processFuture.then((Process p) { 890 processFuture.then((Process p) {
1093 process = p; 891 process = p;
1094 process.onExit = processExitHandler; 892 process.onExit = processExitHandler;
1095 drainStream(process.stdout, stdout); 893 var stdoutStringStream = new StringInputStream(process.stdout);
1096 drainStream(process.stderr, stderr); 894 var stderrStringStream = new StringInputStream(process.stderr);
895 stdoutStringStream.onLine =
896 makeReadHandler(stdoutStringStream, stdout);
897 stderrStringStream.onLine =
898 makeReadHandler(stderrStringStream, stderr);
1097 if (timeoutTimer == null) { 899 if (timeoutTimer == null) {
1098 // Create one timeout timer when starting test case, remove it at 900 // Create one timeout timer when starting test case, remove it at
1099 // the end. 901 // the end.
1100 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler); 902 timeoutTimer = new Timer(1000 * testCase.timeout, timeoutHandler);
1101 } 903 }
1102 // If the timeout fired in between two commands, kill the just 904 // If the timeout fired in between two commands, kill the just
1103 // started process immediately. 905 // started process immediately.
1104 if (timedOut) safeKill(process); 906 if (timedOut) safeKill(process);
1105 }); 907 });
1106 processFuture.handleException((e) { 908 processFuture.handleException((e) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1142 class BatchRunnerProcess { 944 class BatchRunnerProcess {
1143 Command _command; 945 Command _command;
1144 String _executable; 946 String _executable;
1145 List<String> _batchArguments; 947 List<String> _batchArguments;
1146 948
1147 Process _process; 949 Process _process;
1148 StringInputStream _stdoutStream; 950 StringInputStream _stdoutStream;
1149 StringInputStream _stderrStream; 951 StringInputStream _stderrStream;
1150 952
1151 TestCase _currentTest; 953 TestCase _currentTest;
1152 List<int> _testStdout; 954 List<String> _testStdout;
1153 List<int> _testStderr; 955 List<String> _testStderr;
1154 String _status; 956 String _status;
1155 bool _stdoutDrained = false; 957 bool _stdoutDrained = false;
1156 bool _stderrDrained = false; 958 bool _stderrDrained = false;
1157 MutableValue<bool> _ignoreStreams; 959 MutableValue<bool> _ignoreStreams;
1158 Date _startTime; 960 Date _startTime;
1159 Timer _timer; 961 Timer _timer;
1160 962
1161 bool _isWebDriver; 963 bool _isWebDriver;
1162 964
1163 BatchRunnerProcess(TestCase testCase) { 965 BatchRunnerProcess(TestCase testCase) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1220 } 1022 }
1221 1023
1222 void doStartTest(TestCase testCase) { 1024 void doStartTest(TestCase testCase) {
1223 _startTime = new Date.now(); 1025 _startTime = new Date.now();
1224 _testStdout = []; 1026 _testStdout = [];
1225 _testStderr = []; 1027 _testStderr = [];
1226 _status = null; 1028 _status = null;
1227 _stdoutDrained = false; 1029 _stdoutDrained = false;
1228 _stderrDrained = false; 1030 _stderrDrained = false;
1229 _ignoreStreams = new MutableValue<bool>(false); // Captured by closures. 1031 _ignoreStreams = new MutableValue<bool>(false); // Captured by closures.
1230 _readStdout(_stdoutStream, _testStdout); 1032 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout);
1231 _readStderr(_stderrStream, _testStderr); 1033 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr);
1232 _timer = new Timer(testCase.timeout * 1000, _timeoutHandler); 1034 _timer = new Timer(testCase.timeout * 1000, _timeoutHandler);
1233
1234 if (testCase.commands.last.environment != null) {
1235 print("Warning: command.environment != null, but we don't support custom "
1236 "environments for batch runner tests!");
1237 }
1238
1239 var line = _createArgumentsLine(testCase.batchTestArguments); 1035 var line = _createArgumentsLine(testCase.batchTestArguments);
1240 _process.stdin.onError = (err) { 1036 _process.stdin.onError = (err) {
1241 print('Error on batch runner input stream stdin'); 1037 print('Error on batch runner input stream stdin');
1242 print(' Input line: $line'); 1038 print(' Input line: $line');
1243 print(' Previous test\'s status: $_status'); 1039 print(' Previous test\'s status: $_status');
1244 print(' Error: $err'); 1040 print(' Error: $err');
1245 throw err; 1041 throw err;
1246 }; 1042 };
1247 _process.stdin.write(line.charCodes); 1043 _process.stdin.write(line.charCodes);
1248 } 1044 }
(...skipping 29 matching lines...) Expand all
1278 // Move on when both stdout and stderr has been drained. 1074 // Move on when both stdout and stderr has been drained.
1279 if (_stdoutDrained) _reportResult(); 1075 if (_stdoutDrained) _reportResult();
1280 } 1076 }
1281 1077
1282 void _stdoutDone() { 1078 void _stdoutDone() {
1283 _stdoutDrained = true; 1079 _stdoutDrained = true;
1284 // Move on when both stdout and stderr has been drained. 1080 // Move on when both stdout and stderr has been drained.
1285 if (_stderrDrained) _reportResult(); 1081 if (_stderrDrained) _reportResult();
1286 } 1082 }
1287 1083
1288 void _readStdout(StringInputStream stream, List<int> buffer) { 1084 VoidFunction _readStdout(StringInputStream stream, List<String> buffer) {
1289 var ignoreStreams = _ignoreStreams; // Capture this mutable object. 1085 var ignoreStreams = _ignoreStreams; // Capture this mutable object.
1290 void onLineHandler() { 1086 void reader() {
1291 if (ignoreStreams.value) { 1087 if (ignoreStreams.value) {
1292 while (stream.readLine() != null) { 1088 while (stream.readLine() != null) {
1293 // Do nothing. 1089 // Do nothing.
1294 } 1090 }
1295 return; 1091 return;
1296 } 1092 }
1297 // Otherwise, process output and call _reportResult() when done. 1093 // Otherwise, process output and call _reportResult() when done.
1298 var line = stream.readLine(); 1094 var line = stream.readLine();
1299 while (line != null) { 1095 while (line != null) {
1300 if (line.startsWith('>>> TEST')) { 1096 if (line.startsWith('>>> TEST')) {
1301 _status = line; 1097 _status = line;
1302 } else if (line.startsWith('>>> BATCH START')) { 1098 } else if (line.startsWith('>>> BATCH START')) {
1303 // ignore 1099 // ignore
1304 } else if (line.startsWith('>>> ')) { 1100 } else if (line.startsWith('>>> ')) {
1305 throw new Exception('Unexpected command from dartc batch runner.'); 1101 throw new Exception('Unexpected command from dartc batch runner.');
1306 } else { 1102 } else {
1307 buffer.addAll("$line\n".charCodes); 1103 buffer.add(line);
1308 } 1104 }
1309 line = stream.readLine(); 1105 line = stream.readLine();
1310 } 1106 }
1311 if (_status != null) { 1107 if (_status != null) {
1312 _timer.cancel(); 1108 _timer.cancel();
1313 _stdoutDone(); 1109 _stdoutDone();
1314 } 1110 }
1315 } 1111 }
1316 stream.onLine = onLineHandler; 1112 return reader;
1317 } 1113 }
1318 1114
1319 void _readStderr(StringInputStream stream, List<int> buffer) { 1115 VoidFunction _readStderr(StringInputStream stream, List<String> buffer) {
1320 var ignoreStreams = _ignoreStreams; // Capture this mutable object. 1116 var ignoreStreams = _ignoreStreams; // Capture this mutable object.
1321 void onLineHandler() { 1117 void reader() {
1322 if (ignoreStreams.value) { 1118 if (ignoreStreams.value) {
1323 while (stream.readLine() != null) { 1119 while (stream.readLine() != null) {
1324 // Do nothing. 1120 // Do nothing.
1325 } 1121 }
1326 return; 1122 return;
1327 } 1123 }
1328 // Otherwise, process output and call _reportResult() when done. 1124 // Otherwise, process output and call _reportResult() when done.
1329 var line = stream.readLine(); 1125 var line = stream.readLine();
1330 while (line != null) { 1126 while (line != null) {
1331 if (line.startsWith('>>> EOF STDERR')) { 1127 if (line.startsWith('>>> EOF STDERR')) {
1332 _stderrDone(); 1128 _stderrDone();
1333 } else { 1129 } else {
1334 buffer.addAll("$line\n".charCodes); 1130 buffer.add(line);
1335 } 1131 }
1336 line = stream.readLine(); 1132 line = stream.readLine();
1337 } 1133 }
1338 } 1134 }
1339 stream.onLine = onLineHandler; 1135 return reader;
1340 } 1136 }
1341 1137
1342 ExitCodeEvent makeExitHandler(String status) { 1138 ExitCodeEvent makeExitHandler(String status) {
1343 void handler(int exitCode) { 1139 void handler(int exitCode) {
1344 if (active) { 1140 if (active) {
1345 if (_timer != null) _timer.cancel(); 1141 if (_timer != null) _timer.cancel();
1346 _status = status; 1142 _status = status;
1347 // Read current content of streams, ignore any later output. 1143 // Read current content of streams, ignore any later output.
1348 _ignoreStreams.value = true; 1144 _ignoreStreams.value = true;
1349 var line = _stdoutStream.readLine(); 1145 var line = _stdoutStream.readLine();
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
1725 // the developer doesn't waste his or her time trying to fix a bunch of 1521 // the developer doesn't waste his or her time trying to fix a bunch of
1726 // tests that appear to be broken but were actually just flakes that 1522 // tests that appear to be broken but were actually just flakes that
1727 // didn't get retried because there had already been one failure. 1523 // didn't get retried because there had already been one failure.
1728 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; 1524 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests;
1729 new RunningProcess(test, allowRetry, this).start(); 1525 new RunningProcess(test, allowRetry, this).start();
1730 } 1526 }
1731 _numProcesses++; 1527 _numProcesses++;
1732 } 1528 }
1733 } 1529 }
1734 } 1530 }
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