use crate::config::LlmConfig;
use crate::llm::chain::ProviderChain;
use crate::llm::error::LlmError;
#[test]
fn an_empty_chain_is_refused() {
let err = ProviderChain::new(&[]).expect_err("a chain needs at least one provider");
match err {
LlmError::NotConfigured(message) => assert!(
message.contains("[[llm]]"),
"the message must name the config section, got {message:?}"
),
other => panic!("expected NotConfigured, got {other:?}"),
}
}
#[test]
fn a_misconfigured_entry_is_fatal_and_names_its_position() {
let good = LlmConfig {
endpoint: Some("http://localhost:1/v1".to_owned()),
model: Some("a".to_owned()),
..LlmConfig::default()
};
let no_endpoint = LlmConfig {
model: Some("b".to_owned()),
..LlmConfig::default()
};
let err = ProviderChain::new(&[&good, &no_endpoint]).expect_err("entry 2 has no endpoint");
match err {
LlmError::NotConfigured(message) => {
assert!(
message.contains("#2"),
"the message must name the second entry, got {message:?}"
);
assert!(
message.contains("endpoint"),
"the message must keep the underlying reason, got {message:?}"
);
}
other => panic!("expected NotConfigured, got {other:?}"),
}
}
#[test]
fn a_disabled_entry_reaching_the_chain_is_an_error() {
let disabled = LlmConfig {
enabled: false,
endpoint: Some("http://localhost:1/v1".to_owned()),
model: Some("a".to_owned()),
..LlmConfig::default()
};
let err = ProviderChain::new(&[&disabled]).expect_err("a disabled entry must not build");
assert!(
matches!(err, LlmError::NotConfigured(_)),
"expected NotConfigured, got {err:?}"
);
}
#[test]
fn providers_keep_their_order_with_their_own_model_and_endpoint() {
let first = LlmConfig {
endpoint: Some("http://first/v1".to_owned()),
model: Some("model-one".to_owned()),
..LlmConfig::default()
};
let second = LlmConfig {
endpoint: Some("http://second/v1".to_owned()),
model: Some("model-two".to_owned()),
..LlmConfig::default()
};
let chain = ProviderChain::new(&[&first, &second]).expect("chain builds");
let seen: Vec<(&str, &str)> = chain
.providers()
.iter()
.map(|p| (p.model(), p.location()))
.collect();
assert_eq!(
seen,
vec![
("model-one", "http://first/v1"),
("model-two", "http://second/v1"),
]
);
}
#[test]
fn a_fresh_chain_has_no_provider_down() {
let cfg = LlmConfig {
endpoint: Some("http://localhost:1/v1".to_owned()),
model: Some("a".to_owned()),
..LlmConfig::default()
};
let chain = ProviderChain::new(&[&cfg]).expect("chain builds");
assert!(!chain.providers()[0].is_down());
assert_eq!(chain.providers()[0].served(), 0);
}