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

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

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