fixed failing tests and updated screenshots
|
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 295 KiB |
|
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 386 KiB |
|
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 273 KiB |
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 388 KiB |
|
Before Width: | Height: | Size: 19 MiB After Width: | Height: | Size: 19 MiB |
|
Before Width: | Height: | Size: 24 MiB After Width: | Height: | Size: 25 MiB |
|
Before Width: | Height: | Size: 12 MiB After Width: | Height: | Size: 12 MiB |
|
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 386 KiB |
|
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 388 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 139 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 135 KiB |
|
|
@ -16,6 +16,7 @@
|
|||
use crate::dynamic::lang;
|
||||
use crate::dynamic::spec::HarnessSpec;
|
||||
use crate::evidence::UnsupportedReason;
|
||||
use crate::labels::Cap;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -23,6 +24,7 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
static WORKDIR_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
const HARNESS_BASE_ENV: &str = "NYX_HARNESS_BASE";
|
||||
|
||||
/// A built harness ready to hand off to the sandbox.
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
@ -69,6 +71,11 @@ pub fn build(spec: &HarnessSpec) -> Result<BuiltHarness, HarnessError> {
|
|||
/// shallow (resolves to `/private/tmp` on macOS, `/tmp` on Linux) and keeps
|
||||
/// payload depth assumptions portable.
|
||||
///
|
||||
/// Tests and hermetic callers may set `NYX_HARNESS_BASE` to redirect this
|
||||
/// scratch tree away from a small system `/tmp`. `CARGO_TARGET_TMPDIR` is used
|
||||
/// automatically for non-FILE_IO cargo test runs; FILE_IO keeps the shallow
|
||||
/// default unless the explicit override is present.
|
||||
///
|
||||
/// The per-run suffix is intentional: the workdir contains mutable build
|
||||
/// products, probe channels, and sometimes a long-lived Docker container
|
||||
/// mount. Reusing `/tmp/nyx-harness/{spec_hash}` across concurrent
|
||||
|
|
@ -78,11 +85,7 @@ fn stage_harness(
|
|||
spec: &HarnessSpec,
|
||||
harness_src: &lang::HarnessSource,
|
||||
) -> Result<PathBuf, HarnessError> {
|
||||
let base_dir = if cfg!(unix) {
|
||||
PathBuf::from("/tmp/nyx-harness")
|
||||
} else {
|
||||
std::env::temp_dir().join("nyx-harness")
|
||||
};
|
||||
let base_dir = harness_base_dir(spec);
|
||||
let workdir = unique_workdir(&base_dir, &spec.spec_hash);
|
||||
fs::create_dir_all(&workdir)?;
|
||||
|
||||
|
|
@ -120,6 +123,37 @@ fn stage_harness(
|
|||
Ok(workdir)
|
||||
}
|
||||
|
||||
fn harness_base_dir(spec: &HarnessSpec) -> PathBuf {
|
||||
let explicit = std::env::var_os(HARNESS_BASE_ENV)
|
||||
.filter(|p| !p.is_empty())
|
||||
.map(PathBuf::from);
|
||||
harness_base_dir_from(
|
||||
explicit,
|
||||
std::env::var_os("CARGO_TARGET_TMPDIR").map(PathBuf::from),
|
||||
spec,
|
||||
)
|
||||
}
|
||||
|
||||
fn harness_base_dir_from(
|
||||
explicit: Option<PathBuf>,
|
||||
cargo_target_tmpdir: Option<PathBuf>,
|
||||
spec: &HarnessSpec,
|
||||
) -> PathBuf {
|
||||
if let Some(base) = explicit {
|
||||
return base;
|
||||
}
|
||||
if !spec.expected_cap.contains(Cap::FILE_IO)
|
||||
&& let Some(base) = cargo_target_tmpdir.filter(|p| !p.as_os_str().is_empty())
|
||||
{
|
||||
return base.join("nyx-harness");
|
||||
}
|
||||
if cfg!(unix) {
|
||||
PathBuf::from("/tmp/nyx-harness")
|
||||
} else {
|
||||
std::env::temp_dir().join("nyx-harness")
|
||||
}
|
||||
}
|
||||
|
||||
fn unique_workdir(base_dir: &Path, spec_hash: &str) -> PathBuf {
|
||||
let seq = WORKDIR_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
let pid = std::process::id();
|
||||
|
|
|
|||
|
|
@ -181,6 +181,25 @@ pub enum RunError {
|
|||
},
|
||||
}
|
||||
|
||||
struct HarnessWorkdirCleanup {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl HarnessWorkdirCleanup {
|
||||
fn new(path: PathBuf) -> Self {
|
||||
Self { path }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for HarnessWorkdirCleanup {
|
||||
fn drop(&mut self) {
|
||||
if std::env::var_os("NYX_KEEP_HARNESS").is_some() {
|
||||
return;
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&self.path);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SandboxError> for RunError {
|
||||
fn from(e: SandboxError) -> Self {
|
||||
RunError::Sandbox(e)
|
||||
|
|
@ -273,6 +292,7 @@ pub fn run_spec(spec: &HarnessSpec, opts: &SandboxOptions) -> Result<RunOutcome,
|
|||
Err(e) => return Err(RunError::Harness(e)),
|
||||
}
|
||||
};
|
||||
let _harness_workdir_cleanup = HarnessWorkdirCleanup::new(harness.workdir.clone());
|
||||
|
||||
// Build-time isolation and dependency setup — dispatched by language.
|
||||
match spec.lang {
|
||||
|
|
|
|||
|
|
@ -327,8 +327,17 @@ pub fn run_fixture_and_compare_to_golden(spec: &FixtureSpec<'_>) {
|
|||
let fixture_src = fixture_root.join(spec.fixture);
|
||||
let golden_path = fixture_root.join(format!("{}.golden.json", spec.fixture));
|
||||
|
||||
let tmp = TempDir::new().expect("create tempdir");
|
||||
let tmp = fixture_tempdir();
|
||||
let diag_path = stage_fixture(&fixture_src, &tmp, spec.copy);
|
||||
let previous_harness_base = if should_redirect_harness_base(spec.cap) {
|
||||
let previous = std::env::var_os("NYX_HARNESS_BASE");
|
||||
unsafe {
|
||||
std::env::set_var("NYX_HARNESS_BASE", tmp.path().join("harness"));
|
||||
}
|
||||
Some(previous)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// SAFETY: env mutation is serialised by FIXTURE_LOCK and the vars are
|
||||
// cleared before the lock guard drops at end of function.
|
||||
|
|
@ -361,6 +370,12 @@ pub fn run_fixture_and_compare_to_golden(spec: &FixtureSpec<'_>) {
|
|||
unsafe {
|
||||
std::env::remove_var("NYX_REPRO_BASE");
|
||||
std::env::remove_var("NYX_TELEMETRY_PATH");
|
||||
if let Some(previous) = previous_harness_base {
|
||||
match previous {
|
||||
Some(path) => std::env::set_var("NYX_HARNESS_BASE", path),
|
||||
None => std::env::remove_var("NYX_HARNESS_BASE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let current = GoldenVerdict::from(&result);
|
||||
|
|
@ -403,6 +418,28 @@ fn fixture_dir(lang_dir: &str) -> PathBuf {
|
|||
.join(lang_dir)
|
||||
}
|
||||
|
||||
fn fixture_scratch_root() -> PathBuf {
|
||||
std::env::var_os("CARGO_TARGET_TMPDIR")
|
||||
.filter(|p| !p.is_empty())
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("target"))
|
||||
.join("nyx-fixtures")
|
||||
}
|
||||
|
||||
fn fixture_tempdir() -> TempDir {
|
||||
let root = fixture_scratch_root();
|
||||
std::fs::create_dir_all(&root)
|
||||
.unwrap_or_else(|e| panic!("create fixture scratch root {}: {e}", root.display()));
|
||||
tempfile::Builder::new()
|
||||
.prefix("nyx-fixture-")
|
||||
.tempdir_in(&root)
|
||||
.expect("create fixture tempdir")
|
||||
}
|
||||
|
||||
fn should_redirect_harness_base(cap: Cap) -> bool {
|
||||
!cap.contains(Cap::FILE_IO)
|
||||
}
|
||||
|
||||
fn stage_fixture(src: &Path, tmp: &TempDir, copy: CopyStrategy) -> PathBuf {
|
||||
match copy {
|
||||
CopyStrategy::PreserveName => {
|
||||
|
|
@ -490,9 +527,18 @@ pub fn run_shape_fixture_lang(
|
|||
.join(shape_dir);
|
||||
let fixture_src = fixture_root.join(file);
|
||||
|
||||
let tmp = TempDir::new().expect("create tempdir");
|
||||
let tmp = fixture_tempdir();
|
||||
let dst = tmp.path().join(file);
|
||||
std::fs::copy(&fixture_src, &dst).expect("copy fixture into tempdir");
|
||||
let previous_harness_base = if should_redirect_harness_base(cap) {
|
||||
let previous = std::env::var_os("NYX_HARNESS_BASE");
|
||||
unsafe {
|
||||
std::env::set_var("NYX_HARNESS_BASE", tmp.path().join("harness"));
|
||||
}
|
||||
Some(previous)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// SAFETY: env mutation is serialised by FIXTURE_LOCK and cleared at end.
|
||||
unsafe {
|
||||
|
|
@ -575,6 +621,12 @@ pub fn run_shape_fixture_lang(
|
|||
unsafe {
|
||||
std::env::remove_var("NYX_REPRO_BASE");
|
||||
std::env::remove_var("NYX_TELEMETRY_PATH");
|
||||
if let Some(previous) = previous_harness_base {
|
||||
match previous {
|
||||
Some(path) => std::env::set_var("NYX_HARNESS_BASE", path),
|
||||
None => std::env::remove_var("NYX_HARNESS_BASE"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Project the [`RunOutcome`] / [`RunError`] back onto a
|
||||
|
|
@ -859,7 +911,7 @@ pub fn run_harness_snapshot_lang(
|
|||
|
||||
// Stage into tempdir so the spec.entry_file path matches what the
|
||||
// verifier sees at runtime.
|
||||
let tmp = TempDir::new().expect("create tempdir");
|
||||
let tmp = fixture_tempdir();
|
||||
let dst = tmp.path().join(file);
|
||||
std::fs::copy(&fixture_src, &dst).expect("copy fixture into tempdir");
|
||||
let entry_file = dst.to_string_lossy().into_owned();
|
||||
|
|
|
|||