use std::sync::{Arc, Mutex};
use serial_test::serial;
use trusty_common::inference::InferenceAdapter;
use trusty_common::inference::credentials::MemoryKeyStore;
use trusty_common::inference::registry::{ProviderId, capabilities};
use trusty_common::inference::test_support::ScriptedAdapter;
use super::{
DEFAULT_MANAGER_MODEL, FALLBACK_MODEL_ENV, InferenceUnavailable, Inner, MANAGER_MODEL_ENV,
ManagerInference, Source, resolve_manager_model,
};
fn clear_env() {
for var in [MANAGER_MODEL_ENV, FALLBACK_MODEL_ENV, "OPENROUTER_API_KEY"] {
unsafe { std::env::remove_var(var) };
}
}
fn credentialed_over(store: MemoryKeyStore, model: &str) -> ManagerInference {
let mut configurator = trusty_common::inference::Configurator::new();
trusty_common::inference::register_default_factories(&mut configurator);
ManagerInference {
inner: Mutex::new(Inner {
model: model.to_string(),
source: Source::Credentialed {
configurator,
store: Box::new(store),
},
}),
}
}
#[test]
#[serial(manager_inference_env)]
fn resolve_reports_no_provider_when_unconfigured() {
clear_env();
let seam = credentialed_over(MemoryKeyStore::new(), "openai/gpt-4o-mini");
let Err(err) = seam.resolve() else {
panic!("empty store must not resolve a provider");
};
assert!(matches!(err, InferenceUnavailable::NoProvider));
}
#[test]
fn resolve_returns_injected_adapter() {
let caps = capabilities(ProviderId::OpenRouter);
let scripted: Arc<dyn InferenceAdapter> = Arc::new(ScriptedAdapter::echo("scripted", caps));
let seam = ManagerInference::with_adapter(scripted, "test/model");
let (model, adapter) = seam.resolve().expect("fixed adapter resolves");
assert_eq!(model, "test/model");
assert_eq!(adapter.name(), "scripted");
}
#[test]
#[serial(manager_inference_env)]
fn set_adapter_overrides_credentialed_source() {
clear_env();
let seam = credentialed_over(MemoryKeyStore::new(), "openai/gpt-4o-mini");
assert!(seam.resolve().is_err(), "starts unconfigured");
let caps = capabilities(ProviderId::OpenRouter);
let scripted: Arc<dyn InferenceAdapter> = Arc::new(ScriptedAdapter::echo("scripted", caps));
seam.set_adapter(scripted, "swapped/model");
let (model, adapter) = seam.resolve().expect("resolves after swap");
assert_eq!(model, "swapped/model");
assert_eq!(adapter.name(), "scripted");
}
#[test]
#[serial(manager_inference_env)]
fn manager_model_env_precedence() {
clear_env();
assert_eq!(resolve_manager_model(), DEFAULT_MANAGER_MODEL);
unsafe { std::env::set_var(FALLBACK_MODEL_ENV, "fleet/model") };
assert_eq!(resolve_manager_model(), "fleet/model");
unsafe { std::env::set_var(MANAGER_MODEL_ENV, "manager/model") };
assert_eq!(resolve_manager_model(), "manager/model");
clear_env();
}