v0.3.3-pre.006
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-store-postgres-lib/unit_tests/raw_transaction.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
fn network() -> ksp_store_api::RawNetworkId {
|
||||
return match ksp_store_api::RawNetworkId::new("devnet") {
|
||||
@@ -353,3 +353,108 @@ fn pre_005_observation_origin_encoding_is_exact_and_static() {
|
||||
assert_eq!(super::encode_origin(ksp_store_api::RawAcquisitionOrigin::Replay), std::result::Result::Ok("replay"));
|
||||
return;
|
||||
}
|
||||
|
||||
fn page_query(
|
||||
network_id: &str,
|
||||
start: std::option::Option<u64>,
|
||||
end: std::option::Option<u64>,
|
||||
direction: ksp_store_api::RawSortDirection,
|
||||
cursor: std::option::Option<ksp_store_api::RawPageCursor>,
|
||||
) -> ksp_store_api::RawTransactionQuery {
|
||||
let network = match ksp_store_api::RawNetworkId::new(network_id) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid page-query network rejected: {error:?}"),
|
||||
};
|
||||
let range = match ksp_store_api::RawSlotRange::new(start, end) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid page-query range rejected: {error:?}"),
|
||||
};
|
||||
let limit = match ksp_store_api::RawPageLimit::new(2) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid page limit rejected: {error:?}"),
|
||||
};
|
||||
let page = match cursor {
|
||||
std::option::Option::Some(value) => ksp_store_api::RawPageRequest::after(limit, value),
|
||||
std::option::Option::None => ksp_store_api::RawPageRequest::first(limit),
|
||||
};
|
||||
return ksp_store_api::RawTransactionQuery::new(network, range, direction, page);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_006_cursor_v1_round_trip_is_fixed_109_bytes_and_exact() {
|
||||
let query = page_query("devnet", std::option::Option::Some(10), std::option::Option::Some(20), ksp_store_api::RawSortDirection::Ascending, None);
|
||||
let signature = ksp_store_api::RawTransactionSignature::new([7_u8; 64]);
|
||||
let cursor = match crate::encode_raw_transaction_cursor(&query, 15, &signature) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid cursor encoding rejected: {error:?}"),
|
||||
};
|
||||
assert_eq!(cursor.as_bytes().len(), 109);
|
||||
assert_eq!(cursor.as_bytes().get(0..4), std::option::Option::Some(b"KSPT".as_ref()));
|
||||
assert_eq!(cursor.as_bytes().get(4).copied(), std::option::Option::Some(1));
|
||||
let decoded = match crate::decode_raw_transaction_cursor(&query, &cursor) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid cursor decoding rejected: {error:?}"),
|
||||
};
|
||||
assert_eq!(decoded.last_slot, 15);
|
||||
assert_eq!(decoded.last_signature, [7_u8; 64]);
|
||||
assert_eq!(std::format!("{cursor:?}"), "RawPageCursor { len: 109 }");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_006_cursor_v1_rejects_replay_across_network_direction_and_range() {
|
||||
let query = page_query("devnet", std::option::Option::Some(10), std::option::Option::Some(20), ksp_store_api::RawSortDirection::Ascending, None);
|
||||
let signature = ksp_store_api::RawTransactionSignature::new([9_u8; 64]);
|
||||
let cursor = match crate::encode_raw_transaction_cursor(&query, 15, &signature) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid cursor encoding rejected: {error:?}"),
|
||||
};
|
||||
let other_network = page_query("mainnet-beta", Some(10), Some(20), ksp_store_api::RawSortDirection::Ascending, None);
|
||||
let other_direction = page_query("devnet", Some(10), Some(20), ksp_store_api::RawSortDirection::Descending, None);
|
||||
let other_range = page_query("devnet", Some(11), Some(20), ksp_store_api::RawSortDirection::Ascending, None);
|
||||
for candidate in [&other_network, &other_direction, &other_range] {
|
||||
let error = crate::decode_raw_transaction_cursor(candidate, &cursor).err();
|
||||
assert_eq!(error.map(|value| return value.kind()), Some(crate::PostgresBackendErrorKind::QueryInvalid));
|
||||
}
|
||||
let outside_range = page_query("devnet", Some(16), Some(20), ksp_store_api::RawSortDirection::Ascending, None);
|
||||
let error = crate::decode_raw_transaction_cursor(&outside_range, &cursor).err();
|
||||
assert_eq!(error.map(|value| return value.phase()), Some("raw_cursor_slot_range"));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_006_cursor_v1_hostile_size_magic_version_and_digest_are_rejected() {
|
||||
let query = page_query("devnet", None, None, ksp_store_api::RawSortDirection::Ascending, None);
|
||||
for size in [1_usize, 108, 109, 110, 4_096] {
|
||||
let raw = match ksp_store_api::RawPageCursor::try_new(vec![0_u8; size].into_boxed_slice()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("bounded hostile cursor rejected by API before backend test: {error:?}"),
|
||||
};
|
||||
assert!(crate::decode_raw_transaction_cursor(&query, &raw).is_err());
|
||||
}
|
||||
let signature = ksp_store_api::RawTransactionSignature::new([3_u8; 64]);
|
||||
let valid = match crate::encode_raw_transaction_cursor(&query, 42, &signature) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("valid cursor encoding rejected: {error:?}"),
|
||||
};
|
||||
for index in [0_usize, 4, 108] {
|
||||
let mut bytes = valid.as_bytes().to_vec();
|
||||
bytes[index] ^= 0xff;
|
||||
let hostile = match ksp_store_api::RawPageCursor::try_new(bytes.into_boxed_slice()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("fixed-size hostile cursor rejected by API before backend test: {error:?}"),
|
||||
};
|
||||
let error = crate::decode_raw_transaction_cursor(&query, &hostile).err();
|
||||
assert_eq!(error.map(|value| return value.kind()), Some(crate::PostgresBackendErrorKind::QueryInvalid));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_006_page_limit_exposes_only_the_real_postgres_limit_plus_one_boundary() {
|
||||
let maximum = crate::raw_transaction_physical_page_limit(9_223_372_036_854_775_806);
|
||||
assert_eq!(maximum, Ok((9_223_372_036_854_775_806_usize, i64::MAX)));
|
||||
let rejected = crate::raw_transaction_physical_page_limit(9_223_372_036_854_775_807).err();
|
||||
assert_eq!(rejected.map(|value| return value.kind()), Some(crate::PostgresBackendErrorKind::PageLimitUnsupported));
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user