169 lines
7.4 KiB
Rust
169 lines
7.4 KiB
Rust
// file: crates/ksp-job-backfill-lib/unit_tests/checkpoint.rs
|
|
// version: 1
|
|
|
|
fn signature(character: char) -> std::option::Option<crate::BackfillSignature> {
|
|
return crate::BackfillSignature::new(character.to_string().repeat(crate::MIN_BACKFILL_SIGNATURE_TEXT_BYTES)).ok();
|
|
}
|
|
|
|
fn request(scope: crate::BackfillScope) -> std::option::Option<crate::BackfillRequest> {
|
|
let job_id = match ksp_job_api::JobId::new("backfill:checkpoint-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,
|
|
10,
|
|
4,
|
|
std::option::Option::None,
|
|
)
|
|
.ok();
|
|
}
|
|
|
|
fn candidate(request: &crate::BackfillRequest, character: char) -> std::option::Option<crate::BackfillCandidate> {
|
|
let signature = match signature(character) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return std::option::Option::None,
|
|
};
|
|
let identity = crate::BackfillCandidateIdentity::new(request.network().clone(), signature);
|
|
return std::option::Option::Some(crate::BackfillCandidate::new(identity, std::option::Option::None));
|
|
}
|
|
|
|
fn discovery(
|
|
request: &crate::BackfillRequest,
|
|
characters: &[char],
|
|
boundary: crate::BackfillDiscoveryBoundary,
|
|
) -> std::option::Option<crate::BackfillDiscovery> {
|
|
let mut candidates = std::vec::Vec::with_capacity(characters.len());
|
|
for character in characters {
|
|
let value = match candidate(request, *character) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return std::option::Option::None,
|
|
};
|
|
candidates.push(value);
|
|
}
|
|
return std::option::Option::Some(crate::BackfillDiscovery::new(request.network().clone(), request.scope_fingerprint(), candidates, 1, boundary));
|
|
}
|
|
|
|
#[test]
|
|
fn pre_008_frontier_advances_only_across_contiguous_durable_results() {
|
|
let mut frontier = crate::CompletionFrontier::new(4);
|
|
assert!(frontier.mark_durable(1).is_ok());
|
|
assert_eq!(frontier.contiguous_completed(), 0);
|
|
assert!(frontier.mark_durable(0).is_ok());
|
|
assert_eq!(frontier.contiguous_completed(), 2);
|
|
assert!(frontier.mark_durable(3).is_ok());
|
|
assert_eq!(frontier.contiguous_completed(), 2);
|
|
assert!(frontier.mark_durable(2).is_ok());
|
|
assert_eq!(frontier.contiguous_completed(), 4);
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn pre_008_checkpoint_is_bound_to_job_and_scope_fingerprint() {
|
|
let scope = crate::BackfillScope::latest_address(ksp_core_lib::Pubkey::new_from_array([1_u8; 32]));
|
|
let request = match request(scope) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let other_job = match ksp_job_api::JobId::new("backfill:other") {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let wrong_job = crate::BackfillCheckpoint::new(other_job, request.scope_fingerprint(), 0, std::option::Option::None);
|
|
let result = request.clone().with_checkpoint(wrong_job);
|
|
assert!(result.is_err());
|
|
if let std::result::Result::Err(error) = result {
|
|
assert_eq!(error.code(), crate::ERROR_CODE_BACKFILL_CHECKPOINT_INVALID);
|
|
}
|
|
let other_scope = crate::BackfillScope::latest_address(ksp_core_lib::Pubkey::new_from_array([2_u8; 32]));
|
|
let other_request = match request(other_scope) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let wrong_scope = crate::BackfillCheckpoint::new(request.job_id().clone(), other_request.scope_fingerprint(), 0, std::option::Option::None);
|
|
assert!(request.with_checkpoint(wrong_scope).is_err());
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn pre_008_before_checkpoint_is_cumulative_and_tracks_last_contiguous_candidate() {
|
|
let anchor = match signature('8') {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let scope = crate::BackfillScope::before_address(ksp_core_lib::Pubkey::new_from_array([3_u8; 32]), anchor);
|
|
let request = match request(scope) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let first_discovery = match discovery(&request, &['7', '6', '5'], crate::BackfillDiscoveryBoundary::RpcBoundary) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mut first_frontier = crate::CompletionFrontier::new(3);
|
|
assert!(first_frontier.mark_durable(1).is_ok());
|
|
assert_eq!(first_frontier.contiguous_completed(), 0);
|
|
assert!(first_frontier.mark_durable(0).is_ok());
|
|
let first = match crate::checkpoint_from_frontier(&request, &first_discovery, &first_frontier) {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(first.completed_prefix(), 2);
|
|
let expected_first = "6".repeat(64);
|
|
assert_eq!(first.resume_before().map(crate::BackfillSignature::as_str), std::option::Option::Some(expected_first.as_str()));
|
|
let resumed = match request.with_checkpoint(first) {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let second_discovery = match discovery(&resumed, &['5', '4'], crate::BackfillDiscoveryBoundary::RpcBoundary) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mut second_frontier = crate::CompletionFrontier::new(2);
|
|
assert!(second_frontier.mark_durable(0).is_ok());
|
|
let second = match crate::checkpoint_from_frontier(&resumed, &second_discovery, &second_frontier) {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(second.completed_prefix(), 3);
|
|
let expected_second = "5".repeat(64);
|
|
assert_eq!(second.resume_before().map(crate::BackfillSignature::as_str), std::option::Option::Some(expected_second.as_str()));
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn pre_008_after_anchor_not_reached_never_advances_checkpoint() {
|
|
let anchor = match signature('1') {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let scope = crate::BackfillScope::after_address(ksp_core_lib::Pubkey::new_from_array([4_u8; 32]), anchor);
|
|
let request = match request(scope) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let partial = match discovery(&request, &['7', '6', '5'], crate::BackfillDiscoveryBoundary::AfterAnchorNotReached) {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let mut frontier = crate::CompletionFrontier::new(3);
|
|
assert!(frontier.mark_durable(0).is_ok());
|
|
assert!(frontier.mark_durable(1).is_ok());
|
|
let checkpoint = match crate::checkpoint_from_frontier(&request, &partial, &frontier) {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(checkpoint.completed_prefix(), 0);
|
|
return;
|
|
}
|