use anyhow::Result;
use nntp_proxy::RoutingMode;
use crate::test_helpers::{
connect_and_read_greeting, send_article_read_multiline_response, setup_proxy_with_backends,
};
#[tokio::test]
async fn test_availability_only_mode_tracks_backend_availability() -> Result<()> {
let (proxy_port, _backend_ports, _mock_handles) = setup_proxy_with_backends(
vec![("Backend1", true), ("Backend2", false)],
RoutingMode::PerCommand,
)
.await?;
let mut client = connect_and_read_greeting(proxy_port).await?;
let msgid = "<availability-test@example.com>";
let (status1, body1) = send_article_read_multiline_response(&mut client, msgid).await?;
assert!(
status1.starts_with("220"),
"First request should succeed: {status1}"
);
assert!(!body1.is_empty());
let (status2, body2) = send_article_read_multiline_response(&mut client, msgid).await?;
assert!(
status2.starts_with("220"),
"Second request should use cached availability"
);
assert!(!body2.is_empty());
Ok(())
}
#[tokio::test]
async fn test_availability_only_mode_retries_430() -> Result<()> {
let (proxy_port, _backend_ports, _mock_handles) = setup_proxy_with_backends(
vec![
("Backend1", false), ("Backend2", true), ],
RoutingMode::PerCommand,
)
.await?;
let mut client = connect_and_read_greeting(proxy_port).await?;
let (status, body) =
send_article_read_multiline_response(&mut client, "<retry-test@example.com>").await?;
assert!(
status.starts_with("220"),
"Should find article on Backend2 after retry"
);
assert!(!body.is_empty(), "Should return article body");
Ok(())
}
#[tokio::test]
async fn test_availability_only_mode_learns_from_requests() -> Result<()> {
let (proxy_port, _backend_ports, _mock_handles) = setup_proxy_with_backends(
vec![
("Backend1", false), ("Backend2", true), ],
RoutingMode::PerCommand,
)
.await?;
let mut client = connect_and_read_greeting(proxy_port).await?;
for i in 0..5 {
let msgid = format!("<article-{i}@example.com>");
let (status, body) = send_article_read_multiline_response(&mut client, &msgid).await?;
assert!(status.starts_with("220"), "Article {i} should succeed");
assert!(!body.is_empty());
}
Ok(())
}
#[tokio::test]
async fn test_availability_only_mode_mixed_availability() -> Result<()> {
let (proxy_port, _backend_ports, _mock_handles) = setup_proxy_with_backends(
vec![
("Backend1", true), ("Backend2", true), ],
RoutingMode::PerCommand,
)
.await?;
let mut client = connect_and_read_greeting(proxy_port).await?;
for i in 0..10 {
let msgid = format!("<mixed-article-{i}@example.com>");
let (status, _body) = send_article_read_multiline_response(&mut client, &msgid).await?;
assert!(
status.starts_with("220") || status.starts_with("430"),
"Valid response for article {i}"
);
}
Ok(())
}
#[tokio::test]
async fn test_availability_only_mode_all_backends_missing() -> Result<()> {
let (proxy_port, _backend_ports, _mock_handles) = setup_proxy_with_backends(
vec![
("Backend1", false),
("Backend2", false),
("Backend3", false),
],
RoutingMode::PerCommand,
)
.await?;
let mut client = connect_and_read_greeting(proxy_port).await?;
let (status, body) =
send_article_read_multiline_response(&mut client, "<missing@example.com>").await?;
assert!(
status.starts_with("430"),
"Should return 430 when all backends missing"
);
assert!(body.is_empty(), "430 response should have no body");
Ok(())
}