use crate::config::AgentConfig;
use crate::config::timeout::{TimeoutTier, resolve_timeout};
fn factory_source() -> String {
std::fs::read_to_string(
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/brain/provider/factory.rs"),
)
.expect("factory.rs must be readable")
}
#[test]
fn provider_tier_wins_over_agent_and_default() {
let r = resolve_timeout(Some(120), Some(60), Some(300));
assert_eq!(r.effective, Some(120));
assert_eq!(r.tier, TimeoutTier::Provider);
}
#[test]
fn agent_tier_applies_when_the_provider_names_none() {
let r = resolve_timeout(None, Some(60), Some(300));
assert_eq!(r.effective, Some(60));
assert_eq!(r.tier, TimeoutTier::Agent);
}
#[test]
fn compiled_default_applies_when_neither_tier_is_set() {
let r = resolve_timeout(None, None, Some(300));
assert_eq!(r.effective, Some(300));
assert_eq!(r.tier, TimeoutTier::Default);
assert!(!r.provider_zero && !r.agent_zero);
}
#[test]
fn a_zero_is_skipped_and_reported_never_honoured() {
let r = resolve_timeout(Some(0), None, Some(300));
assert_eq!(r.effective, Some(300), "0 must never become the timeout");
assert_eq!(r.tier, TimeoutTier::Default);
assert!(r.provider_zero, "the skipped tier must be visible");
}
#[test]
fn a_skipped_provider_zero_falls_through_to_the_agent_tier() {
let r = resolve_timeout(Some(0), Some(60), Some(300));
assert_eq!(r.effective, Some(60));
assert_eq!(r.tier, TimeoutTier::Agent);
assert!(r.provider_zero);
}
#[test]
fn both_tiers_zero_reports_both() {
let r = resolve_timeout(Some(0), Some(0), Some(300));
assert_eq!(r.effective, Some(300));
assert!(r.provider_zero && r.agent_zero);
assert_eq!(
r.zero_note(),
Some("[providers.<name>] and [agent] both carried 0")
);
}
#[test]
fn stream_idle_without_a_compiled_floor_defers_to_the_runtime_default() {
let r = resolve_timeout(None, None, None);
assert_eq!(r.effective, None, "must not invent a floor");
assert_eq!(r.tier, TimeoutTier::Default);
assert_eq!(r.duration(), None);
}
#[test]
fn duration_maps_the_effective_seconds() {
let r = resolve_timeout(None, Some(45), None);
assert_eq!(r.duration(), Some(std::time::Duration::from_secs(45)));
}
#[test]
fn the_compiled_default_is_never_reported_as_an_override() {
let unset = resolve_timeout(None, None, Some(300));
assert_eq!(unset.duration(), Some(std::time::Duration::from_secs(300)));
assert_eq!(unset.override_duration(), None);
let zeroed = resolve_timeout(Some(0), Some(0), Some(300));
assert_eq!(zeroed.override_duration(), None);
for configured in [
resolve_timeout(Some(120), None, Some(300)),
resolve_timeout(None, Some(60), Some(300)),
] {
assert_eq!(configured.override_duration(), configured.duration());
assert_ne!(configured.tier, TimeoutTier::Default);
}
}
#[test]
fn zero_note_names_only_the_section_that_actually_carried_it() {
assert_eq!(
resolve_timeout(Some(0), None, Some(300)).zero_note(),
Some("[providers.<name>] carried 0")
);
assert_eq!(
resolve_timeout(None, Some(0), Some(300)).zero_note(),
Some("[agent] carried 0")
);
assert_eq!(
resolve_timeout(Some(30), Some(30), Some(300)).zero_note(),
None,
"no skip, no warning"
);
}
#[test]
fn agent_config_parses_both_global_timeout_keys() {
let agent: AgentConfig = toml::from_str(
r#"
timeout_secs = 120
stream_idle_timeout_secs = 45
"#,
)
.expect("[agent] timeout_secs / stream_idle_timeout_secs must parse");
assert_eq!(agent.timeout_secs, Some(120));
assert_eq!(agent.stream_idle_timeout_secs, Some(45));
}
#[test]
fn agent_config_leaves_both_global_keys_unset_by_default() {
let agent = AgentConfig::default();
assert_eq!(agent.timeout_secs, None);
assert_eq!(agent.stream_idle_timeout_secs, None);
}
#[test]
fn factory_never_reads_a_timeout_tier_by_hand() {
let src = factory_source();
assert!(
!src.contains("filter(|&s| s > 0)"),
"a hand-rolled tier read is back in factory.rs — it bypasses the \
[providers.<name>] -> [agent] -> default chain (#1688)"
);
}
#[test]
fn factory_resolves_every_timeout_flag_through_the_chain() {
let src = factory_source();
for needle in [
"config.timeout_secs",
"agent.timeout_secs",
"config.stream_idle_timeout_secs",
"agent.stream_idle_timeout_secs",
"COMPAT_STREAM_IDLE_SECS",
] {
assert!(
src.contains(needle),
"factory.rs no longer mentions {needle} — one of the two tiers \
stopped being consulted for a timeout flag (#1688)"
);
}
assert!(
src.matches("resolve_and_report(").count() >= 2,
"expected resolve_and_report() to cover both flags, found {}",
src.matches("resolve_and_report(").count()
);
assert!(
src.matches("report_timeout_chain(").count() >= 3,
"expected report_timeout_chain() in the compat, anthropic and gemini \
families, found {}",
src.matches("report_timeout_chain(").count()
);
}