use std::path::Path;
use std::process::Command;
use tempfile::TempDir;
fn areev(args: &[&str]) -> (bool, String, String) {
let out = Command::new(env!("CARGO_BIN_EXE_areev")).args(args).output().expect("spawn areev");
(
out.status.success(),
String::from_utf8_lossy(&out.stdout).to_string(),
String::from_utf8_lossy(&out.stderr).to_string(),
)
}
fn write_pack(dir: &Path, expected_workflow: Option<&str>) {
std::fs::create_dir_all(dir.join("grains")).unwrap();
std::fs::create_dir_all(dir.join("blobs")).unwrap();
std::fs::write(dir.join("blobs/poll.wasm"), b"\0asm\x01\0\0\0not-a-real-module").unwrap();
std::fs::write(
dir.join("grains/010-tool-poll.json"),
r#"{ "id": "poll", "type": "tool", "tool_name": "poll", "kind": "definition",
"tool_description": "read the queue", "created_at": 1788134400000,
"executor_uri": "blob:poll", "runtime": "wasm32-areev-io",
"capabilities": [ { "blob": { "read": true } } ] }"#,
)
.unwrap();
std::fs::write(
dir.join("grains/020-workflow.json"),
r#"{ "id": "plan", "type": "workflow", "name": "queue",
"nodes": ["poll"], "bindings": { "poll": "grain:poll" },
"created_at": 1788134400000 }"#,
)
.unwrap();
std::fs::write(
dir.join("grains/030-trigger.json"),
r#"{ "id": "watch", "type": "trigger", "kind": "polling",
"workflow": "grain:plan", "connector": "queue",
"connector_tool": "grain:poll", "interval_secs": 60,
"dedup_key": ["/id"], "created_at": 1788134400000,
"because": "the desk watches this queue" }"#,
)
.unwrap();
let expect = match expected_workflow {
Some(h) => format!(
r#"{{ "file": "grains/020-workflow.json", "expected_hash": "{h}" }}"#
),
None => "\"grains/020-workflow.json\"".to_string(),
};
std::fs::write(
dir.join("pack.json"),
format!(
r#"{{ "pack": "queue-watch", "version": "1.0.0", "namespace": "ops",
"blobs": {{ "poll": "blobs/poll.wasm" }},
"grains": [ "grains/010-tool-poll.json", {expect},
"grains/030-trigger.json" ],
"queries": {{ "pulse": {{ "body": "RECALL facts LIMIT 5" }} }} }}"#
),
)
.unwrap();
}
fn hash_of(json: &str, ty: &str) -> String {
let v: serde_json::Value = serde_json::from_str(json).expect("json output");
v["grains"]
.as_array()
.expect("grains")
.iter()
.find(|g| g["type"] == ty)
.unwrap_or_else(|| panic!("no {ty} in {json}"))["hash"]
.as_str()
.unwrap()
.to_string()
}
#[test]
fn validate_opens_no_memory_and_addresses_every_grain() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, None);
let (ok, out, err) = areev(&["pack", "validate", pack.to_str().unwrap()]);
assert!(ok, "validate failed: {err}");
assert!(out.contains("valid"), "{out}");
assert!(out.contains("--allow-executor"), "{out}");
assert_eq!(out.matches("--allow-executor").count(), 1, "{out}");
let created: Vec<_> = std::fs::read_dir(dir.path())
.unwrap()
.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().to_string())
.collect();
assert_eq!(created, vec!["pack".to_string()], "validate created {created:?}");
}
#[test]
fn install_resolves_blob_and_grain_references_to_the_addresses_they_earn() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, None);
let db = dir.path().join("m.db");
let (ok, out, err) = areev(&[
"pack", "install", pack.to_str().unwrap(), "--db", db.to_str().unwrap(), "--format", "json",
]);
assert!(ok, "install failed: {err}");
let v: serde_json::Value = serde_json::from_str(&out).unwrap();
let plan = hash_of(&out, "workflow");
let tool = hash_of(&out, "tool");
let (ok, shown, err) = areev(&[
"cal", "RECALL workflows RECENT 5", "--db", db.to_str().unwrap(), "--ns", "ops",
"--format", "json",
]);
assert!(ok, "recall failed: {err}");
assert!(shown.contains(&plan), "the plan is not in the memory: {shown}");
assert!(shown.contains(&tool), "the plan does not bind {tool}: {shown}");
let (ok, triggers, err) = areev(&[
"trigger", "list", "--db", db.to_str().unwrap(), "--ns", "ops", "--format", "json",
]);
assert!(ok, "{err}");
assert!(triggers.contains(&plan), "the trigger does not name {plan}: {triggers}");
let pin = v["allow_executor"][0].as_str().unwrap();
assert_eq!(pin.len(), 64, "{out}");
assert_eq!(v["allow_executor"].as_array().unwrap().len(), 1, "only the code is pinned: {out}");
}
#[test]
fn a_mismatched_expected_hash_is_refused_with_nothing_written() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, Some(&"0".repeat(64)));
let db = dir.path().join("m.db");
let (ok, _out, err) = areev(&[
"pack", "install", pack.to_str().unwrap(), "--db", db.to_str().unwrap(),
]);
assert!(!ok, "a pack that does not build what it claims must be refused");
assert!(err.contains("expected"), "{err}");
assert!(err.contains("Nothing was written"), "{err}");
let (ok, out, _) = areev(&[
"cal", "RECALL tools RECENT 5", "--db", db.to_str().unwrap(), "--ns", "ops",
"--format", "json",
]);
assert!(ok, "{out}");
assert!(out.contains("\"total_available\": 0"), "a refused install left grains behind: {out}");
}
#[test]
fn a_forward_grain_reference_is_refused_rather_than_guessed_at() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, None);
std::fs::write(
pack.join("pack.json"),
r#"{ "pack": "queue-watch", "version": "1.0.0", "namespace": "ops",
"blobs": { "poll": "blobs/poll.wasm" },
"grains": [ "grains/020-workflow.json", "grains/010-tool-poll.json" ] }"#,
)
.unwrap();
let (ok, _out, err) = areev(&["pack", "validate", pack.to_str().unwrap()]);
assert!(!ok, "a forward reference must be refused");
assert!(err.contains("grain:poll"), "{err}");
assert!(err.contains("built first"), "{err}");
}
#[test]
fn a_source_pack_round_trips_into_a_fresh_memory_at_the_same_addresses() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, None);
let first = dir.path().join("first.db");
let (ok, installed, err) = areev(&[
"pack", "install", pack.to_str().unwrap(), "--db", first.to_str().unwrap(),
"--format", "json",
]);
assert!(ok, "{err}");
let plan = hash_of(&installed, "workflow");
let exported = dir.path().join("exported");
let (ok, _out, err) = areev(&[
"pack", "export", "--db", first.to_str().unwrap(), "--ns", "ops",
"--out", exported.to_str().unwrap(), "--name", "queue-watch",
]);
assert!(ok, "export failed: {err}");
let manifest = std::fs::read_to_string(exported.join("pack.json")).unwrap();
assert!(manifest.contains("pulse"), "the saved query did not travel: {manifest}");
let second = dir.path().join("second.db");
let (ok, again, err) = areev(&[
"pack", "install", exported.to_str().unwrap(), "--db", second.to_str().unwrap(),
"--format", "json",
]);
assert!(ok, "reinstall failed: {err}");
assert_eq!(hash_of(&again, "workflow"), plan, "the round trip changed the plan");
}
#[test]
fn a_bundle_pack_round_trips_and_asserts_what_it_carries() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, None);
let first = dir.path().join("first.db");
let (ok, installed, err) = areev(&[
"pack", "install", pack.to_str().unwrap(), "--db", first.to_str().unwrap(),
"--format", "json",
]);
assert!(ok, "{err}");
let plan = hash_of(&installed, "workflow");
let exported = dir.path().join("bundle-pack");
let (ok, _out, err) = areev(&[
"pack", "export", "--db", first.to_str().unwrap(), "--ns", "ops",
"--out", exported.to_str().unwrap(), "--pack-format", "bundle",
]);
assert!(ok, "bundle export failed: {err}");
let manifest = std::fs::read_to_string(exported.join("pack.json")).unwrap();
assert!(manifest.contains(&plan), "the manifest does not expect its own plan: {manifest}");
assert!(exported.join("pack.mgb").is_file());
let second = dir.path().join("second.db");
let (ok, out, err) = areev(&[
"pack", "install", exported.to_str().unwrap(), "--db", second.to_str().unwrap(),
]);
assert!(ok, "bundle install failed: {err}");
assert!(out.contains("expectations met"), "{out}");
let (ok, shown, _) = areev(&[
"cal", "RECALL workflows RECENT 5", "--db", second.to_str().unwrap(), "--ns", "ops",
"--format", "json",
]);
assert!(ok && shown.contains(&plan), "the bundle did not carry the plan: {shown}");
}
#[test]
fn a_capability_declaration_without_the_runtime_that_honours_it_is_refused() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, None);
std::fs::write(
pack.join("grains/010-tool-poll.json"),
r#"{ "id": "poll", "type": "tool", "tool_name": "poll", "kind": "definition",
"tool_description": "read the queue", "created_at": 1788134400000,
"executor_uri": "blob:poll",
"capabilities": [ { "blob": { "read": true } } ] }"#,
)
.unwrap();
let (ok, _out, err) = areev(&["pack", "validate", pack.to_str().unwrap()]);
assert!(!ok, "a declaration no runtime can honour describes nothing");
assert!(err.contains("wasm32-areev-io"), "{err}");
}
#[test]
fn pin_checks_the_host_pins_without_writing_them_or_moving_the_plan_hash() {
let dir = TempDir::new().unwrap();
let pack = dir.path().join("pack");
write_pack(&pack, None);
let (ok, validated, err) = areev(&["pack", "validate", pack.to_str().unwrap(), "--format", "json"]);
assert!(ok, "{err}");
let v: serde_json::Value = serde_json::from_str(&validated).unwrap();
let exec = &v["executors"][0];
assert_eq!(exec["tool"], "poll", "{validated}");
assert_eq!(exec["pinned"], false, "{validated}");
let addr = exec["executor_uri"].as_str().unwrap().to_string();
let db = dir.path().join("m.db");
let (ok, _out, err) = areev(&[
"pack", "install", pack.to_str().unwrap(), "--db", db.to_str().unwrap(),
"--pin", &format!("poll={}", "ab".repeat(32)),
]);
assert!(!ok, "a mismatched pin must refuse");
assert!(err.contains("PCK-E005"), "{err}");
let (ok, out, _) = areev(&[
"cal", "RECALL tools RECENT 5", "--db", db.to_str().unwrap(), "--ns", "ops",
"--format", "json",
]);
assert!(ok && out.contains("\"total_available\": 0"), "a refused install left grains: {out}");
let (ok, out, err) = areev(&[
"pack", "install", pack.to_str().unwrap(), "--db", db.to_str().unwrap(),
"--pin", &format!("poll={addr}"), "--format", "json",
]);
assert!(ok, "{err}");
let installed: serde_json::Value = serde_json::from_str(&out).unwrap();
assert_eq!(installed["executors"][0]["pinned"], true, "{out}");
assert_eq!(hash_of(&out, "workflow"), hash_of(&validated, "workflow"));
}