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 27 matching lines...) Expand all Loading... |
38 import '../lib/src/package.dart'; | 38 import '../lib/src/package.dart'; |
39 import '../lib/src/pubspec.dart'; | 39 import '../lib/src/pubspec.dart'; |
40 import '../lib/src/source/hosted.dart'; | 40 import '../lib/src/source/hosted.dart'; |
41 import '../lib/src/source/path.dart'; | 41 import '../lib/src/source/path.dart'; |
42 import '../lib/src/source_registry.dart'; | 42 import '../lib/src/source_registry.dart'; |
43 import '../lib/src/system_cache.dart'; | 43 import '../lib/src/system_cache.dart'; |
44 import '../lib/src/utils.dart'; | 44 import '../lib/src/utils.dart'; |
45 import '../lib/src/validator.dart'; | 45 import '../lib/src/validator.dart'; |
46 import '../lib/src/version.dart'; | 46 import '../lib/src/version.dart'; |
47 import 'descriptor.dart' as d; | 47 import 'descriptor.dart' as d; |
| 48 import 'serve_packages.dart'; |
| 49 |
| 50 export 'serve_packages.dart'; |
48 | 51 |
49 /// This should be called at the top of a test file to set up an appropriate | 52 /// This should be called at the top of a test file to set up an appropriate |
50 /// test configuration for the machine running the tests. | 53 /// test configuration for the machine running the tests. |
51 initConfig() { | 54 initConfig() { |
52 useCompactVMConfiguration(); | 55 useCompactVMConfiguration(); |
53 filterStacks = true; | 56 filterStacks = true; |
54 unittestConfiguration.timeout = null; | 57 unittestConfiguration.timeout = null; |
55 } | 58 } |
56 | 59 |
57 /// The current [HttpServer] created using [serve]. | 60 /// The current [HttpServer] created using [serve]. |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 var future = _server.close(); | 218 var future = _server.close(); |
216 _server = null; | 219 _server = null; |
217 _hasServer = false; | 220 _hasServer = false; |
218 _portCompleterCache = null; | 221 _portCompleterCache = null; |
219 return future; | 222 return future; |
220 } | 223 } |
221 | 224 |
222 /// `true` if the current test spins up an HTTP server. | 225 /// `true` if the current test spins up an HTTP server. |
223 bool _hasServer = false; | 226 bool _hasServer = false; |
224 | 227 |
225 /// The [d.DirectoryDescriptor] describing the server layout of `/api/packages` | |
226 /// on the test server. | |
227 /// | |
228 /// This contains metadata for packages that are being served via | |
229 /// [servePackages]. It's `null` if [servePackages] has not yet been called for | |
230 /// this test. | |
231 d.DirectoryDescriptor _servedApiPackageDir; | |
232 | |
233 /// The [d.DirectoryDescriptor] describing the server layout of `/packages` on | |
234 /// the test server. | |
235 /// | |
236 /// This contains the tarballs for packages that are being served via | |
237 /// [servePackages]. It's `null` if [servePackages] has not yet been called for | |
238 /// this test. | |
239 d.DirectoryDescriptor _servedPackageDir; | |
240 | |
241 /// A map from package names to parsed pubspec maps for those packages. | |
242 /// | |
243 /// This represents the packages currently being served by [servePackages], and | |
244 /// is `null` if [servePackages] has not yet been called for this test. | |
245 Map<String, List<Map>> _servedPackages; | |
246 | |
247 /// Creates an HTTP server that replicates the structure of pub.dartlang.org. | |
248 /// | |
249 /// [pubspecs] is a list of unserialized pubspecs representing the packages to | |
250 /// serve. | |
251 /// | |
252 /// If [replace] is false, subsequent calls to [servePackages] will add to the | |
253 /// set of packages that are being served. Previous packages will continue to be | |
254 /// served. Otherwise, the previous packages will no longer be served. | |
255 /// | |
256 /// If [contents] is given, its contents are added to every served | |
257 /// package. | |
258 /// | |
259 /// If [serveBarback] is true, the repo versions of barback and its dependencies | |
260 /// will be served as well. | |
261 void servePackages(List<Map> pubspecs, {bool replace: false, | |
262 Iterable<d.Descriptor> contents, bool serveBarback: false}) { | |
263 if (_servedPackages == null || _servedPackageDir == null) { | |
264 _servedPackages = <String, List<Map>>{}; | |
265 _servedApiPackageDir = d.dir('packages', []); | |
266 _servedPackageDir = d.dir('packages', []); | |
267 serve([ | |
268 d.dir('api', [_servedApiPackageDir]), | |
269 _servedPackageDir | |
270 ]); | |
271 | |
272 currentSchedule.onComplete.schedule(() { | |
273 _servedPackages = null; | |
274 _servedApiPackageDir = null; | |
275 _servedPackageDir = null; | |
276 }, 'cleaning up served packages'); | |
277 } | |
278 | |
279 schedule(() { | |
280 return awaitObject(pubspecs).then((resolvedPubspecs) { | |
281 if (replace) _servedPackages.clear(); | |
282 | |
283 for (var pubspec in resolvedPubspecs) { | |
284 var name = pubspec['name']; | |
285 var version = pubspec['version']; | |
286 var versions = _servedPackages.putIfAbsent(name, () => []); | |
287 versions.add(pubspec); | |
288 } | |
289 | |
290 var repoPackages = new Set(); | |
291 if (serveBarback) { | |
292 _addPackage(name) { | |
293 if (_servedPackages.containsKey(name)) return; | |
294 repoPackages.add(name); | |
295 | |
296 var pubspec = new Map.from(loadYaml( | |
297 readTextFile(path.join(repoRoot, 'pkg', name, 'pubspec.yaml')))); | |
298 | |
299 // Remove any SDK constraints since we don't have a valid SDK version | |
300 // while testing. | |
301 pubspec.remove('environment'); | |
302 | |
303 _servedPackages[name] = [pubspec]; | |
304 if (pubspec.containsKey('dependencies')) { | |
305 pubspec['dependencies'].keys.forEach(_addPackage); | |
306 } | |
307 } | |
308 | |
309 _addPackage('barback'); | |
310 } | |
311 | |
312 _servedApiPackageDir.contents.clear(); | |
313 _servedPackageDir.contents.clear(); | |
314 for (var name in _servedPackages.keys) { | |
315 _servedApiPackageDir.contents.addAll([ | |
316 d.file('$name', JSON.encode({ | |
317 'name': name, | |
318 'uploaders': ['nweiz@google.com'], | |
319 'versions': _servedPackages[name].map(packageVersionApiMap).toList() | |
320 })), | |
321 d.dir(name, [ | |
322 d.dir('versions', _servedPackages[name].map((pubspec) { | |
323 return d.file(pubspec['version'], JSON.encode( | |
324 packageVersionApiMap(pubspec, full: true))); | |
325 })) | |
326 ]) | |
327 ]); | |
328 | |
329 _servedPackageDir.contents.add(d.dir(name, [ | |
330 d.dir('versions', _servedPackages[name].map((pubspec) { | |
331 var version = pubspec['version']; | |
332 | |
333 if (repoPackages.contains(name)) { | |
334 return d.tar('$version.tar.gz', [ | |
335 d.file('pubspec.yaml', JSON.encode(pubspec)), | |
336 new d.DirectoryDescriptor.fromFilesystem('lib', | |
337 path.join(repoRoot, 'pkg', name, 'lib')) | |
338 ]); | |
339 } | |
340 | |
341 var archiveContents = [ | |
342 d.file('pubspec.yaml', JSON.encode(pubspec)), | |
343 d.libDir(name, '$name $version') | |
344 ]; | |
345 | |
346 if (contents != null) { | |
347 archiveContents.addAll(contents); | |
348 } | |
349 | |
350 return d.tar('$version.tar.gz', archiveContents); | |
351 })) | |
352 ])); | |
353 } | |
354 }); | |
355 }, 'initializing the package server'); | |
356 } | |
357 | |
358 /// Converts [value] into a YAML string. | 228 /// Converts [value] into a YAML string. |
359 String yaml(value) => JSON.encode(value); | 229 String yaml(value) => JSON.encode(value); |
360 | 230 |
361 /// The full path to the created sandbox directory for an integration test. | 231 /// The full path to the created sandbox directory for an integration test. |
362 String get sandboxDir => _sandboxDir; | 232 String get sandboxDir => _sandboxDir; |
363 String _sandboxDir; | 233 String _sandboxDir; |
364 | 234 |
365 /// The path to the Dart repo's packages. | 235 /// The path to the Dart repo's packages. |
366 final String pkgPath = path.absolute(path.join( | 236 final String pkgPath = path.absolute(path.join( |
367 path.dirname(Platform.executable), | 237 path.dirname(Platform.executable), |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 /// Schedules activating a global package [package] without running | 641 /// Schedules activating a global package [package] without running |
772 /// "pub global activate". | 642 /// "pub global activate". |
773 /// | 643 /// |
774 /// This is useful because global packages must be hosted, but the test hosted | 644 /// This is useful because global packages must be hosted, but the test hosted |
775 /// server doesn't serve barback. The other parameters here follow | 645 /// server doesn't serve barback. The other parameters here follow |
776 /// [createLockFile]. | 646 /// [createLockFile]. |
777 void makeGlobalPackage(String package, String version, | 647 void makeGlobalPackage(String package, String version, |
778 Iterable<d.Descriptor> contents, {Iterable<String> pkg, | 648 Iterable<d.Descriptor> contents, {Iterable<String> pkg, |
779 Map<String, String> hosted}) { | 649 Map<String, String> hosted}) { |
780 // Start the server so we know what port to use in the cache directory name. | 650 // Start the server so we know what port to use in the cache directory name. |
781 servePackages([]); | 651 serveNoPackages(); |
782 | 652 |
783 // Create the package in the hosted cache. | 653 // Create the package in the hosted cache. |
784 d.hostedCache([ | 654 d.hostedCache([ |
785 d.dir("$package-$version", contents) | 655 d.dir("$package-$version", contents) |
786 ]).create(); | 656 ]).create(); |
787 | 657 |
788 var lockFile = _createLockFile(pkg: pkg, hosted: hosted); | 658 var lockFile = _createLockFile(pkg: pkg, hosted: hosted); |
789 | 659 |
790 // Add the root package to the lockfile. | 660 // Add the root package to the lockfile. |
791 var id = new PackageId(package, "hosted", new Version.parse(version), | 661 var id = new PackageId(package, "hosted", new Version.parse(version), |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1073 _lastMatcher.matches(item.last, matchState); | 943 _lastMatcher.matches(item.last, matchState); |
1074 } | 944 } |
1075 | 945 |
1076 Description describe(Description description) { | 946 Description describe(Description description) { |
1077 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); | 947 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); |
1078 } | 948 } |
1079 } | 949 } |
1080 | 950 |
1081 /// A [StreamMatcher] that matches multiple lines of output. | 951 /// A [StreamMatcher] that matches multiple lines of output. |
1082 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); | 952 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); |
OLD | NEW |