Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: utils/tests/pub/test_pub.dart

Issue 10873051: Reverting 11261 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « utils/tests/pub/pub_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 */
11 #library('test_pub'); 11 #library('test_pub');
12 12
13 #import('dart:io'); 13 #import('dart:io');
14 #import('dart:isolate'); 14 #import('dart:isolate');
15 #import('dart:json'); 15 #import('dart:json');
16 #import('dart:math'); 16 #import('dart:math');
17 #import('dart:uri'); 17 #import('dart:uri');
18 18
19 #import('../../../pkg/unittest/unittest.dart'); 19 #import('../../../pkg/unittest/unittest.dart');
20 #import('../../lib/file_system.dart', prefix: 'fs'); 20 #import('../../lib/file_system.dart', prefix: 'fs');
21 #import('../../pub/git_source.dart');
22 #import('../../pub/io.dart'); 21 #import('../../pub/io.dart');
23 #import('../../pub/repo_source.dart');
24 #import('../../pub/sdk_source.dart');
25 #import('../../pub/utils.dart'); 22 #import('../../pub/utils.dart');
26 #import('../../pub/yaml/yaml.dart'); 23 #import('../../pub/yaml/yaml.dart');
27 24
28 /** 25 /**
29 * Creates a new [FileDescriptor] with [name] and [contents]. 26 * Creates a new [FileDescriptor] with [name] and [contents].
30 */ 27 */
31 FileDescriptor file(Pattern name, String contents) => 28 FileDescriptor file(Pattern name, String contents) =>
32 new FileDescriptor(name, contents); 29 new FileDescriptor(name, contents);
33 30
34 /** 31 /**
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 _server.close(); 116 _server.close();
120 _server = null; 117 _server = null;
121 // TODO(nweiz): Remove this once issue 4155 is fixed. Pumping the event loop 118 // TODO(nweiz): Remove this once issue 4155 is fixed. Pumping the event loop
122 // *seems* to be enough to ensure that the server is actually closed, but I'm 119 // *seems* to be enough to ensure that the server is actually closed, but I'm
123 // putting this at 10ms to be safe. 120 // putting this at 10ms to be safe.
124 return sleep(10); 121 return sleep(10);
125 } 122 }
126 123
127 /** 124 /**
128 * Creates an HTTP server that replicates the structure of pub.dartlang.org. 125 * Creates an HTTP server that replicates the structure of pub.dartlang.org.
129 * [pubspecs] is a list of unserialized pubspecs representing the packages to 126 * [pubspecs] is a list of YAML-format pubspecs representing the packages to
130 * serve. 127 * serve.
131 */ 128 */
132 void servePackages(String host, int port, List<Map> pubspecs) { 129 void servePackages(String host, int port, List<String> pubspecs) {
133 var packages = <String, Map<String, String>>{}; 130 var packages = <String, Map<String, String>>{};
134 for (var spec in pubspecs) { 131 pubspecs.forEach((spec) {
135 var name = spec['name']; 132 var parsed = loadYaml(spec);
136 var version = spec['version']; 133 var name = parsed['name'];
137 packages.putIfAbsent(name, () => <String, String>{})[version] = yaml(spec); 134 var version = parsed['version'];
138 } 135 packages.putIfAbsent(name, () => <String, String>{})[version] = spec;
136 });
139 137
140 serve(host, port, [ 138 serve(host, port, [
141 dir('packages', flatten(packages.getKeys().map((name) { 139 dir('packages', flatten(packages.getKeys().map((name) {
142 return [ 140 return [
143 file('$name.json', 141 file('$name.json',
144 JSON.stringify({'versions': packages[name].getKeys()})), 142 JSON.stringify({'versions': packages[name].getKeys()})),
145 dir(name, [ 143 dir(name, [
146 dir('versions', flatten(packages[name].getKeys().map((version) { 144 dir('versions', flatten(packages[name].getKeys().map((version) {
147 return [ 145 return [
148 file('$version.yaml', packages[name][version]), 146 file('$version.yaml', packages[name][version]),
149 tar('$version.tar.gz', [ 147 tar('$version.tar.gz', [
150 file('pubspec.yaml', packages[name][version]), 148 file('pubspec.yaml', packages[name][version]),
151 file('$name.dart', 'main() => print("$name $version");') 149 file('$name.dart', 'main() => print("$name $version");')
152 ]) 150 ])
153 ]; 151 ];
154 }))) 152 })))
155 ]) 153 ])
156 ]; 154 ];
157 }))) 155 })))
158 ]); 156 ]);
159 } 157 }
160 158
161 /** Converts [value] into a YAML string. */
162 String yaml(value) => JSON.stringify(value);
163
164 /**
165 * Describes a file named `pubspec.yaml` with the given YAML-serialized
166 * [contents], which should be a serializable object.
167 *
168 * [contents] may contain [Future]s that resolve to serializable objects, which
169 * may in turn contain [Future]s recursively.
170 */
171 Descriptor pubspec(Map contents) {
172 return async(_awaitObject(contents).transform((resolvedContents) =>
173 file("pubspec.yaml", yaml(resolvedContents))));
174 }
175
176 /**
177 * Describes a file named `pubspec.yaml` for an application package with the
178 * given [dependencies].
179 */
180 Descriptor appPubspec(List dependencies) =>
181 pubspec({"dependencies": _dependencyListToMap(dependencies)});
182
183 /**
184 * Describes a file named `pubspec.yaml` for a library package with the given
185 * [name], [version], and [dependencies].
186 */
187 Descriptor libPubspec(String name, String version, [List dependencies]) =>
188 pubspec(package(name, version, dependencies));
189
190 /**
191 * Describes a map representing a library package with the given [name],
192 * [version], and [dependencies].
193 */
194 Map package(String name, String version, [List dependencies]) {
195 var package = {"name": name, "version": version};
196 if (dependencies != null) {
197 package["dependencies"] = _dependencyListToMap(dependencies);
198 }
199 return package;
200 }
201
202 /**
203 * Describes a map representing a dependency on a package in the package
204 * repository.
205 */
206 Map dependency(String name, [String versionConstraint]) {
207 var dependency = {"repo": {"name": name, "url": "http://localhost:3123"}};
208 if (versionConstraint != null) dependency["version"] = versionConstraint;
209 return dependency;
210 }
211
212 /**
213 * Describes a directory for a package installed from the mock package repo.
214 * This directory is of the form found in the `packages/` directory.
215 */
216 DirectoryDescriptor packageDir(String name, String version) {
217 return dir(name, [
218 file("$name.dart", 'main() => print("$name $version");')
219 ]);
220 }
221
222 /**
223 * Describes a directory for a package installed from the mock package server.
224 * This directory is of the form found in the global package cache.
225 */
226 DirectoryDescriptor packageCacheDir(String name, String version) {
227 return dir("$name-$version", [
228 file("$name.dart", 'main() => print("$name $version");')
229 ]);
230 }
231
232 /**
233 * Describes a directory for a Git package. This directory is of the form found
234 * in the global package cache.
235 */
236 DirectoryDescriptor gitPackageCacheDir(String name, [int modifier]) {
237 var value = name;
238 if (modifier != null) value = "$name $modifier";
239 return dir(new RegExp("$name${@'-[a-f0-9]+'}"), [
240 file('$name.dart', 'main() => "$value";')
241 ]);
242 }
243
244 /**
245 * Describes the `packages/` directory containing all the given [packages],
246 * which should be name/version pairs. The packages will be validated against
247 * the format produced by the mock package server.
248 */
249 DirectoryDescriptor packagesDir(Map<String, String> packages) {
250 var contents = <Map>[];
251 packages.forEach((name, version) {
252 contents.add(packageDir(name, version));
253 });
254 return dir(packagesPath, contents);
255 }
256
257 /**
258 * Describes the global package cache directory containing all the given
259 * [packages], which should be name/version pairs. The packages will be
260 * validated against the format produced by the mock package server.
261 *
262 * A package's value may also be a list of versions, in which case all versions
263 * are expected to be installed.
264 */
265 DirectoryDescriptor cacheDir(Map packages) {
266 var contents = <Map>[];
267 packages.forEach((name, versions) {
268 if (versions is! List) versions = [versions];
269 for (var version in versions) {
270 contents.add(packageCacheDir(name, version));
271 }
272 });
273 return dir(cachePath, [
274 dir('repo', [dir('localhost%583123', contents)])
275 ]);
276 }
277
278 /**
279 * Describes the application directory, containing only a pubspec specifying the
280 * given [dependencies].
281 */
282 DirectoryDescriptor appDir(List dependencies) =>
283 dir(appPath, [appPubspec(dependencies)]);
284
285 /**
286 * Converts a list of dependencies as passed to [package] into a hash as used in
287 * a pubspec.
288 */
289 Map _dependencyListToMap(List<Map> dependencies) {
290 var result = <String, Map>{};
291 dependencies.map((dependency) {
292 var sourceName = only(dependency.getKeys());
293 var source;
294 switch (sourceName) {
295 case "git":
296 source = new GitSource();
297 break;
298 case "repo":
299 source = new RepoSource();
300 break;
301 case "sdk":
302 source = new SdkSource('');
303 break;
304 default:
305 throw 'Unknown source "$sourceName"';
306 }
307
308 result[source.packageName(dependency[sourceName])] = dependency;
309 });
310 return result;
311 }
312
313 /** 159 /**
314 * The path of the package cache directory used for tests. Relative to the 160 * The path of the package cache directory used for tests. Relative to the
315 * sandbox directory. 161 * sandbox directory.
316 */ 162 */
317 final String cachePath = "cache"; 163 final String cachePath = "cache";
318 164
319 /** 165 /**
320 * The path of the mock SDK directory used for tests. Relative to the sandbox 166 * The path of the mock SDK directory used for tests. Relative to the sandbox
321 * directory. 167 * directory.
322 */ 168 */
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 */ 578 */
733 final List<Descriptor> contents; 579 final List<Descriptor> contents;
734 580
735 DirectoryDescriptor(Pattern name, this.contents) : super(name); 581 DirectoryDescriptor(Pattern name, this.contents) : super(name);
736 582
737 /** 583 /**
738 * Creates the file within [dir]. Returns a [Future] that is completed after 584 * Creates the file within [dir]. Returns a [Future] that is completed after
739 * the creation is done. 585 * the creation is done.
740 */ 586 */
741 Future<Directory> create(parentDir) { 587 Future<Directory> create(parentDir) {
588 final completer = new Completer<Directory>();
589
742 // Create the directory. 590 // Create the directory.
743 return ensureDir(join(parentDir, _stringName)).chain((dir) { 591 ensureDir(join(parentDir, _stringName)).then((dir) {
744 if (contents == null) return new Future<Directory>.immediate(dir); 592 if (contents == null) {
593 completer.complete(dir);
594 } else {
595 // Recursively create all of its children.
596 final childFutures = contents.map((child) => child.create(dir));
597 Futures.wait(childFutures).then((_) {
598 // Only complete once all of the children have been created too.
599 completer.complete(dir);
600 });
601 }
602 });
745 603
746 // Recursively create all of its children. 604 return completer.future;
747 final childFutures = contents.map((child) => child.create(dir));
748 // Only complete once all of the children have been created too.
749 return Futures.wait(childFutures).transform((_) => dir);
750 });
751 } 605 }
752 606
753 /** 607 /**
754 * Deletes the directory within [dir]. Returns a [Future] that is completed 608 * Deletes the directory within [dir]. Returns a [Future] that is completed
755 * after the deletion is done. 609 * after the deletion is done.
756 */ 610 */
757 Future delete(dir) { 611 Future delete(dir) {
758 return deleteDir(join(dir, _stringName)); 612 return deleteDir(join(dir, _stringName));
759 } 613 }
760 614
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 }).then((tar) { 797 }).then((tar) {
944 var sourceStream = tar.openInputStream(); 798 var sourceStream = tar.openInputStream();
945 pipeInputToInput( 799 pipeInputToInput(
946 sourceStream, sinkStream, onClosed: tempDir.deleteRecursively); 800 sourceStream, sinkStream, onClosed: tempDir.deleteRecursively);
947 }); 801 });
948 return sinkStream; 802 return sinkStream;
949 } 803 }
950 } 804 }
951 805
952 /** 806 /**
953 * Takes a simple data structure (composed of [Map]s, [List]s, scalar objects,
954 * and [Future]s) and recursively resolves all the [Future]s contained within.
955 * Completes with the fully resolved structure.
956 */
957 Future _awaitObject(object) {
958 // Unroll nested futures.
959 if (object is Future) return object.chain(_awaitObject);
960 if (object is Collection) return Futures.wait(object.map(_awaitObject));
961 if (object is! Map) return new Future.immediate(object);
962
963 var pairs = <Future<Pair>>[];
964 object.forEach((key, value) {
965 pairs.add(_awaitObject(value)
966 .transform((resolved) => new Pair(key, resolved)));
967 });
968 return Futures.wait(pairs).transform((resolvedPairs) {
969 var map = {};
970 for (var pair in resolvedPairs) {
971 map[pair.first] = pair.last;
972 }
973 return map;
974 });
975 }
976
977 /**
978 * Schedules a callback to be called as part of the test case. 807 * Schedules a callback to be called as part of the test case.
979 */ 808 */
980 void _schedule(_ScheduledEvent event) { 809 void _schedule(_ScheduledEvent event) {
981 if (_scheduled == null) _scheduled = []; 810 if (_scheduled == null) _scheduled = [];
982 _scheduled.add(event); 811 _scheduled.add(event);
983 } 812 }
984 813
985 /** 814 /**
986 * Schedules a callback to be called after Pub is run with [runPub], even if it 815 * Schedules a callback to be called after Pub is run with [runPub], even if it
987 * fails. 816 * fails.
988 */ 817 */
989 void _scheduleCleanup(_ScheduledEvent event) { 818 void _scheduleCleanup(_ScheduledEvent event) {
990 if (_scheduledCleanup == null) _scheduledCleanup = []; 819 if (_scheduledCleanup == null) _scheduledCleanup = [];
991 _scheduledCleanup.add(event); 820 _scheduledCleanup.add(event);
992 } 821 }
OLDNEW
« no previous file with comments | « utils/tests/pub/pub_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698