litellm-rs 0.6.0

A high-performance AI Gateway written in Rust, providing OpenAI-compatible APIs with intelligent routing, load balancing, and enterprise features
Documentation
use super::{
    Budget, BudgetAmount, BudgetAmountError, BudgetReservationError, BudgetScope, BudgetTracker,
};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Barrier, Mutex};
use std::thread;

fn budget(max_budget: f64) -> Budget {
    Budget::new("global", "Global", BudgetScope::Global, max_budget)
}

#[test]
fn budget_amount_rejects_invalid_inputs() {
    assert!(matches!(
        BudgetAmount::from_f64(f64::NAN),
        Err(BudgetAmountError::NonFinite)
    ));
    assert!(matches!(
        BudgetAmount::from_f64(f64::INFINITY),
        Err(BudgetAmountError::NonFinite)
    ));
    assert!(matches!(
        BudgetAmount::from_f64(-0.01),
        Err(BudgetAmountError::Negative)
    ));
}

#[test]
fn tracker_reservation_settle_refunds_unused_amount() {
    let tracker = BudgetTracker::new();
    tracker.register_budget(budget(100.0));

    let reservation = tracker.reserve_spend(&BudgetScope::Global, 10.0).unwrap();
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 10.0);

    let result = reservation.settle(3.0).unwrap().unwrap();
    assert_eq!(result.current_spend, 3.0);
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 3.0);
}

#[test]
fn tracker_reservation_settle_records_actual_above_reserved_amount() {
    let tracker = BudgetTracker::new();
    tracker.register_budget(budget(10.0));

    let reservation = tracker.reserve_spend(&BudgetScope::Global, 5.0).unwrap();
    let result = reservation.settle(12.0).unwrap().unwrap();

    assert_eq!(result.current_spend, 12.0);
    assert_eq!(result.new_status, super::BudgetStatus::Exceeded);
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 12.0);
}

#[test]
fn tracker_reservation_records_spend_for_disabled_budget() {
    let tracker = BudgetTracker::new();
    let mut budget = budget(100.0);
    budget.enabled = false;
    tracker.register_budget(budget);

    let reservation = tracker.reserve_spend(&BudgetScope::Global, 10.0).unwrap();
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 0.0);

    let result = reservation.settle(4.0).unwrap().unwrap();
    assert_eq!(result.current_spend, 4.0);
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 4.0);
}

#[test]
fn tracker_reservation_settle_preserves_alert_transitions() {
    let tracker = BudgetTracker::new();
    tracker.register_budget(budget(10.0));

    let reservation = tracker.reserve_spend(&BudgetScope::Global, 9.0).unwrap();
    let result = reservation.settle(9.0).unwrap().unwrap();

    assert!(result.should_alert_soft_limit);
    assert!(!result.should_alert_exceeded);

    let reservation = tracker.reserve_spend(&BudgetScope::Global, 0.5).unwrap();
    let result = reservation.settle(2.0).unwrap().unwrap();

    assert!(!result.should_alert_soft_limit);
    assert!(result.should_alert_exceeded);
}

#[test]
fn tracker_reservation_cancel_and_drop_release_amount() {
    let tracker = BudgetTracker::new();
    tracker.register_budget(budget(100.0));

    tracker
        .reserve_spend(&BudgetScope::Global, 25.0)
        .unwrap()
        .cancel();
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 0.0);

    {
        let _reservation = tracker.reserve_spend(&BudgetScope::Global, 40.0).unwrap();
        assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 40.0);
    }
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 0.0);
}

#[test]
fn tracker_reservation_rejects_invalid_and_oversized_amounts() {
    let tracker = BudgetTracker::new();
    tracker.register_budget(budget(10.0));

    assert!(matches!(
        tracker.reserve_spend(&BudgetScope::Global, f64::NAN),
        Err(BudgetReservationError::InvalidAmount(
            BudgetAmountError::NonFinite
        ))
    ));
    assert!(matches!(
        tracker.reserve_spend(&BudgetScope::Global, 11.0),
        Err(BudgetReservationError::BudgetExceeded)
    ));
    assert!(
        tracker
            .record_spend(&BudgetScope::Global, f64::INFINITY)
            .is_none()
    );
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 0.0);
}

#[test]
fn tracker_reservation_settle_after_reset_records_actual_spend() {
    let tracker = BudgetTracker::new();
    tracker.register_budget(budget(100.0));

    let reservation = tracker.reserve_spend(&BudgetScope::Global, 10.0).unwrap();
    assert!(tracker.reset_budget(&BudgetScope::Global));
    tracker.record_spend(&BudgetScope::Global, 5.0);

    let result = reservation.settle(3.0).unwrap().unwrap();
    assert_eq!(result.current_spend, 8.0);
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 8.0);
}

#[test]
fn tracker_reservation_cancel_after_reset_keeps_new_period_spend() {
    let tracker = BudgetTracker::new();
    tracker.register_budget(budget(100.0));

    let reservation = tracker.reserve_spend(&BudgetScope::Global, 10.0).unwrap();
    assert!(tracker.reset_budget(&BudgetScope::Global));
    tracker.record_spend(&BudgetScope::Global, 5.0);

    reservation.cancel();
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 5.0);
}

#[test]
fn concurrent_reservations_allow_only_one_last_budget_winner() {
    let tracker = Arc::new(BudgetTracker::new());
    tracker.register_budget(budget(10.0));
    let barrier = Arc::new(Barrier::new(16));
    let winners = Arc::new(AtomicUsize::new(0));
    let reservations = Arc::new(Mutex::new(Vec::new()));

    let handles: Vec<_> = (0..16)
        .map(|_| {
            let tracker = Arc::clone(&tracker);
            let barrier = Arc::clone(&barrier);
            let winners = Arc::clone(&winners);
            let reservations = Arc::clone(&reservations);
            thread::spawn(move || {
                barrier.wait();
                if let Ok(reservation) = tracker.reserve_spend(&BudgetScope::Global, 10.0) {
                    winners.fetch_add(1, Ordering::SeqCst);
                    reservations.lock().unwrap().push(reservation);
                }
            })
        })
        .collect();

    for handle in handles {
        handle.join().unwrap();
    }

    assert_eq!(winners.load(Ordering::SeqCst), 1);
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 10.0);
    reservations.lock().unwrap().clear();
    assert_eq!(tracker.get_current_spend(&BudgetScope::Global), 0.0);
}