Use the world SDK for cargo builds and seed it only when missing

This commit is contained in:
Sausage Worker
2026-10-28 08:39:36 +00:00
parent dc81f78c20
commit 9ef73e6bc7
4 changed files with 138 additions and 54 deletions
+92 -9
View File
@@ -278,14 +278,7 @@ async fn manifest_and_nested_sources() {
assert!(manifest.contains("optional = true"));
let document: toml_edit::DocumentMut = manifest.parse().unwrap();
let sdk = Path::new(document["target"]["cfg(target_arch = \"wasm32\")"]["dependencies"]["sausage_plugin"]["path"].as_str().unwrap());
assert_eq!(sdk.parent().unwrap(), Path::new(CACHE).join("sdk"));
let hash = sdk.file_name().unwrap().to_str().unwrap();
assert_eq!(hash.len(), 64);
assert!(hash.bytes().all(|byte| byte.is_ascii_hexdigit()));
assert_eq!(
std::fs::read(sdk.join("src/lib.rs")).unwrap(),
std::fs::read(valid.world.0.join("plugins/cargo/sdk/src/lib.rs")).unwrap()
);
assert_eq!(sdk, valid.world.0.join("plugins/cargo/sdk"));
assert_eq!(
std::fs::read_to_string(root.join("src/target/data")).unwrap(),
"nested target"
@@ -483,7 +476,7 @@ async fn source_copy() {
assert!(
std::fs::read_to_string(valid.world.0.join("state/cargo/work/Cargo.toml"))
.unwrap()
.contains(Path::new(CACHE).join("sdk").to_str().unwrap())
.contains(valid.world.0.join("plugins/cargo/sdk").to_str().unwrap())
);
}
/// PROTOCOL 11: compiler failures return compiler diagnostics.
@@ -637,6 +630,96 @@ async fn unchanged_sdk() {
modified
);
}
/// PROTOCOL 11: an SDK edit is used by the next build on the same running host.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn world_sdk_edits_apply_without_restart() {
tokio::time::timeout(std::time::Duration::from_secs(180), async {
let world = TestWorld::new();
world.simple("sdk-probe", "fn main() {}\n#[test]\nfn world_sdk_probe() { assert_eq!(sausage_plugin::world_sdk_probe(), 1); }\n");
let manifest = world.0.join("plugins/sdk-probe/source/Cargo.toml");
let mut text = std::fs::read_to_string(&manifest).unwrap();
text.push_str("\n[dependencies]\nsausage-plugin = '0.1'\n");
std::fs::write(manifest, text).unwrap();
let host = Host::start_with_cache(&world.0, Path::new(CACHE)).await.unwrap();
let library = world.0.join("plugins/cargo/sdk/src/lib.rs");
let original = std::fs::read_to_string(&library).unwrap();
std::fs::write(&library, format!("{original}\npub fn world_sdk_probe() -> u8 {{ 1 }}\n")).unwrap();
let params = json!({"plugin":"sdk-probe", "timeout_secs":120, "test_timeout_secs":10});
let first = host.call("cargo.build", params.clone()).await.unwrap();
assert_eq!(first["tests"]["passed"], 1);
// Only the SDK changes: Cargo must not reuse its old compiled version.
std::fs::write(&library, format!("{original}\npub fn world_sdk_probe() -> u8 {{ 2 }}\n")).unwrap();
let second = host.call("cargo.build", params).await.unwrap_err();
assert_eq!(second["code"], -32004);
assert_eq!(second["data"]["tests"]["failed"], 1);
assert!(second["data"]["tests"]["output"].as_str().unwrap().contains("world_sdk_probe"));
host.stop().await;
}).await.expect("SDK edit regression timed out");
}
/// PROTOCOL 11: startup seeds a missing SDK, but never repairs or overwrites an existing one.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn world_sdk_survives_restart_and_missing_sdk_is_reseeded() {
tokio::time::timeout(std::time::Duration::from_secs(30), async {
let world = TestWorld::new();
let sdk = world.0.join("plugins/cargo/sdk");
let host = Host::start_with_cache(&world.0, Path::new(CACHE))
.await
.unwrap();
let library = sdk.join("src/lib.rs");
let original = std::fs::read(&library).unwrap();
let manifest = sdk.join("Cargo.toml");
let edited = b"// world SDK edit must survive restart\n";
std::fs::write(&library, edited).unwrap();
std::fs::write(&manifest, "# edited manifest\n").unwrap();
let removed = sdk.join("macros/src/lib.rs");
std::fs::remove_file(&removed).unwrap();
host.stop().await;
let host = Host::start_with_cache(&world.0, Path::new(CACHE))
.await
.unwrap();
assert_eq!(std::fs::read(&library).unwrap(), edited);
assert_eq!(
std::fs::read_to_string(&manifest).unwrap(),
"# edited manifest\n"
);
assert!(!removed.exists(), "existing SDK must not be repaired");
host.stop().await;
std::fs::remove_dir_all(&sdk).unwrap();
let host = Host::start_with_cache(&world.0, Path::new(CACHE))
.await
.unwrap();
assert_eq!(std::fs::read(&library).unwrap(), original);
assert!(removed.is_file());
assert!(sdk.join("interface/src/lib.rs").is_file());
host.stop().await;
})
.await
.expect("SDK restart regression timed out");
}
/// PROTOCOL 11: removing the SDK while the host is running re-seeds it on the next build.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn world_sdk_missing_at_build_is_reseeded() {
tokio::time::timeout(std::time::Duration::from_secs(180), async {
let world = TestWorld::new();
world.simple("reseed-probe", "fn main() {}\n");
let host = Host::start_with_cache(&world.0, Path::new(CACHE))
.await
.unwrap();
let sdk = world.0.join("plugins/cargo/sdk");
let original = std::fs::read(sdk.join("src/lib.rs")).unwrap();
std::fs::remove_dir_all(&sdk).unwrap();
host.call(
"cargo.build",
json!({"plugin":"reseed-probe", "timeout_secs":120, "test_timeout_secs":10}),
)
.await
.unwrap();
assert_eq!(std::fs::read(sdk.join("src/lib.rs")).unwrap(), original);
host.stop().await;
})
.await
.expect("SDK re-seed build regression timed out");
}
/// PROTOCOL 11: init can build a plugin without a running host.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn standalone_builder() {