v0.2.5-pre.009

This commit is contained in:
2026-08-20 09:24:10 +02:00
parent 1125ade4c1
commit e91bf36e9e
83 changed files with 2467 additions and 1801 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/unit_tests/resilience.rs
// version: 1
// version: 2
fn non_zero(value: u32) -> std::num::NonZeroU32 {
return std::num::NonZeroU32::new(value).expect("test limit must be non-zero");
@@ -46,46 +46,46 @@ fn retry_backoff_is_exponential_and_bounded() {
#[test]
fn retry_safe_timeout_is_retried_until_budget_is_exhausted() {
let settings = retry_settings();
let first = super::evaluate_transport_retry(
let first = crate::evaluate_transport_retry(
method("getBalance"),
&settings,
super::HttpRetryCause::Timeout,
super::HttpDispatchState::DispatchedAmbiguous,
crate::HttpRetryCause::Timeout,
crate::HttpDispatchState::DispatchedAmbiguous,
0,
std::option::Option::None,
);
assert_eq!(first, super::HttpRetryDecision::RetryAfter(std::time::Duration::from_millis(100)));
let exhausted = super::evaluate_transport_retry(
assert_eq!(first, crate::HttpRetryDecision::RetryAfter(std::time::Duration::from_millis(100)));
let exhausted = crate::evaluate_transport_retry(
method("getBalance"),
&settings,
super::HttpRetryCause::Timeout,
super::HttpDispatchState::DispatchedAmbiguous,
crate::HttpRetryCause::Timeout,
crate::HttpDispatchState::DispatchedAmbiguous,
settings.max_retries(),
std::option::Option::None,
);
assert_eq!(exhausted, super::HttpRetryDecision::Stop);
assert_eq!(exhausted, crate::HttpRetryDecision::Stop);
}
#[test]
fn write_submission_never_retries_after_ambiguous_dispatch() {
let decision = super::evaluate_transport_retry(
let decision = crate::evaluate_transport_retry(
method("sendTransaction"),
&retry_settings(),
super::HttpRetryCause::Connection,
super::HttpDispatchState::DispatchedAmbiguous,
crate::HttpRetryCause::Connection,
crate::HttpDispatchState::DispatchedAmbiguous,
0,
std::option::Option::None,
);
assert_eq!(decision, super::HttpRetryDecision::Stop);
assert_eq!(decision, crate::HttpRetryDecision::Stop);
}
#[test]
fn write_submission_can_retry_when_transport_proves_no_dispatch() {
let decision = super::evaluate_transport_retry(
let decision = crate::evaluate_transport_retry(
method("sendTransaction"),
&retry_settings(),
super::HttpRetryCause::Connection,
super::HttpDispatchState::NotDispatched,
crate::HttpRetryCause::Connection,
crate::HttpDispatchState::NotDispatched,
0,
std::option::Option::None,
);
@@ -94,36 +94,36 @@ fn write_submission_can_retry_when_transport_proves_no_dispatch() {
#[test]
fn rpc_application_and_invalid_response_are_not_transport_retries() {
for cause in [super::HttpRetryCause::RpcApplication, super::HttpRetryCause::InvalidResponse, super::HttpRetryCause::Request] {
let decision = super::evaluate_transport_retry(
for cause in [crate::HttpRetryCause::RpcApplication, crate::HttpRetryCause::InvalidResponse, crate::HttpRetryCause::Request] {
let decision = crate::evaluate_transport_retry(
method("getBalance"),
&retry_settings(),
cause,
super::HttpDispatchState::NotDispatched,
crate::HttpDispatchState::NotDispatched,
0,
std::option::Option::None,
);
assert_eq!(decision, super::HttpRetryDecision::Stop);
assert_eq!(decision, crate::HttpRetryDecision::Stop);
}
}
#[test]
fn provider_retry_after_can_extend_backoff_but_is_defensively_bounded() {
let settings = retry_settings();
let extended = super::evaluate_transport_retry(
let extended = crate::evaluate_transport_retry(
method("getBalance"),
&settings,
super::HttpRetryCause::RateLimited,
super::HttpDispatchState::DispatchedAmbiguous,
crate::HttpRetryCause::RateLimited,
crate::HttpDispatchState::DispatchedAmbiguous,
0,
std::option::Option::Some(std::time::Duration::from_secs(3)),
);
assert_eq!(extended.delay(), std::option::Option::Some(std::time::Duration::from_secs(3)));
let bounded = super::evaluate_transport_retry(
let bounded = crate::evaluate_transport_retry(
method("getBalance"),
&settings,
super::HttpRetryCause::RateLimited,
super::HttpDispatchState::DispatchedAmbiguous,
crate::HttpRetryCause::RateLimited,
crate::HttpDispatchState::DispatchedAmbiguous,
0,
std::option::Option::Some(std::time::Duration::from_secs(600)),
);
@@ -144,29 +144,29 @@ fn token_bucket_consumes_burst_then_refills_from_elapsed_time() {
#[test]
fn absent_burst_capacity_defaults_to_one_second_of_rps_capacity() {
let role = role_limits(std::option::Option::Some(2), std::option::Option::None, std::option::Option::None, std::option::Option::None);
let runtime = std::sync::Arc::new(super::HttpRoleRuntime::new(&role, std::sync::Arc::new(tokio::sync::Notify::new())));
let runtime = std::sync::Arc::new(crate::HttpRoleRuntime::new(&role, std::sync::Arc::new(tokio::sync::Notify::new())));
let now = std::time::Instant::now();
let first = runtime.try_acquire(now);
let second = runtime.try_acquire(now);
let third = runtime.try_acquire(now);
assert!(matches!(first, super::RoleAdmissionAttempt::Ready(_)));
assert!(matches!(second, super::RoleAdmissionAttempt::Ready(_)));
assert!(matches!(third, super::RoleAdmissionAttempt::BlockedUntil(_)));
assert!(matches!(first, crate::RoleAdmissionAttempt::Ready(_)));
assert!(matches!(second, crate::RoleAdmissionAttempt::Ready(_)));
assert!(matches!(third, crate::RoleAdmissionAttempt::BlockedUntil(_)));
}
#[test]
fn concurrency_semaphore_releases_capacity_when_permit_is_dropped() {
let role = role_limits(std::option::Option::None, std::option::Option::None, std::option::Option::Some(1), std::option::Option::None);
let runtime = std::sync::Arc::new(super::HttpRoleRuntime::new(&role, std::sync::Arc::new(tokio::sync::Notify::new())));
let runtime = std::sync::Arc::new(crate::HttpRoleRuntime::new(&role, std::sync::Arc::new(tokio::sync::Notify::new())));
let now = std::time::Instant::now();
let first = runtime.try_acquire(now);
let held = match first {
super::RoleAdmissionAttempt::Ready(permit) => permit,
crate::RoleAdmissionAttempt::Ready(permit) => permit,
_ => panic!("first concurrency permit must be available"),
};
assert!(matches!(runtime.try_acquire(now), super::RoleAdmissionAttempt::ConcurrencySaturated));
assert!(matches!(runtime.try_acquire(now), crate::RoleAdmissionAttempt::ConcurrencySaturated));
drop(held);
assert!(matches!(runtime.try_acquire(now), super::RoleAdmissionAttempt::Ready(_)));
assert!(matches!(runtime.try_acquire(now), crate::RoleAdmissionAttempt::Ready(_)));
}
#[test]
@@ -177,7 +177,7 @@ fn rate_limit_cooldown_marks_role_and_caps_provider_delay() {
std::option::Option::None,
std::option::Option::Some(std::time::Duration::from_millis(10)),
);
let runtime = super::HttpRoleRuntime::new(&role, std::sync::Arc::new(tokio::sync::Notify::new()));
let runtime = crate::HttpRoleRuntime::new(&role, std::sync::Arc::new(tokio::sync::Notify::new()));
let pause = runtime.record_rate_limited(std::option::Option::Some(std::time::Duration::from_secs(600)));
assert_eq!(pause, std::time::Duration::from_secs(60));
assert_eq!(runtime.rate_limit_count(), 1);