use crate::brain::provider::Provider;
use crate::brain::provider::factory::wrap_with_fallback_chain;
use crate::config::{Config, FallbackProviderConfig};
use std::sync::Arc;
#[tokio::test]
async fn rsi_wrap_returns_raw_when_no_fallback_configured() {
let mut config = Config::default();
config.providers.fallback = None;
let primary: Arc<dyn Provider> = Arc::new(crate::tests::agent_service_mocks::MockProvider);
let result = wrap_with_fallback_chain(&config, primary.clone())
.await
.unwrap();
assert!(
!result.is_fallback_chain(),
"with no fallback configured, wrap_with_fallback_chain must return the raw primary"
);
}
#[tokio::test]
async fn rsi_wrap_returns_raw_when_fallback_disabled() {
let mut config = Config::default();
config.providers.fallback = Some(FallbackProviderConfig {
enabled: false,
providers: vec!["minimax".to_string()],
provider: None,
});
let primary: Arc<dyn Provider> = Arc::new(crate::tests::agent_service_mocks::MockProvider);
let result = wrap_with_fallback_chain(&config, primary.clone())
.await
.unwrap();
assert!(
!result.is_fallback_chain(),
"with fallback disabled, wrap_with_fallback_chain must return the raw primary"
);
}
#[tokio::test]
async fn rsi_wrap_actually_wraps_when_valid_fallback_configured() {
use crate::config::ProviderConfig;
use std::collections::BTreeMap;
let mut config = Config::default();
let mut customs = BTreeMap::new();
customs.insert(
"stub-fallback".to_string(),
ProviderConfig {
enabled: true,
api_key: Some("test-key".to_string()),
base_url: Some("http://127.0.0.1:1/v1".to_string()),
default_model: Some("stub-model".to_string()),
..Default::default()
},
);
config.providers.custom = Some(customs);
config.providers.fallback = Some(FallbackProviderConfig {
enabled: true,
providers: vec!["stub-fallback".to_string()],
provider: None,
});
let primary: Arc<dyn Provider> = Arc::new(crate::tests::agent_service_mocks::MockProvider);
let result = wrap_with_fallback_chain(&config, primary.clone())
.await
.unwrap();
assert!(
result.is_fallback_chain(),
"with a valid fallback configured, wrap_with_fallback_chain must return a FallbackProvider — \
a no-op return would silently break the RSI loop's rescue path that this PR exists to fix"
);
}
#[tokio::test]
async fn rsi_wrap_skips_fallback_with_same_name_as_primary() {
let mut config = Config::default();
config.providers.fallback = Some(FallbackProviderConfig {
enabled: true,
providers: vec!["mock".to_string()],
provider: None,
});
let primary: Arc<dyn Provider> = Arc::new(crate::tests::agent_service_mocks::MockProvider);
let result = wrap_with_fallback_chain(&config, primary.clone())
.await
.unwrap();
assert!(
!result.is_fallback_chain(),
"fallback with the same name as primary must be filtered out — \
leaving an empty chain that produces no wrap. Without this, a primary 429 \
would cascade right back to itself, hitting the same dead endpoint."
);
}