diff --git a/host/src/world.rs b/host/src/world.rs index 6e6a5b6..a08c29e 100644 --- a/host/src/world.rs +++ b/host/src/world.rs @@ -24,7 +24,9 @@ fn copy_tree(source: &Path, destination: &Path) -> std::io::Result<()> { for entry in std::fs::read_dir(source)? { let entry = entry?; let target = destination.join(entry.file_name()); - if entry.file_type()?.is_dir() { + if entry.file_type()?.is_symlink() { + std::os::unix::fs::symlink(std::fs::read_link(entry.path())?, &target)?; + } else if entry.file_type()?.is_dir() { copy_tree(&entry.path(), &target)?; } else { std::fs::copy(entry.path(), target)?; diff --git a/host/tests/README.md b/host/tests/README.md index 4278b34..e319aaf 100644 --- a/host/tests/README.md +++ b/host/tests/README.md @@ -11,9 +11,17 @@ cargo test -p sausage --test it -- --test-threads=1 Use `nix develop -c` and the required build slot wrapper for these commands. Set `CARGO_TARGET_DIR` to your executor's target directory. +The journal timing benchmark keeps its 10% threshold but does not run in the default suite. +Run it by hand on an idle machine: + +```sh +cargo test --release -p sausage --test it -- --ignored undo_cost +``` + Add new modules under `host/tests/it/` and declare them in `it/main.rs`. Cargo does not discover separate test executables in `host/tests/`. Fixture sources remain in `builder-fixture/`. +The bundle-copy regression preserves relative symlink targets, including broken links. `common.rs` shares the target lookup and the cached userland Git build. A shared mutex protects the cwd-init output and the brush checkout during fixture builds. @@ -24,5 +32,5 @@ Child processes receive environment variables through `Command`, not through cha SIGKILL parents use fully qualified test filters with `--exact`. The `hook::hook_git` and `hook_git` registrations both existed before this move. -Both remain to preserve the test count. +Both remain as wrappers around one shared helper to preserve the test count. The shared `hook_guest` module now builds its fixture once per process. diff --git a/host/tests/it/hook.rs b/host/tests/it/hook.rs index ed3263d..d3c3e73 100644 --- a/host/tests/it/hook.rs +++ b/host/tests/it/hook.rs @@ -1,6 +1,11 @@ //! Real guest HTTP requests pass through caller identity, credential injection, and streaming transport. -#[path = "hook_git.rs"] -mod hook_git; +mod hook_git { + //! Preserve the Git push registration that also ran inside the former hook executable. + #[tokio::test] + async fn several_mb_git_push() { + crate::hook_git::push().await; + } +} use super::hook_guest; use sausage::{ cred::{ diff --git a/host/tests/it/hook_git.rs b/host/tests/it/hook_git.rs index 280ad24..acd9269 100644 --- a/host/tests/it/hook_git.rs +++ b/host/tests/it/hook_git.rs @@ -4,12 +4,7 @@ use sausage::{ process::Runtime, world::World, }; -use std::{ - io::Write, - path::Path, - process::Stdio, - sync::Arc, -}; +use std::{io::Write, path::Path, process::Stdio, sync::Arc}; fn git(cwd: &Path, args: &[&str]) { assert!( std::process::Command::new("git") @@ -22,6 +17,9 @@ fn git(cwd: &Path, args: &[&str]) { } #[tokio::test] async fn several_mb_git_push() { + push().await; +} +pub async fn push() { let component = crate::common::build_git().join("wasm32-wasip2/release/git.wasm"); let temp = tempfile::tempdir().unwrap(); let world = World::open(temp.path()).unwrap(); diff --git a/host/tests/it/p3.rs b/host/tests/it/p3.rs index 4d432c4..62c2d0e 100644 --- a/host/tests/it/p3.rs +++ b/host/tests/it/p3.rs @@ -48,12 +48,7 @@ fn prepare(dir: &Path, all_extensions: bool) -> anyhow::Result<()> { )?; if !target.join("wasm32-wasip2/release/brush.wasm").exists() { anyhow::ensure!( - Command::new("nu") - .arg("brush/build.nu") - .env("CARGO_TARGET_DIR", target) - .current_dir(&userland) - .status()? - .success(), + crate::common::build_brush()?.success(), "brush build failed" ); } diff --git a/host/tests/it/process.rs b/host/tests/it/process.rs index 9b5dfbe..44f9af5 100644 --- a/host/tests/it/process.rs +++ b/host/tests/it/process.rs @@ -21,6 +21,9 @@ fn world_copies_programs_and_nested_source_only_once() -> anyhow::Result<()> { b"ref: refs/heads/main\n", )?; std::fs::write(bundle.join("src/sausage/README.md"), b"source")?; + for (name, target) in [("readme-link", "README.md"), ("broken-link", "missing.wasm")] { + std::os::unix::fs::symlink(target, bundle.join("src/sausage").join(name))?; + } let path = temp.path().join("world"); let _world = World::open_with_userland(&path, Some(&bundle))?; assert_eq!( @@ -32,6 +35,12 @@ fn world_copies_programs_and_nested_source_only_once() -> anyhow::Result<()> { b"source" ); assert!(path.join("world/src/sausage/.git/HEAD").is_file()); + for (name, target) in [("readme-link", "README.md"), ("broken-link", "missing.wasm")] { + assert_eq!( + std::fs::read_link(path.join("world/src/sausage").join(name))?, + Path::new(target) + ); + } std::fs::write(path.join("world/src/sausage/README.md"), b"agent patch")?; let _world = World::open_with_userland(&path, Some(Path::new("/missing-bundle")))?; assert_eq!( diff --git a/host/tests/it/undo_cost.rs b/host/tests/it/undo_cost.rs index 0496d56..d0a38b5 100644 --- a/host/tests/it/undo_cost.rs +++ b/host/tests/it/undo_cost.rs @@ -6,7 +6,9 @@ use sausage::{ }; use sausage_vfs::{Host, Mounts, Process}; use std::{path::PathBuf, sync::Arc, time::Instant}; +// This timing benchmark has a 10% threshold and is flaky on a loaded machine. #[tokio::test(flavor = "multi_thread")] +#[ignore = "Run this timing benchmark by hand on an idle machine"] async fn status_cost() { let target = PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap()); if !target.join("wasm32-wasip2/release/git.wasm").is_file() {