tests: include git runtime and prepare preview1 fixtures from the bundle

This commit is contained in:
2026-11-08 01:15:41 +00:00
parent ad795d8528
commit 8c958aa351
4 changed files with 64 additions and 90 deletions
@@ -14,39 +14,8 @@ use std::{
fn guests() -> &'static Path {
static BUILT: OnceLock<PathBuf> = 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")
})
}
+1
View File
@@ -34,6 +34,7 @@ mod durable;
mod events;
mod extension_names;
mod extensions;
mod git_runtime;
mod goal_questions;
mod harness;
mod harness_api;
+8 -10
View File
@@ -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
```
+53 -47
View File
@@ -14,8 +14,9 @@ fn engine() -> &'static Engine {
static E: OnceLock<Engine> = 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");