use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use teloxide::RequestError;
use teloxide::types::Seconds;
#[tokio::test]
async fn long_rate_limit_bails_immediately() {
let attempts = Arc::new(AtomicU32::new(0));
let attempts_clone = attempts.clone();
let result = crate::channels::telegram::intermediates::send_retrying_rate_limit(
"test send",
move || {
let attempts = attempts_clone.clone();
async move {
attempts.fetch_add(1, Ordering::SeqCst);
Err::<(), _>(RequestError::RetryAfter(Seconds::from_seconds(28442)))
}
},
)
.await;
assert!(result.is_err(), "Long rate-limit should return error");
assert_eq!(
attempts.load(Ordering::SeqCst),
1,
"Long rate-limit should bail after 1 attempt, not retry"
);
}
#[tokio::test]
async fn short_rate_limit_retries_normally() {
let attempts = Arc::new(AtomicU32::new(0));
let attempts_clone = attempts.clone();
let result = crate::channels::telegram::intermediates::send_retrying_rate_limit(
"test send",
move || {
let attempts = attempts_clone.clone();
async move {
let count = attempts.fetch_add(1, Ordering::SeqCst);
if count < 3 {
Err::<(), _>(RequestError::RetryAfter(Seconds::from_seconds(30)))
} else {
Ok(())
}
}
},
)
.await;
assert!(
result.is_ok(),
"Short rate-limit should succeed after retries"
);
assert_eq!(
attempts.load(Ordering::SeqCst),
4,
"Short rate-limit should make 4 attempts (1 initial + 3 retries)"
);
}
#[tokio::test]
async fn rate_limit_at_threshold_retries() {
let attempts = Arc::new(AtomicU32::new(0));
let attempts_clone = attempts.clone();
let result = crate::channels::telegram::intermediates::send_retrying_rate_limit(
"test send",
move || {
let attempts = attempts_clone.clone();
async move {
attempts.fetch_add(1, Ordering::SeqCst);
Err::<(), _>(RequestError::RetryAfter(Seconds::from_seconds(3600)))
}
},
)
.await;
assert!(result.is_err(), "Should fail after exhausting retries");
assert_eq!(
attempts.load(Ordering::SeqCst),
4,
"Rate-limit at threshold should make 4 attempts (1 initial + 3 retries)"
);
}