1 use std
::fs
::{self, File}
;
3 use std
::net
::TcpListener
;
4 use std
::process
::Stdio
;
5 use std
::sync
::mpsc
::channel
;
7 use std
::time
::Duration
;
11 use crate::support
::cargo_process
;
12 use crate::support
::git
;
13 use crate::support
::install
::{cargo_home, assert_has_installed_exe}
;
14 use crate::support
::registry
::Package
;
15 use crate::support
::{basic_manifest, execs, project}
;
17 fn pkg(name
: &str, vers
: &str) {
18 Package
::new(name
, vers
)
19 .file("src/main.rs", "fn main() {{}}")
24 fn multiple_installs() {
27 .file("a/Cargo.toml", &basic_manifest("foo", "0.0.0"))
28 .file("a/src/main.rs", "fn main() {}")
29 .file("b/Cargo.toml", &basic_manifest("bar", "0.0.0"))
30 .file("b/src/main.rs", "fn main() {}");
33 let mut a
= p
.cargo("install").cwd(p
.root().join("a")).build_command();
34 let mut b
= p
.cargo("install").cwd(p
.root().join("b")).build_command();
36 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
37 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
39 let a
= a
.spawn().unwrap();
40 let b
= b
.spawn().unwrap();
41 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
42 let b
= b
.wait_with_output().unwrap();
43 let a
= a
.join().unwrap();
45 execs().run_output(&a
);
46 execs().run_output(&b
);
48 assert_has_installed_exe(cargo_home(), "foo");
49 assert_has_installed_exe(cargo_home(), "bar");
53 fn concurrent_installs() {
54 const LOCKED_BUILD
: &str = "waiting for file lock on build directory";
59 let mut a
= cargo_process("install foo").build_command();
60 let mut b
= cargo_process("install bar").build_command();
62 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
63 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
65 let a
= a
.spawn().unwrap();
66 let b
= b
.spawn().unwrap();
67 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
68 let b
= b
.wait_with_output().unwrap();
69 let a
= a
.join().unwrap();
71 assert
!(!str::from_utf8(&a
.stderr
).unwrap().contains(LOCKED_BUILD
));
72 assert
!(!str::from_utf8(&b
.stderr
).unwrap().contains(LOCKED_BUILD
));
74 execs().run_output(&a
);
75 execs().run_output(&b
);
77 assert_has_installed_exe(cargo_home(), "foo");
78 assert_has_installed_exe(cargo_home(), "bar");
82 fn one_install_should_be_bad() {
85 .file("a/Cargo.toml", &basic_manifest("foo", "0.0.0"))
86 .file("a/src/main.rs", "fn main() {}")
87 .file("b/Cargo.toml", &basic_manifest("foo", "0.0.0"))
88 .file("b/src/main.rs", "fn main() {}");
91 let mut a
= p
.cargo("install").cwd(p
.root().join("a")).build_command();
92 let mut b
= p
.cargo("install").cwd(p
.root().join("b")).build_command();
94 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
95 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
97 let a
= a
.spawn().unwrap();
98 let b
= b
.spawn().unwrap();
99 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
100 let b
= b
.wait_with_output().unwrap();
101 let a
= a
.join().unwrap();
103 let (bad
, good
) = if a
.status
.code() == Some(101) {
110 .with_stderr_contains(
111 "[ERROR] binary `foo[..]` already exists in destination as part of `[..]`",
114 .with_stderr_contains("warning: be sure to add `[..]` to your PATH [..]")
117 assert_has_installed_exe(cargo_home(), "foo");
121 fn multiple_registry_fetches() {
122 let mut pkg
= Package
::new("bar", "1.0.2");
124 let name
= format
!("foo{}", i
);
125 Package
::new(&name
, "1.0.0").publish();
143 ).file("a/src/main.rs", "fn main() {}")
155 ).file("b/src/main.rs", "fn main() {}");
158 let mut a
= p
.cargo("build").cwd(p
.root().join("a")).build_command();
159 let mut b
= p
.cargo("build").cwd(p
.root().join("b")).build_command();
161 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
162 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
164 let a
= a
.spawn().unwrap();
165 let b
= b
.spawn().unwrap();
166 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
167 let b
= b
.wait_with_output().unwrap();
168 let a
= a
.join().unwrap();
170 execs().run_output(&a
);
171 execs().run_output(&b
);
173 let suffix
= env
::consts
::EXE_SUFFIX
;
176 .join("a/target/debug")
177 .join(format
!("foo{}", suffix
))
182 .join("b/target/debug")
183 .join(format
!("bar{}", suffix
))
189 fn git_same_repo_different_tags() {
190 let a
= git
::new("dep", |project
| {
192 .file("Cargo.toml", &basic_manifest("dep", "0.5.0"))
193 .file("src/lib.rs", "pub fn tag1() {}")
196 let repo
= git2
::Repository
::open(&a
.root()).unwrap();
197 git
::tag(&repo
, "tag1");
199 File
::create(a
.root().join("src/lib.rs"))
201 .write_all(b
"pub fn tag2() {}")
205 git
::tag(&repo
, "tag2");
219 dep = {{ git = '{}', tag = 'tag1' }}
225 "extern crate dep; fn main() { dep::tag1(); }",
236 dep = {{ git = '{}', tag = 'tag2' }}
242 "extern crate dep; fn main() { dep::tag2(); }",
246 let mut a
= p
.cargo("build -v").cwd(p
.root().join("a")).build_command();
247 let mut b
= p
.cargo("build -v").cwd(p
.root().join("b")).build_command();
249 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
250 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
252 let a
= a
.spawn().unwrap();
253 let b
= b
.spawn().unwrap();
254 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
255 let b
= b
.wait_with_output().unwrap();
256 let a
= a
.join().unwrap();
258 execs().run_output(&a
);
259 execs().run_output(&b
);
263 fn git_same_branch_different_revs() {
264 let a
= git
::new("dep", |project
| {
266 .file("Cargo.toml", &basic_manifest("dep", "0.5.0"))
267 .file("src/lib.rs", "pub fn f1() {}")
282 dep = {{ git = '{}' }}
288 "extern crate dep; fn main() { dep::f1(); }",
299 dep = {{ git = '{}' }}
305 "extern crate dep; fn main() { dep::f2(); }",
309 // Generate a Cargo.lock pointing at the current rev, then clear out the
311 p
.cargo("build").cwd(p
.root().join("a")).run();
312 fs
::remove_dir_all(p
.root().join("a/target")).unwrap();
314 // Make a new commit on the master branch
315 let repo
= git2
::Repository
::open(&a
.root()).unwrap();
316 File
::create(a
.root().join("src/lib.rs"))
318 .write_all(b
"pub fn f2() {}")
323 // Now run both builds in parallel. The build of `b` should pick up the
324 // newest commit while the build of `a` should use the locked old commit.
325 let mut a
= p
.cargo("build").cwd(p
.root().join("a")).build_command();
326 let mut b
= p
.cargo("build").cwd(p
.root().join("b")).build_command();
328 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
329 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
331 let a
= a
.spawn().unwrap();
332 let b
= b
.spawn().unwrap();
333 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
334 let b
= b
.wait_with_output().unwrap();
335 let a
= a
.join().unwrap();
337 execs().run_output(&a
);
338 execs().run_output(&b
);
344 .file("src/main.rs", "fn main() {}")
345 .file("src/lib.rs", "");
348 let mut a
= p
.cargo("build").build_command();
349 let mut b
= p
.cargo("build").build_command();
351 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
352 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
354 let a
= a
.spawn().unwrap();
355 let b
= b
.spawn().unwrap();
356 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
357 let b
= b
.wait_with_output().unwrap();
358 let a
= a
.join().unwrap();
360 execs().run_output(&a
);
361 execs().run_output(&b
);
364 // Make sure that if Cargo dies while holding a lock that it's released and the
365 // next Cargo to come in will take over cleanly.
366 // older win versions don't support job objects, so skip test there
368 #[cfg_attr(target_os = "windows", ignore)]
369 fn killing_cargo_releases_the_lock() {
380 ).file("src/main.rs", "fn main() {}")
384 use std::net::TcpStream;
387 if std::env::var("A").is_ok() {
388 TcpStream::connect(&std::env::var("ADDR").unwrap()[..])
390 std::thread::sleep(std::time::Duration::new(10, 0));
397 // Our build script will connect to our local TCP socket to inform us that
398 // it's started and that's how we know that `a` will have the lock
400 let l
= TcpListener
::bind("127.0.0.1:0").unwrap();
401 let mut a
= p
.cargo("build").build_command();
402 let mut b
= p
.cargo("build").build_command();
403 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
404 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
405 a
.env("ADDR", l
.local_addr().unwrap().to_string())
407 b
.env("ADDR", l
.local_addr().unwrap().to_string())
410 // Spawn `a`, wait for it to get to the build script (at which point the
411 // lock is held), then kill it.
412 let mut a
= a
.spawn().unwrap();
416 // Spawn `b`, then just finish the output of a/b the same way the above
418 let b
= b
.spawn().unwrap();
419 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
420 let b
= b
.wait_with_output().unwrap();
421 let a
= a
.join().unwrap();
423 // We killed `a`, so it shouldn't succeed, but `b` should have succeeded.
424 assert
!(!a
.status
.success());
425 execs().run_output(&b
);
429 fn debug_release_ok() {
430 let p
= project().file("src/main.rs", "fn main() {}");
433 p
.cargo("build").run();
434 fs
::remove_dir_all(p
.root().join("target")).unwrap();
436 let mut a
= p
.cargo("build").build_command();
437 let mut b
= p
.cargo("build --release").build_command();
438 a
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
439 b
.stdout(Stdio
::piped()).stderr(Stdio
::piped());
440 let a
= a
.spawn().unwrap();
441 let b
= b
.spawn().unwrap();
442 let a
= thread
::spawn(move || a
.wait_with_output().unwrap());
443 let b
= b
.wait_with_output().unwrap();
444 let a
= a
.join().unwrap();
449 [COMPILING] foo v0.0.1 [..]
450 [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
456 [COMPILING] foo v0.0.1 [..]
457 [FINISHED] release [optimized] target(s) in [..]
463 fn no_deadlock_with_git_dependencies() {
464 let dep1
= git
::new("dep1", |project
| {
466 .file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
467 .file("src/lib.rs", "")
470 let dep2
= git
::new("dep2", |project
| {
472 .file("Cargo.toml", &basic_manifest("dep2", "0.5.0"))
473 .file("src/lib.rs", "")
487 dep1 = {{ git = '{}' }}
488 dep2 = {{ git = '{}' }}
493 ).file("src/main.rs", "fn main() { }");
496 let n_concurrent_builds
= 5;
498 let (tx
, rx
) = channel();
499 for _
in 0..n_concurrent_builds
{
503 .stdout(Stdio
::piped())
504 .stderr(Stdio
::piped())
507 thread
::spawn(move || {
508 let result
= cmd
.unwrap().wait_with_output().unwrap();
509 tx
.send(result
).unwrap()
513 for _
in 0..n_concurrent_builds
{
514 let result
= rx
.recv_timeout(Duration
::from_secs(30)).expect("Deadlock!");
515 execs().run_output(&result
);