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 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub | 5 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub |
6 /// tests are integration tests that stage some stuff on the file system, run | 6 /// tests are integration tests that stage some stuff on the file system, run |
7 /// pub, and then validate the results. This library provides an API to build | 7 /// pub, and then validate the results. This library provides an API to build |
8 /// tests like that. | 8 /// tests like that. |
9 library test_pub; | 9 library test_pub; |
10 | 10 |
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 bool _abortScheduled = false; | 455 bool _abortScheduled = false; |
456 | 456 |
457 /// The time (in milliseconds) to wait for the entire scheduled test to | 457 /// The time (in milliseconds) to wait for the entire scheduled test to |
458 /// complete. | 458 /// complete. |
459 final _TIMEOUT = 30000; | 459 final _TIMEOUT = 30000; |
460 | 460 |
461 /// Defines an integration test. The [body] should schedule a series of | 461 /// Defines an integration test. The [body] should schedule a series of |
462 /// operations which will be run asynchronously. | 462 /// operations which will be run asynchronously. |
463 void integration(String description, void body()) { | 463 void integration(String description, void body()) { |
464 test(description, () { | 464 test(description, () { |
| 465 // Sanity check. Make sure we cleaned up the last test. |
| 466 assert(_scheduled == null); |
| 467 assert(_scheduledCleanup == null); |
| 468 assert(_scheduledOnException == null); |
| 469 |
| 470 // Schedule the test. |
465 body(); | 471 body(); |
466 _run(); | 472 |
| 473 // Run all of the scheduled tasks. If an error occurs, it will propagate |
| 474 // through the futures back up to here where we can hand it off to unittest. |
| 475 var asyncDone = expectAsync0(() {}); |
| 476 var createdSandboxDir; |
| 477 _setUpSandbox().then((sandboxDir) { |
| 478 createdSandboxDir = sandboxDir; |
| 479 return timeout(_runScheduled(sandboxDir, _scheduled), |
| 480 _TIMEOUT, 'waiting for a test to complete'); |
| 481 }).catchError((e) { |
| 482 return _runScheduled(createdSandboxDir, _scheduledOnException).then((_) { |
| 483 // Rethrow the original error so it keeps propagating. |
| 484 throw e; |
| 485 }); |
| 486 }).whenComplete(() { |
| 487 // Clean up after ourselves. Do this first before reporting back to |
| 488 // unittest because it will advance to the next test immediately. |
| 489 return _runScheduled(createdSandboxDir, _scheduledCleanup).then((_) { |
| 490 _scheduled = null; |
| 491 _scheduledCleanup = null; |
| 492 _scheduledOnException = null; |
| 493 if (createdSandboxDir != null) return deleteDir(createdSandboxDir); |
| 494 }); |
| 495 }).then((_) { |
| 496 // If we got here, the test completed successfully so tell unittest so. |
| 497 asyncDone(); |
| 498 }).catchError((e) { |
| 499 // If we got here, an error occurred. We will register it with unittest |
| 500 // directly so that the error message isn't wrapped in any matcher stuff. |
| 501 // We do this call last because it will cause unittest to *synchronously* |
| 502 // advance to the next test and run it. |
| 503 registerException(e.error, e.stackTrace); |
| 504 }); |
467 }); | 505 }); |
468 } | 506 } |
469 | 507 |
470 /// Runs all the scheduled events for a test case. This should only be called | |
471 /// once per test case. | |
472 void _run() { | |
473 var createdSandboxDir; | |
474 var asyncDone = expectAsync0(() {}); | |
475 | |
476 Future cleanup() { | |
477 return _runScheduled(createdSandboxDir, _scheduledCleanup).then((_) { | |
478 _scheduled = null; | |
479 _scheduledCleanup = null; | |
480 _scheduledOnException = null; | |
481 if (createdSandboxDir != null) return deleteDir(createdSandboxDir); | |
482 }); | |
483 } | |
484 | |
485 timeout(_setUpSandbox().then((sandboxDir) { | |
486 createdSandboxDir = sandboxDir; | |
487 return _runScheduled(sandboxDir, _scheduled); | |
488 }).catchError((e) { | |
489 // If an error occurs during testing, delete the sandbox, throw the error so | |
490 // that the test framework sees it, then finally call asyncDone so that the | |
491 // test framework knows we're done doing asynchronous stuff. | |
492 return _runScheduled(createdSandboxDir, _scheduledOnException) | |
493 .then((_) => registerException(e.error, e.stackTrace)).catchError((e) { | |
494 print("Exception while cleaning up: ${e.error}"); | |
495 print(e.stackTrace); | |
496 registerException(e.error, e.stackTrace); | |
497 }); | |
498 }), _TIMEOUT, 'waiting for a test to complete') | |
499 .then((_) => cleanup()) | |
500 .then((_) => asyncDone()); | |
501 } | |
502 | |
503 /// Get the path to the root "util/test/pub" directory containing the pub | 508 /// Get the path to the root "util/test/pub" directory containing the pub |
504 /// tests. | 509 /// tests. |
505 String get testDirectory { | 510 String get testDirectory { |
506 var dir = new Options().script; | 511 var dir = new Options().script; |
507 while (basename(dir) != 'pub') dir = dirname(dir); | 512 while (basename(dir) != 'pub') dir = dirname(dir); |
508 | 513 |
509 return getFullPath(dir); | 514 return getFullPath(dir); |
510 } | 515 } |
511 | 516 |
512 /// Schedules a call to the Pub command-line utility. Runs Pub with [args] and | 517 /// Schedules a call to the Pub command-line utility. Runs Pub with [args] and |
513 /// validates that its results match [output], [error], and [exitCode]. | 518 /// validates that its results match [output], [error], and [exitCode]. |
514 void schedulePub({List args, Pattern output, Pattern error, | 519 void schedulePub({List args, Pattern output, Pattern error, |
515 Future<Uri> tokenEndpoint, int exitCode: 0}) { | 520 Future<Uri> tokenEndpoint, int exitCode: 0}) { |
516 _schedule((sandboxDir) { | 521 _schedule((sandboxDir) { |
517 return _doPub(runProcess, sandboxDir, args, tokenEndpoint) | 522 return _doPub(runProcess, sandboxDir, args, tokenEndpoint).then((result) { |
518 .then((result) { | |
519 var failures = []; | 523 var failures = []; |
520 | 524 |
521 _validateOutput(failures, 'stdout', output, result.stdout); | 525 _validateOutput(failures, 'stdout', output, result.stdout); |
522 _validateOutput(failures, 'stderr', error, result.stderr); | 526 _validateOutput(failures, 'stderr', error, result.stderr); |
523 | 527 |
524 if (result.exitCode != exitCode) { | 528 if (result.exitCode != exitCode) { |
525 failures.add( | 529 failures.add( |
526 'Pub returned exit code ${result.exitCode}, expected $exitCode.'); | 530 'Pub returned exit code ${result.exitCode}, expected $exitCode.'); |
527 } | 531 } |
528 | 532 |
(...skipping 1022 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1551 /// calling [completion] is unnecessary. | 1555 /// calling [completion] is unnecessary. |
1552 void expectLater(Future actual, matcher, {String reason, | 1556 void expectLater(Future actual, matcher, {String reason, |
1553 FailureHandler failureHandler, bool verbose: false}) { | 1557 FailureHandler failureHandler, bool verbose: false}) { |
1554 _schedule((_) { | 1558 _schedule((_) { |
1555 return actual.then((value) { | 1559 return actual.then((value) { |
1556 expect(value, matcher, reason: reason, failureHandler: failureHandler, | 1560 expect(value, matcher, reason: reason, failureHandler: failureHandler, |
1557 verbose: false); | 1561 verbose: false); |
1558 }); | 1562 }); |
1559 }); | 1563 }); |
1560 } | 1564 } |
OLD | NEW |