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

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

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