use super::*;
use crate::config_edit::brazen::NOT_REQUIRED;
fn row(name: &str, auth: &str, credential: &str) -> ProviderRow {
ProviderRow {
name: name.to_owned(),
protocol: String::new(),
auth: auth.to_owned(),
credential: credential.to_owned(),
effort: false,
priority: false,
tools: Some(true),
device: String::new(),
}
}
fn role(role: &str, provider: &str) -> RoleModel {
RoleModel {
role: role.to_owned(),
provider: provider.to_owned(),
model: "m".to_owned(),
effort: None,
priority: false,
}
}
#[test]
fn a_lineage_that_declares_no_worker_falls_back_to_the_wall() {
let keyless = [
row("ollama", "none", NOT_REQUIRED),
row("acme", "api_key", "missing"),
];
assert_eq!(verdict(&keyless, &[], WORKER_ROLE), Some(Unready::Wall));
assert_eq!(
verdict(&[row("acme", "api_key", "stored")], &[], WORKER_ROLE),
None
);
assert_eq!(
verdict(
&[row(
"acme",
"api_key",
"a-spelling-this-build-never-heard-of"
)],
&[],
WORKER_ROLE
),
None,
"every spelling but missing and not-required is a credential"
);
}
#[test]
fn a_credentialed_row_the_roles_do_not_name_readies_nothing() {
let rows = [
row("sideline", "bearer", "ambient"),
row("anthropic", "api_key", "missing"),
];
let roles = [role("worker", "anthropic")];
assert_eq!(
verdict(&rows, &roles, WORKER_ROLE),
Some(Unready::Uncredentialed {
row: rows[1].clone(),
})
);
let signed = [rows[0].clone(), row("anthropic", "api_key", "stored")];
assert_eq!(verdict(&signed, &roles, WORKER_ROLE), None);
}
#[test]
fn a_role_naming_a_keyless_row_readies_the_wall() {
let rows = [row("ollama", "none", NOT_REQUIRED)];
assert_eq!(
verdict(&rows, &[role("worker", "ollama")], WORKER_ROLE),
None
);
assert_eq!(verdict(&rows, &[], WORKER_ROLE), Some(Unready::Wall));
}
#[test]
fn only_the_fired_role_gates_the_fire() {
let rows = [row("acme", "api_key", "stored")];
assert_eq!(
verdict(
&rows,
&[
role("worker", "acme"),
role("compactor", "gone"),
role("reviewer", "also-gone"),
],
WORKER_ROLE
),
None
);
assert_eq!(
verdict(
&rows,
&[role("compactor", "acme"), role("worker", "gone")],
WORKER_ROLE
),
Some(Unready::Undeclared {
provider: "gone".to_owned(),
})
);
}
#[test]
fn each_refusal_names_its_own_act() {
let rows = [
row("openai-chatgpt", "oauth2", "missing"),
row("anthropic", "api_key", "missing"),
];
let keyed = refusal::say(
&Unready::Uncredentialed {
row: rows[1].clone(),
},
&rows,
WORKER_ROLE,
);
assert!(keyed.starts_with("sign in first"), "{keyed}");
assert!(
keyed.contains("`worker` resolves provider `anthropic`"),
"{keyed}"
);
assert!(keyed.ends_with("/config brazen"), "{keyed}");
let oauth = refusal::say(
&Unready::Uncredentialed {
row: rows[0].clone(),
},
&rows,
WORKER_ROLE,
);
assert!(oauth.ends_with("/login openai-chatgpt"), "{oauth}");
let absent = refusal::say(
&Unready::Undeclared {
provider: "claude-session-direct".to_owned(),
},
&rows,
WORKER_ROLE,
);
assert!(!absent.contains("/login"), "{absent}");
assert!(absent.contains("declares no such row"), "{absent}");
assert!(absent.contains("/config brazen"), "{absent}");
assert!(
absent.contains("/model worker <provider> <model-id>"),
"{absent}"
);
assert!(
absent.ends_with("(rows here: openai-chatgpt, anthropic)"),
"{absent}"
);
let wall = refusal::say(&Unready::Wall, &rows, WORKER_ROLE);
assert!(wall.starts_with("sign in first"), "{wall}");
assert!(
wall.ends_with(
"sign in with /login: openai-chatgpt; \
write a key with /config brazen: anthropic"
),
"{wall}"
);
}
#[test]
fn the_wall_offers_each_row_the_act_that_would_ready_it() {
let mut rows = vec![
row("openai-chatgpt", "oauth2", "missing"),
row("anthropic", "api_key", "missing"),
row("google", "api_key", "missing"),
row("ollama", "none", NOT_REQUIRED),
row("claude-code", "none", NOT_REQUIRED),
];
rows[4].tools = Some(false);
rows[4].protocol = "claude_code".to_owned();
let said = refusal::say(&Unready::Wall, &rows, WORKER_ROLE);
assert!(
said.ends_with(
"sign in with /login: openai-chatgpt; \
write a key with /config brazen: anthropic, google; \
name in a role with /model <role> <provider> <model-id>: ollama; \
can serve no role: claude-code"
),
"{said}"
);
let one = refusal::say(&Unready::Wall, &rows[3..4], WORKER_ROLE);
assert!(
one.ends_with("name in a role with /model <role> <provider> <model-id>: ollama"),
"{one}"
);
}
#[test]
fn the_role_the_start_names_is_the_one_the_door_reads() {
let rows = [
row("anthropic", "api_key", "stored"),
row("openai-chatgpt", "oauth2", "missing"),
];
let roles = [
role("worker", "anthropic"),
role("planner", "openai-chatgpt"),
];
assert_eq!(
verdict(&rows, &roles, WORKER_ROLE),
None,
"the worker is fine"
);
assert_eq!(
verdict(&rows, &roles, "planner"),
Some(Unready::Uncredentialed {
row: rows[1].clone(),
}),
"and the planner is not"
);
let flipped = [
row("anthropic", "api_key", "missing"),
row("openai-chatgpt", "oauth2", "stored"),
];
assert_eq!(verdict(&flipped, &roles, "planner"), None);
assert_eq!(
verdict(&flipped, &roles, WORKER_ROLE),
Some(Unready::Uncredentialed {
row: flipped[0].clone(),
})
);
}
#[test]
fn a_role_shaped_refusal_names_the_role_that_fired() {
let rows = [row("anthropic", "api_key", "missing")];
let said = refusal::say(
&Unready::Uncredentialed {
row: rows[0].clone(),
},
&rows,
"planner",
);
assert!(
said.contains("`planner` resolves provider `anthropic`"),
"{said}"
);
let absent = refusal::say(
&Unready::Undeclared {
provider: "gone".to_owned(),
},
&rows,
"planner",
);
assert!(
absent.contains("/model planner <provider> <model-id>"),
"{absent}"
);
}