| 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 * Test infrastructure for testing pub. Unlike typical unit tests, most pub | 6 * Test infrastructure for testing pub. Unlike typical unit tests, most pub |
| 7 * tests are integration tests that stage some stuff on the file system, run | 7 * tests are integration tests that stage some stuff on the file system, run |
| 8 * pub, and then validate the results. This library provides an API to build | 8 * pub, and then validate the results. This library provides an API to build |
| 9 * tests like that. | 9 * tests like that. |
| 10 */ | 10 */ |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 FileDescriptor file(Pattern name, String contents) => | 27 FileDescriptor file(Pattern name, String contents) => |
| 28 new FileDescriptor(name, contents); | 28 new FileDescriptor(name, contents); |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * Creates a new [DirectoryDescriptor] with [name] and [contents]. | 31 * Creates a new [DirectoryDescriptor] with [name] and [contents]. |
| 32 */ | 32 */ |
| 33 DirectoryDescriptor dir(Pattern name, [List<Descriptor> contents]) => | 33 DirectoryDescriptor dir(Pattern name, [List<Descriptor> contents]) => |
| 34 new DirectoryDescriptor(name, contents); | 34 new DirectoryDescriptor(name, contents); |
| 35 | 35 |
| 36 /** | 36 /** |
| 37 * Creates a new [FutureDescriptor] wrapping [future]. |
| 38 */ |
| 39 FutureDescriptor async(Future<Descriptor> future) => |
| 40 new FutureDescriptor(future); |
| 41 |
| 42 /** |
| 37 * Creates a new [GitRepoDescriptor] with [name] and [contents]. | 43 * Creates a new [GitRepoDescriptor] with [name] and [contents]. |
| 38 */ | 44 */ |
| 39 DirectoryDescriptor git(Pattern name, [List<Descriptor> contents]) => | 45 GitRepoDescriptor git(Pattern name, [List<Descriptor> contents]) => |
| 40 new GitRepoDescriptor(name, contents); | 46 new GitRepoDescriptor(name, contents); |
| 41 | 47 |
| 42 /** | 48 /** |
| 43 * Creates a new [TarFileDescriptor] with [name] and [contents]. | 49 * Creates a new [TarFileDescriptor] with [name] and [contents]. |
| 44 */ | 50 */ |
| 45 TarFileDescriptor tar(Pattern name, [List<Descriptor> contents]) => | 51 TarFileDescriptor tar(Pattern name, [List<Descriptor> contents]) => |
| 46 new TarFileDescriptor(name, contents); | 52 new TarFileDescriptor(name, contents); |
| 47 | 53 |
| 48 /** | 54 /** |
| 49 * Creates an HTTP server to serve [contents] as static files. This server will | 55 * Creates an HTTP server to serve [contents] as static files. This server will |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 */ | 168 */ |
| 163 List<_ScheduledEvent> _scheduled; | 169 List<_ScheduledEvent> _scheduled; |
| 164 | 170 |
| 165 /** | 171 /** |
| 166 * The list of events that are scheduled to run after the test case, even if it | 172 * The list of events that are scheduled to run after the test case, even if it |
| 167 * failed. | 173 * failed. |
| 168 */ | 174 */ |
| 169 List<_ScheduledEvent> _scheduledCleanup; | 175 List<_ScheduledEvent> _scheduledCleanup; |
| 170 | 176 |
| 171 /** | 177 /** |
| 178 * Set to true when the current batch of scheduled events should be aborted. |
| 179 */ |
| 180 bool _abortScheduled = false; |
| 181 |
| 182 /** |
| 172 * Runs all the scheduled events for a test case. This should only be called | 183 * Runs all the scheduled events for a test case. This should only be called |
| 173 * once per test case. | 184 * once per test case. |
| 174 */ | 185 */ |
| 175 void run() { | 186 void run() { |
| 176 var createdSandboxDir; | 187 var createdSandboxDir; |
| 177 | 188 |
| 178 var asyncDone = expectAsync0(() {}); | 189 var asyncDone = expectAsync0(() {}); |
| 179 | 190 |
| 180 Future cleanup() { | 191 Future cleanup() { |
| 181 return _runScheduled(createdSandboxDir, _scheduledCleanup).chain((_) { | 192 return _runScheduled(createdSandboxDir, _scheduledCleanup).chain((_) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 * A shorthand for [schedulePub] and [run] when no validation needs to be done | 262 * A shorthand for [schedulePub] and [run] when no validation needs to be done |
| 252 * after Pub has been run. | 263 * after Pub has been run. |
| 253 */ | 264 */ |
| 254 void runPub([List<String> args, Pattern output, Pattern error, | 265 void runPub([List<String> args, Pattern output, Pattern error, |
| 255 int exitCode = 0]) { | 266 int exitCode = 0]) { |
| 256 schedulePub(args, output, error, exitCode); | 267 schedulePub(args, output, error, exitCode); |
| 257 run(); | 268 run(); |
| 258 } | 269 } |
| 259 | 270 |
| 260 /** | 271 /** |
| 261 * Wraps a test that needs git in order to run. This validates that the test is | 272 * Skips the current test if Git is not installed. This validates that the |
| 262 * running on a builbot in which case we expect git to be installed. If we are | 273 * current test is running on a buildbot in which case we expect git to be |
| 263 * not running on the buildbot, we will instead see if git is installed and | 274 * installed. If we are not running on the buildbot, we will instead see if git |
| 264 * skip the test if not. This way, users don't need to have git installed to | 275 * is installed and skip the test if not. This way, users don't need to have git |
| 265 * run the tests locally (unless they actually care about the pub git tests). | 276 * installed to run the tests locally (unless they actually care about the pub |
| 277 * git tests). |
| 266 */ | 278 */ |
| 267 void withGit(void callback()) { | 279 void ensureGit() { |
| 268 isGitInstalled.then(expectAsync1((installed) { | 280 _schedule((_) { |
| 269 if (installed || Platform.environment.containsKey('BUILDBOT_BUILDERNAME')) { | 281 return isGitInstalled.transform((installed) { |
| 270 callback(); | 282 if (!installed && |
| 271 } | 283 !Platform.environment.containsKey('BUILDBOT_BUILDERNAME')) { |
| 272 })); | 284 _abortScheduled = true; |
| 285 } |
| 286 return null; |
| 287 }); |
| 288 }); |
| 273 } | 289 } |
| 274 | 290 |
| 275 Future<Directory> _setUpSandbox() { | 291 Future<Directory> _setUpSandbox() { |
| 276 return createTempDir('pub-test-sandbox-'); | 292 return createTempDir('pub-test-sandbox-'); |
| 277 } | 293 } |
| 278 | 294 |
| 279 Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) { | 295 Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) { |
| 280 if (scheduled == null) return new Future.immediate(null); | 296 if (scheduled == null) return new Future.immediate(null); |
| 281 var iterator = scheduled.iterator(); | 297 var iterator = scheduled.iterator(); |
| 282 | 298 |
| 283 Future runNextEvent([_]) { | 299 Future runNextEvent([_]) { |
| 284 if (!iterator.hasNext()) { | 300 if (_abortScheduled || !iterator.hasNext()) { |
| 301 _abortScheduled = false; |
| 285 scheduled.clear(); | 302 scheduled.clear(); |
| 286 return new Future.immediate(null); | 303 return new Future.immediate(null); |
| 287 } | 304 } |
| 288 | 305 |
| 289 var future = iterator.next()(parentDir); | 306 var future = iterator.next()(parentDir); |
| 290 if (future != null) { | 307 if (future != null) { |
| 291 return future.chain(runNextEvent); | 308 return future.chain(runNextEvent); |
| 292 } else { | 309 } else { |
| 293 return runNextEvent(); | 310 return runNextEvent(); |
| 294 } | 311 } |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 595 if (descriptor.name == path[0]) { | 612 if (descriptor.name == path[0]) { |
| 596 return descriptor.load(path.getRange(1, path.length - 1)); | 613 return descriptor.load(path.getRange(1, path.length - 1)); |
| 597 } | 614 } |
| 598 } | 615 } |
| 599 | 616 |
| 600 throw "Directory $name doesn't contain ${Strings.join(path, '/')}."; | 617 throw "Directory $name doesn't contain ${Strings.join(path, '/')}."; |
| 601 } | 618 } |
| 602 } | 619 } |
| 603 | 620 |
| 604 /** | 621 /** |
| 622 * Wraps a [Future] that will complete to a [Descriptor] and makes it behave |
| 623 * like a concrete [Descriptor]. This is necessary when the contents of the |
| 624 * descriptor depends on information that's not available until part of the test |
| 625 * run is completed. |
| 626 */ |
| 627 class FutureDescriptor extends Descriptor { |
| 628 Future<Descriptor> _future; |
| 629 |
| 630 FutureDescriptor(this._future) : super('<unknown>'); |
| 631 |
| 632 Future create(dir) => _future.chain((desc) => desc.create(dir)); |
| 633 |
| 634 Future validate(dir) => _future.chain((desc) => desc.validate(dir)); |
| 635 |
| 636 Future delete(dir) => _future.chain((desc) => desc.delete(dir)); |
| 637 |
| 638 InputStream load(List<String> path) { |
| 639 var resultStream = new ListInputStream(); |
| 640 _future.then((desc) => pipeInputToInput(desc.load(path), resultStream)); |
| 641 return resultStream; |
| 642 } |
| 643 } |
| 644 |
| 645 /** |
| 605 * Describes a Git repository and its contents. | 646 * Describes a Git repository and its contents. |
| 606 */ | 647 */ |
| 607 class GitRepoDescriptor extends DirectoryDescriptor { | 648 class GitRepoDescriptor extends DirectoryDescriptor { |
| 608 GitRepoDescriptor(Pattern name, List<Descriptor> contents) | 649 GitRepoDescriptor(Pattern name, List<Descriptor> contents) |
| 609 : super(name, contents); | 650 : super(name, contents); |
| 610 | 651 |
| 611 /** | 652 /** |
| 612 * Creates the Git repository and commits the contents. | 653 * Creates the Git repository and commits the contents. |
| 613 */ | 654 */ |
| 614 Future<Directory> create(parentDir) { | 655 Future<Directory> create(parentDir) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 634 workingDir = rootDir; | 675 workingDir = rootDir; |
| 635 return runGit(['add', '.']); | 676 return runGit(['add', '.']); |
| 636 }).chain((_) => runGit(['commit', '-m', 'update'])); | 677 }).chain((_) => runGit(['commit', '-m', 'update'])); |
| 637 } | 678 } |
| 638 | 679 |
| 639 /** | 680 /** |
| 640 * Schedules changes to be committed to the Git repository. | 681 * Schedules changes to be committed to the Git repository. |
| 641 */ | 682 */ |
| 642 void scheduleCommit() => _schedule((dir) => this.commit(dir)); | 683 void scheduleCommit() => _schedule((dir) => this.commit(dir)); |
| 643 | 684 |
| 644 Future _runGit(List<String> args, Directory workingDir) { | 685 /** |
| 686 * Return a Future that completes to the commit in the git repository referred |
| 687 * to by [ref] at the current point in the scheduled test run. |
| 688 */ |
| 689 Future<String> revParse(String ref) { |
| 690 var completer = new Completer<String>(); |
| 691 // TODO(nweiz): inline this once issue 3197 is fixed |
| 692 var superCreate = super.create; |
| 693 _schedule((parentDir) { |
| 694 return superCreate(parentDir).chain((rootDir) { |
| 695 return _runGit(['rev-parse', ref], rootDir); |
| 696 }).transform((output) { |
| 697 completer.complete(output[0]); |
| 698 return null; |
| 699 }); |
| 700 }); |
| 701 return completer.future; |
| 702 } |
| 703 |
| 704 Future<String> _runGit(List<String> args, Directory workingDir) { |
| 645 return runProcess('git', args, workingDir: workingDir.path). | 705 return runProcess('git', args, workingDir: workingDir.path). |
| 646 transform((result) { | 706 transform((result) { |
| 647 if (!result.success) throw "Error running git: ${result.stderr}"; | 707 if (!result.success) throw "Error running git: ${result.stderr}"; |
| 648 return null; | 708 return result.stdout; |
| 649 }); | 709 }); |
| 650 } | 710 } |
| 651 } | 711 } |
| 652 | 712 |
| 653 /** | 713 /** |
| 654 * Describes a gzipped tar file and its contents. | 714 * Describes a gzipped tar file and its contents. |
| 655 */ | 715 */ |
| 656 class TarFileDescriptor extends Descriptor { | 716 class TarFileDescriptor extends Descriptor { |
| 657 final List<Descriptor> contents; | 717 final List<Descriptor> contents; |
| 658 | 718 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 } | 784 } |
| 725 | 785 |
| 726 /** | 786 /** |
| 727 * Schedules a callback to be called after Pub is run with [runPub], even if it | 787 * Schedules a callback to be called after Pub is run with [runPub], even if it |
| 728 * fails. | 788 * fails. |
| 729 */ | 789 */ |
| 730 void _scheduleCleanup(_ScheduledEvent event) { | 790 void _scheduleCleanup(_ScheduledEvent event) { |
| 731 if (_scheduledCleanup == null) _scheduledCleanup = []; | 791 if (_scheduledCleanup == null) _scheduledCleanup = []; |
| 732 _scheduledCleanup.add(event); | 792 _scheduledCleanup.add(event); |
| 733 } | 793 } |
| OLD | NEW |