host: review fixes for cargo.build, the test runner, the console, and main; tests for every PROTOCOL.md rule

cargo.build and the runner (review T22R): builds use the network again;
core.unlock and core.notify in order under the runner; quiet test
output; manifest preparation keeps [workspace], target tables, renamed
and optional entries; cargo.rpc.discover; -32004 with data.output;
retention of 10 builds; light, empty test worlds with an in-memory
journal; only CARGO_/RUST_/SAUSAGE_ variables; stdin is null; the runner
through --config. A compile cache that cannot be created is not fatal.
Activation replaces plugin.wasm without a gap.

Console and main: init ships the workspace Cargo.lock and creates the
world atomically; each console command runs in its own task, so ps,
stop, and kill work during a slow call; SAUSAGE_HEADLESS; the terminal
mode is restored; signals during boot; chat text is not taken as a
command.

Tests: 20 more tests for PROTOCOL.md sections 2 to 10; the cargo tests
choose the libtest binary from cargo's JSON output and time out.
This commit is contained in:
2026-10-23 07:47:39 +01:00
parent 61d5d5f817
commit a090e1fd57
24 changed files with 1889 additions and 242 deletions
+9 -3
View File
@@ -1,9 +1,15 @@
[package]
name = "cargo-valid"
version = "0.1.0"
edition = "2024"
edition.workspace = true
[dependencies]
sausage-plugin = "0.1"
[target.'cfg(target_arch = "wasm32")'.dependencies]
sausage_plugin = { package = "sausage-plugin", version = "0.1", optional = true }
[features]
default = ["dep:sausage_plugin"]
[workspace]
[workspace.package]
edition = "2024"
+4
View File
@@ -0,0 +1,4 @@
//! Produces a warning so the build response can retain diagnostics.
fn main() {
println!("cargo:warning=fixture build warning");
}
+80
View File
@@ -34,6 +34,12 @@ mod tests {
async fn sdk_lock() {
let guard = sausage_plugin::lock("/state/lock").await.unwrap();
assert!(guard.held());
let locks: sausage_plugin::serde_json::Value = sausage_plugin::serde_json::from_str(
&std::fs::read_to_string("/proc/core/locks.json").unwrap(),
)
.unwrap();
assert_eq!(locks.as_object().unwrap().len(), 1);
assert!(locks.get("/state/lock").is_some());
let mut guard = Some(guard);
let mut waiting = Box::pin(std::future::IntoFuture::into_future(sausage_plugin::lock(
"/state/lock",
@@ -66,6 +72,80 @@ mod tests {
.unwrap_err();
assert!(error.to_string().contains("a test has no other plugins"));
}
#[sausage_plugin::test]
async fn unlock_order() {
for iteration in 0..300 {
let guard = sausage_plugin::lock("/state/order").await.unwrap();
assert!(guard.held());
drop(guard);
let guard = sausage_plugin::lock("/state/order")
.try_now()
.await
.unwrap();
assert!(guard.held(), "iteration {iteration}");
}
}
#[test]
fn empty_world() {
for path in [
"/plugins",
"/config",
"/state",
"/state/core/journal.sqlite",
] {
assert!(!std::path::Path::new(path).exists(), "{path}");
}
let names: Vec<_> = std::fs::read_dir("/")
.unwrap()
.map(|entry| entry.unwrap().file_name())
.collect();
assert!(names.iter().all(|name| {
["proc", "self", "run", "tmp"]
.iter()
.any(|allowed| name == allowed)
}));
for path in ["/proc", "/self", "/run"] {
assert!(std::path::Path::new(path).is_dir());
}
assert!(std::fs::write("/proc/forbidden", "no").is_err());
}
fn isolated() {
assert!(!std::path::Path::new("/self/own").exists());
assert!(!std::path::Path::new("/run/own").exists());
std::fs::write("/self/own", "self").unwrap();
std::fs::write("/run/own", "run").unwrap();
assert_eq!(std::fs::read_to_string("/self/own").unwrap(), "self");
}
#[test]
fn isolation_one() {
isolated();
}
#[test]
fn isolation_two() {
isolated();
}
#[test]
fn environment() {
for (key, _) in std::env::vars() {
assert!(
["CARGO_", "RUST_", "SAUSAGE_"]
.iter()
.any(|prefix| key.starts_with(prefix)),
"{key}"
);
}
assert!(std::env::var("PWD").is_err());
}
#[test]
fn late_response() {
use std::io::Write;
for id in 0..100 {
println!(
"\n{{\"jsonrpc\":\"2.0\",\"id\":{id},\"method\":\"core.log\",\"params\":{{}}}}"
);
}
std::io::stdout().flush().unwrap();
}
#[test]
#[ignore]
fn ignored_case() {
@@ -0,0 +1,5 @@
//! Checks that cargo invokes integration test binaries through the WASI runner.
#[test]
fn integration_case() {
println!("INTEGRATION_CASE");
}