Files
khadhroony-solana-project/crates/ksp-onchain-transport-lib/tests/release_completeness.rs
2026-08-24 11:10:59 +02:00

1069 lines
55 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs
// version: 34
//! 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 nest 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 dinté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"));
}
#[test]
fn release_v0_2_9_pre_002_materializes_minimal_yellowstone_engine_without_provider_or_ws_coupling() {
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace = manifest_directory.parent().and_then(std::path::Path::parent).expect("Transport test must resolve workspace root");
let root_manifest = std::fs::read_to_string(workspace.join("Cargo.toml")).expect("workspace manifest must be readable");
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
let settings_source = include_str!("../src/grpc_settings.rs");
let channel_source = include_str!("../src/grpc_channel.rs");
let crate_root = include_str!("../src/lib.rs");
assert!(root_manifest.contains("tonic = { version = \"^0.14\", default-features = false }"));
assert!(root_manifest.contains("yellowstone-grpc-proto = { version = \"^12.6\", default-features = false }"));
assert!(transport_manifest.contains("tonic = { workspace = true, features = [\"channel\""));
assert!(transport_manifest.contains("yellowstone-grpc-proto.workspace = true"));
assert!(!transport_manifest.contains("yellowstone-grpc-client"));
assert!(!transport_manifest.contains("ksp-config-lib"));
assert!(settings_source.contains("YellowstoneGrpcEndpointUrl"));
assert!(settings_source.contains("YellowstoneGrpcSessionSettings"));
assert!(settings_source.contains("YellowstoneGrpcTransportSettings"));
assert!(!settings_source.contains("WsProtocolKind"));
assert!(!settings_source.contains("KSP_SECRET_"));
assert!(channel_source.contains("tonic::transport::Endpoint::from_shared"));
assert!(channel_source.contains("connect_lazy"));
assert!(!channel_source.contains("WsSession"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _published_wire = std::any::type_name::<yellowstone_grpc_proto::geyser::SubscribeRequest>();
}
#[test]
fn release_v0_2_9_pre_003_adds_tls_metadata_and_exactly_seven_standard_unary_methods_without_subscribe() {
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace = manifest_directory.parent().and_then(std::path::Path::parent).expect("Transport test must resolve workspace root");
let root_manifest = std::fs::read_to_string(workspace.join("Cargo.toml")).expect("workspace manifest must be readable");
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
let settings_source = include_str!("../src/grpc_settings.rs");
let channel_source = include_str!("../src/grpc_channel.rs");
let unary_source = include_str!("../src/grpc_unary.rs");
let crate_root = include_str!("../src/lib.rs");
assert!(root_manifest.contains("http = { version = \"^1.5\", default-features = false }"));
assert!(root_manifest.contains("tonic-prost = { version = \"^0.14\", default-features = false }"));
assert!(transport_manifest.contains("tonic = { workspace = true, features = [\"channel\", \"tls-aws-lc\", \"tls-webpki-roots\"] }"));
assert!(transport_manifest.contains("tonic = { workspace = true, features = [\"codegen\", \"server\"] }"));
assert!(transport_manifest.contains("tonic-prost.workspace = true"));
assert!(transport_manifest.contains("yellowstone-grpc-proto.workspace = true"));
assert!(transport_manifest.contains("yellowstone-grpc-proto = { workspace = true, features = [\"tonic\"] }"));
assert!(!transport_manifest.contains("yellowstone-grpc-client"));
assert!(settings_source.contains("YellowstoneGrpcMetadataEntry"));
assert!(settings_source.contains("set_sensitive"));
assert!(channel_source.contains("ClientTlsConfig"));
assert!(channel_source.contains("with_webpki_roots"));
assert!(channel_source.contains("pub async fn connect"));
for path in [
"/geyser.Geyser/SubscribeReplayInfo",
"/geyser.Geyser/Ping",
"/geyser.Geyser/GetLatestBlockhash",
"/geyser.Geyser/GetBlockHeight",
"/geyser.Geyser/GetSlot",
"/geyser.Geyser/IsBlockhashValid",
"/geyser.Geyser/GetVersion",
] {
assert!(unary_source.contains(path), "missing standard Yellowstone unary path: {path}");
}
assert!(!unary_source.contains("const PATH_SUBSCRIBE: "));
assert!(!unary_source.contains("SubscribeDeshred"));
assert!(!unary_source.contains("PublicNode"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _client = std::any::type_name::<ksp_onchain_transport_lib::SolanaYellowstoneGrpcUnaryClient>();
}