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

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

Issue 10874039: Use ephemeral ports for serving stuff during the pub tests. (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 */
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 * Creates a new [TarFileDescriptor] with [name] and [contents]. 53 * Creates a new [TarFileDescriptor] with [name] and [contents].
54 */ 54 */
55 TarFileDescriptor tar(Pattern name, [List<Descriptor> contents]) => 55 TarFileDescriptor tar(Pattern name, [List<Descriptor> contents]) =>
56 new TarFileDescriptor(name, contents); 56 new TarFileDescriptor(name, contents);
57 57
58 /** 58 /**
59 * The current [HttpServer] created using [serve]. 59 * The current [HttpServer] created using [serve].
60 */ 60 */
61 var _server; 61 var _server;
62 62
63 /** The cached value for [_portCompleter]. */
64 Completer<int> _portCompleterCache;
65
66 /** The completer for [port]. */
67 Completer<int> get _portCompleter() {
Bob Nystrom 2012/08/23 21:49:13 New getter syntax. :)
nweiz 2012/08/23 22:25:49 Done.
68 if (_portCompleterCache != null) return _portCompleterCache;
69 _portCompleterCache = new Completer<int>();
70 _scheduleCleanup((_) {
71 _portCompleterCache = null;
72 });
73 return _portCompleterCache;
74 }
75
76 /**
77 * A future that will complete to the port used for the current server.
78 */
79 Future<int> get port() => _portCompleter.future;
80
63 /** 81 /**
64 * Creates an HTTP server to serve [contents] as static files. This server will 82 * Creates an HTTP server to serve [contents] as static files. This server will
65 * exist only for the duration of the pub run. 83 * exist only for the duration of the pub run.
66 * 84 *
67 * Subsequent calls to [serve] will replace the previous server. 85 * Subsequent calls to [serve] will replace the previous server.
68 */ 86 */
69 void serve(String host, int port, [List<Descriptor> contents]) { 87 void serve([List<Descriptor> contents]) {
70 var baseDir = dir("serve-dir", contents); 88 var baseDir = dir("serve-dir", contents);
71 if (host == 'localhost') {
72 host = '127.0.0.1';
73 }
74 89
75 _schedule((_) { 90 _schedule((_) {
76 _closeServer().transform((_) { 91 _closeServer().transform((resolvedPort) {
77 _server = new HttpServer(); 92 _server = new HttpServer();
78 _server.defaultRequestHandler = (request, response) { 93 _server.defaultRequestHandler = (request, response) {
79 var path = request.uri.replaceFirst("/", "").split("/"); 94 var path = request.uri.replaceFirst("/", "").split("/");
80 response.persistentConnection = false; 95 response.persistentConnection = false;
81 var stream; 96 var stream;
82 try { 97 try {
83 stream = baseDir.load(path); 98 stream = baseDir.load(path);
84 } catch (var e) { 99 } catch (var e) {
85 response.statusCode = 404; 100 response.statusCode = 404;
86 response.contentLength = 0; 101 response.contentLength = 0;
87 response.outputStream.close(); 102 response.outputStream.close();
88 return; 103 return;
89 } 104 }
90 105
91 var future = consumeInputStream(stream); 106 var future = consumeInputStream(stream);
92 future.then((data) { 107 future.then((data) {
93 response.statusCode = 200; 108 response.statusCode = 200;
94 response.contentLength = data.length; 109 response.contentLength = data.length;
95 response.outputStream.write(data); 110 response.outputStream.write(data);
96 response.outputStream.close(); 111 response.outputStream.close();
97 }); 112 });
98 113
99 future.handleException((e) { 114 future.handleException((e) {
100 print("Exception while handling ${request.uri}: $e"); 115 print("Exception while handling ${request.uri}: $e");
101 response.statusCode = 500; 116 response.statusCode = 500;
102 response.reasonPhrase = e.message; 117 response.reasonPhrase = e.message;
103 response.outputStream.close(); 118 response.outputStream.close();
104 }); 119 });
105 }; 120 };
106 _server.listen(host, port); 121 _server.listen("127.0.0.1", 0);
122 _portCompleter.complete(_server.port);
107 _scheduleCleanup((_) => _closeServer()); 123 _scheduleCleanup((_) => _closeServer());
108 return null; 124 return null;
109 }); 125 });
110 }); 126 });
111 } 127 }
112 128
113 /** 129 /**
114 * Closes [_server]. Returns a [Future] that will complete after the [_server] 130 * Closes [_server]. Returns a [Future] that will complete after the [_server]
115 * is closed. 131 * is closed.
116 */ 132 */
117 Future _closeServer() { 133 Future _closeServer() {
118 if (_server == null) return new Future.immediate(null); 134 if (_server == null) return new Future.immediate(null);
119 _server.close(); 135 _server.close();
120 _server = null; 136 _server = null;
137 _portCompleterCache = null;
121 // TODO(nweiz): Remove this once issue 4155 is fixed. Pumping the event loop 138 // 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 139 // *seems* to be enough to ensure that the server is actually closed, but I'm
123 // putting this at 10ms to be safe. 140 // putting this at 10ms to be safe.
124 return sleep(10); 141 return sleep(10);
125 } 142 }
126 143
127 /** 144 /**
145 * The [DirectoryDescriptor] describing the server layout of packages that are
146 * being served via [servePackages]. This is `null` if [servePackages] has not
147 * yet been called for this test.
148 */
149 DirectoryDescriptor _servedPackageDir;
150
151 /**
152 * A map from package names to version numbers to YAML-serialized pubspecs for
153 * those packagesk. This represents the packages currently being served by
Bob Nystrom 2012/08/23 21:49:13 "packagesk" -> "packages".
nweiz 2012/08/23 22:25:49 Done.
154 * [servePackages], and is `null` if [servePackages] has not yet been called for
155 * this test.
156 */
157 Map<String, Map<String, String>> _servedPackages;
158
159 /**
128 * Creates an HTTP server that replicates the structure of pub.dartlang.org. 160 * Creates an HTTP server that replicates the structure of pub.dartlang.org.
129 * [pubspecs] is a list of unserialized pubspecs representing the packages to 161 * [pubspecs] is a list of unserialized pubspecs representing the packages to
130 * serve. 162 * serve.
163 *
164 * Subsequent calls to [servePackages] will add to the set of packages that are
165 * being served. Previous packages will continue to be served.
131 */ 166 */
132 void servePackages(String host, int port, List<Map> pubspecs) { 167 void servePackages(List<Map> pubspecs) {
133 var packages = <String, Map<String, String>>{}; 168 if (_servedPackages == null || _servedPackageDir) {
134 for (var spec in pubspecs) { 169 _servedPackages = <String, Map<String, String>>{};
135 var name = spec['name']; 170 _servedPackageDir = dir('packages', []);
136 var version = spec['version']; 171 serve([_servedPackageDir]);
137 packages.putIfAbsent(name, () => <String, String>{})[version] = yaml(spec); 172
173 _scheduleCleanup((_) {
174 _servedPackages = null;
175 _servedPackageDir = null;
176 });
138 } 177 }
139 178
140 serve(host, port, [ 179 _schedule((_) {
141 dir('packages', flatten(packages.getKeys().map((name) { 180 return Futures.wait(pubspecs.map(_awaitObject))
Bob Nystrom 2012/08/23 21:49:13 Can you just do _awaitObject(pubspects)?
nweiz 2012/08/23 22:25:49 Done.
142 return [ 181 .transform((resolvedPubspecs) {
143 file('$name.json', 182 for (var spec in resolvedPubspecs) {
144 JSON.stringify({'versions': packages[name].getKeys()})), 183 var name = spec['name'];
145 dir(name, [ 184 var version = spec['version'];
146 dir('versions', flatten(packages[name].getKeys().map((version) { 185 var versions = _servedPackages.putIfAbsent(name, () => <String, String>{ });
Bob Nystrom 2012/08/23 21:49:13 Long line.
nweiz 2012/08/23 22:25:49 Done.
147 return [ 186 versions[version] = yaml(spec);
148 file('$version.yaml', packages[name][version]), 187 }
149 tar('$version.tar.gz', [ 188
150 file('pubspec.yaml', packages[name][version]), 189 _servedPackageDir.contents.clear();
151 file('$name.dart', 'main() => print("$name $version");') 190 for (var name in _servedPackages.getKeys()) {
152 ]) 191 _servedPackageDir.contents.addAll([
153 ]; 192 file('$name.json',
154 }))) 193 JSON.stringify({'versions': _servedPackages[name].getKeys()})),
Bob Nystrom 2012/08/23 21:49:13 +2
nweiz 2012/08/23 22:25:49 Done.
155 ]) 194 dir(name, [
156 ]; 195 dir('versions', flatten(_servedPackages[name].getKeys().map((version ) {
Bob Nystrom 2012/08/23 21:49:13 Lone line.
nweiz 2012/08/23 22:25:49 Done.
157 }))) 196 return [
158 ]); 197 file('$version.yaml', _servedPackages[name][version]),
198 tar('$version.tar.gz', [
199 file('pubspec.yaml', _servedPackages[name][version]),
200 file('$name.dart', 'main() => print("$name $version");')
201 ])
202 ];
203 })))
204 ])
205 ]);
206 }
207 });
208 });
159 } 209 }
160 210
161 /** Converts [value] into a YAML string. */ 211 /** Converts [value] into a YAML string. */
162 String yaml(value) => JSON.stringify(value); 212 String yaml(value) => JSON.stringify(value);
163 213
164 /** 214 /**
165 * Describes a file named `pubspec.yaml` with the given YAML-serialized 215 * Describes a file named `pubspec.yaml` with the given YAML-serialized
166 * [contents], which should be a serializable object. 216 * [contents], which should be a serializable object.
167 * 217 *
168 * [contents] may contain [Future]s that resolve to serializable objects, which 218 * [contents] may contain [Future]s that resolve to serializable objects, which
(...skipping 28 matching lines...) Expand all
197 package["dependencies"] = _dependencyListToMap(dependencies); 247 package["dependencies"] = _dependencyListToMap(dependencies);
198 } 248 }
199 return package; 249 return package;
200 } 250 }
201 251
202 /** 252 /**
203 * Describes a map representing a dependency on a package in the package 253 * Describes a map representing a dependency on a package in the package
204 * repository. 254 * repository.
205 */ 255 */
206 Map dependency(String name, [String versionConstraint]) { 256 Map dependency(String name, [String versionConstraint]) {
207 var dependency = {"repo": {"name": name, "url": "http://localhost:3123"}}; 257 var url = port.transform((p) => "http://localhost:$p");
258 var dependency = {"repo": {"name": name, "url": url}};
208 if (versionConstraint != null) dependency["version"] = versionConstraint; 259 if (versionConstraint != null) dependency["version"] = versionConstraint;
209 return dependency; 260 return dependency;
210 } 261 }
211 262
212 /** 263 /**
213 * Describes a directory for a package installed from the mock package repo. 264 * Describes a directory for a package installed from the mock package repo.
214 * This directory is of the form found in the `packages/` directory. 265 * This directory is of the form found in the `packages/` directory.
215 */ 266 */
216 DirectoryDescriptor packageDir(String name, String version) { 267 DirectoryDescriptor packageDir(String name, String version) {
217 return dir(name, [ 268 return dir(name, [
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 */ 315 */
265 DirectoryDescriptor cacheDir(Map packages) { 316 DirectoryDescriptor cacheDir(Map packages) {
266 var contents = <Map>[]; 317 var contents = <Map>[];
267 packages.forEach((name, versions) { 318 packages.forEach((name, versions) {
268 if (versions is! List) versions = [versions]; 319 if (versions is! List) versions = [versions];
269 for (var version in versions) { 320 for (var version in versions) {
270 contents.add(packageCacheDir(name, version)); 321 contents.add(packageCacheDir(name, version));
271 } 322 }
272 }); 323 });
273 return dir(cachePath, [ 324 return dir(cachePath, [
274 dir('repo', [dir('localhost%583123', contents)]) 325 dir('repo', [
326 async(port.transform((p) => dir('localhost%58$p', contents)))
327 ])
275 ]); 328 ]);
276 } 329 }
277 330
278 /** 331 /**
279 * Describes the application directory, containing only a pubspec specifying the 332 * Describes the application directory, containing only a pubspec specifying the
280 * given [dependencies]. 333 * given [dependencies].
281 */ 334 */
282 DirectoryDescriptor appDir(List dependencies) => 335 DirectoryDescriptor appDir(List dependencies) =>
283 dir(appPath, [appPubspec(dependencies)]); 336 dir(appPath, [appPubspec(dependencies)]);
284 337
(...skipping 698 matching lines...) Expand 10 before | Expand all | Expand 10 after
983 } 1036 }
984 1037
985 /** 1038 /**
986 * Schedules a callback to be called after Pub is run with [runPub], even if it 1039 * Schedules a callback to be called after Pub is run with [runPub], even if it
987 * fails. 1040 * fails.
988 */ 1041 */
989 void _scheduleCleanup(_ScheduledEvent event) { 1042 void _scheduleCleanup(_ScheduledEvent event) {
990 if (_scheduledCleanup == null) _scheduledCleanup = []; 1043 if (_scheduledCleanup == null) _scheduledCleanup = [];
991 _scheduledCleanup.add(event); 1044 _scheduledCleanup.add(event);
992 } 1045 }
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