v0.3.6-pre.009

This commit is contained in:
2026-09-01 16:04:58 +02:00
parent d89aee9910
commit b861a1e3b8
16 changed files with 1846 additions and 86 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-job-backfill-lib/unit_tests/discovery.rs
// version: 2
// version: 5
#[derive(Clone, Debug, Eq, PartialEq)]
struct PageCall {
@@ -15,6 +15,34 @@ struct FakeSource {
calls: std::sync::Mutex<std::vec::Vec<PageCall>>,
}
struct PendingSource {
calls: std::sync::atomic::AtomicUsize,
}
impl PendingSource {
fn new() -> Self {
return Self { calls: std::sync::atomic::AtomicUsize::new(0) };
}
fn calls(&self) -> usize {
return self.calls.load(std::sync::atomic::Ordering::Acquire);
}
}
impl super::SignaturePageSource for PendingSource {
fn fetch_signature_page<'a>(
&'a self,
_role: &'a ksp_onchain_transport_lib::HttpRoleName,
_address: &'a ksp_core_lib::Pubkey,
_config: ksp_onchain_transport_lib::SolanaSignaturesForAddressConfig,
) -> super::SignaturePageFuture<'a> {
self.calls.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
return std::boxed::Box::pin(async {
return std::future::pending::<ksp_core_lib::Result<std::vec::Vec<super::SignaturePageEntry>>>().await;
});
}
}
impl FakeSource {
fn new(pages: std::vec::Vec<std::vec::Vec<super::SignaturePageEntry>>) -> Self {
return Self { pages: std::sync::Mutex::new(pages.into()), calls: std::sync::Mutex::new(std::vec::Vec::new()) };
@@ -130,7 +158,7 @@ async fn pre_005_latest_paginates_newest_first_and_deduplicates_pages_stably() {
std::vec![page_entry('6', 60), page_entry('5', 50), page_entry('5', 50)],
std::vec![page_entry('4', 40), page_entry('3', 30)],
]);
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
assert!(result.is_ok());
let discovery = match result {
std::result::Result::Ok(value) => value,
@@ -164,7 +192,7 @@ async fn pre_005_before_uses_exclusive_anchor_then_advances_rpc_cursor() {
std::option::Option::None => return,
};
let source = FakeSource::new(std::vec![std::vec![page_entry('6', 60), page_entry('5', 50)], std::vec![page_entry('4', 40)]]);
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
let discovery = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -194,7 +222,7 @@ async fn pre_005_after_keeps_only_nearest_newer_window_and_preserves_rpc_order()
std::vec![page_entry('7', 70), page_entry('6', 60), page_entry('5', 50)],
std::vec![page_entry('4', 40), page_entry('3', 30)],
]);
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
let discovery = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -223,7 +251,7 @@ async fn pre_005_after_page_bound_is_partial_and_does_not_claim_anchor_completio
std::option::Option::None => return,
};
let source = FakeSource::new(std::vec![std::vec![page_entry('7', 70), page_entry('6', 60)], std::vec![page_entry('5', 50), page_entry('4', 40)],]);
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
let discovery = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -243,7 +271,7 @@ async fn pre_005_latest_page_bound_is_partial_when_full_pages_leave_more_history
std::option::Option::None => return,
};
let source = FakeSource::new(std::vec![std::vec![page_entry('7', 70), page_entry('6', 60)]]);
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
let discovery = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -293,7 +321,7 @@ async fn pre_005_explicit_scope_never_calls_transport_and_preserves_network_scop
std::result::Result::Err(_) => return,
};
let source = FakeSource::new(std::vec::Vec::new());
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
let discovery = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
@@ -327,7 +355,7 @@ async fn pre_008_before_resume_uses_checkpoint_cursor_instead_of_original_anchor
std::result::Result::Err(_) => return,
};
let source = FakeSource::new(std::vec![std::vec![page_entry('4', 40)]]);
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
assert!(result.is_ok());
let calls = source.calls();
assert_eq!(calls.len(), 1);
@@ -348,10 +376,36 @@ async fn pre_008_latest_resume_restarts_from_current_latest_without_rpc_cursor()
std::result::Result::Err(_) => return,
};
let source = FakeSource::new(std::vec![std::vec![page_entry('7', 70)]]);
let result = super::discover_with_source(&source, &request).await;
let result = super::discover_with_source(&source, &request, std::option::Option::None).await;
assert!(result.is_ok());
let calls = source.calls();
assert_eq!(calls.len(), 1);
assert_eq!(calls[0].before, std::option::Option::None);
return;
}
#[tokio::test]
async fn pre_009_discovery_rpc_wait_is_cancelled_cooperatively() {
let scope = crate::BackfillScope::latest_address(ksp_core_lib::Pubkey::new_from_array([9_u8; 32]));
let request = match request(scope, 2, 2, 5) {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let source = PendingSource::new();
let (cancel_sender, cancel_receiver) = tokio::sync::watch::channel(false);
let control = crate::BackfillRuntimeControl::new(cancel_sender);
let cancellation = crate::BackfillCancellationSignal::new(control.token(), cancel_receiver);
let discovery = super::discover_with_source(&source, &request, std::option::Option::Some(&cancellation));
let cancel = async {
tokio::task::yield_now().await;
assert!(control.request_cancellation());
};
let (result, ()) = tokio::join!(discovery, cancel);
let error = match result {
std::result::Result::Ok(_) => return,
std::result::Result::Err(error) => error,
};
assert_eq!(error.code(), crate::ERROR_CODE_BACKFILL_CANCELLED);
assert_eq!(source.calls(), 1);
return;
}