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 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 | 35 |
| 36 String toString() => commandLine; | 36 String toString() => commandLine; |
| 37 } | 37 } |
| 38 | 38 |
| 39 /** | 39 /** |
| 40 * 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 |
| 41 * its output. Running a test involves starting a separate process, with | 41 * its output. Running a test involves starting a separate process, with |
| 42 * the executable and arguments given by the TestCase, and recording its | 42 * the executable and arguments given by the TestCase, and recording its |
| 43 * stdout and stderr output streams, and its exit code. TestCase only | 43 * stdout and stderr output streams, and its exit code. TestCase only |
| 44 * contains static information about the test; actually running the test is | 44 * contains static information about the test; actually running the test is |
| 45 * performed by [ProcessQueue] using a [RunningProcess] object. | 45 * performed by [ProcessQueue] using a [RunningProcess] object. |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 | 167 |
| 168 /** | 168 /** |
| 169 * TestOutput records the output of a completed test: the process's exit code, | 169 * TestOutput records the output of a completed test: the process's exit code, |
| 170 * the standard output and standard error, whether the process timed out, and | 170 * the standard output and standard error, whether the process timed out, and |
| 171 * the time the process took to run. It also contains a pointer to the | 171 * the time the process took to run. It also contains a pointer to the |
| 172 * [TestCase] this is the output of. | 172 * [TestCase] this is the output of. |
| 173 */ | 173 */ |
| 174 interface TestOutput default TestOutputImpl { | 174 interface TestOutput default TestOutputImpl { |
| 175 TestOutput.fromCase(TestCase testCase, int exitCode, bool timedOut, | 175 TestOutput.fromCase(TestCase testCase, int exitCode, bool timedOut, |
| 176 List<String> stdout, List<String> stderr, Duration time); | 176 List<String> stdout, List<String> stderr, Duration time); |
| 177 | 177 |
| 178 String get result(); | 178 String get result(); |
| 179 | 179 |
| 180 bool get unexpectedOutput(); | 180 bool get unexpectedOutput(); |
| 181 | 181 |
| 182 bool get hasCrashed(); | 182 bool get hasCrashed(); |
| 183 | 183 |
| 184 bool get hasTimedOut(); | 184 bool get hasTimedOut(); |
| 185 | 185 |
| 186 bool get didFail(); | 186 bool get didFail(); |
| 187 | 187 |
| 188 List<String> get diagnostics(); | 188 List<String> get diagnostics(); |
| 189 } | 189 } |
| 190 | 190 |
| 191 class TestOutputImpl implements TestOutput { | 191 class TestOutputImpl implements TestOutput { |
| 192 TestCase testCase; | 192 TestCase testCase; |
| 193 int exitCode; | 193 int exitCode; |
| 194 bool timedOut; | 194 bool timedOut; |
| 195 bool failed = false; | 195 bool failed = false; |
| 196 List<String> stdout; | 196 List<String> stdout; |
| 197 List<String> stderr; | 197 List<String> stderr; |
| 198 Duration time; | 198 Duration time; |
| 199 List<String> diagnostics; | 199 List<String> diagnostics; |
| 200 | 200 |
| 201 /** | 201 /** |
| 202 * Set to true if we encounter a condition in the output that indicates we | 202 * Set to true if we encounter a condition in the output that indicates we |
| 203 * need to rerun this test. | 203 * need to rerun this test. |
| 204 */ | 204 */ |
| 205 bool requestRetry = false; | 205 bool requestRetry = false; |
| 206 | 206 |
| 207 // Don't call this constructor, call TestOutput.fromCase() to | 207 // Don't call this constructor, call TestOutput.fromCase() to |
| 208 // get anew TestOutput instance. | 208 // get anew TestOutput instance. |
| 209 TestOutputImpl(this.testCase, this.exitCode, this.timedOut, this.stdout, | 209 TestOutputImpl(this.testCase, this.exitCode, this.timedOut, this.stdout, |
| 210 this.stderr, this.time) { | 210 this.stderr, this.time) { |
| 211 testCase.output = this; | 211 testCase.output = this; |
| 212 diagnostics = []; | 212 diagnostics = []; |
| 213 } | 213 } |
| 214 | 214 |
| 215 factory TestOutputImpl.fromCase (testCase, exitCode, timedOut, stdout, stderr, | 215 factory TestOutputImpl.fromCase (testCase, exitCode, timedOut, stdout, stderr, |
| 216 time) { | 216 time) { |
| 217 if (testCase is BrowserTestCase) { | 217 if (testCase is BrowserTestCase) { |
| 218 return new BrowserTestOutputImpl(testCase, exitCode, timedOut, | 218 return new BrowserTestOutputImpl(testCase, exitCode, timedOut, |
| 219 stdout, stderr, time); | 219 stdout, stderr, time); |
| 220 } else if (testCase.configuration['component'] == 'dartc') { | 220 } else if (testCase.configuration['component'] == 'dartc') { |
| 221 return new AnalysisTestOutputImpl(testCase, exitCode, timedOut, | 221 return new AnalysisTestOutputImpl(testCase, exitCode, timedOut, |
| 222 stdout, stderr, time); | 222 stdout, stderr, time); |
| 223 } | 223 } |
| 224 return new TestOutputImpl(testCase, exitCode, timedOut, | 224 return new TestOutputImpl(testCase, exitCode, timedOut, |
| 225 stdout, stderr, time); | 225 stdout, stderr, time); |
| 226 } | 226 } |
| 227 | 227 |
| 228 String get result() => | 228 String get result() => |
| 229 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); | 229 hasCrashed ? CRASH : (hasTimedOut ? TIMEOUT : (hasFailed ? FAIL : PASS)); |
| 230 | 230 |
| 231 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result); | 231 bool get unexpectedOutput() => !testCase.expectedOutcomes.contains(result); |
| 232 | 232 |
| 233 bool get hasCrashed() { | 233 bool get hasCrashed() { |
| 234 if (new Platform().operatingSystem() == 'windows') { | 234 if (new Platform().operatingSystem() == 'windows') { |
| 235 // The VM uses std::abort to terminate on asserts. | 235 // The VM uses std::abort to terminate on asserts. |
| 236 // std::abort terminates with exit code 3 on Windows. | 236 // std::abort terminates with exit code 3 on Windows. |
| 237 if (exitCode == 3) { | 237 if (exitCode == 3) { |
| 238 return !timedOut; | 238 return !timedOut; |
| 239 } | 239 } |
| 240 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); | 240 return (!timedOut && (exitCode < 0) && ((0x3FFFFF00 & exitCode) == 0)); |
| 241 } | 241 } |
| 242 // The Java dartc runner exits with code 253 in case of unhandled | 242 // The Java dartc runner exits with code 253 in case of unhandled |
| 243 // exceptions. | 243 // exceptions. |
| 244 return (!timedOut && ((exitCode < 0) || (exitCode == 253))); | 244 return (!timedOut && ((exitCode < 0) || (exitCode == 253))); |
| 245 } | 245 } |
| 246 | 246 |
| 247 bool get hasTimedOut() => timedOut; | 247 bool get hasTimedOut() => timedOut; |
| 248 | 248 |
| 249 bool get didFail() { | 249 bool get didFail() { |
| 250 return (exitCode != 0 && !hasCrashed); | 250 return (exitCode != 0 && !hasCrashed); |
| 251 } | 251 } |
| 252 | 252 |
| 253 // Reverse result of a negative test. | 253 // Reverse result of a negative test. |
| 254 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); | 254 bool get hasFailed() => (testCase.isNegative ? !didFail : didFail); |
| 255 | 255 |
| 256 } | 256 } |
| 257 | 257 |
| 258 class BrowserTestOutputImpl extends TestOutputImpl { | 258 class BrowserTestOutputImpl extends TestOutputImpl { |
| 259 BrowserTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : | 259 BrowserTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : |
| 260 super(testCase, exitCode, timedOut, stdout, stderr, time); | 260 super(testCase, exitCode, timedOut, stdout, stderr, time); |
| 261 | 261 |
| 262 bool get didFail() { | 262 bool get didFail() { |
| 263 // Browser case: | 263 // Browser case: |
| 264 // If the browser test failed, it may have been because DumpRenderTree | 264 // If the browser test failed, it may have been because DumpRenderTree |
| 265 // and the virtual framebuffer X server didn't hook up, or DRT crashed with | 265 // and the virtual framebuffer X server didn't hook up, or DRT crashed with |
| 266 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, | 266 // a core dump. Sometimes DRT crashes after it has set the stdout to PASS, |
| 267 // so we have to do this check first. | 267 // so we have to do this check first. |
| 268 for (String line in stderr) { | 268 for (String line in stderr) { |
| 269 if (line.contains('Gtk-WARNING **: cannot open display: :99') || | 269 if (line.contains('Gtk-WARNING **: cannot open display: :99') || |
| 270 line.contains('Failed to run command. return code=1')) { | 270 line.contains('Failed to run command. return code=1')) { |
| 271 // If we get the X server error, or DRT crashes with a core dump, retry | 271 // If we get the X server error, or DRT crashes with a core dump, retry |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 292 | 292 |
| 293 // The static analyzer does not actaully execute code, so | 293 // The static analyzer does not actaully execute code, so |
| 294 // the criteria for success now depend on the text sent | 294 // the criteria for success now depend on the text sent |
| 295 // to stderr. | 295 // to stderr. |
| 296 class AnalysisTestOutputImpl extends TestOutputImpl { | 296 class AnalysisTestOutputImpl extends TestOutputImpl { |
| 297 boolean alreadyComputed = false; | 297 boolean alreadyComputed = false; |
| 298 boolean failResult; | 298 boolean failResult; |
| 299 AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : | 299 AnalysisTestOutputImpl(testCase, exitCode, timedOut, stdout, stderr, time) : |
| 300 super(testCase, exitCode, timedOut, stdout, stderr, time) { | 300 super(testCase, exitCode, timedOut, stdout, stderr, time) { |
| 301 } | 301 } |
| 302 | 302 |
| 303 bool get didFail() { | 303 bool get didFail() { |
| 304 if (!alreadyComputed) { | 304 if (!alreadyComputed) { |
| 305 failResult = _didFail(); | 305 failResult = _didFail(); |
| 306 alreadyComputed = true; | 306 alreadyComputed = true; |
| 307 } | 307 } |
| 308 return failResult; | 308 return failResult; |
| 309 } | 309 } |
| 310 | 310 |
| 311 bool _didFail() { | 311 bool _didFail() { |
| 312 if (hasCrashed) return false; | 312 if (hasCrashed) return false; |
| 313 | 313 |
| 314 List<String> errors = []; | 314 List<String> errors = []; |
| 315 List<String> staticWarnings = []; | 315 List<String> staticWarnings = []; |
| 316 | 316 |
| 317 // Read the returned list of errors and stuff them away. | 317 // Read the returned list of errors and stuff them away. |
| 318 for (String line in stderr) { | 318 for (String line in stderr) { |
| 319 if (line.length == 0) continue; | 319 if (line.length == 0) continue; |
| 320 List<String> fields = splitMachineError(line); | 320 List<String> fields = splitMachineError(line); |
| 321 if (fields[0] == 'ERROR') { | 321 if (fields[0] == 'ERROR') { |
| 322 errors.add(fields); | 322 errors.add(fields); |
| 323 } else if (fields[0] == 'WARNING') { | 323 } else if (fields[0] == 'WARNING') { |
| 324 // We only care about testing Static type warnings | 324 // We only care about testing Static type warnings |
| 325 // ignore all others | 325 // ignore all others |
| 326 if (fields[1] == 'STATIC_TYPE') { | 326 if (fields[1] == 'STATIC_TYPE') { |
| 327 staticWarnings.add(fields); | 327 staticWarnings.add(fields); |
| 328 } | 328 } |
| 329 } | 329 } |
| 330 // OK to Skip error output that doesn't match the machine format | 330 // OK to Skip error output that doesn't match the machine format |
| 331 } | 331 } |
| 332 if (testCase.info != null | 332 if (testCase.info != null |
| 333 && testCase.info.optionsFromFile['isMultitest']) { | 333 && testCase.info.optionsFromFile['isMultitest']) { |
| 334 return _didMultitestFail(errors, staticWarnings); | 334 return _didMultitestFail(errors, staticWarnings); |
| 335 } | 335 } |
| 336 return _didStandardTestFail(errors, staticWarnings); | 336 return _didStandardTestFail(errors, staticWarnings); |
| 337 } | 337 } |
| 338 | 338 |
| 339 bool _didMultitestFail(List errors, List staticWarnings) { | 339 bool _didMultitestFail(List errors, List staticWarnings) { |
| 340 String outcome = testCase.info.multitestOutcome; | 340 String outcome = testCase.info.multitestOutcome; |
| 341 if ((outcome == '' || outcome == 'compile-time error') && errors.length > 0) { | 341 if ((outcome == '' || outcome == 'compile-time error') && errors.length > 0) { |
| 342 return true; | 342 return true; |
| 343 } else if (outcome == 'static type error' && staticWarnings.length > 0) { | 343 } else if (outcome == 'static type error' && staticWarnings.length > 0) { |
| 344 return true; | 344 return true; |
| 345 } | 345 } |
| 346 return false; | 346 return false; |
| 347 } | 347 } |
| 348 | 348 |
| 349 bool _didStandardTestFail(List errors, List staticWarnings) { | 349 bool _didStandardTestFail(List errors, List staticWarnings) { |
| 350 bool hasFatalTypeErrors = false; | 350 bool hasFatalTypeErrors = false; |
| 351 int numStaticTypeAnnotations = 0; | 351 int numStaticTypeAnnotations = 0; |
| 352 int numCompileTimeAnnotations = 0; | 352 int numCompileTimeAnnotations = 0; |
| 353 var isStaticClean = false; | 353 var isStaticClean = false; |
| 354 if (testCase.info != null) { | 354 if (testCase.info != null) { |
| 355 var optionsFromFile = testCase.info.optionsFromFile; | 355 var optionsFromFile = testCase.info.optionsFromFile; |
| 356 hasFatalTypeErrors = optionsFromFile['hasFatalTypeErrors']; | 356 hasFatalTypeErrors = optionsFromFile['hasFatalTypeErrors']; |
| 357 for (Command c in testCase.commands) { | 357 for (Command c in testCase.commands) { |
| 358 for (String arg in c.arguments) { | 358 for (String arg in c.arguments) { |
| 359 if (arg == '--fatal-type-errors') { | 359 if (arg == '--fatal-type-errors') { |
| 360 hasFatalTypeErrors = true; | 360 hasFatalTypeErrors = true; |
| 361 break; | 361 break; |
| 362 } | 362 } |
| 363 } | 363 } |
| 364 } | 364 } |
| 365 numStaticTypeAnnotations = optionsFromFile['numStaticTypeAnnotations']; | 365 numStaticTypeAnnotations = optionsFromFile['numStaticTypeAnnotations']; |
| 366 numCompileTimeAnnotations = optionsFromFile['numCompileTimeAnnotations']; | 366 numCompileTimeAnnotations = optionsFromFile['numCompileTimeAnnotations']; |
| 367 isStaticClean = optionsFromFile['isStaticClean']; | 367 isStaticClean = optionsFromFile['isStaticClean']; |
| 368 } | 368 } |
| 369 | 369 |
| 370 if (errors.length == 0) { | 370 if (errors.length == 0) { |
| 371 if (!hasFatalTypeErrors && exitCode != 0) { | 371 if (!hasFatalTypeErrors && exitCode != 0) { |
| 372 diagnostics.add("EXIT CODE MISMATCH: Expected error message:"); | 372 diagnostics.add("EXIT CODE MISMATCH: Expected error message:"); |
| 373 diagnostics.add(" command[0]:${testCase.commands[0]}"); | 373 diagnostics.add(" command[0]:${testCase.commands[0]}"); |
| 374 diagnostics.add(" exitCode:${exitCode}"); | 374 diagnostics.add(" exitCode:${exitCode}"); |
| 375 return true; | 375 return true; |
| 376 } | 376 } |
| 377 } else if (exitCode == 0) { | 377 } else if (exitCode == 0) { |
| 378 diagnostics.add("EXIT CODE MISMATCH: Unexpected error message:"); | 378 diagnostics.add("EXIT CODE MISMATCH: Unexpected error message:"); |
| 379 diagnostics.add(" errors[0]:${errors[0]}"); | 379 diagnostics.add(" errors[0]:${errors[0]}"); |
| 380 diagnostics.add(" command[0]:${testCase.commands[0]}"); | 380 diagnostics.add(" command[0]:${testCase.commands[0]}"); |
| 381 diagnostics.add(" exitCode:${exitCode}"); | 381 diagnostics.add(" exitCode:${exitCode}"); |
| 382 return true; | 382 return true; |
| 383 } | 383 } |
| 384 if (numStaticTypeAnnotations > 0 && isStaticClean) { | 384 if (numStaticTypeAnnotations > 0 && isStaticClean) { |
| 385 diagnostics.add("Cannot have both @static-clean and /// static type warnin g annotations."); | 385 diagnostics.add("Cannot have both @static-clean and /// static type warnin g annotations."); |
| 386 return true; | 386 return true; |
| 387 } | 387 } |
| 388 | 388 |
| 389 if (isStaticClean && staticWarnings.length > 0) { | 389 if (isStaticClean && staticWarnings.length > 0) { |
| 390 diagnostics.add("@static-clean annotation found but analyzer returned warn ings."); | 390 diagnostics.add("@static-clean annotation found but analyzer returned warn ings."); |
| 391 return true; | 391 return true; |
| 392 } | 392 } |
| 393 | 393 |
| 394 if (numCompileTimeAnnotations > 0 | 394 if (numCompileTimeAnnotations > 0 |
| 395 && numCompileTimeAnnotations < errors.length) { | 395 && numCompileTimeAnnotations < errors.length) { |
| 396 | 396 |
| 397 // Expected compile-time errors were not returned. The test did not 'fail ' in the way | 397 // Expected compile-time errors were not returned. The test did not 'fail ' in the way |
| 398 // intended so don't return failed. | 398 // intended so don't return failed. |
| 399 diagnostics.add("Fewer compile time errors than annotated: ${numCompileTim eAnnotations}"); | 399 diagnostics.add("Fewer compile time errors than annotated: ${numCompileTim eAnnotations}"); |
| 400 return false; | 400 return false; |
| 401 } | 401 } |
| 402 | 402 |
| 403 if (numStaticTypeAnnotations > 0 || hasFatalTypeErrors) { | 403 if (numStaticTypeAnnotations > 0 || hasFatalTypeErrors) { |
| 404 // TODO(zundel): match up the annotation line numbers | 404 // TODO(zundel): match up the annotation line numbers |
| 405 // with the reported error line numbers | 405 // with the reported error line numbers |
| 406 if (staticWarnings.length < numStaticTypeAnnotations) { | 406 if (staticWarnings.length < numStaticTypeAnnotations) { |
| 407 diagnostics.add("Fewer static type warnings than annotated: ${numStaticT ypeAnnotations}"); | 407 diagnostics.add("Fewer static type warnings than annotated: ${numStaticT ypeAnnotations}"); |
| 408 return true; | 408 return true; |
| 409 } | 409 } |
| 410 return false; | 410 return false; |
| 411 } else if (errors.length != 0) { | 411 } else if (errors.length != 0) { |
| 412 return true; | 412 return true; |
| 413 } | 413 } |
| 414 return false; | 414 return false; |
| 415 } | 415 } |
| 416 | 416 |
| 417 // Parse a line delimited by the | character using \ as an escape charager | 417 // Parse a line delimited by the | character using \ as an escape charager |
| 418 // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ | 418 // like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ |
| 419 List<String> splitMachineError(String line) { | 419 List<String> splitMachineError(String line) { |
| 420 StringBuffer field = new StringBuffer(); | 420 StringBuffer field = new StringBuffer(); |
| 421 List<String> result = []; | 421 List<String> result = []; |
| 422 bool escaped = false; | 422 bool escaped = false; |
| 423 for (var i = 0 ; i < line.length; i++) { | 423 for (var i = 0 ; i < line.length; i++) { |
| 424 var c = line[i]; | 424 var c = line[i]; |
| 425 if (!escaped && c == '\\') { | 425 if (!escaped && c == '\\') { |
| 426 escaped = true; | 426 escaped = true; |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 672 | 672 |
| 673 int _reportResult(String output) { | 673 int _reportResult(String output) { |
| 674 _stdoutDrained = true; | 674 _stdoutDrained = true; |
| 675 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' | 675 // output = '>>> TEST {PASS, FAIL, OK, CRASH, FAIL, TIMEOUT}' |
| 676 var outcome = output.split(" ")[2]; | 676 var outcome = output.split(" ")[2]; |
| 677 var exitCode = 0; | 677 var exitCode = 0; |
| 678 if (outcome == "CRASH") exitCode = -10; | 678 if (outcome == "CRASH") exitCode = -10; |
| 679 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; | 679 if (outcome == "FAIL" || outcome == "TIMEOUT") exitCode = 1; |
| 680 new TestOutput.fromCase(_currentTest, exitCode, outcome == "TIMEOUT", | 680 new TestOutput.fromCase(_currentTest, exitCode, outcome == "TIMEOUT", |
| 681 _testStdout, _testStderr, new Date.now().difference(_startTim e)); | 681 _testStdout, _testStderr, new Date.now().difference(_startTim e)); |
| 682 // Move on when both stdout and stderr has been drained. | 682 // Move on when both stdout and stderr has been drained. If the test |
| 683 if (_stderrDrained) _testCompleted(); | 683 // crashed, we restarted the process and therefore do not attempt to |
| 684 // drain stderr. | |
| 685 if (_stderrDrained || (_currentTest.output.hasCrashed)) _testCompleted(); | |
| 684 } | 686 } |
| 685 | 687 |
| 686 void _stderrDone() { | 688 void _stderrDone() { |
| 687 _stderrDrained = true; | 689 _stderrDrained = true; |
| 688 // Move on when both stdout and stderr has been drained. | 690 // Move on when both stdout and stderr has been drained. |
| 689 if (_stdoutDrained) _testCompleted(); | 691 if (_stdoutDrained) _testCompleted(); |
|
zundel
2012/03/08 12:22:16
What about here?
zundel
2012/03/08 12:28:29
nm, I guess we just wait for the process to exit a
| |
| 690 } | 692 } |
| 691 | 693 |
| 692 Function _readStdout(StringInputStream stream, List<String> buffer) { | 694 Function _readStdout(StringInputStream stream, List<String> buffer) { |
| 693 return () { | 695 return () { |
| 694 var status; | 696 var status; |
| 695 var line = stream.readLine(); | 697 var line = stream.readLine(); |
| 696 while (line != null) { | 698 while (line != null) { |
| 697 if (line.startsWith('>>> TEST')) { | 699 if (line.startsWith('>>> TEST')) { |
| 698 status = line; | 700 status = line; |
| 699 } else if (line.startsWith('>>> BATCH START')) { | 701 } else if (line.startsWith('>>> BATCH START')) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 798 // configurations there is no need to repeatedly search the file | 800 // configurations there is no need to repeatedly search the file |
| 799 // system, generate tests, and search test files for options. | 801 // system, generate tests, and search test files for options. |
| 800 Map<String, List<TestInformation>> _testCache; | 802 Map<String, List<TestInformation>> _testCache; |
| 801 | 803 |
| 802 /** | 804 /** |
| 803 * String indicating the browser used to run the tests. Empty if no browser | 805 * String indicating the browser used to run the tests. Empty if no browser |
| 804 * used. | 806 * used. |
| 805 */ | 807 */ |
| 806 String browserUsed = ''; | 808 String browserUsed = ''; |
| 807 | 809 |
| 808 /** | 810 /** |
| 809 * Process running the selenium server .jar (only used for Safari and Opera | 811 * Process running the selenium server .jar (only used for Safari and Opera |
| 810 * tests.) | 812 * tests.) |
| 811 */ | 813 */ |
| 812 Process _seleniumServer = null; | 814 Process _seleniumServer = null; |
| 813 | 815 |
| 814 /** True if we are in the process of starting the server. */ | 816 /** True if we are in the process of starting the server. */ |
| 815 bool _startingServer = false; | 817 bool _startingServer = false; |
| 816 | 818 |
| 817 /** True if we find that there is already a selenium jar running. */ | 819 /** True if we find that there is already a selenium jar running. */ |
| 818 bool _seleniumAlreadyRunning = false; | 820 bool _seleniumAlreadyRunning = false; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 941 } | 943 } |
| 942 } else { | 944 } else { |
| 943 print('\nDeletion of temp dir $_temporaryDirectory failed.'); | 945 print('\nDeletion of temp dir $_temporaryDirectory failed.'); |
| 944 } | 946 } |
| 945 _cleanupAndMarkDone(); | 947 _cleanupAndMarkDone(); |
| 946 }; | 948 }; |
| 947 } | 949 } |
| 948 } | 950 } |
| 949 } | 951 } |
| 950 } | 952 } |
| 951 | 953 |
| 952 /** | 954 /** |
| 953 * True if we are using a browser + platform combination that needs the | 955 * True if we are using a browser + platform combination that needs the |
| 954 * Selenium server jar. | 956 * Selenium server jar. |
| 955 */ | 957 */ |
| 956 bool get _needsSelenium() => new Platform().operatingSystem() == 'macos' && | 958 bool get _needsSelenium() => new Platform().operatingSystem() == 'macos' && |
| 957 browserUsed == 'safari'; | 959 browserUsed == 'safari'; |
| 958 | 960 |
| 959 /** True if the Selenium Server is ready to be used. */ | 961 /** True if the Selenium Server is ready to be used. */ |
| 960 bool get _isSeleniumAvailable() => _seleniumServer != null || | 962 bool get _isSeleniumAvailable() => _seleniumServer != null || |
| 961 _seleniumAlreadyRunning; | 963 _seleniumAlreadyRunning; |
| 962 | 964 |
| 963 /** | 965 /** |
| 964 * Restart all the processes that have been waiting/stopped for the server to | 966 * Restart all the processes that have been waiting/stopped for the server to |
| 965 * start up. If we just call this once we end up with a single-"threaded" run. | 967 * start up. If we just call this once we end up with a single-"threaded" run. |
| 966 */ | 968 */ |
| 967 void resumeTesting() { | 969 void resumeTesting() { |
| 968 for (int i = 0; i < _maxProcesses; i++) _tryRunTest(); | 970 for (int i = 0; i < _maxProcesses; i++) _tryRunTest(); |
| 969 } | 971 } |
| 970 | 972 |
| 971 /** Start the Selenium Server jar, if appropriate for this platform. */ | 973 /** Start the Selenium Server jar, if appropriate for this platform. */ |
| 972 void _ensureSeleniumServerRunning() { | 974 void _ensureSeleniumServerRunning() { |
| 973 if (!_isSeleniumAvailable && !_startingServer) { | 975 if (!_isSeleniumAvailable && !_startingServer) { |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1002 void _runTest(TestCase test) { | 1004 void _runTest(TestCase test) { |
| 1003 if (test.usesWebDriver) { | 1005 if (test.usesWebDriver) { |
| 1004 browserUsed = test.configuration['browser']; | 1006 browserUsed = test.configuration['browser']; |
| 1005 if (_needsSelenium) _ensureSeleniumServerRunning(); | 1007 if (_needsSelenium) _ensureSeleniumServerRunning(); |
| 1006 } | 1008 } |
| 1007 _progress.testAdded(); | 1009 _progress.testAdded(); |
| 1008 _tests.add(test); | 1010 _tests.add(test); |
| 1009 _tryRunTest(); | 1011 _tryRunTest(); |
| 1010 } | 1012 } |
| 1011 | 1013 |
| 1012 /** | 1014 /** |
| 1013 * Monitor the output of the Selenium server, to know when we are ready to | 1015 * Monitor the output of the Selenium server, to know when we are ready to |
| 1014 * begin running tests. | 1016 * begin running tests. |
| 1015 * source: Output(Stream) from the Java server. | 1017 * source: Output(Stream) from the Java server. |
| 1016 */ | 1018 */ |
| 1017 Function makeSeleniumServerHandler(StringInputStream source) { | 1019 Function makeSeleniumServerHandler(StringInputStream source) { |
| 1018 return () { | 1020 return () { |
| 1019 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. | 1021 if (source.closed) return; // TODO(whesse): Remove when bug is fixed. |
| 1020 var line = source.readLine(); | 1022 var line = source.readLine(); |
| 1021 while (null != line) { | 1023 while (null != line) { |
| 1022 if (const RegExp(@".*Started.*Server.*").hasMatch(line) || | 1024 if (const RegExp(@".*Started.*Server.*").hasMatch(line) || |
| 1023 const RegExp(@"Exception.*Selenium is already running.*").hasMatch( | 1025 const RegExp(@"Exception.*Selenium is already running.*").hasMatch( |
| 1024 line)) { | 1026 line)) { |
| 1025 resumeTesting(); | 1027 resumeTesting(); |
| 1026 } | 1028 } |
| 1027 line = source.readLine(); | 1029 line = source.readLine(); |
| 1028 } | 1030 } |
| 1029 }; | 1031 }; |
| 1030 } | 1032 } |
| 1031 | 1033 |
| 1032 /** | 1034 /** |
| 1033 * For browser tests using Safari or Opera, we need to use the Selenium 1.0 | 1035 * For browser tests using Safari or Opera, we need to use the Selenium 1.0 |
| 1034 * Java server. | 1036 * Java server. |
| 1035 */ | 1037 */ |
| 1036 void _startSeleniumServer() { | 1038 void _startSeleniumServer() { |
| 1037 // Get the absolute path to the Selenium jar. | 1039 // Get the absolute path to the Selenium jar. |
| 1038 String filePath = new Options().script; | 1040 String filePath = new Options().script; |
| 1039 String pathSep = new Platform().pathSeparator(); | 1041 String pathSep = new Platform().pathSeparator(); |
| 1040 int index = filePath.lastIndexOf(pathSep); | 1042 int index = filePath.lastIndexOf(pathSep); |
| 1041 filePath = filePath.substring(0, index) + '${pathSep}testing${pathSep}'; | 1043 filePath = filePath.substring(0, index) + '${pathSep}testing${pathSep}'; |
| 1042 var dir = new Directory(filePath); | 1044 var dir = new Directory(filePath); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1126 // the developer doesn't waste his or her time trying to fix a bunch of | 1128 // the developer doesn't waste his or her time trying to fix a bunch of |
| 1127 // tests that appear to be broken but were actually just flakes that | 1129 // tests that appear to be broken but were actually just flakes that |
| 1128 // didn't get retried because there had already been one failure. | 1130 // didn't get retried because there had already been one failure. |
| 1129 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; | 1131 bool allowRetry = _MAX_FAILED_NO_RETRY > _progress.numFailedTests; |
| 1130 new RunningProcess(test, allowRetry, this).start(); | 1132 new RunningProcess(test, allowRetry, this).start(); |
| 1131 } | 1133 } |
| 1132 _numProcesses++; | 1134 _numProcesses++; |
| 1133 } | 1135 } |
| 1134 } | 1136 } |
| 1135 } | 1137 } |
| OLD | NEW |