| 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 14 matching lines...) Expand all Loading... |
| 25 | 25 |
| 26 /** Command line arguments to the executable. */ | 26 /** Command line arguments to the executable. */ |
| 27 List<String> arguments; | 27 List<String> arguments; |
| 28 | 28 |
| 29 /** The actual command line that will be executed. */ | 29 /** The actual command line that will be executed. */ |
| 30 String commandLine; | 30 String commandLine; |
| 31 | 31 |
| 32 Command(this.executable, this.arguments) { | 32 Command(this.executable, this.arguments) { |
| 33 commandLine = "$executable ${Strings.join(arguments, ' ')}"; | 33 commandLine = "$executable ${Strings.join(arguments, ' ')}"; |
| 34 } | 34 } |
| 35 |
| 36 String toString() => commandLine; |
| 35 } | 37 } |
| 36 | 38 |
| 37 /** | 39 /** |
| 38 * TestCase contains all the information needed to run a test and evaluate | 40 * TestCase contains all the information needed to run a test and evaluate |
| 39 * its output. Running a test involves starting a separate process, with | 41 * its output. Running a test involves starting a separate process, with |
| 40 * the executable and arguments given by the TestCase, and recording its | 42 * the executable and arguments given by the TestCase, and recording its |
| 41 * stdout and stderr output streams, and its exit code. TestCase only | 43 * stdout and stderr output streams, and its exit code. TestCase only |
| 42 * contains static information about the test; actually running the test is | 44 * contains static information about the test; actually running the test is |
| 43 * performed by [ProcessQueue] using a [RunningProcess] object. | 45 * performed by [ProcessQueue] using a [RunningProcess] object. |
| 44 * | 46 * |
| (...skipping 13 matching lines...) Expand all Loading... |
| 58 * multiple sources that are run in isolation. | 60 * multiple sources that are run in isolation. |
| 59 */ | 61 */ |
| 60 final List<Command> commands; | 62 final List<Command> commands; |
| 61 | 63 |
| 62 Map configuration; | 64 Map configuration; |
| 63 String displayName; | 65 String displayName; |
| 64 TestOutput output; | 66 TestOutput output; |
| 65 bool isNegative; | 67 bool isNegative; |
| 66 Set<String> expectedOutcomes; | 68 Set<String> expectedOutcomes; |
| 67 Function completedHandler; | 69 Function completedHandler; |
| 70 TestInformation info; |
| 68 | 71 |
| 69 TestCase(this.displayName, | 72 TestCase(this.displayName, |
| 70 this.commands, | 73 this.commands, |
| 71 this.configuration, | 74 this.configuration, |
| 72 this.completedHandler, | 75 this.completedHandler, |
| 73 this.expectedOutcomes, | 76 this.expectedOutcomes, |
| 74 [this.isNegative = false]) { | 77 [this.isNegative = false, |
| 78 this.info = null]) { |
| 75 if (!isNegative) { | 79 if (!isNegative) { |
| 76 this.isNegative = displayName.contains("NegativeTest"); | 80 this.isNegative = displayName.contains("NegativeTest"); |
| 77 } | 81 } |
| 78 | 82 |
| 79 // Special command handling. If a special command is specified | 83 // Special command handling. If a special command is specified |
| 80 // we have to completely rewrite the command that we are using. | 84 // we have to completely rewrite the command that we are using. |
| 81 // We generate a new command-line that is the special command | 85 // We generate a new command-line that is the special command |
| 82 // where we replace '@' with the original command. | 86 // where we replace '@' with the original command. |
| 83 var specialCommand = configuration['special-command']; | 87 var specialCommand = configuration['special-command']; |
| 84 if (!specialCommand.isEmpty()) { | 88 if (!specialCommand.isEmpty()) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 _lastArguments.getRange(1, _lastArguments.length - 1); | 162 _lastArguments.getRange(1, _lastArguments.length - 1); |
| 159 } | 163 } |
| 160 | 164 |
| 161 | 165 |
| 162 /** | 166 /** |
| 163 * TestOutput records the output of a completed test: the process's exit code, | 167 * TestOutput records the output of a completed test: the process's exit code, |
| 164 * the standard output and standard error, whether the process timed out, and | 168 * the standard output and standard error, whether the process timed out, and |
| 165 * the time the process took to run. It also contains a pointer to the | 169 * the time the process took to run. It also contains a pointer to the |
| 166 * [TestCase] this is the output of. | 170 * [TestCase] this is the output of. |
| 167 */ | 171 */ |
| 168 class TestOutput { | 172 interface TestOutput default TestOutputImpl { |
| 173 TestOutput.fromCase(TestCase testCase, int exitCode, bool timedOut, |
| 174 List<String> stdout, List<String> stderr, Duration time); |
| 175 |
| 176 String get result(); |
| 177 |
| 178 bool get unexpectedOutput(); |
| 179 |
| 180 bool get hasCrashed(); |
| 181 |
| 182 bool get hasTimedOut(); |
| 183 |
| 184 bool get didFail(); |
| 185 |
| 186 List<String> get diagnostics(); |
| 187 } |
| 188 |
| 189 class TestOutputImpl implements TestOutput { |
| 169 TestCase testCase; | 190 TestCase testCase; |
| 170 int exitCode; | 191 int exitCode; |
| 171 bool timedOut; | 192 bool timedOut; |
| 172 bool failed = false; | 193 bool failed = false; |
| 173 List<String> stdout; | 194 List<String> stdout; |
| 174 List<String> stderr; | 195 List<String> stderr; |
| 175 Duration time; | 196 Duration time; |
| 197 List<String> diagnostics; |
| 198 |
| 176 /** | 199 /** |
| 177 * Set to true if we encounter a condition in the output that indicates we | 200 * Set to true if we encounter a condition in the output that indicates we |
| 178 * need to rerun this test. | 201 * need to rerun this test. |
| 179 */ | 202 */ |
| 180 bool requestRetry; | 203 bool requestRetry = false; |
| 181 | 204 |
| 182 TestOutput(this.testCase, this.exitCode, this.timedOut, this.stdout, | 205 // Don't call this constructor, call TestOutput.fromCase() to |
| 206 // get anew TestOutput instance. |
| 207 TestOutputImpl(this.testCase, this.exitCode, this.timedOut, this.stdout, |
| 183 this.stderr, this.time) { | 208 this.stderr, this.time) { |
| 184 testCase.output = this; | 209 testCase.output = this; |
| 185 requestRetry = false; | 210 diagnostics = []; |
| 186 } | 211 } |
| 187 | 212 |
| 213 factory TestOutputImpl.fromCase (testCase, exitCode, timedOut, stdout, stderr,
|
| 214 time) { |
| 215 if (testCase is BrowserTestCase) { |
| 216 return new BrowserTestOutputImpl(testCase, exitCode, timedOut, |
| 217 stdout, stderr, time); |
| 218 } else if (testCase.configuration['component'] == 'dartc') { |
| 219 return new AnalysisTestOutputImpl(testCase, exitCode, timedOut, |
| 220 stdout, stderr, time); |
| 221 } |
| 222 return new TestOutputImpl(testCase, exitCode, timedOut, |
| 223 stdout, stderr, time); |
| 224 } |
| 225 |
| 188 String get result() => | 226 String get result() => |
| 189 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); | 227 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); |
| 190 | 228 |
| 191 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result); | 229 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result); |
| 192 | 230 |
| 193 bool get hasCrashed() { | 231 bool get hasCrashed() { |
| 194 if (new Platform().operatingSystem() == 'windows') { | 232 if (new Platform().operatingSystem() == 'windows') { |
| 195 // The VM uses std::abort to terminate on asserts. | 233 // The VM uses std::abort to terminate on asserts. |
| 196 // std::abort terminates with exit code 3 on Windows. | 234 // std::abort terminates with exit code 3 on Windows. |
| 197 if (exitCode == 3) { | 235 if (exitCode == 3) { |
| 198 return !timedOut; | 236 return !timedOut; |
| 199 } | 237 } |
| 200 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); | 238 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); |
| 201 } | 239 } |
| 202 // The Java dartc runner exits with code 253 in case of unhandled | 240 // The Java dartc runner exits with code 253 in case of unhandled |
| 203 // exceptions. | 241 // exceptions. |
| 204 return (!timedOut && ((exitCode < 0) || (exitCode == 253))); | 242 return (!timedOut && ((exitCode < 0) || (exitCode == 253))); |
| 205 } | 243 } |
| 206 | 244 |
| 207 bool get hasTimedOut() => timedOut; | 245 bool get hasTimedOut() => timedOut; |
| 208 | 246 |
| 209 bool get didFail() { | 247 bool get didFail() { |
| 210 if (testCase is !BrowserTestCase) return (exitCode != 0 && !hasCrashed); | 248 return (exitCode != 0 && !hasCrashed); |
| 249 } |
| 250 |
| 251 // Reverse result of a negative test. |
| 252 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); |
| 211 | 253 |
| 254 } |
| 255 |
| 256 class BrowserTestOutputImpl extends TestOutputImpl { |
| 257 BrowserTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : |
| 258 super(testCase, exitCode, timedOut, stdout, stderr, time); |
| 259 |
| 260 bool get didFail() { |
| 212 // Browser case: | 261 // Browser case: |
| 213 // If the browser test failed, it may have been because DumpRenderTree | 262 // If the browser test failed, it may have been because DumpRenderTree |
| 214 // and the virtual framebuffer X server didn't hook up, or DRT crashed with | 263 // and the virtual framebuffer X server didn't hook up, or DRT crashed with |
| 215 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, | 264 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, |
| 216 // so we have to do this check first. | 265 // so we have to do this check first. |
| 217 for (String line in stderr) { | 266 for (String line in stderr) { |
| 218 if (line.contains('Gtk-WARNING **: cannot open display: :99') || | 267 if (line.contains('Gtk-WARNING **: cannot open display: :99') || |
| 219 line.contains('Failed to run command. return code=1')) { | 268 line.contains('Failed to run command. return code=1')) { |
| 220 // If we get the X server error, or DRT crashes with a core dump, retry | 269 // If we get the X server error, or DRT crashes with a core dump, retry |
| 221 // the test. | 270 // the test. |
| 222 if (testCase.dynamic.numRetries > 0) { | 271 if (testCase.dynamic.numRetries > 0) { |
| 223 requestRetry = true; | 272 requestRetry = true; |
| 224 } | 273 } |
| 225 return true; | 274 return true; |
| 226 } | 275 } |
| 227 } | 276 } |
| 228 | 277 |
| 229 // Browser tests fail unless stdout contains | 278 // Browser tests fail unless stdout contains |
| 230 // 'Content-Type: text/plain\nPASS'. | 279 // 'Content-Type: text/plain\nPASS'. |
| 231 String previous_line = ''; | 280 String previous_line = ''; |
| 232 for (String line in stdout) { | 281 for (String line in stdout) { |
| 233 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') { | 282 if (line == 'PASS' && previous_line == 'Content-Type: text/plain') { |
| 234 return (exitCode != 0 && !hasCrashed); | 283 return (exitCode != 0 && !hasCrashed); |
| 235 } | 284 } |
| 236 previous_line = line; | 285 previous_line = line; |
| 237 } | 286 } |
| 238 | |
| 239 return true; | 287 return true; |
| 240 } | 288 } |
| 289 } |
| 241 | 290 |
| 242 // Reverse result of a negative test. | 291 // The static analyzer does not actaully execute code, so |
| 243 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); | 292 // the criteria for success now depend on the text sent |
| 293 // to stderr. |
| 294 class AnalysisTestOutputImpl extends TestOutputImpl { |
| 295 boolean alreadyComputed = false; |
| 296 boolean failResult; |
| 297 AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : |
| 298 super(testCase, exitCode, timedOut, stdout, stderr, time) { |
| 299 } |
| 300 |
| 301 bool get didFail() { |
| 302 if (!alreadyComputed) { |
| 303 failResult = _didFail(); |
| 304 alreadyComputed = true; |
| 305 } |
| 306 return failResult; |
| 307 } |
| 308 |
| 309 bool _didFail() { |
| 310 if (hasCrashed) return false; |
| 311 |
| 312 List<String> errors = []; |
| 313 List<String> staticWarnings = []; |
| 314 |
| 315 // Read the returned list of errors and stuff them away. |
| 316 for (String line in stderr) { |
| 317 if (line.length == 0) continue; |
| 318 List<String> fields = splitMachineError(line); |
| 319 if (fields[0] == 'ERROR') { |
| 320 errors.add(fields); |
| 321 } else if (fields[0] == 'WARNING') { |
| 322 // We only care about testing Static type warnings |
| 323 // ignore all others |
| 324 if (fields[1] == 'STATIC_TYPE') { |
| 325 staticWarnings.add(fields); |
| 326 } |
| 327 } |
| 328 // OK to Skip error output that doesn't match the machine format |
| 329 } |
| 330 if (testCase.info != null |
| 331 && testCase.info.optionsFromFile['isMultitest']) { |
| 332 return _didMultitestFail(errors, staticWarnings); |
| 333 } |
| 334 return _didStandardTestFail(errors, staticWarnings); |
| 335 } |
| 336 |
| 337 bool _didMultitestFail(List errors, List staticWarnings) { |
| 338 String outcome = testCase.info.multitestOutcome; |
| 339 if ((outcome == '' || outcome == 'compile-time error') && errors.length > 0)
{ |
| 340 return true; |
| 341 } else if (outcome == 'static type error' && staticWarnings.length > 0) { |
| 342 return true; |
| 343 } |
| 344 return false; |
| 345 } |
| 346 |
| 347 bool _didStandardTestFail(List errors, List staticWarnings) { |
| 348 bool hasFatalTypeErrors = false; |
| 349 int numStaticTypeAnnotations = 0; |
| 350 int numCompileTimeAnnotations = 0; |
| 351 var isStaticClean = false; |
| 352 if (testCase.info != null) { |
| 353 var optionsFromFile = testCase.info.optionsFromFile; |
| 354 hasFatalTypeErrors = optionsFromFile['hasFatalTypeErrors']; |
| 355 for (Command c in testCase.commands) { |
| 356 for (String arg in c.arguments) { |
| 357 if (arg == '--fatal-type-errors') { |
| 358 hasFatalTypeErrors = true; |
| 359 break; |
| 360 } |
| 361 } |
| 362 } |
| 363 numStaticTypeAnnotations = optionsFromFile['numStaticTypeAnnotations']; |
| 364 numCompileTimeAnnotations = optionsFromFile['numCompileTimeAnnotations']; |
| 365 isStaticClean = optionsFromFile['isStaticClean']; |
| 366 } |
| 367 |
| 368 if (errors.length == 0) { |
| 369 if (!hasFatalTypeErrors && exitCode != 0) { |
| 370 diagnostics.add("EXIT CODE MISMATCH: Expected error message:"); |
| 371 diagnostics.add(" command[0]:${testCase.commands[0]}"); |
| 372 diagnostics.add(" exitCode:${exitCode}"); |
| 373 return true; |
| 374 } |
| 375 } else if (exitCode == 0) { |
| 376 diagnostics.add("EXIT CODE MISMATCH: Unexpected error message:"); |
| 377 diagnostics.add(" errors[0]:${errors[0]}"); |
| 378 diagnostics.add(" command[0]:${testCase.commands[0]}"); |
| 379 diagnostics.add(" exitCode:${exitCode}"); |
| 380 return true; |
| 381 } |
| 382 if (numStaticTypeAnnotations > 0 && isStaticClean) { |
| 383 diagnostics.add("Cannot have both @static-clean and /// static type warnin
g annotations."); |
| 384 return true; |
| 385 } |
| 386 |
| 387 if (isStaticClean && staticWarnings.length > 0) { |
| 388 diagnostics.add("@static-clean annotation found but analyzer returned warn
ings."); |
| 389 return true; |
| 390 } |
| 391 |
| 392 if (numCompileTimeAnnotations > 0 |
| 393 && numCompileTimeAnnotations < errors.length) { |
| 394 |
| 395 // Expected compile-time errors were not returned. The test did not 'fail
' in the way |
| 396 // intended so don't return failed. |
| 397 diagnostics.add("Fewer compile time errors than annotated: ${numCompileTim
eAnnotations}"); |
| 398 return false; |
| 399 } |
| 400 |
| 401 if (numStaticTypeAnnotations > 0 || hasFatalTypeErrors) { |
| 402 // TODO(zundel): match up the annotation line numbers |
| 403 // with the reported error line numbers |
| 404 if (staticWarnings.length < numStaticTypeAnnotations) { |
| 405 diagnostics.add("Fewer static type warnings than annotated: ${numStaticT
ypeAnnotations}"); |
| 406 return true; |
| 407 } |
| 408 return false; |
| 409 } else if (errors.length != 0) { |
| 410 return true; |
| 411 } |
| 412 return false; |
| 413 } |
| 414 |
| 415 // Parse a line delimited by the | character using \ as an escape charager |
| 416 // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ |
| 417 List<String> splitMachineError(String line) { |
| 418 StringBuffer field = new StringBuffer(); |
| 419 List<String> result = []; |
| 420 bool escaped = false; |
| 421 for (var i = 0 ; i < line.length; i++) { |
| 422 var c = line[i]; |
| 423 if (!escaped && c == '\\') { |
| 424 escaped = true; |
| 425 continue; |
| 426 } |
| 427 escaped = false; |
| 428 if (c == '|') { |
| 429 result.add(field.toString()); |
| 430 field.clear(); |
| 431 continue; |
| 432 } |
| 433 field.add(c); |
| 434 } |
| 435 result.add(field.toString()); |
| 436 return result; |
| 437 } |
| 244 } | 438 } |
| 245 | 439 |
| 246 /** | 440 /** |
| 247 * A RunningProcess actually runs a test, getting the command lines from | 441 * A RunningProcess actually runs a test, getting the command lines from |
| 248 * its [TestCase], starting the test process (and first, a compilation | 442 * its [TestCase], starting the test process (and first, a compilation |
| 249 * process if the TestCase is a [BrowserTestCase]), creating a timeout | 443 * process if the TestCase is a [BrowserTestCase]), creating a timeout |
| 250 * timer, and recording the results in a new [TestOutput] object, which it | 444 * timer, and recording the results in a new [TestOutput] object, which it |
| 251 * attaches to the TestCase. The lifetime of the RunningProcess is limited | 445 * attaches to the TestCase. The lifetime of the RunningProcess is limited |
| 252 * to the time it takes to start the process, run the process, and record | 446 * to the time it takes to start the process, run the process, and record |
| 253 * the result; there are no pointers to it, so it should be available to | 447 * the result; there are no pointers to it, so it should be available to |
| (...skipping 16 matching lines...) Expand all Loading... |
| 270 | 464 |
| 271 RunningProcess(TestCase this.testCase, | 465 RunningProcess(TestCase this.testCase, |
| 272 [this.allowRetries, this.processQueue]); | 466 [this.allowRetries, this.processQueue]); |
| 273 | 467 |
| 274 /** | 468 /** |
| 275 * Called when all commands are executed. [exitCode] is 0 if all command | 469 * Called when all commands are executed. [exitCode] is 0 if all command |
| 276 * succeded, otherwise it will have the exit code of the first failing | 470 * succeded, otherwise it will have the exit code of the first failing |
| 277 * command. | 471 * command. |
| 278 */ | 472 */ |
| 279 void testComplete(int exitCode) { | 473 void testComplete(int exitCode) { |
| 280 new TestOutput(testCase, exitCode, timedOut, stdout, | 474 new TestOutput.fromCase(testCase, exitCode, timedOut, stdout, |
| 281 stderr, new Date.now().difference(startTime)); | 475 stderr, new Date.now().difference(startTime)); |
| 282 timeoutTimer.cancel(); | 476 timeoutTimer.cancel(); |
| 283 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { | 477 if (testCase.output.unexpectedOutput && testCase.configuration['verbose']) { |
| 284 print(testCase.displayName); | 478 print(testCase.displayName); |
| 285 for (var line in testCase.output.stderr) print(line); | 479 for (var line in testCase.output.stderr) print(line); |
| 286 for (var line in testCase.output.stdout) print(line); | 480 for (var line in testCase.output.stdout) print(line); |
| 287 } | 481 } |
| 288 if (allowRetries != null && allowRetries | 482 if (allowRetries != null && allowRetries |
| 289 && testCase.configuration['component'] == 'webdriver' && | 483 && testCase.configuration['component'] == 'webdriver' && |
| 290 testCase.output.unexpectedOutput && testCase.numRetries > 0) { | 484 testCase.output.unexpectedOutput && testCase.numRetries > 0) { |
| 291 // Selenium tests can be flaky. Try rerunning. | 485 // Selenium tests can be flaky. Try rerunning. |
| 292 testCase.output.requestRetry = true; | 486 testCase.output.requestRetry = true; |
| 293 } | 487 } |
| 294 if (testCase.output.requestRetry) { | 488 if (testCase.output.requestRetry) { |
| 295 testCase.output.requestRetry = false; | 489 testCase.output.requestRetry = false; |
| 296 this.timedOut = false; | 490 this.timedOut = false; |
| 297 testCase.dynamic.numRetries--; | 491 testCase.dynamic.numRetries--; |
| 298 print("Potential flake. " + | 492 print("Potential flake. Re-running ${testCase.displayName} " + |
| 299 "Re-running ${testCase.displayName} " + | |
| 300 "(${testCase.dynamic.numRetries} attempt(s) remains)"); | 493 "(${testCase.dynamic.numRetries} attempt(s) remains)"); |
| 301 this.start(); | 494 this.start(); |
| 302 } else { | 495 } else { |
| 303 testCase.completed(); | 496 testCase.completed(); |
| 304 } | 497 } |
| 305 } | 498 } |
| 306 | 499 |
| 307 /** | 500 /** |
| 308 * Process exit handler called at the end of every command. It internally | 501 * Process exit handler called at the end of every command. It internally |
| 309 * treats all but the last command as compilation steps. The last command is | 502 * treats all but the last command as compilation steps. The last command is |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 bool shutdownMillisecs = 30000; | 640 bool shutdownMillisecs = 30000; |
| 448 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); | 641 new Timer((e) { if (!closed) _process.kill(); }, shutdownMillisecs); |
| 449 } else { | 642 } else { |
| 450 _process.kill(); | 643 _process.kill(); |
| 451 } | 644 } |
| 452 } | 645 } |
| 453 } | 646 } |
| 454 | 647 |
| 455 void doStartTest(TestCase testCase) { | 648 void doStartTest(TestCase testCase) { |
| 456 _startTime = new Date.now(); | 649 _startTime = new Date.now(); |
| 457 _testStdout = new List<String>(); | 650 _testStdout = []; |
| 458 _testStderr = new List<String>(); | 651 _testStderr = []; |
| 459 _stdoutDrained = false; | 652 _stdoutDrained = false; |
| 460 _stderrDrained = false; | 653 _stderrDrained = false; |
| 461 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout); | 654 _stdoutStream.onLine = _readStdout(_stdoutStream, _testStdout); |
| 462 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr); | 655 _stderrStream.onLine = _readStderr(_stderrStream, _testStderr); |
| 463 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); | 656 _timer = new Timer(_timeoutHandler, testCase.timeout * 1000); |
| 464 var line = _createArgumentsLine(testCase.batchTestArguments); | 657 var line = _createArgumentsLine(testCase.batchTestArguments); |
| 465 _process.stdin.write(line.charCodes()); | 658 _process.stdin.write(line.charCodes()); |
| 466 } | 659 } |
| 467 | 660 |
| 468 String _createArgumentsLine(List<String> arguments) { | 661 String _createArgumentsLine(List<String> arguments) { |
| 469 return Strings.join(arguments, ' ') + '\n'; | 662 return Strings.join(arguments, ' ') + '\n'; |
| 470 } | 663 } |
| 471 | 664 |
| 472 void _testCompleted() { | 665 void _testCompleted() { |
| 473 var test = _currentTest; | 666 var test = _currentTest; |
| 474 _currentTest = null; | 667 _currentTest = null; |
| 475 test.completed(); | 668 test.completed(); |
| 476 } | 669 } |
| 477 | 670 |
| 478 int _reportResult(String output) { | 671 int _reportResult(String output) { |
| 479 _stdoutDrained = true; | 672 _stdoutDrained = true; |
| 480 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' | 673 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' |
| 481 var outcome = output.split(" ")[2]; | 674 var outcome = output.split(" ")[2]; |
| 482 var exitCode = 0; | 675 var exitCode = 0; |
| 483 if (outcome == "CRASH") exitCode = -10; | 676 if (outcome == "CRASH") exitCode = -10; |
| 484 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; | 677 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; |
| 485 new TestOutput(_currentTest, exitCode, outcome == "TIMEOUT", _testStdout, | 678 new TestOutput.fromCase(_currentTest, exitCode, outcome == "TIMEOUT", |
| 486 _testStderr, new Date.now().difference(_startTime)); | 679 _testStdout, _testStderr, new Date.now().difference(_startTim
e)); |
| 487 // Move on when both stdout and stderr has been drained. | 680 // Move on when both stdout and stderr has been drained. |
| 488 if (_stderrDrained) _testCompleted(); | 681 if (_stderrDrained) _testCompleted(); |
| 489 } | 682 } |
| 490 | 683 |
| 491 void _stderrDone() { | 684 void _stderrDone() { |
| 492 _stderrDrained = true; | 685 _stderrDrained = true; |
| 493 // Move on when both stdout and stderr has been drained. | 686 // Move on when both stdout and stderr has been drained. |
| 494 if (_stdoutDrained) _testCompleted(); | 687 if (_stdoutDrained) _testCompleted(); |
| 495 } | 688 } |
| 496 | 689 |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 805 // the developer doesn't waste his or her time trying to fix a bunch of | 998 // the developer doesn't waste his or her time trying to fix a bunch of |
| 806 // tests that appear to be broken but were actually just flakes that | 999 // tests that appear to be broken but were actually just flakes that |
| 807 // didn't get retried because there had already been one failure. | 1000 // didn't get retried because there had already been one failure. |
| 808 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 1001 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; |
| 809 new RunningProcess(test, allowRetry, this).start(); | 1002 new RunningProcess(test, allowRetry, this).start(); |
| 810 } | 1003 } |
| 811 _numProcesses++; | 1004 _numProcesses++; |
| 812 } | 1005 } |
| 813 } | 1006 } |
| 814 } | 1007 } |
| OLD | NEW |