| 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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 } | 74 } |
| 75 | 75 |
| 76 | 76 |
| 77 /** A command executed as a step in a test case. */ | 77 /** A command executed as a step in a test case. */ |
| 78 class Command { | 78 class Command { |
| 79 /** Path to the executable of this command. */ | 79 /** Path to the executable of this command. */ |
| 80 String executable; | 80 String executable; |
| 81 | 81 |
| 82 /** Command line arguments to the executable. */ | 82 /** Command line arguments to the executable. */ |
| 83 List<String> arguments; | 83 List<String> arguments; |
| 84 | 84 |
| 85 /** Environment for the command */ | 85 /** Environment for the command */ |
| 86 Map<String,String> environment; | 86 Map<String,String> environment; |
| 87 | 87 |
| 88 /** The actual command line that will be executed. */ | 88 /** The actual command line that will be executed. */ |
| 89 String commandLine; | 89 String commandLine; |
| 90 | 90 |
| 91 Command(this.executable, this.arguments, [this.environment = null]) { | 91 Command(this.executable, this.arguments, [this.environment = null]) { |
| 92 if (Platform.operatingSystem == 'windows') { | 92 if (Platform.operatingSystem == 'windows') { |
| 93 // 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 |
| 94 // with the slashes going the other direction. | 94 // with the slashes going the other direction. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 } | 194 } |
| 195 | 195 |
| 196 return env; | 196 return env; |
| 197 } | 197 } |
| 198 | 198 |
| 199 static List<String> _getArguments(List<String> options, String htmlFile) { | 199 static List<String> _getArguments(List<String> options, String htmlFile) { |
| 200 var arguments = new List.from(options); | 200 var arguments = new List.from(options); |
| 201 arguments.add(htmlFile); | 201 arguments.add(htmlFile); |
| 202 return arguments; | 202 return arguments; |
| 203 } | 203 } |
| 204 | 204 |
| 205 Path get expectedOutputFile => expectedOutputPath; | 205 Path get expectedOutputFile => expectedOutputPath; |
| 206 bool get isPixelTest => (expectedOutputFile != null && | 206 bool get isPixelTest => (expectedOutputFile != null && |
| 207 expectedOutputFile.filename.endsWith(".png")); | 207 expectedOutputFile.filename.endsWith(".png")); |
| 208 } | 208 } |
| 209 | 209 |
| 210 | 210 |
| 211 /** | 211 /** |
| 212 * 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 |
| 213 * its output. Running a test involves starting a separate process, with | 213 * its output. Running a test involves starting a separate process, with |
| 214 * the executable and arguments given by the TestCase, and recording its | 214 * the executable and arguments given by the TestCase, and recording its |
| 215 * stdout and stderr output streams, and its exit code. TestCase only | 215 * stdout and stderr output streams, and its exit code. TestCase only |
| 216 * contains static information about the test; actually running the test is | 216 * contains static information about the test; actually running the test is |
| 217 * performed by [ProcessQueue] using a [RunningProcess] object. | 217 * performed by [ProcessQueue] using a [RunningProcess] object. |
| 218 * | 218 * |
| 219 * The output information is stored in a [CommandOutput] instance contained | 219 * The output information is stored in a [CommandOutput] instance contained |
| 220 * in TestCase.commandOutputs. The last CommandOutput instance is responsible | 220 * in TestCase.commandOutputs. The last CommandOutput instance is responsible |
| 221 * for evaluating if the test has passed, failed, crashed, or timed out, and the | 221 * for evaluating if the test has passed, failed, crashed, or timed out, and the |
| 222 * TestCase has information about what the expected result of the test should | 222 * TestCase has information about what the expected result of the test should |
| 223 * be. | 223 * be. |
| 224 * | 224 * |
| 225 * The TestCase has a callback function, [completedHandler], that is run when | 225 * The TestCase has a callback function, [completedHandler], that is run when |
| 226 * the test is completed. | 226 * the test is completed. |
| 227 */ | 227 */ |
| 228 class TestCase { | 228 class TestCase { |
| 229 /** | 229 /** |
| 230 * A list of commands to execute. Most test cases have a single command. | 230 * A list of commands to execute. Most test cases have a single command. |
| 231 * Dart2js tests have two commands, one to compile the source and another | 231 * Dart2js tests have two commands, one to compile the source and another |
| 232 * to execute it. Some isolate tests might even have three, if they require | 232 * to execute it. Some isolate tests might even have three, if they require |
| 233 * compiling multiple sources that are run in isolation. | 233 * compiling multiple sources that are run in isolation. |
| 234 */ | 234 */ |
| 235 List<Command> commands; | 235 List<Command> commands; |
| 236 Map<Command, CommandOutput> commandOutputs = new Map<Command,CommandOutput>(); | 236 Map<Command, CommandOutput> commandOutputs = new Map<Command,CommandOutput>(); |
| 237 | 237 |
| 238 Map configuration; | 238 Map configuration; |
| 239 String displayName; | 239 String displayName; |
| 240 bool isNegative; | 240 bool isNegative; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 * flaky browser tests. | 362 * flaky browser tests. |
| 363 */ | 363 */ |
| 364 int numRetries; | 364 int numRetries; |
| 365 | 365 |
| 366 /** | 366 /** |
| 367 * True if this test is dependent on another test completing before it can | 367 * True if this test is dependent on another test completing before it can |
| 368 * star (for example, we might need to depend on some other test completing | 368 * star (for example, we might need to depend on some other test completing |
| 369 * first). | 369 * first). |
| 370 */ | 370 */ |
| 371 bool waitingForOtherTest; | 371 bool waitingForOtherTest; |
| 372 | 372 |
| 373 /** | 373 /** |
| 374 * The set of test cases that wish to be notified when this test has | 374 * The set of test cases that wish to be notified when this test has |
| 375 * completed. | 375 * completed. |
| 376 */ | 376 */ |
| 377 List<BrowserTestCase> observers; | 377 List<BrowserTestCase> observers; |
| 378 | 378 |
| 379 BrowserTestCase(displayName, commands, configuration, completedHandler, | 379 BrowserTestCase(displayName, commands, configuration, completedHandler, |
| 380 expectedOutcomes, info, isNegative, [this.waitingForOtherTest = false]) | 380 expectedOutcomes, info, isNegative, [this.waitingForOtherTest = false]) |
| 381 : super(displayName, commands, configuration, completedHandler, | 381 : super(displayName, commands, configuration, completedHandler, |
| 382 expectedOutcomes, isNegative: isNegative, info: info) { | 382 expectedOutcomes, isNegative: isNegative, info: info) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 402 */ | 402 */ |
| 403 void notifyObservers() { | 403 void notifyObservers() { |
| 404 for (BrowserTestCase testCase in observers) { | 404 for (BrowserTestCase testCase in observers) { |
| 405 testCase.waitingForOtherTest = false; | 405 testCase.waitingForOtherTest = false; |
| 406 } | 406 } |
| 407 } | 407 } |
| 408 } | 408 } |
| 409 | 409 |
| 410 | 410 |
| 411 /** | 411 /** |
| 412 * CommandOutput records the output of a completed command: the process's exit | 412 * CommandOutput records the output of a completed command: the process's exit |
| 413 * 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, |
| 414 * 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 |
| 415 * [TestCase] this is the output of. | 415 * [TestCase] this is the output of. |
| 416 */ | 416 */ |
| 417 abstract class CommandOutput { | 417 abstract class CommandOutput { |
| 418 factory CommandOutput.fromCase(TestCase testCase, | 418 factory CommandOutput.fromCase(TestCase testCase, |
| 419 Command command, | 419 Command command, |
| 420 int exitCode, | 420 int exitCode, |
| 421 bool incomplete, | 421 bool incomplete, |
| 422 bool timedOut, | 422 bool timedOut, |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 // so we have to do this check first. | 624 // so we have to do this check first. |
| 625 var stderrLines = new String.fromCharCodes(super.stderr).split("\n"); | 625 var stderrLines = new String.fromCharCodes(super.stderr).split("\n"); |
| 626 for (String line in stderrLines) { | 626 for (String line in stderrLines) { |
| 627 if (line.contains('Gtk-WARNING **: cannot open display: :99') || | 627 if (line.contains('Gtk-WARNING **: cannot open display: :99') || |
| 628 line.contains('Failed to run command. return code=1')) { | 628 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 | 629 // If we get the X server error, or DRT crashes with a core dump, retry |
| 630 // the test. | 630 // the test. |
| 631 if ((testCase as BrowserTestCase).numRetries > 0) { | 631 if ((testCase as BrowserTestCase).numRetries > 0) { |
| 632 requestRetry = true; | 632 requestRetry = true; |
| 633 } | 633 } |
| 634 printDebug("Failed because of missing XDisplay"); | 634 printDebug("Test failure because of missing XDisplay"); |
| 635 return true; | 635 return true; |
| 636 } | 636 } |
| 637 } | 637 } |
| 638 return false; | 638 return false; |
| 639 } | 639 } |
| 640 | 640 |
| 641 bool get _failedBecauseOfUnexpectedDRTOutput { | 641 bool get _failedBecauseOfUnexpectedDRTOutput { |
| 642 /* | 642 /* |
| 643 * The output of DumpRenderTree is different for pixel tests than for | 643 * The output of DumpRenderTree is different for pixel tests than for |
| 644 * layout tests. | 644 * layout tests. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 673 var startPosition = newLineAfterContentLength + | 673 var startPosition = newLineAfterContentLength + |
| 674 bytesNewLine.length; | 674 bytesNewLine.length; |
| 675 var endPosition = stdout.length - bytesEOF.length; | 675 var endPosition = stdout.length - bytesEOF.length; |
| 676 | 676 |
| 677 var _failed = !areByteArraysEqual(expectedContent, | 677 var _failed = !areByteArraysEqual(expectedContent, |
| 678 0, | 678 0, |
| 679 stdout, | 679 stdout, |
| 680 startPosition, | 680 startPosition, |
| 681 endPosition - startPosition); | 681 endPosition - startPosition); |
| 682 if (_failed) { | 682 if (_failed) { |
| 683 printDebug("Failed because command.expectedOutputFile doesn't " | 683 printDebug("Test failure because command.expectedOutputFile " |
| 684 "match stdout of DRT"); | 684 "doesn't match stdout of DRT"); |
| 685 } | 685 } |
| 686 return _failed; | 686 return _failed; |
| 687 } | 687 } |
| 688 } | 688 } |
| 689 printDebug("Failed because we didn't find 'Content-Length' in the DRT " | 689 printDebug("Test failure because we didn't find 'Content-Length' in the" |
| 690 "output"); | 690 " DRT output"); |
| 691 return true; | 691 return true; |
| 692 } else { | 692 } else { |
| 693 var _failed = !areByteArraysEqual(expectedContent, 0, | 693 var _failed = !areByteArraysEqual(expectedContent, 0, |
| 694 stdout, 0, | 694 stdout, 0, |
| 695 stdout.length); | 695 stdout.length); |
| 696 if (_failed) { | 696 if (_failed) { |
| 697 printDebug("Failed because command.expectedOutputFile doesn't match " | 697 printDebug("Test failure because command.expectedOutputFile doesn't " |
| 698 "stdout of DRT"); | 698 "match stdout of DRT"); |
| 699 } | 699 } |
| 700 return _failed; | 700 return _failed; |
| 701 } | 701 } |
| 702 } | 702 } |
| 703 printDebug("Failed because command.expectedOutputFile doesn't exist"); | 703 printDebug("Test failure because command.expectedOutputFile doesn't exist"); |
| 704 return true; | 704 return true; |
| 705 } | 705 } |
| 706 | 706 |
| 707 bool get _browserTestFailure { | 707 bool get _browserTestFailure { |
| 708 // Browser tests fail unless stdout contains | 708 // Browser tests fail unless stdout contains |
| 709 // 'Content-Type: text/plain' followed by 'PASS'. | 709 // 'Content-Type: text/plain' followed by 'PASS'. |
| 710 bool has_content_type = false; | 710 bool has_content_type = false; |
| 711 var stdoutLines = new String.fromCharCodes(super.stdout).split("\n"); | 711 var stdoutLines = new String.fromCharCodes(super.stdout).split("\n"); |
| 712 for (String line in stdoutLines) { | 712 for (String line in stdoutLines) { |
| 713 switch (line) { | 713 switch (line) { |
| 714 case 'Content-Type: text/plain': | 714 case 'Content-Type: text/plain': |
| 715 has_content_type = true; | 715 has_content_type = true; |
| 716 break; | 716 break; |
| 717 case 'PASS': | 717 case 'PASS': |
| 718 if (has_content_type) { | 718 if (has_content_type) { |
| 719 var _failed = (exitCode != 0 && !hasCrashed); | 719 var _failed = (exitCode != 0 && !hasCrashed); |
| 720 if (_failed) { | 720 if (_failed) { |
| 721 printDebug("Failed because '(exitCode != 0 && !hasCrashed) was " | 721 printDebug("Test failure because '(exitCode != 0 && !hasCrashed) " |
| 722 "true"); | 722 "was true"); |
| 723 } | 723 } |
| 724 return _failed; | 724 return _failed; |
| 725 } | 725 } |
| 726 break; | 726 break; |
| 727 } | 727 } |
| 728 } | 728 } |
| 729 printDebug("Failed because content-type: text/plain + PASS was not found"); | 729 printDebug("Test failure because content-type: text/plain + PASS was not " |
| 730 "found"); |
| 730 return true; | 731 return true; |
| 731 } | 732 } |
| 732 | 733 |
| 733 void printDebug(String msg) { | 734 void printDebug(String msg) { |
| 734 print(""); | 735 print(""); |
| 735 print("DEBUG(infrastructure): $msg"); | 736 print("DEBUG(infrastructure): $msg"); |
| 736 print("DEBUG(infrastructure): cmd.executable: '${command.executable}'"); | 737 print("DEBUG(infrastructure): cmd.executable: '${command.executable}'"); |
| 737 print("DEBUG(infrastructure): cmd.arguments: '${command.arguments}'"); | 738 print("DEBUG(infrastructure): cmd.arguments: '${command.arguments}'"); |
| 738 print("DEBUG(infrastructure): cmd.environment: '${command.environment}'"); | 739 print("DEBUG(infrastructure): cmd.environment: '${command.environment}'"); |
| 739 print(""); | 740 print(""); |
| (...skipping 1014 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1754 // the developer doesn't waste his or her time trying to fix a bunch of | 1755 // the developer doesn't waste his or her time trying to fix a bunch of |
| 1755 // tests that appear to be broken but were actually just flakes that | 1756 // tests that appear to be broken but were actually just flakes that |
| 1756 // didn't get retried because there had already been one failure. | 1757 // didn't get retried because there had already been one failure. |
| 1757 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 1758 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; |
| 1758 new RunningProcess(test, allowRetry, this).start(); | 1759 new RunningProcess(test, allowRetry, this).start(); |
| 1759 } | 1760 } |
| 1760 _numProcesses++; | 1761 _numProcesses++; |
| 1761 } | 1762 } |
| 1762 } | 1763 } |
| 1763 } | 1764 } |
| OLD | NEW |