//! Snapshot tests run their bodies in child processes: V8 shares one read-only heap //! between all live isolates of a process, so tests sharing a process would race on it. #![allow(dead_code)] use std::path::PathBuf; use std::process::{Command, Stdio}; use std::time::{Duration, Instant}; const ROLE: &str = "AVRIL_CORE_TEST_ROLE"; const DIRECTORY: &str = "AVRIL_CORE_TEST_DIRECTORY"; /// The role this process was spawned for, if it is a test child. pub fn role() -> Option { std::env::var(ROLE).ok() } /// The parent's scratch directory, shared by every role of one test. pub fn directory() -> PathBuf { PathBuf::from(std::env::var_os(DIRECTORY).unwrap()) } /// Run `test` in a child process with `role`, and return its output. pub fn child(test: &str, role: &str, directory: &std::path::Path) -> String { let log = tempfile::NamedTempFile::new().unwrap(); let mut child = Command::new(std::env::current_exe().unwrap()) .args(["--exact", test, "--nocapture", "--test-threads=1"]) .env(ROLE, role) .env(DIRECTORY, directory) .stdin(Stdio::null()) .stdout(log.as_file().try_clone().unwrap()) .stderr(log.as_file().try_clone().unwrap()) .spawn() .unwrap(); let deadline = Instant::now() + Duration::from_secs(60); let status = loop { if let Some(status) = child.try_wait().unwrap() { break status; } if Instant::now() >= deadline { child.kill().unwrap(); child.wait().unwrap(); panic!( "{test} {role} timed out:\n{}", std::fs::read_to_string(log.path()).unwrap() ); } std::thread::sleep(Duration::from_millis(10)); }; let output = std::fs::read_to_string(log.path()).unwrap(); assert!(status.success(), "{test} {role}: {status}\n{output}"); assert!( output.contains("1 passed; 0 failed"), "{test} {role}: child filter did not run its test:\n{output}" ); output } /// Run each role of `test` in its own child process, in order. pub fn roles(test: &str, roles: &[&str]) { let directory = tempfile::tempdir().unwrap(); for role in roles { child(test, role, directory.path()); } }