| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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. | 5 /// Test infrastructure for testing pub. |
| 6 /// | 6 /// |
| 7 /// Unlike typical unit tests, most pub tests are integration tests that stage | 7 /// Unlike typical unit tests, most pub tests are integration tests that stage |
| 8 /// some stuff on the file system, run pub, and then validate the results. This | 8 /// some stuff on the file system, run pub, and then validate the results. This |
| 9 /// library provides an API to build tests like that. | 9 /// library provides an API to build tests like that. |
| 10 library test_pub; | 10 library test_pub; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 Map<String, List<Map>> _servedPackages; | 218 Map<String, List<Map>> _servedPackages; |
| 219 | 219 |
| 220 /// Creates an HTTP server that replicates the structure of pub.dartlang.org. | 220 /// Creates an HTTP server that replicates the structure of pub.dartlang.org. |
| 221 /// | 221 /// |
| 222 /// [pubspecs] is a list of unserialized pubspecs representing the packages to | 222 /// [pubspecs] is a list of unserialized pubspecs representing the packages to |
| 223 /// serve. | 223 /// serve. |
| 224 /// | 224 /// |
| 225 /// If [replace] is false, subsequent calls to [servePackages] will add to the | 225 /// If [replace] is false, subsequent calls to [servePackages] will add to the |
| 226 /// set of packages that are being served. Previous packages will continue to be | 226 /// set of packages that are being served. Previous packages will continue to be |
| 227 /// served. Otherwise, the previous packages will no longer be served. | 227 /// served. Otherwise, the previous packages will no longer be served. |
| 228 void servePackages(List<Map> pubspecs, {bool replace: false}) { | 228 /// |
| 229 /// If [contents] is given, its contents are added to every served |
| 230 /// package. |
| 231 void servePackages(List<Map> pubspecs, {bool replace: false, |
| 232 Iterable<d.Descriptor> contents}) { |
| 229 if (_servedPackages == null || _servedPackageDir == null) { | 233 if (_servedPackages == null || _servedPackageDir == null) { |
| 230 _servedPackages = <String, List<Map>>{}; | 234 _servedPackages = <String, List<Map>>{}; |
| 231 _servedApiPackageDir = d.dir('packages', []); | 235 _servedApiPackageDir = d.dir('packages', []); |
| 232 _servedPackageDir = d.dir('packages', []); | 236 _servedPackageDir = d.dir('packages', []); |
| 233 serve([ | 237 serve([ |
| 234 d.dir('api', [_servedApiPackageDir]), | 238 d.dir('api', [_servedApiPackageDir]), |
| 235 _servedPackageDir | 239 _servedPackageDir |
| 236 ]); | 240 ]); |
| 237 | 241 |
| 238 currentSchedule.onComplete.schedule(() { | 242 currentSchedule.onComplete.schedule(() { |
| 239 _servedPackages = null; | 243 _servedPackages = null; |
| 240 _servedApiPackageDir = null; | 244 _servedApiPackageDir = null; |
| 241 _servedPackageDir = null; | 245 _servedPackageDir = null; |
| 242 }, 'cleaning up served packages'); | 246 }, 'cleaning up served packages'); |
| 243 } | 247 } |
| 244 | 248 |
| 245 schedule(() { | 249 schedule(() { |
| 246 return awaitObject(pubspecs).then((resolvedPubspecs) { | 250 return awaitObject(pubspecs).then((resolvedPubspecs) { |
| 247 if (replace) _servedPackages.clear(); | 251 if (replace) _servedPackages.clear(); |
| 248 | 252 |
| 249 for (var spec in resolvedPubspecs) { | 253 for (var pubspec in resolvedPubspecs) { |
| 250 var name = spec['name']; | 254 var name = pubspec['name']; |
| 251 var version = spec['version']; | 255 var version = pubspec['version']; |
| 252 var versions = _servedPackages.putIfAbsent(name, () => []); | 256 var versions = _servedPackages.putIfAbsent(name, () => []); |
| 253 versions.add(spec); | 257 versions.add(pubspec); |
| 254 } | 258 } |
| 255 | 259 |
| 256 _servedApiPackageDir.contents.clear(); | 260 _servedApiPackageDir.contents.clear(); |
| 257 _servedPackageDir.contents.clear(); | 261 _servedPackageDir.contents.clear(); |
| 258 for (var name in _servedPackages.keys) { | 262 for (var name in _servedPackages.keys) { |
| 259 _servedApiPackageDir.contents.addAll([ | 263 _servedApiPackageDir.contents.addAll([ |
| 260 d.file('$name', JSON.encode({ | 264 d.file('$name', JSON.encode({ |
| 261 'name': name, | 265 'name': name, |
| 262 'uploaders': ['nweiz@google.com'], | 266 'uploaders': ['nweiz@google.com'], |
| 263 'versions': _servedPackages[name].map(packageVersionApiMap).toList() | 267 'versions': _servedPackages[name].map(packageVersionApiMap).toList() |
| 264 })), | 268 })), |
| 265 d.dir(name, [ | 269 d.dir(name, [ |
| 266 d.dir('versions', _servedPackages[name].map((pubspec) { | 270 d.dir('versions', _servedPackages[name].map((pubspec) { |
| 267 return d.file(pubspec['version'], JSON.encode( | 271 return d.file(pubspec['version'], JSON.encode( |
| 268 packageVersionApiMap(pubspec, full: true))); | 272 packageVersionApiMap(pubspec, full: true))); |
| 269 })) | 273 })) |
| 270 ]) | 274 ]) |
| 271 ]); | 275 ]); |
| 272 | 276 |
| 273 _servedPackageDir.contents.add(d.dir(name, [ | 277 _servedPackageDir.contents.add(d.dir(name, [ |
| 274 d.dir('versions', _servedPackages[name].map((pubspec) { | 278 d.dir('versions', _servedPackages[name].map((pubspec) { |
| 275 var version = pubspec['version']; | 279 var version = pubspec['version']; |
| 276 return d.tar('$version.tar.gz', [ | 280 |
| 277 d.file('pubspec.yaml', JSON.encode(pubspec)), | 281 var archiveContents = [ |
| 278 d.libDir(name, '$name $version') | 282 d.file('pubspec.yaml', JSON.encode(pubspec)), |
| 279 ]); | 283 d.libDir(name, '$name $version') |
| 284 ]; |
| 285 |
| 286 if (contents != null) { |
| 287 archiveContents.addAll(contents); |
| 288 } |
| 289 |
| 290 return d.tar('$version.tar.gz', archiveContents); |
| 280 })) | 291 })) |
| 281 ])); | 292 ])); |
| 282 } | 293 } |
| 283 }); | 294 }); |
| 284 }, 'initializing the package server'); | 295 }, 'initializing the package server'); |
| 285 } | 296 } |
| 286 | 297 |
| 287 /// Converts [value] into a YAML string. | 298 /// Converts [value] into a YAML string. |
| 288 String yaml(value) => JSON.encode(value); | 299 String yaml(value) => JSON.encode(value); |
| 289 | 300 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 void pubGet({Iterable<String> args, output, error, warning, int exitCode}) { | 381 void pubGet({Iterable<String> args, output, error, warning, int exitCode}) { |
| 371 pubCommand(RunCommand.get, args: args, output: output, error: error, | 382 pubCommand(RunCommand.get, args: args, output: output, error: error, |
| 372 warning: warning, exitCode: exitCode); | 383 warning: warning, exitCode: exitCode); |
| 373 } | 384 } |
| 374 | 385 |
| 375 void pubUpgrade({Iterable<String> args, output, error, warning, int exitCode}) { | 386 void pubUpgrade({Iterable<String> args, output, error, warning, int exitCode}) { |
| 376 pubCommand(RunCommand.upgrade, args: args, output: output, error: error, | 387 pubCommand(RunCommand.upgrade, args: args, output: output, error: error, |
| 377 warning: warning, exitCode: exitCode); | 388 warning: warning, exitCode: exitCode); |
| 378 } | 389 } |
| 379 | 390 |
| 391 /// Schedules starting the "pub [global] run" process and validates the |
| 392 /// expected startup output. |
| 393 /// |
| 394 /// If [global] is `true`, this invokes "pub global run", otherwise it does |
| 395 /// "pub run". |
| 396 /// |
| 397 /// Returns the `pub run` process. |
| 398 ScheduledProcess pubRun({bool global: false, Iterable<String> args}) { |
| 399 var pubArgs = global ? ["global", "run"] : ["run"]; |
| 400 pubArgs.addAll(args); |
| 401 var pub = startPub(args: pubArgs); |
| 402 |
| 403 // Loading sources and transformers isn't normally printed, but the pub test |
| 404 // infrastructure runs pub in verbose mode, which enables this. |
| 405 pub.stdout.expect(consumeWhile(startsWith("Loading"))); |
| 406 |
| 407 return pub; |
| 408 } |
| 409 |
| 380 /// Defines an integration test. | 410 /// Defines an integration test. |
| 381 /// | 411 /// |
| 382 /// The [body] should schedule a series of operations which will be run | 412 /// The [body] should schedule a series of operations which will be run |
| 383 /// asynchronously. | 413 /// asynchronously. |
| 384 void integration(String description, void body()) => | 414 void integration(String description, void body()) => |
| 385 _integration(description, body, test); | 415 _integration(description, body, test); |
| 386 | 416 |
| 387 /// Like [integration], but causes only this test to run. | 417 /// Like [integration], but causes only this test to run. |
| 388 void solo_integration(String description, void body()) => | 418 void solo_integration(String description, void body()) => |
| 389 _integration(description, body, solo_test); | 419 _integration(description, body, solo_test); |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 void ensureGit() { | 693 void ensureGit() { |
| 664 if (Platform.operatingSystem == "windows") { | 694 if (Platform.operatingSystem == "windows") { |
| 665 currentSchedule.timeout = new Duration(seconds: 30); | 695 currentSchedule.timeout = new Duration(seconds: 30); |
| 666 } | 696 } |
| 667 | 697 |
| 668 if (!gitlib.isInstalled) { | 698 if (!gitlib.isInstalled) { |
| 669 throw new Exception("Git must be installed to run this test."); | 699 throw new Exception("Git must be installed to run this test."); |
| 670 } | 700 } |
| 671 } | 701 } |
| 672 | 702 |
| 703 /// Schedules activating a global package [package] without running |
| 704 /// "pub global activate". |
| 705 /// |
| 706 /// This is useful because global packages must be hosted, but the test hosted |
| 707 /// server doesn't serve barback. The other parameters here follow |
| 708 /// [createLockFile]. |
| 709 void makeGlobalPackage(String package, String version, |
| 710 Iterable<d.Descriptor> contents, {Iterable<String> pkg, |
| 711 Map<String, String> hosted}) { |
| 712 // Start the server so we know what port to use in the cache directory name. |
| 713 servePackages([]); |
| 714 |
| 715 // Create the package in the hosted cache. |
| 716 d.hostedCache([ |
| 717 d.dir("$package-$version", contents) |
| 718 ]).create(); |
| 719 |
| 720 var lockFile = _createLockFile(pkg: pkg, hosted: hosted); |
| 721 |
| 722 // Add the root package to the lockfile. |
| 723 var id = new PackageId(package, "hosted", new Version.parse(version), |
| 724 package); |
| 725 lockFile.packages[package] = id; |
| 726 |
| 727 // Write the lockfile to the global cache. |
| 728 var sources = new SourceRegistry(); |
| 729 sources.register(new HostedSource()); |
| 730 sources.register(new PathSource()); |
| 731 |
| 732 d.dir(cachePath, [ |
| 733 d.dir("global_packages", [ |
| 734 d.file("$package.lock", lockFile.serialize(null, sources)) |
| 735 ]) |
| 736 ]).create(); |
| 737 } |
| 738 |
| 673 /// Creates a lock file for [package] without running `pub get`. | 739 /// Creates a lock file for [package] without running `pub get`. |
| 674 /// | 740 /// |
| 675 /// [sandbox] is a list of path dependencies to be found in the sandbox | 741 /// [sandbox] is a list of path dependencies to be found in the sandbox |
| 676 /// directory. [pkg] is a list of packages in the Dart repo's "pkg" directory; | 742 /// directory. [pkg] is a list of packages in the Dart repo's "pkg" directory; |
| 677 /// each package listed here and all its dependencies will be linked to the | 743 /// each package listed here and all its dependencies will be linked to the |
| 678 /// version in the Dart repo. | 744 /// version in the Dart repo. |
| 679 /// | 745 /// |
| 680 /// [hosted] is a list of package names to version strings for dependencies on | 746 /// [hosted] is a list of package names to version strings for dependencies on |
| 681 /// hosted packages. | 747 /// hosted packages. |
| 682 void createLockFile(String package, {Iterable<String> sandbox, | 748 void createLockFile(String package, {Iterable<String> sandbox, |
| 683 Iterable<String> pkg, Map<String, String> hosted}) { | 749 Iterable<String> pkg, Map<String, String> hosted}) { |
| 750 var lockFile = _createLockFile(sandbox: sandbox, pkg: pkg, hosted: hosted); |
| 751 |
| 752 var sources = new SourceRegistry(); |
| 753 sources.register(new HostedSource()); |
| 754 sources.register(new PathSource()); |
| 755 |
| 756 d.file(path.join(package, 'pubspec.lock'), |
| 757 lockFile.serialize(null, sources)).create(); |
| 758 } |
| 759 |
| 760 /// Creates a lock file for [package] without running `pub get`. |
| 761 /// |
| 762 /// [sandbox] is a list of path dependencies to be found in the sandbox |
| 763 /// directory. [pkg] is a list of packages in the Dart repo's "pkg" directory; |
| 764 /// each package listed here and all its dependencies will be linked to the |
| 765 /// version in the Dart repo. |
| 766 /// |
| 767 /// [hosted] is a list of package names to version strings for dependencies on |
| 768 /// hosted packages. |
| 769 LockFile _createLockFile({Iterable<String> sandbox, |
| 770 Iterable<String> pkg, Map<String, String> hosted}) { |
| 684 var dependencies = {}; | 771 var dependencies = {}; |
| 685 | 772 |
| 686 if (sandbox != null) { | 773 if (sandbox != null) { |
| 687 for (var package in sandbox) { | 774 for (var package in sandbox) { |
| 688 dependencies[package] = '../$package'; | 775 dependencies[package] = '../$package'; |
| 689 } | 776 } |
| 690 } | 777 } |
| 691 | 778 |
| 692 if (pkg != null) { | 779 if (pkg != null) { |
| 693 _addPackage(String package) { | 780 _addPackage(String package) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 725 lockFile.packages[name] = id; | 812 lockFile.packages[name] = id; |
| 726 }); | 813 }); |
| 727 | 814 |
| 728 if (hosted != null) { | 815 if (hosted != null) { |
| 729 hosted.forEach((name, version) { | 816 hosted.forEach((name, version) { |
| 730 var id = new PackageId(name, 'hosted', new Version.parse(version), name); | 817 var id = new PackageId(name, 'hosted', new Version.parse(version), name); |
| 731 lockFile.packages[name] = id; | 818 lockFile.packages[name] = id; |
| 732 }); | 819 }); |
| 733 } | 820 } |
| 734 | 821 |
| 735 var sources = new SourceRegistry(); | 822 return lockFile; |
| 736 sources.register(new HostedSource()); | |
| 737 sources.register(new PathSource()); | |
| 738 | |
| 739 d.file(path.join(package, 'pubspec.lock'), | |
| 740 lockFile.serialize(null, sources)).create(); | |
| 741 } | 823 } |
| 742 | 824 |
| 743 /// Uses [client] as the mock HTTP client for this test. | 825 /// Uses [client] as the mock HTTP client for this test. |
| 744 /// | 826 /// |
| 745 /// Note that this will only affect HTTP requests made via http.dart in the | 827 /// Note that this will only affect HTTP requests made via http.dart in the |
| 746 /// parent process. | 828 /// parent process. |
| 747 void useMockClient(MockClient client) { | 829 void useMockClient(MockClient client) { |
| 748 var oldInnerClient = httpClient.inner; | 830 var oldInnerClient = httpClient.inner; |
| 749 httpClient.inner = client; | 831 httpClient.inner = client; |
| 750 currentSchedule.onComplete.schedule(() { | 832 currentSchedule.onComplete.schedule(() { |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 _lastMatcher.matches(item.last, matchState); | 1004 _lastMatcher.matches(item.last, matchState); |
| 923 } | 1005 } |
| 924 | 1006 |
| 925 Description describe(Description description) { | 1007 Description describe(Description description) { |
| 926 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); | 1008 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); |
| 927 } | 1009 } |
| 928 } | 1010 } |
| 929 | 1011 |
| 930 /// A [StreamMatcher] that matches multiple lines of output. | 1012 /// A [StreamMatcher] that matches multiple lines of output. |
| 931 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); | 1013 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); |
| OLD | NEW |