999 lines
50 KiB
Rust
999 lines
50 KiB
Rust
// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs
|
||
// version: 32
|
||
|
||
//! Release-level completeness canaries for staged HTTP and WebSocket Transport coverage.
|
||
|
||
#[test]
|
||
fn release_registry_partition_matches_the_audited_http_plan() {
|
||
let mut foundation = 0_usize;
|
||
let mut accounts_tokens_cluster = 0_usize;
|
||
let mut transactions = 0_usize;
|
||
let mut blocks_economics = 0_usize;
|
||
let mut historical_in_current = 0_usize;
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
match descriptor.coverage_release() {
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 => foundation += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 => accounts_tokens_cluster += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 => transactions += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 => blocks_economics += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical => historical_in_current += 1,
|
||
}
|
||
}
|
||
assert_eq!(ksp_onchain_transport_lib::current_http_rpc_methods().len(), 52);
|
||
assert_eq!(ksp_onchain_transport_lib::historical_http_rpc_methods().len(), 14);
|
||
assert_eq!(foundation, 4);
|
||
assert_eq!(accounts_tokens_cluster, 22);
|
||
assert_eq!(transactions, 11);
|
||
assert_eq!(blocks_economics, 15);
|
||
assert_eq!(historical_in_current, 0);
|
||
}
|
||
|
||
#[test]
|
||
fn release_foundation_canaries_and_historical_statuses_are_exact() {
|
||
let mut foundation_names = std::vec::Vec::<&str>::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 {
|
||
foundation_names.push(descriptor.method());
|
||
assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported);
|
||
}
|
||
}
|
||
foundation_names.sort_unstable();
|
||
assert_eq!(foundation_names, std::vec!["getBalance", "getGenesisHash", "getHealth", "getVersion"]);
|
||
for descriptor in ksp_onchain_transport_lib::historical_http_rpc_methods() {
|
||
assert_eq!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Deprecated);
|
||
assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Removed);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NotApplicable);
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_003_accounts_subset_is_exact_without_advancing_other_v0_2_2_families() {
|
||
let mut account_names = std::vec::Vec::<&str>::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2
|
||
&& descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Accounts
|
||
{
|
||
account_names.push(descriptor.method());
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
}
|
||
account_names.sort_unstable();
|
||
assert_eq!(
|
||
account_names,
|
||
std::vec!["getAccountInfo", "getLargestAccounts", "getMinimumBalanceForRentExemption", "getMultipleAccounts", "getProgramAccounts",],
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_004_tokens_subset_is_exact_and_retry_safe() {
|
||
let mut token_names = std::vec::Vec::<&str>::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2
|
||
&& descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Tokens
|
||
{
|
||
token_names.push(descriptor.method());
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
}
|
||
token_names.sort_unstable();
|
||
assert_eq!(
|
||
token_names,
|
||
std::vec!["getTokenAccountBalance", "getTokenAccountsByDelegate", "getTokenAccountsByOwner", "getTokenLargestAccounts", "getTokenSupply",],
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_005_simple_cluster_subset_is_exact_and_retry_safe() {
|
||
let expected = std::vec![
|
||
"getClusterNodes",
|
||
"getEpochInfo",
|
||
"getEpochSchedule",
|
||
"getHighestSnapshotSlot",
|
||
"getIdentity",
|
||
"getMaxRetransmitSlot",
|
||
"getMaxShredInsertSlot",
|
||
];
|
||
let deferred = std::vec!["getLeaderSchedule", "getSlot", "getSlotLeader", "getSlotLeaders", "getVoteAccounts"];
|
||
for method_name in &expected {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.005 cluster descriptor must exist");
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Cluster);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
for method_name in &deferred {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 cluster descriptor must remain registered");
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2);
|
||
}
|
||
assert_eq!(expected.len(), 7);
|
||
assert_eq!(deferred.len(), 5);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_006_completes_cluster_subset_exactly_and_retry_safe() {
|
||
let mut expected = std::vec![
|
||
"getClusterNodes",
|
||
"getEpochInfo",
|
||
"getEpochSchedule",
|
||
"getHighestSnapshotSlot",
|
||
"getIdentity",
|
||
"getLeaderSchedule",
|
||
"getMaxRetransmitSlot",
|
||
"getMaxShredInsertSlot",
|
||
"getSlot",
|
||
"getSlotLeader",
|
||
"getSlotLeaders",
|
||
"getVoteAccounts",
|
||
];
|
||
let mut actual = std::vec::Vec::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2
|
||
&& descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Cluster
|
||
{
|
||
actual.push(descriptor.method());
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 12);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_007_v0_2_2_exact_set_is_complete_without_advancing_future_releases() {
|
||
let mut expected = std::vec![
|
||
"getAccountInfo",
|
||
"getClusterNodes",
|
||
"getEpochInfo",
|
||
"getEpochSchedule",
|
||
"getHighestSnapshotSlot",
|
||
"getIdentity",
|
||
"getLargestAccounts",
|
||
"getLeaderSchedule",
|
||
"getMaxRetransmitSlot",
|
||
"getMaxShredInsertSlot",
|
||
"getMinimumBalanceForRentExemption",
|
||
"getMultipleAccounts",
|
||
"getProgramAccounts",
|
||
"getSlot",
|
||
"getSlotLeader",
|
||
"getSlotLeaders",
|
||
"getTokenAccountBalance",
|
||
"getTokenAccountsByDelegate",
|
||
"getTokenAccountsByOwner",
|
||
"getTokenLargestAccounts",
|
||
"getTokenSupply",
|
||
"getVoteAccounts",
|
||
];
|
||
let mut actual = std::vec::Vec::new();
|
||
let mut future_transactions = 0_usize;
|
||
let mut future_blocks_economics = 0_usize;
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
match descriptor.coverage_release() {
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 => {
|
||
actual.push(descriptor.method());
|
||
assert_eq!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Stable);
|
||
assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
},
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 => future_transactions += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 => future_blocks_economics += 1,
|
||
_ => {},
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 22);
|
||
assert_eq!(future_transactions, 11);
|
||
assert_eq!(future_blocks_economics, 15);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_3_descriptor_set_and_safety_classes_are_exact() {
|
||
let mut expected = std::vec![
|
||
"getFeeForMessage",
|
||
"getLatestBlockhash",
|
||
"getRecentPrioritizationFees",
|
||
"getSignaturesForAddress",
|
||
"getSignatureStatuses",
|
||
"getTransaction",
|
||
"getTransactionCount",
|
||
"isBlockhashValid",
|
||
"requestAirdrop",
|
||
"sendTransaction",
|
||
"simulateTransaction",
|
||
];
|
||
let mut actual = std::vec::Vec::new();
|
||
let mut reads = 0_usize;
|
||
let mut writes = 0_usize;
|
||
let mut simulations = 0_usize;
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 {
|
||
continue;
|
||
}
|
||
actual.push(descriptor.method());
|
||
match descriptor.operation_kind() {
|
||
ksp_onchain_transport_lib::RpcOperationKind::Read => {
|
||
reads += 1;
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
},
|
||
ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => {
|
||
writes += 1;
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
|
||
},
|
||
ksp_onchain_transport_lib::RpcOperationKind::Simulation => {
|
||
simulations += 1;
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
},
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(reads, 8);
|
||
assert_eq!(writes, 2);
|
||
assert_eq!(simulations, 1);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_003_transaction_read_subset_is_exact_and_retry_safe() {
|
||
let mut expected = std::vec!["getFeeForMessage", "getLatestBlockhash", "getTransactionCount", "isBlockhashValid"];
|
||
let mut actual = std::vec::Vec::new();
|
||
for method_name in &expected {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.003 Transaction descriptor must exist");
|
||
actual.push(descriptor.method());
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 4);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_004_transaction_read_subset_is_exact_and_retry_safe() {
|
||
let mut expected = std::vec![
|
||
"getFeeForMessage",
|
||
"getLatestBlockhash",
|
||
"getRecentPrioritizationFees",
|
||
"getSignaturesForAddress",
|
||
"getSignatureStatuses",
|
||
"getTransactionCount",
|
||
"isBlockhashValid",
|
||
];
|
||
let deferred = std::vec!["getTransaction", "requestAirdrop", "sendTransaction", "simulateTransaction"];
|
||
let mut actual = std::vec::Vec::new();
|
||
for method_name in &expected {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.004 Transaction descriptor must exist");
|
||
actual.push(descriptor.method());
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
for method_name in &deferred {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("deferred Transaction descriptor must remain registered");
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 7);
|
||
assert_eq!(deferred.len(), 4);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_005_transaction_read_subset_adds_complete_get_transaction_without_advancing_writes_or_simulation() {
|
||
let mut expected = std::vec![
|
||
"getFeeForMessage",
|
||
"getLatestBlockhash",
|
||
"getRecentPrioritizationFees",
|
||
"getSignaturesForAddress",
|
||
"getSignatureStatuses",
|
||
"getTransaction",
|
||
"getTransactionCount",
|
||
"isBlockhashValid",
|
||
];
|
||
let deferred = std::vec!["requestAirdrop", "sendTransaction", "simulateTransaction"];
|
||
let mut actual = std::vec::Vec::new();
|
||
for method_name in &expected {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.005 Transaction descriptor must exist");
|
||
actual.push(descriptor.method());
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist");
|
||
assert!(get_transaction.request_form_status().has_deprecated_legacy());
|
||
for method_name in &deferred {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("deferred Transaction descriptor must remain registered");
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 8);
|
||
assert_eq!(deferred.len(), 3);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_006_transaction_subset_adds_both_write_submissions_without_advancing_simulation() {
|
||
let reads = std::vec![
|
||
"getFeeForMessage",
|
||
"getLatestBlockhash",
|
||
"getRecentPrioritizationFees",
|
||
"getSignaturesForAddress",
|
||
"getSignatureStatuses",
|
||
"getTransaction",
|
||
"getTransactionCount",
|
||
"isBlockhashValid",
|
||
];
|
||
let writes = std::vec!["requestAirdrop", "sendTransaction"];
|
||
for method_name in &reads {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 read descriptor must exist");
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
for method_name in &writes {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 write descriptor must exist");
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
|
||
}
|
||
let simulation = ksp_onchain_transport_lib::find_http_rpc_method("simulateTransaction").expect("simulation descriptor must remain registered");
|
||
assert_eq!(simulation.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Simulation);
|
||
assert_eq!(reads.len(), 8);
|
||
assert_eq!(writes.len(), 2);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_007_completes_all_v0_2_3_transaction_wrappers_with_exact_safety_classes() {
|
||
let reads = std::vec![
|
||
"getFeeForMessage",
|
||
"getLatestBlockhash",
|
||
"getRecentPrioritizationFees",
|
||
"getSignaturesForAddress",
|
||
"getSignatureStatuses",
|
||
"getTransaction",
|
||
"getTransactionCount",
|
||
"isBlockhashValid",
|
||
];
|
||
let writes = std::vec!["requestAirdrop", "sendTransaction"];
|
||
let simulations = std::vec!["simulateTransaction"];
|
||
for method_name in &reads {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 read descriptor must exist");
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
for method_name in &writes {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 write descriptor must exist");
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
|
||
}
|
||
for method_name in &simulations {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 simulation descriptor must exist");
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Simulation);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
assert_eq!(reads.len(), 8);
|
||
assert_eq!(writes.len(), 2);
|
||
assert_eq!(simulations.len(), 1);
|
||
assert_eq!(reads.len() + writes.len() + simulations.len(), 11);
|
||
}
|
||
|
||
#[test]
|
||
fn release_pre_008_ksp_transport_007_retro_audit_covers_all_typed_current_methods() {
|
||
let mut audited = std::vec::Vec::<&str>::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if matches!(
|
||
descriptor.coverage_release(),
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1
|
||
| ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2
|
||
| ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3
|
||
) {
|
||
audited.push(descriptor.method());
|
||
assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported);
|
||
match descriptor.operation_kind() {
|
||
ksp_onchain_transport_lib::RpcOperationKind::Read | ksp_onchain_transport_lib::RpcOperationKind::Simulation => {
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
},
|
||
ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => {
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
|
||
},
|
||
}
|
||
}
|
||
}
|
||
audited.sort_unstable();
|
||
assert_eq!(audited.len(), 37);
|
||
assert_eq!(audited.first(), std::option::Option::Some(&"getAccountInfo"));
|
||
assert_eq!(audited.last(), std::option::Option::Some(&"simulateTransaction"));
|
||
let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist");
|
||
assert!(get_transaction.request_form_status().has_deprecated_legacy());
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_descriptor_set_is_exact_and_remains_read_retry_safe_through_wrapper_completion() {
|
||
let mut expected_blocks = std::vec![
|
||
"getBlock",
|
||
"getBlockCommitment",
|
||
"getBlockHeight",
|
||
"getBlockProduction",
|
||
"getBlocks",
|
||
"getBlocksWithLimit",
|
||
"getBlockTime",
|
||
"getFirstAvailableBlock",
|
||
"getRecentPerformanceSamples",
|
||
"minimumLedgerSlot",
|
||
];
|
||
let mut expected_economics = std::vec!["getInflationGovernor", "getInflationRate", "getInflationReward", "getStakeMinimumDelegation", "getSupply",];
|
||
let mut actual_blocks = std::vec::Vec::new();
|
||
let mut actual_economics = std::vec::Vec::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 {
|
||
continue;
|
||
}
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
match descriptor.category() {
|
||
ksp_onchain_transport_lib::HttpRpcCategory::Blocks => actual_blocks.push(descriptor.method()),
|
||
ksp_onchain_transport_lib::HttpRpcCategory::Economics => actual_economics.push(descriptor.method()),
|
||
_ => {},
|
||
}
|
||
}
|
||
actual_blocks.sort_unstable();
|
||
actual_economics.sort_unstable();
|
||
expected_blocks.sort_unstable();
|
||
expected_economics.sort_unstable();
|
||
assert_eq!(actual_blocks, expected_blocks);
|
||
assert_eq!(actual_economics, expected_economics);
|
||
assert_eq!(actual_blocks.len(), 10);
|
||
assert_eq!(actual_economics.len(), 5);
|
||
let get_block = ksp_onchain_transport_lib::find_http_rpc_method("getBlock").expect("getBlock descriptor must exist");
|
||
assert!(get_block.request_form_status().has_deprecated_legacy());
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_pre_003_simple_blocks_subset_is_exact_and_retry_safe() {
|
||
let mut expected = std::vec!["getBlockCommitment", "getBlockHeight", "getBlockTime", "getFirstAvailableBlock", "minimumLedgerSlot"];
|
||
let mut actual = std::vec::Vec::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4
|
||
|| descriptor.category() != ksp_onchain_transport_lib::HttpRpcCategory::Blocks
|
||
{
|
||
continue;
|
||
}
|
||
match descriptor.method() {
|
||
"getBlockCommitment" | "getBlockHeight" | "getBlockTime" | "getFirstAvailableBlock" | "minimumLedgerSlot" => {
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
actual.push(descriptor.method());
|
||
},
|
||
_ => {},
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 5);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_pre_004_range_performance_subset_is_exact_and_retry_safe() {
|
||
let mut expected = std::vec!["getBlocks", "getBlocksWithLimit", "getRecentPerformanceSamples"];
|
||
let mut actual = std::vec::Vec::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4
|
||
|| descriptor.category() != ksp_onchain_transport_lib::HttpRpcCategory::Blocks
|
||
{
|
||
continue;
|
||
}
|
||
match descriptor.method() {
|
||
"getBlocks" | "getBlocksWithLimit" | "getRecentPerformanceSamples" => {
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
actual.push(descriptor.method());
|
||
},
|
||
_ => {},
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 3);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_pre_005_block_production_subset_is_exact_and_retry_safe() {
|
||
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method("getBlockProduction").expect("getBlockProduction descriptor must exist");
|
||
assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Blocks);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4);
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_pre_006_get_block_completes_all_ten_block_wrappers_with_legacy_marker() {
|
||
let expected = std::vec![
|
||
"getBlock",
|
||
"getBlockCommitment",
|
||
"getBlockHeight",
|
||
"getBlockProduction",
|
||
"getBlocks",
|
||
"getBlocksWithLimit",
|
||
"getBlockTime",
|
||
"getFirstAvailableBlock",
|
||
"getRecentPerformanceSamples",
|
||
"minimumLedgerSlot",
|
||
];
|
||
let mut actual = std::vec::Vec::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4
|
||
&& descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Blocks
|
||
{
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
actual.push(descriptor.method());
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
let mut expected = expected;
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 10);
|
||
let get_block = ksp_onchain_transport_lib::find_http_rpc_method("getBlock").expect("getBlock descriptor must exist");
|
||
assert!(get_block.request_form_status().has_deprecated_legacy());
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_pre_007_simple_economics_subset_is_exact_and_retry_safe() {
|
||
let mut expected = std::vec!["getInflationGovernor", "getInflationRate", "getStakeMinimumDelegation", "getSupply"];
|
||
let mut actual = std::vec::Vec::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4
|
||
|| descriptor.category() != ksp_onchain_transport_lib::HttpRpcCategory::Economics
|
||
{
|
||
continue;
|
||
}
|
||
assert!(matches!(
|
||
descriptor.method(),
|
||
"getInflationGovernor" | "getInflationRate" | "getInflationReward" | "getStakeMinimumDelegation" | "getSupply"
|
||
));
|
||
if descriptor.method() != "getInflationReward" {
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
actual.push(descriptor.method());
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 4);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_pre_008_completes_all_five_economics_wrappers_exactly_and_retry_safe() {
|
||
let mut expected = std::vec!["getInflationGovernor", "getInflationRate", "getInflationReward", "getStakeMinimumDelegation", "getSupply"];
|
||
let mut actual = std::vec::Vec::new();
|
||
for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() {
|
||
if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4
|
||
&& descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Economics
|
||
{
|
||
actual.push(descriptor.method());
|
||
assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
}
|
||
}
|
||
actual.sort_unstable();
|
||
expected.sort_unstable();
|
||
assert_eq!(actual, expected);
|
||
assert_eq!(actual.len(), 5);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_4_pre_009_final_http_inventory_and_coverage_partition_are_exact() {
|
||
let expected_current = std::vec![
|
||
"getAccountInfo",
|
||
"getBalance",
|
||
"getBlock",
|
||
"getBlockCommitment",
|
||
"getBlockHeight",
|
||
"getBlockProduction",
|
||
"getBlocks",
|
||
"getBlocksWithLimit",
|
||
"getBlockTime",
|
||
"getClusterNodes",
|
||
"getEpochInfo",
|
||
"getEpochSchedule",
|
||
"getFeeForMessage",
|
||
"getFirstAvailableBlock",
|
||
"getGenesisHash",
|
||
"getHealth",
|
||
"getHighestSnapshotSlot",
|
||
"getIdentity",
|
||
"getInflationGovernor",
|
||
"getInflationRate",
|
||
"getInflationReward",
|
||
"getLargestAccounts",
|
||
"getLatestBlockhash",
|
||
"getLeaderSchedule",
|
||
"getMaxRetransmitSlot",
|
||
"getMaxShredInsertSlot",
|
||
"getMinimumBalanceForRentExemption",
|
||
"getMultipleAccounts",
|
||
"getProgramAccounts",
|
||
"getRecentPerformanceSamples",
|
||
"getRecentPrioritizationFees",
|
||
"getSignaturesForAddress",
|
||
"getSignatureStatuses",
|
||
"getSlot",
|
||
"getSlotLeader",
|
||
"getSlotLeaders",
|
||
"getStakeMinimumDelegation",
|
||
"getSupply",
|
||
"getTokenAccountBalance",
|
||
"getTokenAccountsByDelegate",
|
||
"getTokenAccountsByOwner",
|
||
"getTokenLargestAccounts",
|
||
"getTokenSupply",
|
||
"getTransaction",
|
||
"getTransactionCount",
|
||
"getVersion",
|
||
"getVoteAccounts",
|
||
"isBlockhashValid",
|
||
"minimumLedgerSlot",
|
||
"requestAirdrop",
|
||
"sendTransaction",
|
||
"simulateTransaction",
|
||
];
|
||
let expected_historical = std::vec![
|
||
"confirmTransaction",
|
||
"getConfirmedBlock",
|
||
"getConfirmedBlocks",
|
||
"getConfirmedBlocksWithLimit",
|
||
"getConfirmedSignaturesForAddress2",
|
||
"getConfirmedTransaction",
|
||
"getFeeCalculatorForBlockhash",
|
||
"getFeeRateGovernor",
|
||
"getFees",
|
||
"getRecentBlockhash",
|
||
"getSignatureConfirmation",
|
||
"getSignatureStatus",
|
||
"getSnapshotSlot",
|
||
"getStakeActivation",
|
||
];
|
||
let current = ksp_onchain_transport_lib::current_http_rpc_methods();
|
||
let historical = ksp_onchain_transport_lib::historical_http_rpc_methods();
|
||
let mut actual_current = std::vec::Vec::with_capacity(current.len());
|
||
let mut actual_historical = std::vec::Vec::with_capacity(historical.len());
|
||
let mut v0_2_1 = 0_usize;
|
||
let mut v0_2_2 = 0_usize;
|
||
let mut v0_2_3 = 0_usize;
|
||
let mut v0_2_4 = 0_usize;
|
||
let mut historical_current = 0_usize;
|
||
for descriptor in current {
|
||
actual_current.push(descriptor.method());
|
||
assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported);
|
||
assert_ne!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Deprecated);
|
||
match descriptor.coverage_release() {
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 => v0_2_1 += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 => v0_2_2 += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 => v0_2_3 += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 => v0_2_4 += 1,
|
||
ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical => historical_current += 1,
|
||
}
|
||
match descriptor.operation_kind() {
|
||
ksp_onchain_transport_lib::RpcOperationKind::Read | ksp_onchain_transport_lib::RpcOperationKind::Simulation => {
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe);
|
||
},
|
||
ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => {
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch);
|
||
},
|
||
}
|
||
}
|
||
for descriptor in historical {
|
||
actual_historical.push(descriptor.method());
|
||
assert_eq!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Deprecated);
|
||
assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Removed);
|
||
assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical);
|
||
assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NotApplicable);
|
||
}
|
||
actual_current.sort_unstable();
|
||
actual_historical.sort_unstable();
|
||
let mut expected_current = expected_current;
|
||
let mut expected_historical = expected_historical;
|
||
expected_current.sort_unstable();
|
||
expected_historical.sort_unstable();
|
||
assert_eq!(actual_current, expected_current);
|
||
assert_eq!(actual_historical, expected_historical);
|
||
assert_eq!(actual_current.len(), 52);
|
||
assert_eq!(actual_historical.len(), 14);
|
||
assert_eq!((v0_2_1, v0_2_2, v0_2_3, v0_2_4), (4, 22, 11, 15));
|
||
assert_eq!(historical_current, 0);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_7_pre_012_websocket_surface_accounts_for_all_nine_standard_pairs() {
|
||
let kinds = [
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Account,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Program,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Root,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Signature,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Slot,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Vote,
|
||
];
|
||
let expected_names = ["account", "block", "logs", "program", "root", "signature", "slot", "slots_updates", "vote"];
|
||
let actual_names = kinds.map(ksp_onchain_transport_lib::WsSubscriptionKind::as_str);
|
||
assert_eq!(actual_names, expected_names);
|
||
assert_eq!(kinds.len() * 2, 18);
|
||
let _account = ksp_onchain_transport_lib::WsSession::account_subscribe;
|
||
let _block = ksp_onchain_transport_lib::WsSession::block_subscribe;
|
||
let _logs = ksp_onchain_transport_lib::WsSession::logs_subscribe;
|
||
let _program = ksp_onchain_transport_lib::WsSession::program_subscribe;
|
||
let _root = ksp_onchain_transport_lib::WsSession::root_subscribe;
|
||
let _signature = ksp_onchain_transport_lib::WsSession::signature_subscribe;
|
||
let _slot = ksp_onchain_transport_lib::WsSession::slot_subscribe;
|
||
let _slots_updates = ksp_onchain_transport_lib::WsSession::slots_updates_subscribe;
|
||
let _vote = ksp_onchain_transport_lib::WsSession::vote_subscribe;
|
||
let _unsubscribe = ksp_onchain_transport_lib::WsSubscription::<serde_json::Value>::unsubscribe;
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_7_pre_012_http_inventory_remains_52_current_plus_14_historical() {
|
||
let current = ksp_onchain_transport_lib::current_http_rpc_methods();
|
||
let historical = ksp_onchain_transport_lib::historical_http_rpc_methods();
|
||
assert_eq!(current.len(), 52);
|
||
assert_eq!(historical.len(), 14);
|
||
assert!(current.iter().all(|descriptor| return descriptor.runtime_status() == ksp_onchain_transport_lib::RpcRuntimeStatus::Supported));
|
||
assert!(historical.iter().all(|descriptor| return descriptor.runtime_status() == ksp_onchain_transport_lib::RpcRuntimeStatus::Removed));
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_002_protocol_facades_preserve_the_standard_partition() {
|
||
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard.as_str(), "solana_standard");
|
||
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
|
||
let standard_kinds = [
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Account,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Program,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Root,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Signature,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Slot,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Vote,
|
||
];
|
||
assert_eq!(standard_kinds.len(), 9);
|
||
assert_eq!(
|
||
std::any::type_name::<ksp_onchain_transport_lib::SolanaStandardWsSession>().rsplit("::").next(),
|
||
std::option::Option::Some("SolanaStandardWsSession")
|
||
);
|
||
assert_eq!(
|
||
std::any::type_name::<ksp_onchain_transport_lib::HeliusLaserStreamWsSession>().rsplit("::").next(),
|
||
std::option::Option::Some("HeliusLaserStreamWsSession")
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_003_original_six_standard_families_remain_available_after_provider_evolution() {
|
||
let _account = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::account_subscribe;
|
||
let _program = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::program_subscribe;
|
||
let _logs = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::logs_subscribe;
|
||
let _signature = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::signature_subscribe;
|
||
let _slot = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slot_subscribe;
|
||
let _root = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::root_subscribe;
|
||
let source = include_str!("../src/ws_protocol_session.rs");
|
||
assert!(source.contains("unsupported_block"));
|
||
assert!(source.contains("unsupported_vote"));
|
||
assert!(!source.contains("pub async fn transaction_subscribe"));
|
||
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_005_helius_transaction_request_surface_is_typed_before_actor_integration() {
|
||
let filter = ksp_onchain_transport_lib::HeliusTransactionSubscribeFilter::new(
|
||
std::option::Option::None,
|
||
std::option::Option::None,
|
||
std::option::Option::None,
|
||
std::option::Option::None,
|
||
std::option::Option::None,
|
||
std::option::Option::None,
|
||
std::option::Option::Some(ksp_onchain_transport_lib::HeliusTokenAccountsFilter::All),
|
||
);
|
||
let options = ksp_onchain_transport_lib::HeliusTransactionSubscribeOptions::new(
|
||
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed),
|
||
std::option::Option::Some(ksp_onchain_transport_lib::HeliusTransactionSubscribeEncoding::Base64),
|
||
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionDetails::Signatures),
|
||
std::option::Option::Some(true),
|
||
std::option::Option::None,
|
||
);
|
||
let request = ksp_onchain_transport_lib::HeliusTransactionSubscribeRequest::new(filter, std::option::Option::Some(options));
|
||
assert!(request.validate().is_ok());
|
||
let facade_source = include_str!("../src/ws_protocol_session.rs");
|
||
assert!(!facade_source.contains("pub async fn transaction_subscribe"));
|
||
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_006_helius_transaction_lifecycle_is_actor_integrated_without_advancing_heartbeat() {
|
||
let _transaction = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::transaction_subscribe;
|
||
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction.as_str(), "helius_transaction");
|
||
let source = include_str!("../src/ws_helius_transactions.rs");
|
||
assert!(source.contains("transactionNotification"));
|
||
assert!(source.contains("WsSubscriptionKind::HeliusTransaction"));
|
||
assert!(!source.contains("tokio_tungstenite::connect_async"));
|
||
let protocol_source = include_str!("../src/ws_protocol_session.rs");
|
||
assert!(protocol_source.contains("unsupported_block"));
|
||
assert!(protocol_source.contains("unsupported_vote"));
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_007_helius_heartbeat_is_provider_owned_by_shared_actor_only() {
|
||
let actor_source = include_str!("../src/ws_session.rs");
|
||
assert!(actor_source.contains("HELIUS_WS_HEARTBEAT_INTERVAL"));
|
||
assert!(actor_source.contains("std::time::Duration::from_secs(60)"));
|
||
assert!(actor_source.contains("WsProtocolKind::HeliusLaserStream"));
|
||
assert!(actor_source.contains("tungstenite::Message::Ping"));
|
||
assert!(actor_source.contains("send_helius_heartbeat"));
|
||
let settings_source = include_str!("../src/ws_settings.rs");
|
||
assert!(!settings_source.contains("heartbeat_interval"));
|
||
assert!(!settings_source.contains("heartbeat_enabled"));
|
||
let protocol_source = include_str!("../src/ws_protocol_session.rs");
|
||
assert!(!protocol_source.contains("heartbeat_interval"));
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_008_adversarial_guards_preserve_provider_isolation_and_safe_diagnostics() {
|
||
let protocol_source = include_str!("../src/ws_protocol_session.rs");
|
||
assert!(protocol_source.contains("unsupported_helius_transaction"));
|
||
assert!(protocol_source.contains("unsupported_block"));
|
||
assert!(protocol_source.contains("unsupported_vote"));
|
||
let helius_source = include_str!("../src/ws_helius_transactions.rs");
|
||
assert!(helius_source.contains("impl std::fmt::Debug for HeliusFullTransactionNotification"));
|
||
assert!(helius_source.contains("impl std::fmt::Debug for HeliusTransactionSignatureNotification"));
|
||
assert!(helius_source.contains("impl std::fmt::Debug for HeliusTransactionNotification"));
|
||
assert!(helius_source.contains("Self::Unknown(_)"));
|
||
assert!(helius_source.contains("<omitted>"));
|
||
let actor_source = include_str!("../src/ws_session.rs");
|
||
assert!(actor_source.contains("max_message_size_bytes"));
|
||
assert!(actor_source.contains("max_frame_size_bytes"));
|
||
assert!(actor_source.contains("WsNotificationDispatchOutcome::QueueFull"));
|
||
assert!(actor_source.contains("ERROR_CODE_WS_BACKPRESSURE_OVERFLOW"));
|
||
assert!(actor_source.contains("remote_to_local.remove"));
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_009_http_and_standard_websocket_inventories_remain_exact() {
|
||
assert_eq!(ksp_onchain_transport_lib::current_http_rpc_methods().len(), 52);
|
||
assert_eq!(ksp_onchain_transport_lib::historical_http_rpc_methods().len(), 14);
|
||
let standard = [
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Account,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Program,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Root,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Signature,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Slot,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates,
|
||
ksp_onchain_transport_lib::WsSubscriptionKind::Vote,
|
||
];
|
||
assert_eq!(standard.len(), 9);
|
||
let lifecycle_source = include_str!("../src/ws_lifecycle.rs");
|
||
for method in [
|
||
"accountSubscribe",
|
||
"accountUnsubscribe",
|
||
"blockSubscribe",
|
||
"blockUnsubscribe",
|
||
"logsSubscribe",
|
||
"logsUnsubscribe",
|
||
"programSubscribe",
|
||
"programUnsubscribe",
|
||
"rootSubscribe",
|
||
"rootUnsubscribe",
|
||
"signatureSubscribe",
|
||
"signatureUnsubscribe",
|
||
"slotSubscribe",
|
||
"slotUnsubscribe",
|
||
"slotsUpdatesSubscribe",
|
||
"slotsUpdatesUnsubscribe",
|
||
"voteSubscribe",
|
||
"voteUnsubscribe",
|
||
] {
|
||
assert!(lifecycle_source.contains(method), "missing standard WebSocket method mapping: {method}");
|
||
}
|
||
let _account = ksp_onchain_transport_lib::SolanaStandardWsSession::account_subscribe;
|
||
let _block = ksp_onchain_transport_lib::SolanaStandardWsSession::block_subscribe;
|
||
let _logs = ksp_onchain_transport_lib::SolanaStandardWsSession::logs_subscribe;
|
||
let _program = ksp_onchain_transport_lib::SolanaStandardWsSession::program_subscribe;
|
||
let _root = ksp_onchain_transport_lib::SolanaStandardWsSession::root_subscribe;
|
||
let _signature = ksp_onchain_transport_lib::SolanaStandardWsSession::signature_subscribe;
|
||
let _slot = ksp_onchain_transport_lib::SolanaStandardWsSession::slot_subscribe;
|
||
let _slots_updates = ksp_onchain_transport_lib::SolanaStandardWsSession::slots_updates_subscribe;
|
||
let _vote = ksp_onchain_transport_lib::SolanaStandardWsSession::vote_subscribe;
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_009_helius_surface_is_seven_standard_families_plus_transaction() {
|
||
let _account = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::account_subscribe;
|
||
let _program = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::program_subscribe;
|
||
let _logs = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::logs_subscribe;
|
||
let _signature = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::signature_subscribe;
|
||
let _slot = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slot_subscribe;
|
||
let _root = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::root_subscribe;
|
||
let _slots_updates = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slots_updates_subscribe;
|
||
let _transaction = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::transaction_subscribe;
|
||
let protocol_source = include_str!("../src/ws_protocol_session.rs");
|
||
assert!(protocol_source.contains("unsupported_block"));
|
||
assert!(protocol_source.contains("unsupported_vote"));
|
||
assert!(!protocol_source.contains("unsupported_slots_updates"));
|
||
let cluster_source = include_str!("../src/ws_cluster.rs");
|
||
assert!(cluster_source.contains("impl crate::HeliusLaserStreamWsSession"));
|
||
assert!(cluster_source.contains("pub async fn slots_updates_subscribe"));
|
||
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates.as_str(), "slots_updates");
|
||
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction.as_str(), "helius_transaction");
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_009_config_secret_and_dependency_boundaries_remain_wired() {
|
||
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
|
||
let workspace = manifest_directory.parent().and_then(std::path::Path::parent).expect("Transport integration test must resolve the workspace root");
|
||
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
|
||
for forbidden in ["ksp-config-lib", "ksp-store-api", "ksp-store-lib", "ksp-program-api", "ksp-program-lib", "tracing =", "tracing."] {
|
||
assert!(!transport_manifest.contains(forbidden), "forbidden direct Transport dependency detected: {forbidden}");
|
||
}
|
||
let config_manifest = std::fs::read_to_string(workspace.join("crates/ksp-config-lib/Cargo.toml")).expect("Config manifest must be readable");
|
||
assert!(config_manifest.contains("ksp-onchain-transport-lib"));
|
||
let config_transport =
|
||
std::fs::read_to_string(workspace.join("crates/ksp-config-lib/src/transport.rs")).expect("Config Transport adapter source must be readable");
|
||
assert!(config_transport.contains("WsProtocolKind::HeliusLaserStream"));
|
||
let transport_example = std::fs::read_to_string(workspace.join("config/examples/std.transport.example.json")).expect("Transport example must be readable");
|
||
assert!(transport_example.contains("\"kind\": \"helius_laserstream\""));
|
||
assert!(transport_example.contains("${KSP_SECRET_HELIUS_API_KEY"));
|
||
let env_example = std::fs::read_to_string(workspace.join(".env.example")).expect(".env.example must be readable");
|
||
assert!(env_example.contains("KSP_SECRET_HELIUS_API_KEY"));
|
||
}
|
||
|
||
#[test]
|
||
fn release_v0_2_8_pre_010_live_smoke_policy_preserves_secret_and_dependency_ownership() {
|
||
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
|
||
let workspace = manifest_directory.parent().and_then(std::path::Path::parent).expect("Transport integration test must resolve the workspace root");
|
||
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
|
||
assert!(!transport_manifest.contains("ksp-config-lib"));
|
||
let transport_ws_smoke =
|
||
std::fs::read_to_string(manifest_directory.join("tests/websocket_devnet_smoke.rs")).expect("Transport WebSocket smoke must be readable");
|
||
assert!(!transport_ws_smoke.contains("KSP_SECRET_HELIUS_API_KEY"));
|
||
assert!(!transport_ws_smoke.contains("ConfigEnvironment"));
|
||
assert!(!workspace.join("crates/ksp-config-lib/tests/helius_websocket_smoke.rs").exists());
|
||
let readme = std::fs::read_to_string(manifest_directory.join("README.md")).expect("Transport README must be readable");
|
||
assert!(readme.contains("Aucun smoke Helius live supplémentaire n’est committé en `0.2.8-pre.010`"));
|
||
assert!(readme.contains("KSP_SECRET_HELIUS_API_KEY"));
|
||
let usage = std::fs::read_to_string(manifest_directory.join("USAGE.md")).expect("Transport USAGE must be readable");
|
||
assert!(usage.contains("### Smoke Helius live"));
|
||
assert!(usage.contains("surface KSP d’intégration/orchestration dédiée"));
|
||
assert!(usage.contains("cargo tree -p ksp-onchain-transport-lib"));
|
||
let env_example = std::fs::read_to_string(workspace.join(".env.example")).expect(".env.example must be readable");
|
||
assert!(env_example.contains("KSP_SECRET_HELIUS_API_KEY"));
|
||
}
|