]> git.proxmox.com Git - rustc.git/blob - vendor/jobserver/tests/server.rs
New upstream version 1.42.0+dfsg1
[rustc.git] / vendor / jobserver / tests / server.rs
1 extern crate jobserver;
2 extern crate tempdir;
3
4 use std::env;
5 use std::fs::File;
6 use std::io::prelude::*;
7 use std::process::Command;
8 use std::sync::atomic::{AtomicBool, Ordering};
9 use std::sync::mpsc;
10 use std::sync::Arc;
11 use std::thread;
12
13 use jobserver::Client;
14 use tempdir::TempDir;
15
16 macro_rules! t {
17 ($e:expr) => {
18 match $e {
19 Ok(e) => e,
20 Err(e) => panic!("{} failed with {}", stringify!($e), e),
21 }
22 };
23 }
24
25 #[test]
26 fn server_smoke() {
27 let c = t!(Client::new(1));
28 drop(c.acquire().unwrap());
29 drop(c.acquire().unwrap());
30 }
31
32 #[test]
33 fn server_multiple() {
34 let c = t!(Client::new(2));
35 let a = c.acquire().unwrap();
36 let b = c.acquire().unwrap();
37 drop((a, b));
38 }
39
40 #[test]
41 fn server_blocks() {
42 let c = t!(Client::new(1));
43 let a = c.acquire().unwrap();
44 let hit = Arc::new(AtomicBool::new(false));
45 let hit2 = hit.clone();
46 let (tx, rx) = mpsc::channel();
47 let t = thread::spawn(move || {
48 tx.send(()).unwrap();
49 let _b = c.acquire().unwrap();
50 hit2.store(true, Ordering::SeqCst);
51 });
52 rx.recv().unwrap();
53 assert!(!hit.load(Ordering::SeqCst));
54 drop(a);
55 t.join().unwrap();
56 assert!(hit.load(Ordering::SeqCst));
57 }
58
59 #[test]
60 fn make_as_a_single_thread_client() {
61 let c = t!(Client::new(1));
62 let td = TempDir::new("foo").unwrap();
63
64 let prog = env::var("MAKE").unwrap_or("make".to_string());
65 let mut cmd = Command::new(prog);
66 cmd.current_dir(td.path());
67
68 t!(t!(File::create(td.path().join("Makefile"))).write_all(
69 b"
70 all: foo bar
71 foo:
72 \techo foo
73 bar:
74 \techo bar
75 "
76 ));
77
78 // The jobserver protocol means that the `make` process itself "runs with a
79 // token", so we acquire our one token to drain the jobserver, and this
80 // should mean that `make` itself never has a second token available to it.
81 let _a = c.acquire();
82 c.configure(&mut cmd);
83 let output = t!(cmd.output());
84 println!(
85 "\n\t=== stderr\n\t\t{}",
86 String::from_utf8_lossy(&output.stderr).replace("\n", "\n\t\t")
87 );
88 println!(
89 "\t=== stdout\n\t\t{}",
90 String::from_utf8_lossy(&output.stdout).replace("\n", "\n\t\t")
91 );
92
93 assert!(output.status.success());
94 assert!(output.stderr.is_empty());
95
96 let stdout = String::from_utf8_lossy(&output.stdout).replace("\r\n", "\n");
97 let a = "\
98 echo foo
99 foo
100 echo bar
101 bar
102 ";
103 let b = "\
104 echo bar
105 bar
106 echo foo
107 foo
108 ";
109
110 assert!(stdout == a || stdout == b);
111 }
112
113 #[test]
114 fn make_as_a_multi_thread_client() {
115 let c = t!(Client::new(1));
116 let td = TempDir::new("foo").unwrap();
117
118 let prog = env::var("MAKE").unwrap_or("make".to_string());
119 let mut cmd = Command::new(prog);
120 cmd.current_dir(td.path());
121
122 t!(t!(File::create(td.path().join("Makefile"))).write_all(
123 b"
124 all: foo bar
125 foo:
126 \techo foo
127 bar:
128 \techo bar
129 "
130 ));
131
132 // We're leaking one extra token to `make` sort of violating the makefile
133 // jobserver protocol. It has the desired effect though.
134 c.configure(&mut cmd);
135 let output = t!(cmd.output());
136 println!(
137 "\n\t=== stderr\n\t\t{}",
138 String::from_utf8_lossy(&output.stderr).replace("\n", "\n\t\t")
139 );
140 println!(
141 "\t=== stdout\n\t\t{}",
142 String::from_utf8_lossy(&output.stdout).replace("\n", "\n\t\t")
143 );
144
145 assert!(output.status.success());
146 }
147
148 #[test]
149 fn zero_client() {
150 let client = t!(Client::new(0));
151 let (tx, rx) = mpsc::channel();
152 let helper = client
153 .into_helper_thread(move |a| drop(tx.send(a)))
154 .unwrap();
155 helper.request_token();
156 helper.request_token();
157
158 for _ in 0..1000 {
159 assert!(rx.try_recv().is_err());
160 }
161 }