// file: crates/ksp-offchain-transport-lib/unit_tests/http_admission.rs // version: 2 #[test] fn fixed_admission_smooths_undocumented_burst_and_refills_deterministically() -> ksp_core_lib::Result<()> { let policy = match crate::HttpAdmissionPolicy::fixed(2, std::time::Duration::from_secs(1), std::option::Option::None) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let controller = match crate::HttpAdmissionController::new(policy, std::option::Option::None) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let start = std::time::Instant::now(); assert!(matches!(controller.try_admit_at(start), crate::HttpAdmissionDecision::Ready)); let deferred = controller.try_admit_at(start); let delay = match deferred { crate::HttpAdmissionDecision::Deferred(value) => value, crate::HttpAdmissionDecision::Ready => { return std::result::Result::Err(ksp_core_lib::Error::new(crate::ERROR_CODE_HTTP_RATE_LIMIT_INVALID, "test expected local deferral")); }, }; assert!(delay > std::time::Duration::ZERO); let half_second = match start.checked_add(std::time::Duration::from_millis(500)) { std::option::Option::Some(value) => value, std::option::Option::None => { return std::result::Result::Err(ksp_core_lib::Error::new(crate::ERROR_CODE_HTTP_RATE_LIMIT_INVALID, "test instant overflow")); }, }; assert!(matches!(controller.try_admit_at(half_second), crate::HttpAdmissionDecision::Ready)); return std::result::Result::Ok(()); } #[test] fn documented_burst_may_exceed_average_window_budget_and_is_consumed_atomically() -> ksp_core_lib::Result<()> { let policy = match crate::HttpAdmissionPolicy::fixed(1, std::time::Duration::from_secs(1), std::option::Option::Some(2)) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let controller = match crate::HttpAdmissionController::new(policy, std::option::Option::None) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let start = std::time::Instant::now(); assert!(matches!(controller.try_admit_at(start), crate::HttpAdmissionDecision::Ready)); assert!(matches!(controller.try_admit_at(start), crate::HttpAdmissionDecision::Ready)); assert!(matches!(controller.try_admit_at(start), crate::HttpAdmissionDecision::Deferred(_))); return std::result::Result::Ok(()); } #[test] fn provider_retry_after_extends_but_cannot_pathologically_lock_cooldown() -> ksp_core_lib::Result<()> { let controller = match crate::HttpAdmissionController::new(crate::HttpAdmissionPolicy::Dynamic, std::option::Option::Some(std::time::Duration::from_secs(2))) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let applied = controller.record_rate_limited(std::option::Option::Some(std::time::Duration::from_secs(99_999))); assert_eq!(applied, crate::HTTP_MAX_RETRY_AFTER); let remaining = controller.cooldown_remaining(); assert!(remaining.is_some()); assert!(matches!(controller.try_admit(), crate::HttpAdmissionDecision::Deferred(_))); return std::result::Result::Ok(()); } #[test] fn admission_policy_rejects_zero_values_and_invalid_fallback() { assert!(crate::HttpAdmissionPolicy::fixed(0, std::time::Duration::from_secs(1), std::option::Option::None).is_err()); assert!(crate::HttpAdmissionPolicy::fixed(1, std::time::Duration::ZERO, std::option::Option::None).is_err()); assert!(crate::HttpAdmissionPolicy::fixed(1, std::time::Duration::from_secs(1), std::option::Option::Some(0)).is_err()); }