use ::litany::cmd::{RoutedCall, ToolInjection as _};
use super::super::{Lane, performs, verdict};
use crate::registry::roster::ClientRow;
use crate::registry::tools::Tool;
use crate::test_support::FakeClock;
use crate::tool_host::Injection;
use crate::tool_host::tests::{budget, front_door, scripted};
use serde_json::json;
use std::path::{Path, PathBuf};
use std::sync::atomic::AtomicBool;
use tempfile::TempDir;
macro_rules! act {
($name:expr, $cwd:expr, $input:expr, $stop:expr) => {
RoutedCall {
id: "toolu_1",
name: $name,
input: $input,
workspace: Path::new("/w/home"),
agent: "dulcet-mongoose",
cwd: $cwd,
stop: $stop,
}
};
}
fn row(client: &str, name: &str, subject_cwd: bool) -> ClientRow {
ClientRow {
client: client.to_owned(),
present: true,
last_seen: None,
tools: vec![Tool {
name: name.to_owned(),
description: "a tool".to_owned(),
input_schema: json!({"type": "object"}),
subject_cwd,
}],
}
}
#[test]
fn the_partition_leaves_the_engine_exactly_the_three_worktree_names() {
let performed: Vec<&str> = ::litany::cmd::BUILTIN_TOOLS
.into_iter()
.filter(|name| performs(name))
.collect();
assert_eq!(performed, ["apply_patch", "bash", "read_file"]);
for elsewhere in [
"cd",
"dispatch",
"message",
"load_skill",
"write_summary",
"mark_for_deletion",
"python",
"remember",
"search_history",
"deploy",
"Bash",
] {
assert!(
!performs(elsewhere),
"{elsewhere} is not the engine's to perform on the lane"
);
}
for name in ::litany::cmd::BUILTIN_TOOLS {
assert!(
performs(name) || crate::tool_host::engine_act::is(name),
"{name} is a built-in on neither lane"
);
}
}
#[test]
fn a_consenting_machine_wins_and_the_engine_takes_what_is_left() {
let mixed = vec![row("laptop", "bash", false), row("tower", "bash", true)];
match verdict(&mixed, "bash") {
Lane::Machine(picked) => {
assert_eq!(picked.client, "tower");
assert!(picked.tool.subject_cwd);
}
_ => panic!("one consenting machine is that machine's"),
}
let unconsented = vec![row("laptop", "bash", false)];
assert!(matches!(verdict(&unconsented, "bash"), Lane::Engine));
assert!(matches!(verdict(&[], "apply_patch"), Lane::Engine));
assert!(matches!(verdict(&[], "read_file"), Lane::Engine));
match verdict(&[], "deploy") {
Lane::Refused(said) => {
assert!(
said.contains("this engine does not implement deploy"),
"{said}"
);
assert!(
said.contains("no machine of this workspace advertises it"),
"{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("load what one advertises"),
"the refusal must not steer to another machine's directory: {said}"
);
}
_ => panic!("a name nothing implements and nothing advertises is refused"),
}
}
#[test]
fn an_empty_roster_performs_a_worktree_name_at_the_front_door() {
let root = TempDir::new().expect("tmp");
let door = front_door(
root.path(),
"printf '%s|%s|%s|%s|%s' \"$1\" \"$2\" \"$LITANY_CONV_BRANCH\" \"$(pwd)\" \"$(cat)\"",
);
let cwd = root.path().join("worktree");
std::fs::create_dir(&cwd).expect("worktree");
let (handle, seen) = scripted(
root.path(),
&[json!({"ok": true, "kind": "clients", "rows": []})],
);
let input = json!({"input": "*** Begin Patch\n*** End Patch\n"});
let stop = AtomicBool::new(false);
let capture = Injection::new(
root.path().to_path_buf(),
door,
budget(),
budget(),
FakeClock::new().arc(),
)
.route(act!("apply_patch", &cwd, &input, &stop));
handle.join().expect("engine");
assert_eq!(capture.exit_code, 0);
assert!(capture.stderr.is_empty());
let said = String::from_utf8_lossy(&capture.stdout).into_owned();
let want = format!(
"tool|apply_patch|dulcet-mongoose|{}|{}",
cwd.canonicalize().expect("cwd").display(),
json!({"input": "*** Begin Patch\n*** End Patch\n"})
);
assert_eq!(said, want);
assert_eq!(
seen.recv().expect("the roster read"),
json!({"op": "clients", "workspace": "home"}),
"the roster is still asked first: a consenting machine must be able to win"
);
}
#[test]
fn an_empty_roster_still_refuses_a_name_the_engine_cannot_perform() {
let root = TempDir::new().expect("tmp");
let (handle, _seen) = scripted(
root.path(),
&[json!({"ok": true, "kind": "clients", "rows": []})],
);
let input = json!({"target": "staging"});
let stop = AtomicBool::new(false);
let capture = Injection::new(
root.path().to_path_buf(),
PathBuf::new(),
budget(),
budget(),
FakeClock::new().arc(),
)
.route(act!("deploy", root.path(), &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("deploy: "), "{said}");
assert!(
said.contains("no machine of this workspace advertises it"),
"{said}"
);
assert!(said.contains("enrolls a thrall"), "{said}");
assert!(
said.contains("clients tool is not a way to do this work"),
"{said}"
);
}