363 lines
20 KiB
Rust
363 lines
20 KiB
Rust
// file: crates/ksp-config-lib/unit_tests/transport.rs
|
|
// version: 4
|
|
|
|
#[test]
|
|
fn fixture_transport_profile_maps_complete_runtime_contract() {
|
|
let engine = fixture_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
|
let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment);
|
|
assert!(resolved.is_ok(), "fixture Transport Config should map: {resolved:?}");
|
|
let resolved = match resolved {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(resolved.file_id().as_str(), crate::FILE_ID_STD_TRANSPORT);
|
|
assert_eq!(resolved.profile_id(), "secret_test");
|
|
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::DefaultProfile);
|
|
assert_eq!(resolved.settings().retry().max_retries(), 4);
|
|
assert_eq!(resolved.settings().retry().initial_backoff(), std::time::Duration::from_millis(125));
|
|
assert_eq!(resolved.settings().retry().max_backoff(), std::time::Duration::from_millis(2500));
|
|
assert_eq!(resolved.settings().endpoints().len(), 1);
|
|
let endpoint = &resolved.settings().endpoints()[0];
|
|
assert_eq!(endpoint.name(), "fixture_private");
|
|
assert_eq!(endpoint.provider().as_str(), "fixture-provider");
|
|
assert_eq!(endpoint.cluster().as_str(), "fixture-cluster");
|
|
assert_eq!(endpoint.url().as_str(), "https://fallback.invalid");
|
|
assert_eq!(endpoint.connect_timeout(), std::time::Duration::from_millis(750));
|
|
assert_eq!(endpoint.request_timeout(), std::time::Duration::from_millis(2500));
|
|
assert_eq!(endpoint.max_idle_connections_per_host(), std::option::Option::Some(3));
|
|
assert_eq!(endpoint.roles().len(), 1);
|
|
let role = &endpoint.roles()[0];
|
|
assert_eq!(role.role().as_str(), "default");
|
|
assert!(role.enabled());
|
|
assert_eq!(role.priority(), 7);
|
|
assert_eq!(role.request_kinds().len(), 1);
|
|
assert!(role.request_kinds()[0].is_wildcard());
|
|
assert_eq!(role.limits().requests_per_second().map(std::num::NonZeroU32::get), std::option::Option::Some(9));
|
|
assert_eq!(role.limits().burst_capacity().map(std::num::NonZeroU32::get), std::option::Option::Some(12));
|
|
assert_eq!(role.limits().max_concurrent_requests().map(std::num::NonZeroU32::get), std::option::Option::Some(4));
|
|
assert_eq!(role.limits().pause_after_rate_limit(), std::option::Option::Some(std::time::Duration::from_millis(650)));
|
|
let ws = resolved.ws_settings();
|
|
assert!(ws.is_some(), "V2 fixture should expose WebSocket settings");
|
|
if let std::option::Option::Some(ws) = ws {
|
|
assert_eq!(ws.endpoints().len(), 1);
|
|
let endpoint = &ws.endpoints()[0];
|
|
assert_eq!(endpoint.name(), "fixture_private_ws");
|
|
assert_eq!(endpoint.provider().as_str(), "fixture-provider");
|
|
assert_eq!(endpoint.cluster().as_str(), "fixture-cluster");
|
|
assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard);
|
|
assert_eq!(endpoint.url().as_str(), "wss://fallback.invalid");
|
|
assert_eq!(endpoint.session().command_timeout(), std::time::Duration::from_millis(4500));
|
|
assert_eq!(endpoint.session().close_timeout(), std::time::Duration::from_millis(4000));
|
|
assert_eq!(endpoint.session().reconnect().max_retries(), 7);
|
|
assert_eq!(endpoint.session().reconnect().initial_backoff(), std::time::Duration::from_millis(200));
|
|
assert_eq!(endpoint.session().reconnect().max_backoff(), std::time::Duration::from_millis(4000));
|
|
assert_eq!(endpoint.session().resubscribe(), ksp_onchain_transport_lib::WsResubscribePolicy::Never);
|
|
assert_eq!(endpoint.session().command_queue_capacity(), 64);
|
|
assert_eq!(endpoint.session().notification_queue_capacity(), 48);
|
|
assert_eq!(endpoint.session().max_active_subscriptions(), 256);
|
|
assert_eq!(endpoint.session().max_pending_requests(), 24);
|
|
assert_eq!(endpoint.session().max_message_size_bytes(), 33_554_432);
|
|
assert_eq!(endpoint.session().max_frame_size_bytes(), 8_388_608);
|
|
assert_eq!(endpoint.session().max_write_buffer_size_bytes(), 524_288);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn v1_transport_fixture_remains_backward_readable_and_http_only() {
|
|
let engine = v1_fixture_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
|
let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment);
|
|
assert!(resolved.is_ok(), "strict Transport V1 fixture should remain readable: {resolved:?}");
|
|
if let std::result::Result::Ok(resolved) = resolved {
|
|
assert_eq!(resolved.profile_id(), "legacy_http");
|
|
assert_eq!(resolved.settings().retry().max_retries(), 1);
|
|
assert_eq!(resolved.settings().endpoints().len(), 1);
|
|
assert_eq!(resolved.settings().endpoints()[0].url().as_str(), "https://legacy.invalid");
|
|
assert!(resolved.ws_settings().is_none(), "V1 must not invent WebSocket runtime settings");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn committed_transport_document_maps_default_and_explicit_profiles() {
|
|
let engine = committed_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
|
let default = engine.load_resolved_transport_config(std::option::Option::None, &environment);
|
|
let mainnet = engine.load_resolved_transport_config(std::option::Option::Some("mainnet_public"), &environment);
|
|
assert!(default.is_ok(), "committed default Transport profile should map: {default:?}");
|
|
assert!(mainnet.is_ok(), "committed explicit Transport profile should map: {mainnet:?}");
|
|
if let std::result::Result::Ok(default) = default {
|
|
assert_eq!(default.profile_id(), "devnet_public");
|
|
assert_eq!(default.settings().endpoints()[0].cluster().as_str(), "devnet");
|
|
assert_eq!(default.settings().endpoints()[0].url().as_str(), "https://api.devnet.solana.com");
|
|
let ws = default.ws_settings();
|
|
assert!(ws.is_some(), "committed V2 Devnet profile should expose WebSocket settings");
|
|
if let std::option::Option::Some(ws) = ws {
|
|
assert_eq!(ws.endpoints()[0].url().as_str(), "wss://api.devnet.solana.com");
|
|
assert_eq!(ws.endpoints()[0].protocol(), ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard);
|
|
}
|
|
}
|
|
if let std::result::Result::Ok(mainnet) = mainnet {
|
|
assert_eq!(mainnet.profile_id(), "mainnet_public");
|
|
assert_eq!(mainnet.selection_source(), crate::ConfigProfileSelectionSource::Explicit);
|
|
assert_eq!(mainnet.settings().endpoints()[0].cluster().as_str(), "mainnet-beta");
|
|
assert_eq!(mainnet.settings().endpoints()[0].url().as_str(), "https://api.mainnet-beta.solana.com");
|
|
let ws = mainnet.ws_settings();
|
|
assert!(ws.is_some(), "committed V2 Mainnet profile should expose WebSocket settings");
|
|
if let std::option::Option::Some(ws) = ws {
|
|
assert_eq!(ws.endpoints()[0].url().as_str(), "wss://api.mainnet-beta.solana.com");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn committed_v2_websocket_endpoint_composes_with_public_session_constructor_without_polling() {
|
|
let engine = committed_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
|
let resolved = engine.load_resolved_transport_config(std::option::Option::Some("devnet_public"), &environment);
|
|
assert!(resolved.is_ok(), "committed V2 Transport profile should map: {resolved:?}");
|
|
if let std::result::Result::Ok(resolved) = resolved {
|
|
let (http, ws) = resolved.into_transport_settings();
|
|
assert_eq!(http.endpoints().len(), 1);
|
|
assert!(ws.is_some(), "committed V2 Transport profile should expose WebSocket settings");
|
|
if let std::option::Option::Some(ws) = ws {
|
|
assert!(ws.validate().is_ok(), "Config-produced WebSocket settings should satisfy Transport validation");
|
|
assert_eq!(ws.endpoints().len(), 1);
|
|
let endpoint = ws.endpoints()[0].clone();
|
|
assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard);
|
|
let _connect_future = ksp_onchain_transport_lib::WsSession::connect(endpoint);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn transport_profile_preserves_global_and_profile_origin() {
|
|
let engine = committed_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let file_id = crate::ConfigFileId::new(crate::FILE_ID_STD_TRANSPORT);
|
|
let file_id = match file_id {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let profile = engine.load_resolved_profile(&file_id, std::option::Option::None);
|
|
assert!(profile.is_ok(), "committed Transport profile should resolve: {profile:?}");
|
|
if let std::result::Result::Ok(profile) = profile {
|
|
assert_eq!(profile.origin("retry"), std::option::Option::Some(crate::ConfigValueOrigin::Global));
|
|
assert_eq!(profile.origin("ws_defaults"), std::option::Option::Some(crate::ConfigValueOrigin::Global));
|
|
assert_eq!(profile.origin("endpoints"), std::option::Option::Some(crate::ConfigValueOrigin::Profile));
|
|
assert_eq!(profile.origin("ws_endpoints"), std::option::Option::Some(crate::ConfigValueOrigin::Profile));
|
|
assert_eq!(profile.origin("format_version"), std::option::Option::Some(crate::ConfigValueOrigin::Global));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn composite_selected_transport_profile_preserves_composite_provenance() {
|
|
let engine = committed_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let composite_file_id = crate::ConfigFileId::new(crate::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK);
|
|
let composite_file_id = match composite_file_id {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let composite = engine.load_resolved_composite(&composite_file_id, std::option::Option::None);
|
|
assert!(composite.is_ok(), "committed Wallet Desk composite should resolve: {composite:?}");
|
|
let composite = match composite {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let component = composite.component("transport");
|
|
assert!(component.is_some(), "Wallet Desk composite should contain Transport");
|
|
let component = match component {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
|
let resolved = engine.resolve_transport_config_profile(component.resolved(), &environment);
|
|
assert!(resolved.is_ok(), "composite-selected Transport profile should map: {resolved:?}");
|
|
if let std::result::Result::Ok(resolved) = resolved {
|
|
assert_eq!(resolved.profile_id(), "devnet_public");
|
|
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::Composite);
|
|
assert_eq!(resolved.settings().endpoints()[0].cluster().as_str(), "devnet");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn secret_transport_url_is_runtime_available_but_safe_projection_is_redacted() {
|
|
let engine = fixture_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let canary = "https://secret-provider.invalid/?api-key=transport-secret-canary";
|
|
let mut process = std::collections::BTreeMap::<String, String>::new();
|
|
process.insert("KSP_SECRET_TRANSPORT_TEST_URL".to_owned(), canary.to_owned());
|
|
let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
|
|
let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment);
|
|
assert!(resolved.is_ok(), "secret Transport endpoint should map without being rejected: {resolved:?}");
|
|
let resolved = match resolved {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(resolved.effective().sensitivity(), crate::ConfigSensitivity::Secret);
|
|
assert_eq!(resolved.settings().endpoints()[0].url().as_str(), canary);
|
|
let safe_url = resolved.effective().safe_value().pointer("/endpoints/0/url").and_then(serde_json::Value::as_str);
|
|
assert_eq!(safe_url, std::option::Option::Some(crate::REDACTED_CONFIG_VALUE));
|
|
let debug = format!("{resolved:?}");
|
|
assert!(!debug.contains("transport-secret-canary"));
|
|
assert!(debug.contains(crate::REDACTED_CONFIG_VALUE));
|
|
}
|
|
|
|
#[test]
|
|
fn secret_websocket_url_is_runtime_available_but_safe_projection_is_redacted() {
|
|
let engine = fixture_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let canary = "wss://user:pass@secret-provider.invalid/path?api-key=transport-ws-secret-canary";
|
|
let mut process = std::collections::BTreeMap::<String, String>::new();
|
|
process.insert("KSP_SECRET_TRANSPORT_TEST_WS_URL".to_owned(), canary.to_owned());
|
|
let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
|
|
let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment);
|
|
assert!(resolved.is_ok(), "secret WebSocket endpoint should map without being exposed: {resolved:?}");
|
|
let resolved = match resolved {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let ws = resolved.ws_settings();
|
|
assert!(ws.is_some(), "V2 fixture should expose WebSocket settings");
|
|
if let std::option::Option::Some(ws) = ws {
|
|
assert_eq!(ws.endpoints()[0].url().as_str(), canary);
|
|
}
|
|
let safe_url = resolved.effective().safe_value().pointer("/ws_endpoints/0/url").and_then(serde_json::Value::as_str);
|
|
assert_eq!(safe_url, std::option::Option::Some(crate::REDACTED_CONFIG_VALUE));
|
|
let debug = format!("{resolved:?}");
|
|
assert!(!debug.contains("transport-ws-secret-canary"));
|
|
assert!(!debug.contains("user:pass"));
|
|
assert!(debug.contains(crate::REDACTED_CONFIG_VALUE));
|
|
}
|
|
|
|
#[test]
|
|
fn transport_secret_url_provenance_uses_process_and_process_beats_dotenv() {
|
|
let engine = fixture_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let mut process = std::collections::BTreeMap::<String, String>::new();
|
|
process.insert("KSP_SECRET_TRANSPORT_TEST_URL".to_owned(), "https://process.invalid".to_owned());
|
|
let mut dotenv = std::collections::BTreeMap::<String, String>::new();
|
|
dotenv.insert("KSP_SECRET_TRANSPORT_TEST_URL".to_owned(), "https://dotenv.invalid".to_owned());
|
|
let environment = crate::ConfigEnvironment::from_maps(process, dotenv);
|
|
let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment);
|
|
assert!(resolved.is_ok(), "secret Transport environment precedence should map: {resolved:?}");
|
|
let resolved = match resolved {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(resolved.settings().endpoints()[0].url().as_str(), "https://process.invalid");
|
|
let provenance = resolved.effective().provenance_at("/endpoints/0/url");
|
|
assert!(provenance.is_some(), "endpoint URL should retain environment provenance");
|
|
if let std::option::Option::Some(provenance) = provenance {
|
|
assert_eq!(provenance.len(), 1);
|
|
assert_eq!(provenance[0].environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::Process));
|
|
assert_eq!(provenance[0].variable_name(), std::option::Option::Some("KSP_SECRET_TRANSPORT_TEST_URL"));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_secret_transport_url_is_effective_config_error_without_secret_leak() {
|
|
let engine = fixture_engine();
|
|
let engine = match engine {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let canary = "transport-invalid-secret-canary";
|
|
let mut process = std::collections::BTreeMap::<String, String>::new();
|
|
process.insert("KSP_SECRET_TRANSPORT_TEST_URL".to_owned(), canary.to_owned());
|
|
let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
|
|
let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment);
|
|
assert!(resolved.is_err(), "invalid secret-derived endpoint URL must fail effective mapping");
|
|
if let std::result::Result::Err(error) = resolved {
|
|
assert_eq!(error.code(), crate::ERROR_CODE_EFFECTIVE_CONFIG_INVALID);
|
|
let debug = format!("{error:?}");
|
|
assert!(!debug.contains(canary));
|
|
assert!(error.context().iter().any(|item| -> bool {
|
|
return item.key() == "transport_error_code" && item.value() == "invalid_settings";
|
|
}));
|
|
}
|
|
}
|
|
|
|
fn fixture_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
|
|
let workspace = workspace_root();
|
|
let fixture_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("unit_tests/fixtures");
|
|
let bootstrap = crate::ConfigBootstrapOptions::from_paths(fixture_root, workspace.join("config/schemas"));
|
|
let bootstrap = match bootstrap {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let registry = crate::ConfigFileRegistry::defaults();
|
|
let registry = match registry {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, registry));
|
|
}
|
|
|
|
fn v1_fixture_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
|
|
let workspace = workspace_root();
|
|
let fixture_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("unit_tests/fixtures_v1");
|
|
let bootstrap = crate::ConfigBootstrapOptions::from_paths(fixture_root, workspace.join("config/schemas"));
|
|
let bootstrap = match bootstrap {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let registry = crate::ConfigFileRegistry::defaults();
|
|
let registry = match registry {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, registry));
|
|
}
|
|
|
|
fn committed_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
|
|
let workspace = workspace_root();
|
|
let bootstrap = crate::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas"));
|
|
let bootstrap = match bootstrap {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let registry = crate::ConfigFileRegistry::defaults();
|
|
let registry = match registry {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, registry));
|
|
}
|
|
|
|
fn workspace_root() -> std::path::PathBuf {
|
|
return std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
|
|
}
|