| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |