use ::litany::cmd::{RoutedCall, ToolInjection as _};
use super::{advertised, injection, roster};
use crate::test_support::FakeClock;
use crate::tool_host::tests::scripted;
use serde_json::json;
use std::path::Path;
use std::sync::atomic::AtomicBool;
use tempfile::TempDir;
#[test]
fn an_unconsenting_advertiser_is_refused_naming_the_remedy() {
let root = TempDir::new().expect("tmp");
let (handle, _seen) = scripted(
root.path(),
&[roster("laptop", &[advertised("deploy", false)])],
);
let input = json!({"target": "staging"});
let stop = AtomicBool::new(false);
let capture = injection(root.path()).route(call!("deploy", &input, &stop));
handle.join().expect("engine");
assert_eq!(capture.exit_code, 1);
let said = String::from_utf8_lossy(&capture.stderr).into_owned();
assert!(said.contains("laptop advertises deploy"), "{said}");
assert!(
said.contains("no machine of this workspace consents"),
"{said}"
);
assert!(said.contains("\"subject_cwd\": true"), "{said}");
assert!(
said.contains("clients tool is not a way to do this work"),
"{said}"
);
assert!(
said.contains("never this conversation's"),
"the sentence must say where a loaded instance would run: {said}"
);
}
#[test]
fn two_consenting_machines_are_an_ambiguity_refused_naming_them() {
let root = TempDir::new().expect("tmp");
let (handle, _seen) = scripted(
root.path(),
&[json!({"ok": true, "kind": "clients", "rows": [
{"client": "laptop", "present": true,
"tools": [advertised("bash", true)]},
{"client": "tower", "present": false,
"tools": [advertised("bash", true)]},
]})],
);
let input = json!({"command": "ls"});
let stop = AtomicBool::new(false);
let capture = injection(root.path()).route(call!("bash", &input, &stop));
handle.join().expect("engine");
assert_eq!(capture.exit_code, 1);
let said = String::from_utf8_lossy(&capture.stderr).into_owned();
assert!(said.contains("2 machines consent"), "{said}");
assert!(said.contains("laptop, tower"), "{said}");
assert!(said.contains("exactly one entry"), "{said}");
}
#[test]
fn a_lane_whose_invoke_is_never_answered_refuses_in_band() {
let root = TempDir::new().expect("tmp");
let (handle, _seen) = scripted(
root.path(),
&[roster("laptop", &[advertised("bash", true)])],
);
let input = json!({"command": "ls"});
let stop = AtomicBool::new(false);
let capture = injection(root.path()).route(call!("bash", &input, &stop));
handle.join().expect("engine");
assert_eq!(capture.exit_code, 1);
let said = String::from_utf8_lossy(&capture.stderr).into_owned();
assert!(said.starts_with("bash: "), "{said}");
assert!(said.contains("no engine answered"), "{said}");
}
#[test]
fn a_lane_whose_roster_is_never_answered_refuses_in_band() {
let root = TempDir::new().expect("tmp");
let input = json!({"command": "ls"});
let stop = AtomicBool::new(false);
let site = crate::tool_host::Site {
state_root: root.path().to_path_buf(),
workspace: "home".to_owned(),
agent: "dulcet-mongoose".to_owned(),
budget: crate::tool_host::tests::impatient(),
patience: crate::tool_host::tests::impatient(),
clock: FakeClock::new().arc(),
};
let capture = crate::tool_host::subject::answer(
std::path::Path::new("/nonexistent/litany"),
crate::tool_host::tests::impatient().span(),
&site,
&call!("bash", &input, &stop),
);
assert_eq!(capture.exit_code, 1);
let said = String::from_utf8_lossy(&capture.stderr).into_owned();
assert!(said.starts_with("bash: "), "{said}");
assert!(said.contains("no engine answered"), "{said}");
assert!(
!said.contains("advertises"),
"a failed roster read is a transport fact, not a selection one: {said}"
);
}