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

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

Issue 22817002: test.py: Reduce the number of times we retry commands before showing them as failed. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | 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.
(...skipping 12 matching lines...) Expand all
23 import "http_server.dart" as http_server; 23 import "http_server.dart" as http_server;
24 import "status_file_parser.dart"; 24 import "status_file_parser.dart";
25 import "test_progress.dart"; 25 import "test_progress.dart";
26 import "test_suite.dart"; 26 import "test_suite.dart";
27 import "utils.dart"; 27 import "utils.dart";
28 import 'record_and_replay.dart'; 28 import 'record_and_replay.dart';
29 29
30 const int CRASHING_BROWSER_EXITCODE = -10; 30 const int CRASHING_BROWSER_EXITCODE = -10;
31 const int SLOW_TIMEOUT_MULTIPLIER = 4; 31 const int SLOW_TIMEOUT_MULTIPLIER = 4;
32 32
33 const MESSAGE_CANNOT_OPEN_DISPLAY = 'Gtk-WARNING **: cannot open display';
34 const MESSAGE_FAILED_TO_RUN_COMMAND = 'Failed to run command. return code=1';
35
33 typedef void TestCaseEvent(TestCase testCase); 36 typedef void TestCaseEvent(TestCase testCase);
34 typedef void ExitCodeEvent(int exitCode); 37 typedef void ExitCodeEvent(int exitCode);
35 typedef void EnqueueMoreWork(ProcessQueue queue); 38 typedef void EnqueueMoreWork(ProcessQueue queue);
36 39
37 // Some IO tests use these variables and get confused if the host environment 40 // Some IO tests use these variables and get confused if the host environment
38 // variables are inherited so they are excluded. 41 // variables are inherited so they are excluded.
39 const List<String> EXCLUDED_ENVIRONMENT_VARIABLES = 42 const List<String> EXCLUDED_ENVIRONMENT_VARIABLES =
40 const ['http_proxy', 'https_proxy', 'no_proxy', 43 const ['http_proxy', 'https_proxy', 'no_proxy',
41 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY']; 44 'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY'];
42 45
43 46
44 /** A command executed as a step in a test case. */ 47 /** A command executed as a step in a test case. */
45 class Command { 48 class Command {
46 /** Path to the executable of this command. */ 49 /** Path to the executable of this command. */
47 String executable; 50 String executable;
48 51
49 /** The actual command line that will be executed. */ 52 /** The actual command line that will be executed. */
50 String commandLine; 53 String commandLine;
51 54
52 /** A descriptive name for this command. */ 55 /** A descriptive name for this command. */
53 String displayName; 56 String displayName;
54 57
55 /** Command line arguments to the executable. */ 58 /** Command line arguments to the executable. */
56 List<String> arguments; 59 List<String> arguments;
57 60
58 /** Environment for the command */ 61 /** Environment for the command */
59 Map<String, String> environmentOverrides; 62 Map<String, String> environmentOverrides;
60 63
61 /** Number of times this command can be retried */ 64 /** Number of times this command *can* be retried */
62 int get numRetries => 0; 65 int get maxNumRetries => 2;
63 66
64 // We compute the Command.hashCode lazily and cache it here, since it might 67 // We compute the Command.hashCode lazily and cache it here, since it might
65 // be expensive to compute (and hashCode is called often). 68 // be expensive to compute (and hashCode is called often).
66 int _cachedHashCode; 69 int _cachedHashCode;
67 70
68 Command._(this.displayName, this.executable, 71 Command._(this.displayName, this.executable,
69 this.arguments, String configurationDir, 72 this.arguments, String configurationDir,
70 [this.environmentOverrides = null]) { 73 [this.environmentOverrides = null]) {
71 if (io.Platform.operatingSystem == 'windows') { 74 if (io.Platform.operatingSystem == 'windows') {
72 // Windows can't handle the first command if it is a .bat file or the like 75 // Windows can't handle the first command if it is a .bat file or the like
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 builder.add(expectedOutputPath.toString()); 291 builder.add(expectedOutputPath.toString());
289 } 292 }
290 293
291 bool _equal(Command other) { 294 bool _equal(Command other) {
292 return 295 return
293 other is ContentShellCommand && 296 other is ContentShellCommand &&
294 super._equal(other) && 297 super._equal(other) &&
295 expectedOutputPath.toString() == other.expectedOutputPath.toString(); 298 expectedOutputPath.toString() == other.expectedOutputPath.toString();
296 } 299 }
297 300
298 // FIXME(kustermann): Remove this once we're stable 301 int get maxNumRetries => 3;
299 int get numRetries => 2;
300 } 302 }
301 303
302 class BrowserTestCommand extends Command { 304 class BrowserTestCommand extends Command {
303 final String browser; 305 final String browser;
304 final String url; 306 final String url;
305 307
306 BrowserTestCommand._(String _browser, 308 BrowserTestCommand._(String _browser,
307 this.url, 309 this.url,
308 String executable, 310 String executable,
309 List<String> arguments, 311 List<String> arguments,
310 String configurationDir) 312 String configurationDir)
311 : super._(_browser, executable, arguments, configurationDir), 313 : super._(_browser, executable, arguments, configurationDir),
312 browser = _browser; 314 browser = _browser;
313 315
314 void _buildHashCode(HashCodeBuilder builder) { 316 void _buildHashCode(HashCodeBuilder builder) {
315 super._buildHashCode(builder); 317 super._buildHashCode(builder);
316 builder.add(browser); 318 builder.add(browser);
317 builder.add(url); 319 builder.add(url);
318 } 320 }
319 321
320 bool _equal(Command other) { 322 bool _equal(Command other) {
321 return 323 return
322 other is BrowserTestCommand && 324 other is BrowserTestCommand &&
323 super._equal(other) && 325 super._equal(other) &&
324 browser == other.browser && 326 browser == other.browser &&
325 url == other.url; 327 url == other.url;
326 } 328 }
327
328 // FIXME(kustermann): Remove this once we're stable
329 int get numRetries => 2;
330 } 329 }
331 330
332 class SeleniumTestCommand extends Command { 331 class SeleniumTestCommand extends Command {
333 final String browser; 332 final String browser;
334 final String url; 333 final String url;
335 334
336 SeleniumTestCommand._(String _browser, 335 SeleniumTestCommand._(String _browser,
337 this.url, 336 this.url,
338 String executable, 337 String executable,
339 List<String> arguments, 338 List<String> arguments,
340 String configurationDir) 339 String configurationDir)
341 : super._(_browser, executable, arguments, configurationDir), 340 : super._(_browser, executable, arguments, configurationDir),
342 browser = _browser; 341 browser = _browser;
343 342
344 void _buildHashCode(HashCodeBuilder builder) { 343 void _buildHashCode(HashCodeBuilder builder) {
345 super._buildHashCode(builder); 344 super._buildHashCode(builder);
346 builder.add(browser); 345 builder.add(browser);
347 builder.add(url); 346 builder.add(url);
348 } 347 }
349 348
350 bool _equal(Command other) { 349 bool _equal(Command other) {
351 return 350 return
352 other is SeleniumTestCommand && 351 other is SeleniumTestCommand &&
353 super._equal(other) && 352 super._equal(other) &&
354 browser == other.browser && 353 browser == other.browser &&
355 url == other.url; 354 url == other.url;
356 } 355 }
357
358 // FIXME(kustermann): Remove this once we're stable
359 int get numRetries => 2;
360 } 356 }
361 357
362 class AnalysisCommand extends Command { 358 class AnalysisCommand extends Command {
363 final String flavor; 359 final String flavor;
364 360
365 AnalysisCommand._(this.flavor, 361 AnalysisCommand._(this.flavor,
366 String displayName, 362 String displayName,
367 String executable, 363 String executable,
368 List<String> arguments, 364 List<String> arguments,
369 String configurationDir) 365 String configurationDir)
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 return false; 544 return false;
549 } 545 }
550 546
551 var flags = new Set.from(expectedOutcomes); 547 var flags = new Set.from(expectedOutcomes);
552 flags..remove(TIMEOUT) 548 flags..remove(TIMEOUT)
553 ..remove(SLOW); 549 ..remove(SLOW);
554 return flags.contains(PASS) && flags.length > 1; 550 return flags.contains(PASS) && flags.length > 1;
555 } 551 }
556 552
557 bool get isFinished { 553 bool get isFinished {
558 return !lastCommandOutput.successfull || 554 return !lastCommandOutput.successful ||
559 commands.length == commandOutputs.length; 555 commands.length == commandOutputs.length;
560 } 556 }
561 } 557 }
562 558
563 559
564 /** 560 /**
565 * BrowserTestCase has an extra compilation command that is run in a separate 561 * BrowserTestCase has an extra compilation command that is run in a separate
566 * process, before the regular test is run as in the base class [TestCase]. 562 * process, before the regular test is run as in the base class [TestCase].
567 * If the compilation command fails, then the rest of the test is not run. 563 * If the compilation command fails, then the rest of the test is not run.
568 */ 564 */
(...skipping 23 matching lines...) Expand all
592 bool get hasCrashed; 588 bool get hasCrashed;
593 589
594 bool get hasTimedOut; 590 bool get hasTimedOut;
595 591
596 bool didFail(testcase); 592 bool didFail(testcase);
597 593
598 bool hasFailed(TestCase testCase); 594 bool hasFailed(TestCase testCase);
599 595
600 bool get canRunDependendCommands; 596 bool get canRunDependendCommands;
601 597
602 bool get successfull; // otherwise we might to retry running 598 bool get successful; // otherwise we might to retry running
603 599
604 Duration get time; 600 Duration get time;
605 601
606 int get exitCode; 602 int get exitCode;
607 603
608 List<int> get stdout; 604 List<int> get stdout;
609 605
610 List<int> get stderr; 606 List<int> get stderr;
611 607
612 List<String> get diagnostics; 608 List<String> get diagnostics;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 671
676 bool didFail(TestCase testCase) { 672 bool didFail(TestCase testCase) {
677 return (exitCode != 0 && !hasCrashed); 673 return (exitCode != 0 && !hasCrashed);
678 } 674 }
679 675
680 bool get canRunDependendCommands { 676 bool get canRunDependendCommands {
681 // FIXME(kustermann): We may need to change this 677 // FIXME(kustermann): We may need to change this
682 return !hasTimedOut && exitCode == 0; 678 return !hasTimedOut && exitCode == 0;
683 } 679 }
684 680
685 bool get successfull { 681 bool get successful {
686 // FIXME(kustermann): We may need to change this 682 // FIXME(kustermann): We may need to change this
687 return !hasTimedOut && exitCode == 0; 683 return !hasTimedOut && exitCode == 0;
688 } 684 }
689 685
690 // Reverse result of a negative test. 686 // Reverse result of a negative test.
691 bool hasFailed(TestCase testCase) { 687 bool hasFailed(TestCase testCase) {
692 // FIXME(kustermann): this is a hack, remove it 688 // FIXME(kustermann): this is a hack, remove it
693 bool isCompilationCommand = testCase.commands.first == command 689 bool isCompilationCommand = testCase.commands.first == command
694 && testCase.commands.length > 1; 690 && testCase.commands.length > 1;
695 if (isCompilationCommand && 691 if (isCompilationCommand &&
(...skipping 23 matching lines...) Expand all
719 time, 715 time,
720 compilationSkipped) { 716 compilationSkipped) {
721 _failedBecauseOfMissingXDisplay = _didFailBecauseOfMissingXDisplay(); 717 _failedBecauseOfMissingXDisplay = _didFailBecauseOfMissingXDisplay();
722 if (_failedBecauseOfMissingXDisplay) { 718 if (_failedBecauseOfMissingXDisplay) {
723 DebugLogger.warning("Warning: Test failure because of missing XDisplay"); 719 DebugLogger.warning("Warning: Test failure because of missing XDisplay");
724 // If we get the X server error, or DRT crashes with a core dump, retry 720 // If we get the X server error, or DRT crashes with a core dump, retry
725 // the test. 721 // the test.
726 } 722 }
727 } 723 }
728 724
725 bool get successful => canRunDependendCommands;
726
729 bool get canRunDependendCommands { 727 bool get canRunDependendCommands {
730 // We cannot rely on the exit code of content_shell as a method to determine 728 // We cannot rely on the exit code of content_shell as a method to determine
731 // if we were successful or not. 729 // if we were successful or not.
732 return super.canRunDependendCommands && !didFail(null); 730 return super.canRunDependendCommands && !didFail(null);
733 } 731 }
734 732
735 bool didFail(TestCase _) { 733 bool didFail(TestCase _) {
736 if (_failedBecauseOfMissingXDisplay) { 734 if (_failedBecauseOfMissingXDisplay) {
737 return true; 735 return true;
738 } 736 }
739 737
740 if (command.expectedOutputFile != null) { 738 if (command.expectedOutputFile != null) {
741 // We are either doing a pixel test or a layout test with content shell 739 // We are either doing a pixel test or a layout test with content shell
742 return _failedBecauseOfUnexpectedDRTOutput; 740 return _failedBecauseOfUnexpectedDRTOutput;
743 } 741 }
744 return _browserTestFailure; 742 return _browserTestFailure;
745 } 743 }
746 744
747 bool _didFailBecauseOfMissingXDisplay() { 745 bool _didFailBecauseOfMissingXDisplay() {
748 // Browser case: 746 // Browser case:
749 // If the browser test failed, it may have been because content shell 747 // If the browser test failed, it may have been because content shell
750 // and the virtual framebuffer X server didn't hook up, or it crashed with 748 // and the virtual framebuffer X server didn't hook up, or it crashed with
751 // a core dump. Sometimes content shell crashes after it has set the stdout 749 // a core dump. Sometimes content shell crashes after it has set the stdout
752 // to PASS, so we have to do this check first. 750 // to PASS, so we have to do this check first.
753 var stderrLines = decodeUtf8(super.stderr).split("\n"); 751 var stderrLines = decodeUtf8(super.stderr).split("\n");
754 for (String line in stderrLines) { 752 for (String line in stderrLines) {
755 // TODO(kustermann,ricow): Issue: 7564 753 // TODO(kustermann,ricow): Issue: 7564
756 // This seems to happen quite frequently, we need to figure out why. 754 // This seems to happen quite frequently, we need to figure out why.
757 if (line.contains('Gtk-WARNING **: cannot open display') || 755 if (line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) ||
758 line.contains('Failed to run command. return code=1')) { 756 line.contains(MESSAGE_FAILED_TO_RUN_COMMAND)) {
759 return true; 757 return true;
760 } 758 }
761 } 759 }
762 return false; 760 return false;
763 } 761 }
764 762
765 bool get _failedBecauseOfUnexpectedDRTOutput { 763 bool get _failedBecauseOfUnexpectedDRTOutput {
766 /* 764 /*
767 * The output of content shell is different for pixel tests than for 765 * The output of content shell is different for pixel tests than for
768 * layout tests. 766 * layout tests.
(...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after
1765 } 1763 }
1766 1764
1767 return Future.wait([_terminateBatchRunners(), _terminateBrowserRunners()]); 1765 return Future.wait([_terminateBatchRunners(), _terminateBrowserRunners()]);
1768 } 1766 }
1769 1767
1770 Future<CommandOutput> runCommand(node, Command command, int timeout) { 1768 Future<CommandOutput> runCommand(node, Command command, int timeout) {
1771 assert(!_finishing); 1769 assert(!_finishing);
1772 1770
1773 Future<CommandOutput> runCommand(int retriesLeft) { 1771 Future<CommandOutput> runCommand(int retriesLeft) {
1774 return _runCommand(command, timeout).then((CommandOutput output) { 1772 return _runCommand(command, timeout).then((CommandOutput output) {
1775 if (!output.canRunDependendCommands && retriesLeft > 0) { 1773 if (retriesLeft > 0 && shouldRetryCommand(output)) {
1776 DebugLogger.warning("Rerunning Command: ($retriesLeft " 1774 DebugLogger.warning("Rerunning Command: ($retriesLeft "
1777 "attempt(s) remains) [cmd: $command]"); 1775 "attempt(s) remains) [cmd: $command]");
1778 return runCommand(retriesLeft - 1); 1776 return runCommand(retriesLeft - 1);
1779 } else { 1777 } else {
1780 return new Future.value(output); 1778 return new Future.value(output);
1781 } 1779 }
1782 }); 1780 });
1783 } 1781 }
1784 return runCommand(command.numRetries); 1782 return runCommand(command.maxNumRetries);
1785 } 1783 }
1786 1784
1787 Future<CommandOutput> _runCommand(Command command, int timeout) { 1785 Future<CommandOutput> _runCommand(Command command, int timeout) {
1788 var batchMode = !globalConfiguration['noBatch']; 1786 var batchMode = !globalConfiguration['noBatch'];
1789 1787
1790 if (command is BrowserTestCommand) { 1788 if (command is BrowserTestCommand) {
1791 return _startBrowserControllerTest(command, timeout); 1789 return _startBrowserControllerTest(command, timeout);
1792 } else if (command is SeleniumTestCommand && batchMode) { 1790 } else if (command is SeleniumTestCommand && batchMode) {
1793 var arguments = ['--force-refresh', '--browser=${command.browser}', 1791 var arguments = ['--force-refresh', '--browser=${command.browser}',
1794 '--timeout=${timeout}', '--out', '${command.url}']; 1792 '--timeout=${timeout}', '--out', '${command.url}'];
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1902 } 1900 }
1903 1901
1904 Future cleanup() => new Future.value(); 1902 Future cleanup() => new Future.value();
1905 1903
1906 Future<CommandOutput> runCommand(node, Command command, int timeout) { 1904 Future<CommandOutput> runCommand(node, Command command, int timeout) {
1907 assert(node.dependencies.length == 0); 1905 assert(node.dependencies.length == 0);
1908 return new Future.value(_archive.outputOf(command)); 1906 return new Future.value(_archive.outputOf(command));
1909 } 1907 }
1910 } 1908 }
1911 1909
1910 bool shouldRetryCommand(CommandOutput output) {
1911 var command = output.command;
1912
1913 if (!output.successful) {
1914 List<String> stdout, stderr;
1915
1916 decodeOutput() {
1917 if (stdout == null && stderr == null) {
1918 stdout = decodeUtf8(output.stderr).split("\n");
1919 stderr = decodeUtf8(output.stderr).split("\n");
1920 }
1921 }
1922
1923 if (io.Platform.operatingSystem == 'linux') {
1924 decodeOutput();
1925 // No matter which command we ran: If we get failures due to the
1926 // "xvfb-run" issue 7564, try re-running the test.
1927 bool containsFailureMsg(String line) {
1928 return line.contains(MESSAGE_CANNOT_OPEN_DISPLAY) ||
1929 line.contains(MESSAGE_FAILED_TO_RUN_COMMAND);
1930 }
1931 if (stdout.any(containsFailureMsg) || stderr.any(containsFailureMsg)) {
1932 return true;
1933 }
1934 }
1935
1936 if (command is BrowserTestCommand) {
1937 // We do not re-run tests on the new browser controller, since it should
1938 // not be as flaky as selenium.
1939 return false;
1940 } else if (command is SeleniumTestCommand) {
1941 // Selenium tests can be flaky. Try re-running.
1942 return true;
1943 } else if (command is ContentShellCommand) {
1944 // FIXME(kustermann): Remove this condition once we figured out why
1945 // content_shell is sometimes not able to fetch resources from the
1946 // HttpServer on windows.
1947 // TODO(kustermann): Don't blindly re-run DRT tests on windows but rather
1948 // check if the stderr/stdout indicates that we actually have this issue.
1949 return io.Platform.operatingSystem == 'windows';
1950 }
1951 }
1952 return false;
1953 }
1912 1954
1913 /* 1955 /*
1914 * [TestCaseCompleter] will listen for 1956 * [TestCaseCompleter] will listen for
1915 * NodeState.Processing -> NodeState.{Successfull,Failed} state changes and 1957 * NodeState.Processing -> NodeState.{Successfull,Failed} state changes and
1916 * will complete a TestCase if it is finished. 1958 * will complete a TestCase if it is finished.
1917 * 1959 *
1918 * It provides a stream [finishedTestCases], which will stream all TestCases 1960 * It provides a stream [finishedTestCases], which will stream all TestCases
1919 * once they're finished. After all TestCases are done, the stream will be 1961 * once they're finished. After all TestCases are done, the stream will be
1920 * closed. 1962 * closed.
1921 */ 1963 */
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
2098 } 2140 }
2099 } 2141 }
2100 2142
2101 void eventAllTestsDone() { 2143 void eventAllTestsDone() {
2102 for (var listener in _eventListener) { 2144 for (var listener in _eventListener) {
2103 listener.allDone(); 2145 listener.allDone();
2104 } 2146 }
2105 _allDone(); 2147 _allDone();
2106 } 2148 }
2107 } 2149 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698