| 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()); | |
| } |