Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
59
third-party/vendor/jobserver/tests/client-of-myself.rs
vendored
Normal file
59
third-party/vendor/jobserver/tests/client-of-myself.rs
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use std::env;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc;
|
||||
use std::thread;
|
||||
|
||||
use jobserver::Client;
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(e) => panic!("{} failed with {}", stringify!($e), e),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if env::var("I_AM_THE_CLIENT").is_ok() {
|
||||
client();
|
||||
} else {
|
||||
server();
|
||||
}
|
||||
}
|
||||
|
||||
fn server() {
|
||||
let me = t!(env::current_exe());
|
||||
let client = t!(Client::new(1));
|
||||
let mut cmd = Command::new(me);
|
||||
cmd.env("I_AM_THE_CLIENT", "1").stdout(Stdio::piped());
|
||||
client.configure(&mut cmd);
|
||||
let acq = client.acquire().unwrap();
|
||||
let mut child = t!(cmd.spawn());
|
||||
let stdout = child.stdout.take().unwrap();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let t = thread::spawn(move || {
|
||||
for line in BufReader::new(stdout).lines() {
|
||||
tx.send(t!(line)).unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..100 {
|
||||
assert!(rx.try_recv().is_err());
|
||||
}
|
||||
|
||||
drop(acq);
|
||||
assert_eq!(rx.recv().unwrap(), "hello!");
|
||||
t.join().unwrap();
|
||||
assert!(rx.recv().is_err());
|
||||
client.acquire().unwrap();
|
||||
}
|
||||
|
||||
fn client() {
|
||||
let client = unsafe { Client::from_env().unwrap() };
|
||||
let acq = client.acquire().unwrap();
|
||||
println!("hello!");
|
||||
drop(acq);
|
||||
}
|
||||
198
third-party/vendor/jobserver/tests/client.rs
vendored
Normal file
198
third-party/vendor/jobserver/tests/client.rs
vendored
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::process::Command;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use futures::future::{self, Future};
|
||||
use futures::stream::{self, Stream};
|
||||
use jobserver::Client;
|
||||
use tokio_core::reactor::Core;
|
||||
use tokio_process::CommandExt;
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(e) => panic!("{} failed with {}", stringify!($e), e),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct Test {
|
||||
name: &'static str,
|
||||
f: &'static dyn Fn(),
|
||||
make_args: &'static [&'static str],
|
||||
rule: &'static dyn Fn(&str) -> String,
|
||||
}
|
||||
|
||||
const TESTS: &[Test] = &[
|
||||
Test {
|
||||
name: "no j args",
|
||||
make_args: &[],
|
||||
rule: &|me| me.to_string(),
|
||||
f: &|| {
|
||||
assert!(unsafe { Client::from_env().is_none() });
|
||||
},
|
||||
},
|
||||
Test {
|
||||
name: "no j args with plus",
|
||||
make_args: &[],
|
||||
rule: &|me| format!("+{}", me),
|
||||
f: &|| {
|
||||
assert!(unsafe { Client::from_env().is_none() });
|
||||
},
|
||||
},
|
||||
Test {
|
||||
name: "j args with plus",
|
||||
make_args: &["-j2"],
|
||||
rule: &|me| format!("+{}", me),
|
||||
f: &|| {
|
||||
assert!(unsafe { Client::from_env().is_some() });
|
||||
},
|
||||
},
|
||||
Test {
|
||||
name: "acquire",
|
||||
make_args: &["-j2"],
|
||||
rule: &|me| format!("+{}", me),
|
||||
f: &|| {
|
||||
let c = unsafe { Client::from_env().unwrap() };
|
||||
drop(c.acquire().unwrap());
|
||||
drop(c.acquire().unwrap());
|
||||
},
|
||||
},
|
||||
Test {
|
||||
name: "acquire3",
|
||||
make_args: &["-j3"],
|
||||
rule: &|me| format!("+{}", me),
|
||||
f: &|| {
|
||||
let c = unsafe { Client::from_env().unwrap() };
|
||||
let a = c.acquire().unwrap();
|
||||
let b = c.acquire().unwrap();
|
||||
drop((a, b));
|
||||
},
|
||||
},
|
||||
Test {
|
||||
name: "acquire blocks",
|
||||
make_args: &["-j2"],
|
||||
rule: &|me| format!("+{}", me),
|
||||
f: &|| {
|
||||
let c = unsafe { Client::from_env().unwrap() };
|
||||
let a = c.acquire().unwrap();
|
||||
let hit = Arc::new(AtomicBool::new(false));
|
||||
let hit2 = hit.clone();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let t = thread::spawn(move || {
|
||||
tx.send(()).unwrap();
|
||||
let _b = c.acquire().unwrap();
|
||||
hit2.store(true, Ordering::SeqCst);
|
||||
});
|
||||
rx.recv().unwrap();
|
||||
assert!(!hit.load(Ordering::SeqCst));
|
||||
drop(a);
|
||||
t.join().unwrap();
|
||||
assert!(hit.load(Ordering::SeqCst));
|
||||
},
|
||||
},
|
||||
Test {
|
||||
name: "acquire_raw",
|
||||
make_args: &["-j2"],
|
||||
rule: &|me| format!("+{}", me),
|
||||
f: &|| {
|
||||
let c = unsafe { Client::from_env().unwrap() };
|
||||
c.acquire_raw().unwrap();
|
||||
c.release_raw().unwrap();
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
fn main() {
|
||||
if let Ok(test) = env::var("TEST_TO_RUN") {
|
||||
return (TESTS.iter().find(|t| t.name == test).unwrap().f)();
|
||||
}
|
||||
|
||||
let me = t!(env::current_exe());
|
||||
let me = me.to_str().unwrap();
|
||||
let filter = env::args().nth(1);
|
||||
|
||||
let mut core = t!(Core::new());
|
||||
|
||||
let futures = TESTS
|
||||
.iter()
|
||||
.filter(|test| match filter {
|
||||
Some(ref s) => test.name.contains(s),
|
||||
None => true,
|
||||
})
|
||||
.map(|test| {
|
||||
let td = t!(tempfile::tempdir());
|
||||
let makefile = format!(
|
||||
"\
|
||||
all: export TEST_TO_RUN={}
|
||||
all:
|
||||
\t{}
|
||||
",
|
||||
test.name,
|
||||
(test.rule)(me)
|
||||
);
|
||||
t!(t!(File::create(td.path().join("Makefile"))).write_all(makefile.as_bytes()));
|
||||
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
|
||||
let mut cmd = Command::new(prog);
|
||||
cmd.args(test.make_args);
|
||||
cmd.current_dir(td.path());
|
||||
future::lazy(move || {
|
||||
cmd.output_async().map(move |e| {
|
||||
drop(td);
|
||||
(test, e)
|
||||
})
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
println!("\nrunning {} tests\n", futures.len());
|
||||
|
||||
let stream = stream::iter(futures.into_iter().map(Ok)).buffer_unordered(num_cpus::get());
|
||||
|
||||
let mut failures = Vec::new();
|
||||
t!(core.run(stream.for_each(|(test, output)| {
|
||||
if output.status.success() {
|
||||
println!("test {} ... ok", test.name);
|
||||
} else {
|
||||
println!("test {} ... FAIL", test.name);
|
||||
failures.push((test, output));
|
||||
}
|
||||
Ok(())
|
||||
})));
|
||||
|
||||
if failures.is_empty() {
|
||||
println!("\ntest result: ok\n");
|
||||
return;
|
||||
}
|
||||
|
||||
println!("\n----------- failures");
|
||||
|
||||
for (test, output) in failures {
|
||||
println!("test {}", test.name);
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
|
||||
println!("\texit status: {}", output.status);
|
||||
if !stdout.is_empty() {
|
||||
println!("\tstdout ===");
|
||||
for line in stdout.lines() {
|
||||
println!("\t\t{}", line);
|
||||
}
|
||||
}
|
||||
|
||||
if !stderr.is_empty() {
|
||||
println!("\tstderr ===");
|
||||
for line in stderr.lines() {
|
||||
println!("\t\t{}", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::process::exit(4);
|
||||
}
|
||||
77
third-party/vendor/jobserver/tests/helper.rs
vendored
Normal file
77
third-party/vendor/jobserver/tests/helper.rs
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
use jobserver::Client;
|
||||
use std::sync::atomic::*;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::*;
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(e) => panic!("{} failed with {}", stringify!($e), e),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn helper_smoke() {
|
||||
let client = t!(Client::new(1));
|
||||
drop(client.clone().into_helper_thread(|_| ()).unwrap());
|
||||
drop(client.clone().into_helper_thread(|_| ()).unwrap());
|
||||
drop(client.clone().into_helper_thread(|_| ()).unwrap());
|
||||
drop(client.clone().into_helper_thread(|_| ()).unwrap());
|
||||
drop(client.clone().into_helper_thread(|_| ()).unwrap());
|
||||
drop(client.into_helper_thread(|_| ()).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn acquire() {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let client = t!(Client::new(1));
|
||||
let helper = client
|
||||
.into_helper_thread(move |a| drop(tx.send(a)))
|
||||
.unwrap();
|
||||
assert!(rx.try_recv().is_err());
|
||||
helper.request_token();
|
||||
rx.recv().unwrap().unwrap();
|
||||
helper.request_token();
|
||||
rx.recv().unwrap().unwrap();
|
||||
|
||||
helper.request_token();
|
||||
helper.request_token();
|
||||
rx.recv().unwrap().unwrap();
|
||||
rx.recv().unwrap().unwrap();
|
||||
|
||||
helper.request_token();
|
||||
helper.request_token();
|
||||
drop(helper);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prompt_shutdown() {
|
||||
for _ in 0..100 {
|
||||
let client = jobserver::Client::new(4).unwrap();
|
||||
let count = Arc::new(AtomicU32::new(0));
|
||||
let count2 = count.clone();
|
||||
let tokens = Arc::new(Mutex::new(Vec::new()));
|
||||
let helper = client
|
||||
.into_helper_thread(move |token| {
|
||||
tokens.lock().unwrap().push(token);
|
||||
count2.fetch_add(1, Ordering::SeqCst);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Request more tokens than what are available.
|
||||
for _ in 0..5 {
|
||||
helper.request_token();
|
||||
}
|
||||
// Wait for at least some of the requests to finish.
|
||||
while count.load(Ordering::SeqCst) < 3 {
|
||||
std::thread::yield_now();
|
||||
}
|
||||
// Drop helper
|
||||
let t = std::time::Instant::now();
|
||||
drop(helper);
|
||||
let d = t.elapsed();
|
||||
assert!(d.as_secs_f64() < 0.5);
|
||||
}
|
||||
}
|
||||
81
third-party/vendor/jobserver/tests/make-as-a-client.rs
vendored
Normal file
81
third-party/vendor/jobserver/tests/make-as-a-client.rs
vendored
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
use std::process::Command;
|
||||
|
||||
use jobserver::Client;
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(e) => panic!("{} failed with {}", stringify!($e), e),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if env::var("_DO_THE_TEST").is_ok() {
|
||||
std::process::exit(
|
||||
Command::new(env::var_os("MAKE").unwrap())
|
||||
.env("MAKEFLAGS", env::var_os("CARGO_MAKEFLAGS").unwrap())
|
||||
.env_remove("_DO_THE_TEST")
|
||||
.args(&env::args_os().skip(1).collect::<Vec<_>>())
|
||||
.status()
|
||||
.unwrap()
|
||||
.code()
|
||||
.unwrap_or(1),
|
||||
);
|
||||
}
|
||||
|
||||
if let Ok(s) = env::var("TEST_ADDR") {
|
||||
let mut contents = Vec::new();
|
||||
t!(t!(TcpStream::connect(&s)).read_to_end(&mut contents));
|
||||
return;
|
||||
}
|
||||
|
||||
let c = t!(Client::new(1));
|
||||
let td = tempfile::tempdir().unwrap();
|
||||
|
||||
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
|
||||
|
||||
let me = t!(env::current_exe());
|
||||
let me = me.to_str().unwrap();
|
||||
|
||||
let mut cmd = Command::new(&me);
|
||||
cmd.current_dir(td.path());
|
||||
cmd.env("MAKE", prog);
|
||||
cmd.env("_DO_THE_TEST", "1");
|
||||
|
||||
t!(t!(File::create(td.path().join("Makefile"))).write_all(
|
||||
format!(
|
||||
"\
|
||||
all: foo bar
|
||||
foo:
|
||||
\t{0}
|
||||
bar:
|
||||
\t{0}
|
||||
",
|
||||
me
|
||||
)
|
||||
.as_bytes()
|
||||
));
|
||||
|
||||
// We're leaking one extra token to `make` sort of violating the makefile
|
||||
// jobserver protocol. It has the desired effect though.
|
||||
c.configure(&mut cmd);
|
||||
|
||||
let listener = t!(TcpListener::bind("127.0.0.1:0"));
|
||||
let addr = t!(listener.local_addr());
|
||||
cmd.env("TEST_ADDR", addr.to_string());
|
||||
let mut child = t!(cmd.spawn());
|
||||
|
||||
// We should get both connections as the two programs should be run
|
||||
// concurrently.
|
||||
let a = t!(listener.accept());
|
||||
let b = t!(listener.accept());
|
||||
drop((a, b));
|
||||
|
||||
assert!(t!(child.wait()).success());
|
||||
}
|
||||
181
third-party/vendor/jobserver/tests/server.rs
vendored
Normal file
181
third-party/vendor/jobserver/tests/server.rs
vendored
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::process::Command;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use jobserver::Client;
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(e) => e,
|
||||
Err(e) => panic!("{} failed with {}", stringify!($e), e),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_smoke() {
|
||||
let c = t!(Client::new(1));
|
||||
drop(c.acquire().unwrap());
|
||||
drop(c.acquire().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_multiple() {
|
||||
let c = t!(Client::new(2));
|
||||
let a = c.acquire().unwrap();
|
||||
let b = c.acquire().unwrap();
|
||||
drop((a, b));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_available() {
|
||||
let c = t!(Client::new(10));
|
||||
assert_eq!(c.available().unwrap(), 10);
|
||||
let a = c.acquire().unwrap();
|
||||
assert_eq!(c.available().unwrap(), 9);
|
||||
drop(a);
|
||||
assert_eq!(c.available().unwrap(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_none_available() {
|
||||
let c = t!(Client::new(2));
|
||||
assert_eq!(c.available().unwrap(), 2);
|
||||
let a = c.acquire().unwrap();
|
||||
assert_eq!(c.available().unwrap(), 1);
|
||||
let b = c.acquire().unwrap();
|
||||
assert_eq!(c.available().unwrap(), 0);
|
||||
drop(a);
|
||||
assert_eq!(c.available().unwrap(), 1);
|
||||
drop(b);
|
||||
assert_eq!(c.available().unwrap(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_blocks() {
|
||||
let c = t!(Client::new(1));
|
||||
let a = c.acquire().unwrap();
|
||||
let hit = Arc::new(AtomicBool::new(false));
|
||||
let hit2 = hit.clone();
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let t = thread::spawn(move || {
|
||||
tx.send(()).unwrap();
|
||||
let _b = c.acquire().unwrap();
|
||||
hit2.store(true, Ordering::SeqCst);
|
||||
});
|
||||
rx.recv().unwrap();
|
||||
assert!(!hit.load(Ordering::SeqCst));
|
||||
drop(a);
|
||||
t.join().unwrap();
|
||||
assert!(hit.load(Ordering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn make_as_a_single_thread_client() {
|
||||
let c = t!(Client::new(1));
|
||||
let td = tempfile::tempdir().unwrap();
|
||||
|
||||
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
|
||||
let mut cmd = Command::new(prog);
|
||||
cmd.current_dir(td.path());
|
||||
|
||||
t!(t!(File::create(td.path().join("Makefile"))).write_all(
|
||||
b"
|
||||
all: foo bar
|
||||
foo:
|
||||
\techo foo
|
||||
bar:
|
||||
\techo bar
|
||||
"
|
||||
));
|
||||
|
||||
// The jobserver protocol means that the `make` process itself "runs with a
|
||||
// token", so we acquire our one token to drain the jobserver, and this
|
||||
// should mean that `make` itself never has a second token available to it.
|
||||
let _a = c.acquire();
|
||||
c.configure(&mut cmd);
|
||||
let output = t!(cmd.output());
|
||||
println!(
|
||||
"\n\t=== stderr\n\t\t{}",
|
||||
String::from_utf8_lossy(&output.stderr).replace("\n", "\n\t\t")
|
||||
);
|
||||
println!(
|
||||
"\t=== stdout\n\t\t{}",
|
||||
String::from_utf8_lossy(&output.stdout).replace("\n", "\n\t\t")
|
||||
);
|
||||
|
||||
assert!(output.status.success());
|
||||
assert!(output.stderr.is_empty());
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout).replace("\r\n", "\n");
|
||||
let a = "\
|
||||
echo foo
|
||||
foo
|
||||
echo bar
|
||||
bar
|
||||
";
|
||||
let b = "\
|
||||
echo bar
|
||||
bar
|
||||
echo foo
|
||||
foo
|
||||
";
|
||||
|
||||
assert!(stdout == a || stdout == b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn make_as_a_multi_thread_client() {
|
||||
let c = t!(Client::new(1));
|
||||
let td = tempfile::tempdir().unwrap();
|
||||
|
||||
let prog = env::var("MAKE").unwrap_or_else(|_| "make".to_string());
|
||||
let mut cmd = Command::new(prog);
|
||||
cmd.current_dir(td.path());
|
||||
|
||||
t!(t!(File::create(td.path().join("Makefile"))).write_all(
|
||||
b"
|
||||
all: foo bar
|
||||
foo:
|
||||
\techo foo
|
||||
bar:
|
||||
\techo bar
|
||||
"
|
||||
));
|
||||
|
||||
// We're leaking one extra token to `make` sort of violating the makefile
|
||||
// jobserver protocol. It has the desired effect though.
|
||||
c.configure(&mut cmd);
|
||||
let output = t!(cmd.output());
|
||||
println!(
|
||||
"\n\t=== stderr\n\t\t{}",
|
||||
String::from_utf8_lossy(&output.stderr).replace("\n", "\n\t\t")
|
||||
);
|
||||
println!(
|
||||
"\t=== stdout\n\t\t{}",
|
||||
String::from_utf8_lossy(&output.stdout).replace("\n", "\n\t\t")
|
||||
);
|
||||
|
||||
assert!(output.status.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_client() {
|
||||
let client = t!(Client::new(0));
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let helper = client
|
||||
.into_helper_thread(move |a| drop(tx.send(a)))
|
||||
.unwrap();
|
||||
helper.request_token();
|
||||
helper.request_token();
|
||||
|
||||
for _ in 0..1000 {
|
||||
assert!(rx.try_recv().is_err());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue