Chromium Code Reviews

Side by Side Diff: test/must_pub_get_test.dart

Issue 1307853004: Improve the heuristics for "pub get" is needed. (Closed) Base URL: git@github.com:dart-lang/pub.git@master
Patch Set: Code review changes Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « lib/src/io.dart ('k') | test/test_pub.dart » ('j') | 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) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:convert'; 6 import 'dart:convert';
7 import 'dart:io';
7 8
8 import 'package:path/path.dart' as p; 9 import 'package:path/path.dart' as p;
9 import 'package:pub/src/exit_codes.dart' as exit_codes; 10 import 'package:pub/src/exit_codes.dart' as exit_codes;
10 import 'package:pub/src/io.dart'; 11 import 'package:pub/src/io.dart';
12 import 'package:scheduled_test/scheduled_stream.dart';
11 import 'package:scheduled_test/scheduled_test.dart'; 13 import 'package:scheduled_test/scheduled_test.dart';
12 14
13 import 'descriptor.dart' as d; 15 import 'descriptor.dart' as d;
14 import 'test_pub.dart'; 16 import 'test_pub.dart';
15 17
16 main() { 18 main() {
17 group("requires the user to run pub get first if", () { 19 setUp(() {
18 setUp(() { 20 servePackages((builder) {
19 d.dir(appPath, [ 21 builder.serve("foo", "1.0.0");
20 d.appPubspec(), 22 builder.serve("foo", "2.0.0");
21 d.dir("web", []),
22 d.dir("bin", [
23 d.file("script.dart", "main() => print('hello!');")
24 ])
25 ]).create();
26
27 pubGet();
28
29 // Delay a bit to make sure the modification times are noticeably
30 // different. 1s seems to be the finest granularity that dart:io reports.
31 schedule(() => new Future.delayed(new Duration(seconds: 1)));
32 }); 23 });
33 24
25 d.dir(appPath, [
26 d.appPubspec(),
27 d.dir("web", []),
28 d.dir("bin", [
29 d.file("script.dart", "main() => print('hello!');")
30 ])
31 ]).create();
32
33 pubGet();
34 });
35
36 group("requires the user to run pub get first if", () {
34 group("there's no lockfile", () { 37 group("there's no lockfile", () {
35 setUp(() { 38 setUp(() {
36 schedule(() => deleteEntry(p.join(sandboxDir, "myapp/pubspec.lock"))); 39 schedule(() => deleteEntry(p.join(sandboxDir, "myapp/pubspec.lock")));
37 }); 40 });
38 41
39 _forEveryCommand( 42 _requiresPubGet(
40 'No pubspec.lock file found, please run "pub get" first.'); 43 'No pubspec.lock file found, please run "pub get" first.');
41 }); 44 });
42 45
43 group("there's no package spec", () { 46 group("there's no package spec", () {
44 setUp(() { 47 setUp(() {
45 schedule(() => deleteEntry(p.join(sandboxDir, "myapp/.packages"))); 48 schedule(() => deleteEntry(p.join(sandboxDir, "myapp/.packages")));
46 }); 49 });
47 50
48 _forEveryCommand('No .packages file found, please run "pub get" first.'); 51 _requiresPubGet('No .packages file found, please run "pub get" first.');
49 }); 52 });
50 53
51 group("the pubspec is newer than the package spec", () { 54 group("the pubspec has a new dependency", () {
52 setUp(() { 55 setUp(() {
53 schedule(() => _touch("pubspec.yaml")); 56 d.dir("foo", [
54 }); 57 d.libPubspec("foo", "1.0.0")
55 58 ]).create();
56 _forEveryCommand('The pubspec.yaml file has changed since the .packages ' 59
60 d.dir(appPath, [
61 d.appPubspec({"foo": {"path": "../foo"}})
62 ]).create();
63
64 // Ensure that the pubspec looks newer than the lockfile.
65 _touch("pubspec.yaml");
66 });
67
68 _requiresPubGet('The pubspec.yaml file has changed since the '
69 'pubspec.lock file was generated, please run "pub get" again.');
70 });
71
72 group("the lockfile has a dependency from the wrong source", () {
73 setUp(() {
74 d.dir(appPath, [
75 d.appPubspec({"foo": "1.0.0"})
76 ]).create();
77
78 pubGet();
79
80 createLockFile(appPath, sandbox: ["foo"]);
81
82 // Ensure that the pubspec looks newer than the lockfile.
83 _touch("pubspec.yaml");
84 });
85
86 _requiresPubGet('The pubspec.yaml file has changed since the '
87 'pubspec.lock file was generated, please run "pub get" again.');
88 });
89
90 group("the lockfile has a dependency from an unknown source", () {
91 setUp(() {
92 d.dir(appPath, [
93 d.appPubspec({"foo": "1.0.0"})
94 ]).create();
95
96 pubGet();
97
98 d.dir(appPath, [
99 d.file("pubspec.lock", yaml({
100 "packages": {
101 "foo": {
102 "description": "foo",
103 "version": "1.0.0",
104 "source": "sdk"
105 }
106 }
107 }))
108 ]).create();
109
110 // Ensure that the pubspec looks newer than the lockfile.
111 _touch("pubspec.yaml");
112 });
113
114 _requiresPubGet('The pubspec.yaml file has changed since the '
115 'pubspec.lock file was generated, please run "pub get" again.');
116 });
117
118 group("the lockfile has a dependency with the wrong description", () {
119 setUp(() {
120 d.dir("bar", [
121 d.libPubspec("foo", "1.0.0")
122 ]).create();
123
124 d.dir(appPath, [
125 d.appPubspec({"foo": {"path": "../bar"}})
126 ]).create();
127
128 pubGet();
129
130 createLockFile(appPath, sandbox: ["foo"]);
131
132 // Ensure that the pubspec looks newer than the lockfile.
133 _touch("pubspec.yaml");
134 });
135
136 _requiresPubGet('The pubspec.yaml file has changed since the '
137 'pubspec.lock file was generated, please run "pub get" again.');
138 });
139
140 group("the pubspec has an incompatible version of a dependency", () {
141 setUp(() {
142 d.dir(appPath, [
143 d.appPubspec({"foo": "1.0.0"})
144 ]).create();
145
146 pubGet();
147
148 d.dir(appPath, [
149 d.appPubspec({"foo": "2.0.0"})
150 ]).create();
151
152 // Ensure that the pubspec looks newer than the lockfile.
153 _touch("pubspec.yaml");
154 });
155
156 _requiresPubGet('The pubspec.yaml file has changed since the '
157 'pubspec.lock file was generated, please run "pub get" again.');
158 });
159
160 group("the lockfile is pointing to an unavailable package with a newer "
161 "pubspec", () {
162 setUp(() {
163 d.dir(appPath, [
164 d.appPubspec({"foo": "1.0.0"})
165 ]).create();
166
167 pubGet();
168
169 schedule(() => deleteEntry(p.join(sandboxDir, cachePath)));
170
171 // Ensure that the pubspec looks newer than the lockfile.
172 _touch("pubspec.yaml");
173 });
174
175 _requiresPubGet('The pubspec.yaml file has changed since the '
176 'pubspec.lock file was generated, please run "pub get" again.');
177 });
178
179 group("the lockfile is pointing to an unavailable package with an older "
180 ".packages", () {
181 setUp(() {
182 d.dir(appPath, [
183 d.appPubspec({"foo": "1.0.0"})
184 ]).create();
185
186 pubGet();
187
188 schedule(() => deleteEntry(p.join(sandboxDir, cachePath)));
189
190 // Ensure that the lockfile looks newer than the .packages file.
191 _touch("pubspec.lock");
192 });
193
194 _requiresPubGet('The pubspec.lock file has changed since the .packages '
57 'file was generated, please run "pub get" again.'); 195 'file was generated, please run "pub get" again.');
58 }); 196 });
59 197
60 group("the lockfile is newer than the package spec", () { 198 group("the lockfile has a package that the .packages file doesn't", () {
61 setUp(() { 199 setUp(() {
62 schedule(() => _touch("pubspec.lock")); 200 d.dir("foo", [
63 }); 201 d.libPubspec("foo", "1.0.0")
64 202 ]).create();
65 _forEveryCommand('The pubspec.lock file has changed since the .packages ' 203
204 d.dir(appPath, [
205 d.appPubspec({"foo": {"path": "../foo"}})
206 ]).create();
207
208 pubGet();
209
210 createPackagesFile(appPath);
211
212 // Ensure that the pubspec looks newer than the lockfile.
213 _touch("pubspec.lock");
214 });
215
216 _requiresPubGet('The pubspec.lock file has changed since the .packages '
66 'file was generated, please run "pub get" again.'); 217 'file was generated, please run "pub get" again.');
67 }); 218 });
219
220 group("the .packages file has a package with a non-file URI", () {
221 setUp(() {
222 d.dir("foo", [
223 d.libPubspec("foo", "1.0.0")
224 ]).create();
225
226 d.dir(appPath, [
227 d.appPubspec({"foo": {"path": "../foo"}})
228 ]).create();
229
230 pubGet();
231
232 d.dir(appPath, [
233 d.file(".packages", """
234 myapp:lib
235 foo:http://example.com/
236 """)
237 ]).create();
238
239 // Ensure that the pubspec looks newer than the lockfile.
240 _touch("pubspec.lock");
241 });
242
243 _requiresPubGet('The pubspec.lock file has changed since the .packages '
244 'file was generated, please run "pub get" again.');
245 });
246
247 group("the .packages file points to the wrong place", () {
248 setUp(() {
249 d.dir("bar", [
250 d.libPubspec("foo", "1.0.0")
251 ]).create();
252
253 d.dir(appPath, [
254 d.appPubspec({"foo": {"path": "../bar"}})
255 ]).create();
256
257 pubGet();
258
259 createPackagesFile(appPath, sandbox: ["foo"]);
260
261 // Ensure that the pubspec looks newer than the lockfile.
262 _touch("pubspec.lock");
263 });
264
265 _requiresPubGet('The pubspec.lock file has changed since the .packages '
266 'file was generated, please run "pub get" again.');
267 });
268 });
269
270 group("doesn't require the user to run pub get first if", () {
271 group("the pubspec is older than the lockfile which is older than the "
272 "packages file, even if the contents are wrong", () {
273 setUp(() {
274 d.dir(appPath, [
275 d.appPubspec({"foo": "1.0.0"})
276 ]).create();
277
278 _touch("pubspec.lock");
279 _touch(".packages");
280 });
281
282 _runsSuccessfully(runDeps: false);
283 });
284
285 group("the pubspec is newer than the lockfile, but they're up-to-date", () {
286 setUp(() {
287 d.dir(appPath, [
288 d.appPubspec({"foo": "1.0.0"})
289 ]).create();
290
291 pubGet();
292
293 _touch("pubspec.yaml");
294 });
295
296 _runsSuccessfully();
297 });
298
299 group("the lockfile is newer than .packages, but they're up-to-date", () {
300 setUp(() {
301 d.dir(appPath, [
302 d.appPubspec({"foo": "1.0.0"})
303 ]).create();
304
305 pubGet();
306
307 _touch("pubspec.lock");
308 });
309
310 _runsSuccessfully();
311 });
68 }); 312 });
69 } 313 }
70 314
71 /// Runs every command that care about the world being up-to-date, and asserts 315 /// Runs every command that care about the world being up-to-date, and asserts
72 /// that it prints [message] as part of its error. 316 /// that it prints [message] as part of its error.
73 void _forEveryCommand(String message) { 317 void _requiresPubGet(String message) {
74 for (var command in ["build", "serve", "run", "deps"]) { 318 for (var command in ["build", "serve", "run", "deps"]) {
75 integration("for pub $command", () { 319 integration("for pub $command", () {
76 var args = [command]; 320 var args = [command];
77 if (command == "run") args.add("script"); 321 if (command == "run") args.add("script");
78 322
79 var output;
80 var error;
81 if (command == "list-package-dirs") {
82 output = contains(JSON.encode(message));
83 } else {
84 error = contains(message);
85 }
86
87 schedulePub( 323 schedulePub(
88 args: args, 324 args: args,
89 output: output, 325 error: contains(message),
90 error: error,
91 exitCode: exit_codes.DATA); 326 exitCode: exit_codes.DATA);
92 }); 327 });
93 } 328 }
94 } 329 }
95 330
331 /// Ensures that pub doesn't require "pub get" for the current package.
332 ///
333 /// If [runDeps] is false, `pub deps` isn't included in the test. This is
334 /// sometimes not desirable, since it uses slightly stronger checks for pubspec
335 /// and lockfile consistency.
336 void _runsSuccessfully({bool runDeps: true}) {
337 var commands = ["build", "serve", "run"];
338 if (runDeps) commands.add("deps");
339
340 for (var command in commands) {
341 integration("for pub $command", () {
342 var args = [command];
343 if (command == "run") args.add("bin/script.dart");
344 if (command == "serve") ;
345
346 if (command != "serve") {
347 schedulePub(args: args);
348 } else {
349 var pub = startPub(args: ["serve", "--port=0"]);
350 pub.stdout.expect(consumeThrough(startsWith("Serving myapp web")));
351 pub.kill();
352 }
353
354 schedule(() {
355 // If pub determines that everything is up-to-date, it should set the
356 // mtimes to indicate that.
357 var pubspecModified = new File(p.join(sandboxDir, "myapp/pubspec.yaml"))
358 .lastModifiedSync();
359 var lockFileModified =
360 new File(p.join(sandboxDir, "myapp/pubspec.lock"))
361 .lastModifiedSync();
362 var packagesModified = new File(p.join(sandboxDir, "myapp/.packages"))
363 .lastModifiedSync();
364
365 expect(!pubspecModified.isAfter(lockFileModified), isTrue);
366 expect(!lockFileModified.isAfter(packagesModified), isTrue);
367 }, "testing last-modified times");
368 });
369 }
370 }
371
372 /// Schedules a non-semantic modification to [path].
96 void _touch(String path) { 373 void _touch(String path) {
97 path = p.join(sandboxDir, "myapp", path); 374 schedule(() async {
98 writeTextFile(path, readTextFile(path) + " "); 375 // Delay a bit to make sure the modification times are noticeably different.
376 // 1s seems to be the finest granularity that dart:io reports.
377 await new Future.delayed(new Duration(seconds: 1));
378
379 path = p.join(sandboxDir, "myapp", path);
380 touch(path);
381 }, "touching $path");
99 } 382 }
OLDNEW
« no previous file with comments | « lib/src/io.dart ('k') | test/test_pub.dart » ('j') | no next file with comments »

Powered by Google App Engine