Files
khadhroony-solana-project/crates/ksp-job-backfill-lib/unit_tests/runtime.rs

159 lines
6.8 KiB
Rust

// file: crates/ksp-job-backfill-lib/unit_tests/runtime.rs
// version: 3
use ksp_job_api::JobSnapshotSource; // rust-rules: trait-import
fn request() -> std::option::Option<crate::BackfillRequest> {
let signature = match crate::BackfillSignature::new("1".repeat(crate::MIN_BACKFILL_SIGNATURE_TEXT_BYTES)) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::option::Option::None,
};
let scope = match crate::BackfillScope::explicit_signatures(std::vec![signature]) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::option::Option::None,
};
let job_id = match ksp_job_api::JobId::new("backfill:runtime-test") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::option::Option::None,
};
let network = match ksp_store_lib::RawNetworkId::new("devnet") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return std::option::Option::None,
};
return crate::BackfillRequest::new(
job_id,
network,
ksp_onchain_transport_lib::HttpRoleName::new("history"),
crate::BackfillCommitment::Confirmed,
scope,
100,
10,
1,
1,
std::option::Option::None,
)
.ok();
}
#[tokio::test]
async fn pre_009_latest_value_source_coalesces_progress_for_slow_independent_listeners() {
let request = match request() {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let runtime = match crate::BackfillJobRuntime::new(request) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let handle = runtime.handle();
let listener_a = handle.snapshots();
let listener_b = handle.snapshots();
let initial = listener_a.current();
assert_eq!(initial.sequence().value(), 0);
assert_eq!(initial.state(), ksp_job_api::JobState::Created);
let first = runtime.publisher.publish_running(crate::BackfillJobPhase::Discovering);
assert!(first.is_ok());
let second = runtime.publisher.publish_running(crate::BackfillJobPhase::Executing);
assert!(second.is_ok());
let coalesced = listener_a.wait_for_change(initial.sequence()).await;
assert_eq!(coalesced.sequence().value(), 2);
assert_eq!(coalesced.snapshot().phase(), crate::BackfillJobPhase::Executing);
let listener_b_current = listener_b.current();
assert_eq!(listener_b_current.sequence().value(), 2);
assert_eq!(listener_b_current.snapshot().phase(), crate::BackfillJobPhase::Executing);
return;
}
#[tokio::test]
async fn pre_009_terminal_snapshot_is_retained_and_late_cancellation_is_rejected() {
let request = match request() {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let runtime = match crate::BackfillJobRuntime::new(request) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let handle = runtime.handle();
let listener = handle.snapshots();
let started = runtime.publisher.publish_running(crate::BackfillJobPhase::Discovering);
assert!(started.is_ok());
assert_eq!(runtime.control.claim_normal_terminal(), super::TerminalClaim::Completed);
let terminal = runtime.publisher.publish_terminal(ksp_job_api::JobState::Completed(ksp_job_api::JobCompletion::Complete), std::option::Option::None);
assert!(terminal.is_ok());
assert!(!handle.cancel());
let current = listener.current();
assert!(current.state().is_terminal());
assert_eq!(current.snapshot().phase(), crate::BackfillJobPhase::Finished);
let retained = listener.wait_for_change(current.sequence()).await;
assert_eq!(retained.sequence(), current.sequence());
assert_eq!(retained.state(), current.state());
return;
}
#[test]
fn pre_009_terminal_race_is_first_decision_wins_for_cancellation_vs_completion() {
let (cancel_sender, _) = tokio::sync::watch::channel(false);
let cancellation_first = super::BackfillRuntimeControl::new(cancel_sender);
assert!(cancellation_first.request_cancellation());
assert_eq!(cancellation_first.claim_normal_terminal(), super::TerminalClaim::Cancelled);
assert!(!cancellation_first.request_cancellation());
let (cancel_sender, _) = tokio::sync::watch::channel(false);
let completion_first = super::BackfillRuntimeControl::new(cancel_sender);
assert_eq!(completion_first.claim_normal_terminal(), super::TerminalClaim::Completed);
assert!(!completion_first.request_cancellation());
return;
}
#[test]
fn pre_009_fatal_failure_overrides_pending_cancellation_before_terminal_publication() {
let (cancel_sender, _) = tokio::sync::watch::channel(false);
let control = super::BackfillRuntimeControl::new(cancel_sender);
assert!(control.request_cancellation());
control.claim_failed();
assert_eq!(control.claim_normal_terminal(), super::TerminalClaim::Failed);
assert!(!control.request_cancellation());
return;
}
#[tokio::test]
async fn pre_009_long_running_pre_store_future_is_cancelled_cooperatively() {
let (cancel_sender, cancel_receiver) = tokio::sync::watch::channel(false);
let control = super::BackfillRuntimeControl::new(cancel_sender);
let signal = crate::BackfillCancellationSignal::new(control.token(), cancel_receiver);
let operation = std::future::pending::<ksp_core_lib::Result<usize>>();
let wait = signal.run_cancellable(operation);
let cancel = async {
tokio::task::yield_now().await;
assert!(control.request_cancellation());
};
let (result, ()) = tokio::join!(wait, 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);
return;
}
#[test]
fn pre_009_snapshot_debug_and_public_shape_do_not_include_transport_or_raw_payloads() {
let request = match request() {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let runtime = match crate::BackfillJobRuntime::new(request) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let snapshot = runtime.handle().snapshots().current();
let debug = format!("{:?}", snapshot.snapshot());
for forbidden in ["http://", "https://", "endpoint", "provider", "raw_payload", "transaction_data"] {
assert!(!debug.contains(forbidden), "unsafe snapshot diagnostic leaked: {forbidden}");
}
assert_eq!(snapshot.snapshot().scope_kind(), crate::BackfillScopeKind::ExplicitSignatures);
assert_eq!(snapshot.snapshot().candidates_selected(), 0);
assert!(snapshot.snapshot().failure_code().is_none());
return;
}