use std::os::unix::fs::PermissionsExt;
use super::*;
fn offline(root: &Path) -> Site {
site(root, impatient())
}
fn load_from(root: &Path, client: &str, advertised: Vec<Tool>, take: &[&str]) {
against(
root,
vec![row(client, true, advertised)],
&json!({"op": "load", "client": client, "tools": take}),
)
.expect("loaded");
}
fn held(root: &Path) -> Vec<String> {
crate::tool_host::loaded::read(root, "home", "dulcet-mongoose")
.iter()
.map(crate::tool_host::loaded::Entry::presented)
.collect()
}
#[test]
fn unload_stops_declaring_the_named_tool_and_leaves_the_rest() {
let root = TempDir::new().expect("tmp");
load_from(
root.path(),
"laptop",
vec![tool("Bash"), tool("Read")],
&["Bash", "Read"],
);
let said = answer(
&offline(root.path()),
&json!({"op": "unload", "client": "laptop", "tools": ["Bash"]}),
&quiet(),
)
.expect("unloaded");
assert!(said.contains("unloaded, observed 1970-01-01"), "{said}");
assert!(said.contains(" laptop_Bash"), "{said}");
assert!(said.contains("now holds 1 loaded tool."), "{said}");
assert!(
said.contains("op=load makes any of them callable again"),
"{said}"
);
assert_eq!(held(root.path()), vec!["laptop_Read".to_owned()]);
}
#[test]
fn unload_without_tools_drops_that_clients_whole_set_and_no_others() {
let root = TempDir::new().expect("tmp");
load_from(
root.path(),
"laptop",
vec![tool("Bash"), tool("Read")],
&["Bash", "Read"],
);
load_from(root.path(), "desk", vec![tool("Bash")], &["Bash"]);
let said = answer(
&offline(root.path()),
&json!({"op": "unload", "client": "laptop"}),
&quiet(),
)
.expect("unloaded");
assert!(said.contains(" laptop_Bash"), "{said}");
assert!(said.contains(" laptop_Read"), "{said}");
assert!(said.contains("now holds 1 loaded tool."), "{said}");
assert_eq!(held(root.path()), vec!["desk_Bash".to_owned()]);
}
#[test]
fn an_unload_drops_only_the_named_clients_copy_of_a_shared_name() {
let root = TempDir::new().expect("tmp");
load_from(root.path(), "laptop", vec![tool("Bash")], &["Bash"]);
load_from(root.path(), "desk", vec![tool("Bash")], &["Bash"]);
answer(
&offline(root.path()),
&json!({"op": "unload", "client": "desk", "tools": ["Bash"]}),
&quiet(),
)
.expect("unloaded");
assert_eq!(held(root.path()), vec!["laptop_Bash".to_owned()]);
}
#[test]
fn a_tool_the_conversation_does_not_hold_refuses_the_whole_unload() {
let root = TempDir::new().expect("tmp");
load_from(root.path(), "laptop", vec![tool("Bash")], &["Bash"]);
let e = answer(
&offline(root.path()),
&json!({"op": "unload", "client": "laptop", "tools": ["Bash", "Read"]}),
&quiet(),
)
.expect_err("refused");
assert!(
e.contains("no tool \"Read\" loaded from client \"laptop\""),
"{e}"
);
assert_eq!(
held(root.path()),
vec!["laptop_Bash".to_owned()],
"the whole act was refused"
);
}
#[test]
fn a_client_this_conversation_loaded_nothing_from_refuses() {
let root = TempDir::new().expect("tmp");
load_from(root.path(), "laptop", vec![tool("Bash")], &["Bash"]);
let whole = answer(
&offline(root.path()),
&json!({"op": "unload", "client": "desk"}),
&quiet(),
)
.expect_err("refused");
assert!(
whole.contains("no tool loaded from client \"desk\""),
"{whole}"
);
let named = answer(
&offline(root.path()),
&json!({"op": "unload", "client": "desk", "tools": ["Bash"]}),
&quiet(),
)
.expect_err("refused");
assert!(
named.contains("no tool \"Bash\" loaded from client \"desk\""),
"{named}"
);
assert_eq!(held(root.path()), vec!["laptop_Bash".to_owned()]);
}
#[test]
fn a_load_after_an_unload_declares_it_again() {
let root = TempDir::new().expect("tmp");
load_from(root.path(), "laptop", vec![tool("Bash")], &["Bash"]);
answer(
&offline(root.path()),
&json!({"op": "unload", "client": "laptop"}),
&quiet(),
)
.expect("unloaded");
assert!(held(root.path()).is_empty());
load_from(root.path(), "laptop", vec![tool("Bash")], &["Bash"]);
assert_eq!(held(root.path()), vec!["laptop_Bash".to_owned()]);
let back = crate::tool_host::loaded::read(root.path(), "home", "dulcet-mongoose");
assert_eq!(back[0].tool, tool("Bash"), "the definition is frozen whole");
}
#[test]
fn an_unload_never_reaches_the_engine() {
let root = TempDir::new().expect("tmp");
crate::tool_host::loaded::add(
root.path(),
"home",
"dulcet-mongoose",
&[crate::tool_host::loaded::Entry {
client: "laptop".to_owned(),
tool: tool("Bash"),
}],
)
.expect("seeded");
answer(
&offline(root.path()),
&json!({"op": "unload", "client": "laptop"}),
&quiet(),
)
.expect("unloaded");
assert!(
crate::boundary::deposit::pending(root.path()).is_empty(),
"nothing was deposited"
);
}
#[test]
fn an_unload_that_cannot_be_recorded_says_so() {
let root = TempDir::new().expect("tmp");
load_from(root.path(), "laptop", vec![tool("Bash")], &["Bash"]);
let file = crate::tool_host::loaded::path(root.path(), "home", "dulcet-mongoose")
.expect("addressable");
std::fs::set_permissions(&file, std::fs::Permissions::from_mode(0o444)).expect("chmod");
let e = answer(
&offline(root.path()),
&json!({"op": "unload", "client": "laptop"}),
&quiet(),
)
.expect_err("unrecordable");
std::fs::set_permissions(&file, std::fs::Permissions::from_mode(0o644)).expect("chmod");
assert!(e.contains("recording the unload"), "{e}");
}