Chromium Code Reviews| 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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 85 } | 85 } |
| 86 | 86 |
| 87 bool _equal(Command other) { | 87 bool _equal(Command other) { |
| 88 return hashCode == other.hashCode && | 88 return hashCode == other.hashCode && |
| 89 commandLine == other.commandLine && | 89 commandLine == other.commandLine && |
| 90 displayName == other.displayName; | 90 displayName == other.displayName; |
| 91 } | 91 } |
| 92 | 92 |
| 93 String toString() => reproductionCommand; | 93 String toString() => reproductionCommand; |
| 94 | 94 |
| 95 Future<bool> get outputIsUpToDate => new Future.value(false); | 95 Future<CachedState> get outputIsUpToDate => |
| 96 new Future.value(const CachedState(false, false)); | |
|
kustermann
2014/04/29 21:20:44
It's not so nice that the Command class itself has
ricow1
2014/04/30 06:51:01
This is actually no different then the fact that i
| |
| 97 | |
| 98 Future<String> get cachedOutput => new Future.value(null); | |
| 99 Future writeCachedOutput(CommandOutput output) => new Future.value(null); | |
| 96 } | 100 } |
| 97 | 101 |
| 102 class CachedState { | |
| 103 const CachedState(this.upToDateCompilation, | |
| 104 this.upToDateCommandOutput); | |
| 105 final bool upToDateCompilation; | |
| 106 final bool upToDateCommandOutput; | |
| 107 } | |
| 108 | |
| 109 | |
| 98 class ProcessCommand extends Command { | 110 class ProcessCommand extends Command { |
| 99 /** Path to the executable of this command. */ | 111 /** Path to the executable of this command. */ |
| 100 String executable; | 112 String executable; |
| 101 | 113 |
| 102 /** Command line arguments to the executable. */ | 114 /** Command line arguments to the executable. */ |
| 103 List<String> arguments; | 115 List<String> arguments; |
| 104 | 116 |
| 105 /** Environment for the command */ | 117 /** Environment for the command */ |
| 106 Map<String, String> environmentOverrides; | 118 Map<String, String> environmentOverrides; |
| 107 | 119 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 | 169 |
| 158 String get reproductionCommand { | 170 String get reproductionCommand { |
| 159 var command = ([executable]..addAll(arguments)) | 171 var command = ([executable]..addAll(arguments)) |
| 160 .map(escapeCommandLineArgument).join(' '); | 172 .map(escapeCommandLineArgument).join(' '); |
| 161 if (workingDirectory != null) { | 173 if (workingDirectory != null) { |
| 162 command = "$command (working directory: $workingDirectory)"; | 174 command = "$command (working directory: $workingDirectory)"; |
| 163 } | 175 } |
| 164 return command; | 176 return command; |
| 165 } | 177 } |
| 166 | 178 |
| 167 Future<bool> get outputIsUpToDate => new Future.value(false); | 179 Future<CachedState> get outputIsUpToDate => |
| 180 new Future.value(const CachedState(false, false)); | |
| 168 } | 181 } |
| 169 | 182 |
| 170 class CompilationCommand extends ProcessCommand { | 183 class CompilationCommand extends ProcessCommand { |
| 171 String _outputFile; | 184 String _outputFile; |
| 172 bool _neverSkipCompilation; | 185 bool _neverSkipCompilation; |
| 173 List<Uri> _bootstrapDependencies; | 186 List<Uri> _bootstrapDependencies; |
| 174 | 187 |
| 188 Future writeCachedOutput(CommandOutput output) { | |
| 189 var file = new io.File(TestUtils.cachedOutputFile(_outputFile)); | |
| 190 return file.writeAsString(output.json); | |
| 191 } | |
| 192 | |
| 193 Future<CommandOutput> get cachedOutput { | |
| 194 var file = new io.File(TestUtils.cachedOutputFile(_outputFile)); | |
| 195 return file.exists().then((exists) { | |
| 196 if (exists) return file.readAsString().then((content) { | |
| 197 return new CompilationCommandOutputImpl.fromJson(this, content); | |
| 198 });; | |
| 199 }); | |
| 200 } | |
| 201 | |
| 175 CompilationCommand._(String displayName, | 202 CompilationCommand._(String displayName, |
| 176 this._outputFile, | 203 this._outputFile, |
| 177 this._neverSkipCompilation, | 204 this._neverSkipCompilation, |
| 178 List<Uri> bootstrapDependencies, | 205 List<Uri> bootstrapDependencies, |
| 179 String executable, | 206 String executable, |
| 180 List<String> arguments, | 207 List<String> arguments, |
| 181 Map<String, String> environmentOverrides) | 208 Map<String, String> environmentOverrides) |
| 182 : super._(displayName, executable, arguments, environmentOverrides) { | 209 : super._(displayName, executable, arguments, environmentOverrides) { |
| 183 // We sort here, so we can do a fast hashCode/operator== | 210 // We sort here, so we can do a fast hashCode/operator== |
| 184 _bootstrapDependencies = new List.from(bootstrapDependencies); | 211 _bootstrapDependencies = new List.from(bootstrapDependencies); |
| 185 _bootstrapDependencies.sort(); | 212 _bootstrapDependencies.sort(); |
| 186 } | 213 } |
| 187 | 214 |
| 188 Future<bool> get outputIsUpToDate { | 215 Future<CachedState> get outputIsUpToDate { |
| 189 if (_neverSkipCompilation) return new Future.value(false); | 216 if (_neverSkipCompilation) return new Future.value(false); |
|
Bill Hesse
2014/04/29 17:51:55
Shouldn't these return CachedState objects?
kustermann
2014/04/29 21:20:44
BTW: I hope we did not disable '--checked' mode wh
ricow1
2014/04/30 06:51:01
We did not
ricow1
2014/04/30 06:51:01
Done.
| |
| 190 | |
| 191 Future<List<Uri>> readDepsFile(String path) { | 217 Future<List<Uri>> readDepsFile(String path) { |
| 192 var file = new io.File(new Path(path).toNativePath()); | 218 var file = new io.File(new Path(path).toNativePath()); |
| 193 if (!file.existsSync()) { | 219 if (!file.existsSync()) { |
| 194 return new Future.value(null); | 220 return new Future.value(null); |
| 195 } | 221 } |
| 196 return file.readAsLines().then((List<String> lines) { | 222 return file.readAsLines().then((List<String> lines) { |
| 197 var dependencies = new List<Uri>(); | 223 var dependencies = new List<Uri>(); |
| 198 for (var line in lines) { | 224 for (var line in lines) { |
| 199 line = line.trim(); | 225 line = line.trim(); |
| 200 if (line.length > 0) { | 226 if (line.length > 0) { |
| 201 dependencies.add(Uri.parse(line)); | 227 dependencies.add(Uri.parse(line)); |
| 202 } | 228 } |
| 203 } | 229 } |
| 204 return dependencies; | 230 return dependencies; |
| 205 }); | 231 }); |
| 206 } | 232 } |
| 207 | 233 |
| 234 bool isUpToDate(lastModified, dependencies) { | |
| 235 if (lastModified == null) return false; | |
| 236 for (var dependency in dependencies) { | |
| 237 var dependencyLastModified = | |
| 238 TestUtils.lastModifiedCache.getLastModified(dependency); | |
| 239 if (dependencyLastModified == null || | |
| 240 dependencyLastModified.isAfter(lastModified)) { | |
| 241 return false; | |
| 242 } | |
| 243 } | |
| 244 return true; | |
| 245 } | |
| 246 | |
| 208 return readDepsFile("$_outputFile.deps").then((dependencies) { | 247 return readDepsFile("$_outputFile.deps").then((dependencies) { |
| 209 if (dependencies != null) { | 248 if (dependencies != null) { |
| 210 dependencies.addAll(_bootstrapDependencies); | 249 dependencies.addAll(_bootstrapDependencies); |
| 211 var jsOutputLastModified = TestUtils.lastModifiedCache.getLastModified( | 250 var lastModified = TestUtils.lastModifiedCache.getLastModified( |
| 212 new Uri(scheme: 'file', path: _outputFile)); | 251 new Uri(scheme: 'file', path: _outputFile)); |
| 213 if (jsOutputLastModified != null) { | 252 if (isUpToDate(lastModified, dependencies)) { |
| 214 for (var dependency in dependencies) { | 253 return const CachedState(true, false); |
|
Bill Hesse
2014/04/29 17:51:55
Is CachedState(true, false) really meaning CachedS
ricow1
2014/04/30 06:51:01
Because it would not be true - if we have up to da
| |
| 215 var dependencyLastModified = | 254 } else { |
| 216 TestUtils.lastModifiedCache.getLastModified(dependency); | 255 // We did not have real output, check if we have stored the |
| 217 if (dependencyLastModified == null || | 256 // output of running the compiler on this test for a failed run. |
| 218 dependencyLastModified.isAfter(jsOutputLastModified)) { | 257 var cachedOutputFile = TestUtils.cachedOutputFile(_outputFile); |
| 219 return false; | 258 var cachedOutputUri = new Uri(scheme: 'file', path: cachedOutputFile); |
| 220 } | 259 var cachedOutputLastModified = |
| 260 TestUtils.lastModifiedCache.getLastModified(cachedOutputUri); | |
| 261 if (isUpToDate(cachedOutputLastModified, dependencies)) { | |
| 262 return const CachedState(false, true); | |
| 221 } | 263 } |
| 222 return true; | |
| 223 } | 264 } |
| 224 } | 265 } |
| 225 return false; | 266 return const CachedState(false, false); |
| 226 }); | 267 }); |
| 227 } | 268 } |
| 228 | 269 |
| 229 void _buildHashCode(HashCodeBuilder builder) { | 270 void _buildHashCode(HashCodeBuilder builder) { |
| 230 super._buildHashCode(builder); | 271 super._buildHashCode(builder); |
| 231 builder.add(_outputFile); | 272 builder.add(_outputFile); |
| 232 builder.add(_neverSkipCompilation); | 273 builder.add(_neverSkipCompilation); |
| 233 for (var uri in _bootstrapDependencies) builder.add(uri); | 274 for (var uri in _bootstrapDependencies) builder.add(uri); |
| 234 } | 275 } |
| 235 | 276 |
| (...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 912 | 953 |
| 913 int get pid; | 954 int get pid; |
| 914 | 955 |
| 915 List<int> get stdout; | 956 List<int> get stdout; |
| 916 | 957 |
| 917 List<int> get stderr; | 958 List<int> get stderr; |
| 918 | 959 |
| 919 List<String> get diagnostics; | 960 List<String> get diagnostics; |
| 920 | 961 |
| 921 bool get compilationSkipped; | 962 bool get compilationSkipped; |
| 963 | |
| 964 String get json; | |
| 922 } | 965 } |
| 923 | 966 |
| 924 class CommandOutputImpl extends UniqueObject implements CommandOutput { | 967 class CommandOutputImpl extends UniqueObject implements CommandOutput { |
| 925 Command command; | 968 Command command; |
| 926 int exitCode; | 969 int exitCode; |
| 927 | 970 |
| 928 bool timedOut; | 971 bool timedOut; |
| 929 List<int> stdout; | 972 List<int> stdout; |
| 930 List<int> stderr; | 973 List<int> stderr; |
| 931 Duration time; | 974 Duration time; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1001 | 1044 |
| 1002 Expectation _negateOutcomeIfNegativeTest(Expectation outcome, | 1045 Expectation _negateOutcomeIfNegativeTest(Expectation outcome, |
| 1003 bool isNegative) { | 1046 bool isNegative) { |
| 1004 if (!isNegative) return outcome; | 1047 if (!isNegative) return outcome; |
| 1005 | 1048 |
| 1006 if (outcome.canBeOutcomeOf(Expectation.FAIL)) { | 1049 if (outcome.canBeOutcomeOf(Expectation.FAIL)) { |
| 1007 return Expectation.PASS; | 1050 return Expectation.PASS; |
| 1008 } | 1051 } |
| 1009 return Expectation.FAIL; | 1052 return Expectation.FAIL; |
| 1010 } | 1053 } |
| 1054 | |
| 1055 String get json => null; | |
| 1056 | |
| 1011 } | 1057 } |
| 1012 | 1058 |
| 1013 class BrowserCommandOutputImpl extends CommandOutputImpl { | 1059 class BrowserCommandOutputImpl extends CommandOutputImpl { |
| 1014 // Although tests are reported as passing, content shell sometimes exits with | 1060 // Although tests are reported as passing, content shell sometimes exits with |
| 1015 // a nonzero exitcode which makes our dartium builders extremely falky. | 1061 // a nonzero exitcode which makes our dartium builders extremely falky. |
| 1016 // See: http://dartbug.com/15139. | 1062 // See: http://dartbug.com/15139. |
| 1017 static int WHITELISTED_CONTENTSHELL_EXITCODE = -1073740022; | 1063 static int WHITELISTED_CONTENTSHELL_EXITCODE = -1073740022; |
| 1018 static bool isWindows = io.Platform.operatingSystem == 'windows'; | 1064 static bool isWindows = io.Platform.operatingSystem == 'windows'; |
| 1019 | 1065 |
| 1020 bool _failedBecauseOfMissingXDisplay; | 1066 bool _failedBecauseOfMissingXDisplay; |
| (...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1598 // We expected to run the test, but we got an compile time error. | 1644 // We expected to run the test, but we got an compile time error. |
| 1599 // If the compilation succeeded, we wouldn't be in here! | 1645 // If the compilation succeeded, we wouldn't be in here! |
| 1600 assert(exitCode != 0); | 1646 assert(exitCode != 0); |
| 1601 return Expectation.COMPILETIME_ERROR; | 1647 return Expectation.COMPILETIME_ERROR; |
| 1602 } | 1648 } |
| 1603 | 1649 |
| 1604 Expectation outcome = | 1650 Expectation outcome = |
| 1605 exitCode == 0 ? Expectation.PASS : Expectation.COMPILETIME_ERROR; | 1651 exitCode == 0 ? Expectation.PASS : Expectation.COMPILETIME_ERROR; |
| 1606 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); | 1652 return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative); |
| 1607 } | 1653 } |
| 1654 | |
| 1655 String get json { | |
| 1656 var map = { | |
| 1657 'stdout': stdout, | |
| 1658 'stderr': stderr, | |
| 1659 'exitCode': exitCode, | |
| 1660 'timedOut': timedOut, | |
|
kustermann
2014/04/29 21:20:44
It may make sense to also add 'time' here, not sur
ricow1
2014/04/30 06:51:01
I did so at first, but removed it, since it would
| |
| 1661 }; | |
| 1662 return JSON.encode(map); | |
| 1663 } | |
| 1664 | |
| 1665 factory CompilationCommandOutputImpl.fromJson(Command command, | |
| 1666 String json) { | |
| 1667 var obj = JSON.decode(json); | |
| 1668 for (var v in ['stdout', 'stderr', 'exitCode', 'timedOut']) { | |
| 1669 assert(obj.containsKey(v)); | |
| 1670 } | |
| 1671 return new CompilationCommandOutputImpl(command, | |
| 1672 obj['exitCode'], | |
| 1673 obj['timedOut'], | |
| 1674 obj['stdout'], | |
| 1675 obj['stderr'], | |
| 1676 const Duration(seconds: 0), | |
| 1677 true); | |
| 1678 | |
| 1679 } | |
| 1608 } | 1680 } |
| 1609 | 1681 |
| 1610 class JsCommandlineOutputImpl extends CommandOutputImpl | 1682 class JsCommandlineOutputImpl extends CommandOutputImpl |
| 1611 with UnittestSuiteMessagesMixin { | 1683 with UnittestSuiteMessagesMixin { |
| 1612 JsCommandlineOutputImpl(Command command, int exitCode, bool timedOut, | 1684 JsCommandlineOutputImpl(Command command, int exitCode, bool timedOut, |
| 1613 List<int> stdout, List<int> stderr, Duration time) | 1685 List<int> stdout, List<int> stderr, Duration time) |
| 1614 : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); | 1686 : super(command, exitCode, timedOut, stdout, stderr, time, false, 0); |
| 1615 | 1687 |
| 1616 Expectation result(TestCase testCase) { | 1688 Expectation result(TestCase testCase) { |
| 1617 // Handle crashes and timeouts first | 1689 // Handle crashes and timeouts first |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1795 RunningProcess(this.command, this.timeout); | 1867 RunningProcess(this.command, this.timeout); |
| 1796 | 1868 |
| 1797 Future<CommandOutput> run() { | 1869 Future<CommandOutput> run() { |
| 1798 completer = new Completer<CommandOutput>(); | 1870 completer = new Completer<CommandOutput>(); |
| 1799 startTime = new DateTime.now(); | 1871 startTime = new DateTime.now(); |
| 1800 _runCommand(); | 1872 _runCommand(); |
| 1801 return completer.future; | 1873 return completer.future; |
| 1802 } | 1874 } |
| 1803 | 1875 |
| 1804 void _runCommand() { | 1876 void _runCommand() { |
| 1805 command.outputIsUpToDate.then((bool isUpToDate) { | 1877 command.outputIsUpToDate.then((CachedState cachedState) { |
| 1806 if (isUpToDate) { | 1878 if (cachedState.upToDateCompilation) { |
| 1807 compilationSkipped = true; | 1879 compilationSkipped = true; |
| 1808 _commandComplete(0); | 1880 _commandComplete(0); |
| 1881 } else if (cachedState.upToDateCommandOutput) { | |
| 1882 compilationSkipped = true; | |
| 1883 command.cachedOutput.then((cached) { | |
| 1884 _commandComplete(cached.exitCode, cachedOutput: cached); | |
| 1885 }); | |
| 1809 } else { | 1886 } else { |
| 1810 var processEnvironment = _createProcessEnvironment(); | 1887 var processEnvironment = _createProcessEnvironment(); |
| 1811 Future processFuture = | 1888 Future processFuture = |
| 1812 io.Process.start(command.executable, | 1889 io.Process.start(command.executable, |
| 1813 command.arguments, | 1890 command.arguments, |
| 1814 environment: processEnvironment, | 1891 environment: processEnvironment, |
| 1815 workingDirectory: command.workingDirectory); | 1892 workingDirectory: command.workingDirectory); |
| 1816 processFuture.then((io.Process process) { | 1893 processFuture.then((io.Process process) { |
| 1817 StreamSubscription stdoutSubscription = | 1894 StreamSubscription stdoutSubscription = |
| 1818 _drainStream(process.stdout, stdout); | 1895 _drainStream(process.stdout, stdout); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1891 print("Process error:"); | 1968 print("Process error:"); |
| 1892 print(" Command: $command"); | 1969 print(" Command: $command"); |
| 1893 print(" Error: $e"); | 1970 print(" Error: $e"); |
| 1894 _commandComplete(-1); | 1971 _commandComplete(-1); |
| 1895 return true; | 1972 return true; |
| 1896 }); | 1973 }); |
| 1897 } | 1974 } |
| 1898 }); | 1975 }); |
| 1899 } | 1976 } |
| 1900 | 1977 |
| 1901 void _commandComplete(int exitCode) { | 1978 void _commandComplete(int exitCode, {cachedOutput: null}) { |
| 1902 if (timeoutTimer != null) { | 1979 if (timeoutTimer != null) { |
| 1903 timeoutTimer.cancel(); | 1980 timeoutTimer.cancel(); |
| 1904 } | 1981 } |
| 1905 var commandOutput = _createCommandOutput(command, exitCode); | 1982 if (cachedOutput != null) { |
| 1906 completer.complete(commandOutput); | 1983 completer.complete(cachedOutput); |
| 1984 } else { | |
| 1985 var commandOutput = _createCommandOutput(command, exitCode); | |
| 1986 if (exitCode != 0) { | |
| 1987 command.writeCachedOutput(commandOutput); | |
| 1988 } | |
|
Bill Hesse
2014/04/29 17:51:55
Should we put a try-catch around this? Or make wr
ricow1
2014/04/30 06:51:01
Changed writeCachedOutput to not ever throw
| |
| 1989 completer.complete(commandOutput); | |
| 1990 } | |
| 1907 } | 1991 } |
| 1908 | 1992 |
| 1909 CommandOutput _createCommandOutput(ProcessCommand command, int exitCode) { | 1993 CommandOutput _createCommandOutput(ProcessCommand command, int exitCode) { |
| 1910 var commandOutput = createCommandOutput( | 1994 var commandOutput = createCommandOutput( |
| 1911 command, | 1995 command, |
| 1912 exitCode, | 1996 exitCode, |
| 1913 timedOut, | 1997 timedOut, |
| 1914 stdout.toList(), | 1998 stdout.toList(), |
| 1915 stderr.toList(), | 1999 stderr.toList(), |
| 1916 new DateTime.now().difference(startTime), | 2000 new DateTime.now().difference(startTime), |
| (...skipping 1053 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2970 } | 3054 } |
| 2971 } | 3055 } |
| 2972 | 3056 |
| 2973 void eventAllTestsDone() { | 3057 void eventAllTestsDone() { |
| 2974 for (var listener in _eventListener) { | 3058 for (var listener in _eventListener) { |
| 2975 listener.allDone(); | 3059 listener.allDone(); |
| 2976 } | 3060 } |
| 2977 _allDone(); | 3061 _allDone(); |
| 2978 } | 3062 } |
| 2979 } | 3063 } |
| OLD | NEW |