From 8c958aa351e7b7d3b69a4ef7588a2feb3ada0c20 Mon Sep 17 00:00:00 2001 From: Surma Date: Sun, 8 Nov 2026 01:15:41 +0000 Subject: [PATCH] tests: include git runtime and prepare preview1 fixtures from the bundle --- host/tests/{ => it}/git_runtime.rs | 35 +--------- host/tests/it/main.rs | 1 + vfs/src/preview1/README.md | 18 +++--- vfs/tests/preview1.rs | 100 +++++++++++++++-------------- 4 files changed, 64 insertions(+), 90 deletions(-) rename host/tests/{ => it}/git_runtime.rs (83%) diff --git a/host/tests/git_runtime.rs b/host/tests/it/git_runtime.rs similarity index 83% rename from host/tests/git_runtime.rs rename to host/tests/it/git_runtime.rs index f0178dc..17fae59 100644 --- a/host/tests/git_runtime.rs +++ b/host/tests/it/git_runtime.rs @@ -14,39 +14,8 @@ use std::{ fn guests() -> &'static Path { static BUILT: OnceLock = OnceLock::new(); BUILT.get_or_init(|| { - let repo = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap(); - let target = PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap()); - for script in ["userland/cwd-init/build.nu", "userland/brush/build.nu"] { - if script == "userland/cwd-init/build.nu" - && repo.join("userland/cwd-init/init.o").is_file() - { - continue; - } - assert!( - std::process::Command::new("nu") - .args(["--no-config-file", script]) - .current_dir(repo) - .status() - .unwrap() - .success() - ); - } - assert!( - std::process::Command::new("cargo") - .args([ - "build", - "--release", - "--locked", - "--target", - "wasm32-wasip2", - "-p", - "git" - ]) - .current_dir(repo.join("userland")) - .status() - .unwrap() - .success() - ); + let target = crate::common::build_git(); + assert!(crate::common::build_brush().unwrap().success()); target.join("wasm32-wasip2/release") }) } diff --git a/host/tests/it/main.rs b/host/tests/it/main.rs index 680a6cf..223e035 100644 --- a/host/tests/it/main.rs +++ b/host/tests/it/main.rs @@ -34,6 +34,7 @@ mod durable; mod events; mod extension_names; mod extensions; +mod git_runtime; mod goal_questions; mod harness; mod harness_api; diff --git a/vfs/src/preview1/README.md b/vfs/src/preview1/README.md index 4c86968..b6ec7cd 100644 --- a/vfs/src/preview1/README.md +++ b/vfs/src/preview1/README.md @@ -27,17 +27,15 @@ Directory descriptors retain their original paths after a rename. Hard links, symlink creation, file preallocation, signals, and sockets return `NOTSUP`. Preview1 does not expose the platform's WASI 0.2 sockets. -The integration test uses the existing S6 and lab guests: - -- esbuild v0.27.7: `/tmp/s6-esbuild/esbuild.wasm` and `/tmp/s6-esbuild/esbuild-native`. -- uutils 0.12.0: `/tmp/wasi-userland-lab/uu/coreutils-0.12.0-wasm32-wasip1/coreutils.wasm`. -- QuickJS-ng v0.18.0: `/tmp/wasi-userland-lab/qjs-wasi.wasm`. - -The QuickJS-ng input matches its recorded release SHA-256. -The S6 fixture also requires `/tmp/s6-esbuild/app/node_modules`. +The integration test needs no prepared files under `/tmp`. +It uses the bundled `userland/qjs/qjs.wasm` for file operations and JavaScript execution. +It builds native and WASI esbuild from the pinned, vendored source under `userland/esbuild/source`. +Go reuses its persistent build cache. The test stores the executables under `CARGO_TARGET_TMPDIR/preview1-fixtures`. +It installs the S6 app dependencies with `npm ci` and the committed lockfile. It stores local Wasmtime compilation artifacts in a persistent test cache. -Run it from the repository root: +The development shell supplies Go, Node.js, and npm. +Run it from the repository root with your executor's target directory and build slot: ```sh -CARGO_TARGET_DIR=target/preview1 nix develop -c cargo test -p sausage-vfs --test preview1 -- --nocapture +CARGO_BUILD_JOBS=2 CARGO_TARGET_DIR=/path/to/shared/target/executor nu /path/to/.board/slot.nu nix develop -c cargo test -p sausage-vfs --test preview1 -- --nocapture ``` diff --git a/vfs/tests/preview1.rs b/vfs/tests/preview1.rs index 906e154..b1082a7 100644 --- a/vfs/tests/preview1.rs +++ b/vfs/tests/preview1.rs @@ -14,8 +14,9 @@ fn engine() -> &'static Engine { static E: OnceLock = OnceLock::new(); E.get_or_init(Engine::default) } -fn module(path: &str) -> Module { - let bytes = std::fs::read(path).unwrap_or_else(|e| panic!("required guest {path}: {e}")); +fn module(path: &Path) -> Module { + let bytes = + std::fs::read(path).unwrap_or_else(|e| panic!("required guest {}: {e}", path.display())); let mut hash = std::collections::hash_map::DefaultHasher::new(); bytes.hash(&mut hash); engine().precompile_compatibility_hash().hash(&mut hash); @@ -230,51 +231,30 @@ async fn poll_preserves_input_and_returns_clock() { #[tokio::test(flavor = "multi_thread")] async fn userland_files() { - let guest = module("/tmp/wasi-userland-lab/uu/coreutils-0.12.0-wasm32-wasip1/coreutils.wasm"); + let qjs = module(&Path::new(env!("CARGO_MANIFEST_DIR")).join("../userland/qjs/qjs.wasm")); let root = Arc::new(Memory::default()); - run(&guest, root.clone(), "/", &["coreutils", "mkdir", "/work"]).await; - run( - &guest, - root.clone(), - "/work", - &["coreutils", "touch", "input"], - ) - .await; - let input = root - .open( - "/work/input", - Open { - write: true, - ..Open::default() - }, - ) - .await - .unwrap(); - input.write(0, b"hello preview1\n".to_vec()).await.unwrap(); - run( - &guest, - root.clone(), - "/work", - &["coreutils", "cp", "input", "copy"], - ) - .await; - let (cat, _) = run(&guest, root.clone(), "/work", &["coreutils", "cat", "copy"]).await; - assert_eq!(cat, "hello preview1\n"); - let (ls, _) = run( - &guest, - root.clone(), - "/work", - &["coreutils", "ls", "-la", "."], - ) - .await; - assert!(ls.contains("copy") && ls.contains("input"), "{ls}"); - run(&guest, root.clone(), "/work", &["coreutils", "rm", "copy"]).await; + let script = r#" + if (os.mkdir('/work') !== 0) throw Error('mkdir'); + let f = std.open('/work/input', 'w'); f.puts('hello preview1\n'); f.close(); + f = std.open('/work/input', 'r'); let text = f.readAsString(); f.close(); + let out = std.open('/work/copy', 'w'); out.puts(text); out.close(); + f = std.open('/work/copy', 'r'); console.log(f.readAsString().trim()); f.close(); + let [entries, error] = os.readdir('/work'); + if (error) throw Error('readdir'); + console.log(entries.sort().join(',')); + if (os.stat('/work/copy')[0].size !== 15) throw Error('stat'); + if (os.remove('/work/copy') !== 0) throw Error('remove'); + "#; + let (out, _) = run(&qjs, root.clone(), "/", &["qjs", "--std", "-e", script]).await; + assert!( + out.starts_with("hello preview1\n") && out.contains("copy") && out.contains("input"), + "{out}" + ); assert_eq!( root.stat("/work/copy", true).await.unwrap_err().kind(), std::io::ErrorKind::NotFound ); - println!("PASS uutils mkdir touch cp cat ls -la rm"); - let qjs = module("/tmp/wasi-userland-lab/qjs-wasi.wasm"); + println!("PASS QuickJS mkdir create copy read stat readdir remove"); let script = b"let f = std.open('input', 'r'); let text = f.readAsString(); f.close(); let out = std.open('js-output', 'w'); out.puts(text.toUpperCase()); out.close(); console.log('QuickJS files ok');"; let file = root .open( @@ -308,13 +288,39 @@ async fn esbuild_bundle() { std::fs::copy(fixture.join(name), dir.path().join(name)).unwrap(); } assert!( - std::process::Command::new("cp") - .args(["-r", "/tmp/s6-esbuild/app/node_modules"]) - .arg(dir.path()) + std::process::Command::new("npm") + .args(["ci", "--ignore-scripts", "--no-audit", "--no-fund"]) + .current_dir(dir.path()) .status() .unwrap() .success() ); + let source = Path::new(env!("CARGO_MANIFEST_DIR")).join("../userland/esbuild/source"); + let programs = Path::new(env!("CARGO_TARGET_TMPDIR")).join("preview1-fixtures"); + std::fs::create_dir_all(&programs).unwrap(); + for (name, wasm) in [("esbuild-native", false), ("esbuild.wasm", true)] { + let mut build = std::process::Command::new("go"); + build + .current_dir(&source) + .env("GOPROXY", "off") + .env("GOSUMDB", "off") + .env("GOMAXPROCS", "2") + .args([ + "build", + "-p", + "2", + "-mod=vendor", + "-trimpath", + "-ldflags=-s -w", + "-o", + ]) + .arg(programs.join(name)) + .arg("./cmd/esbuild"); + if wasm { + build.env("GOOS", "wasip1").env("GOARCH", "wasm"); + } + assert!(build.status().unwrap().success(), "build {name}"); + } let flags = [ "app.tsx", "--bundle", @@ -327,7 +333,7 @@ async fn esbuild_bundle() { "--log-level=error", ]; assert!( - std::process::Command::new("/tmp/s6-esbuild/esbuild-native") + std::process::Command::new(programs.join("esbuild-native")) .current_dir(dir.path()) .args(flags) .arg("--outfile=native.js") @@ -336,7 +342,7 @@ async fn esbuild_bundle() { .success() ); let root = Arc::new(Host::new(dir.path(), Process::default()).unwrap()); - let guest = module("/tmp/s6-esbuild/esbuild.wasm"); + let guest = module(&programs.join("esbuild.wasm")); let mut args = vec!["esbuild"]; args.extend(flags); args.push("--outfile=host.js");