v0.3.13-pre.008
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/persistence.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum PortResponse {
|
||||
@@ -12,6 +12,8 @@ struct FakePersistencePort {
|
||||
calls: std::sync::atomic::AtomicUsize,
|
||||
network: ksp_store_lib::RawNetworkId,
|
||||
normal_mode_seen: std::sync::atomic::AtomicBool,
|
||||
observation_calls: std::sync::atomic::AtomicUsize,
|
||||
observation_response: std::option::Option<ksp_store_lib::RawObservationWriteOutcome>,
|
||||
response: PortResponse,
|
||||
}
|
||||
|
||||
@@ -21,9 +23,16 @@ impl FakePersistencePort {
|
||||
calls: std::sync::atomic::AtomicUsize::new(0),
|
||||
network,
|
||||
normal_mode_seen: std::sync::atomic::AtomicBool::new(false),
|
||||
observation_calls: std::sync::atomic::AtomicUsize::new(0),
|
||||
observation_response: std::option::Option::None,
|
||||
response,
|
||||
};
|
||||
}
|
||||
|
||||
fn with_observation_response(mut self, observation_response: ksp_store_lib::RawObservationWriteOutcome) -> Self {
|
||||
self.observation_response = std::option::Option::Some(observation_response);
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::RawTransactionIngestPersistencePort for FakePersistencePort {
|
||||
@@ -51,9 +60,39 @@ impl crate::RawTransactionIngestPersistencePort for FakePersistencePort {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
fn record_observation<'a>(
|
||||
&'a self,
|
||||
_observation: ksp_store_lib::RawTransactionObservation,
|
||||
) -> ksp_store_lib::StoreApiFuture<'a, ksp_store_lib::Result<ksp_store_lib::RawObservationWriteOutcome>> {
|
||||
self.observation_calls.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
|
||||
let observation_response = self.observation_response;
|
||||
let response = self.response;
|
||||
return std::boxed::Box::pin(async move {
|
||||
if let std::option::Option::Some(outcome) = observation_response {
|
||||
return std::result::Result::Ok(outcome);
|
||||
}
|
||||
return match response {
|
||||
PortResponse::Outcome(_, observation) => std::result::Result::Ok(observation),
|
||||
PortResponse::Conflict => std::result::Result::Err(ksp_core_lib::Error::new(ksp_store_lib::ERROR_CODE_RAW_CONFLICT, "synthetic conflict")),
|
||||
PortResponse::StoreFailure => std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
ksp_core_lib::ErrorCode::new("synthetic_store", "write_failed"),
|
||||
"synthetic remote failure text that must not escape",
|
||||
)),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn acquisition(network_name: &str, signature_byte: u8) -> std::option::Option<ksp_raw_transaction_lib::RawTransactionAcquisition> {
|
||||
return acquisition_with_observation_key(network_name, signature_byte, signature_byte);
|
||||
}
|
||||
|
||||
fn acquisition_with_observation_key(
|
||||
network_name: &str,
|
||||
signature_byte: u8,
|
||||
observation_byte: u8,
|
||||
) -> std::option::Option<ksp_raw_transaction_lib::RawTransactionAcquisition> {
|
||||
let network = match ksp_store_lib::RawNetworkId::new(network_name) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return std::option::Option::None,
|
||||
@@ -92,7 +131,7 @@ fn acquisition(network_name: &str, signature_byte: u8) -> std::option::Option<ks
|
||||
let provenance = ksp_store_lib::RawAcquisitionProvenance::new(provider, protocol, method, ksp_store_lib::RawAcquisitionOrigin::Live, received_at);
|
||||
return std::option::Option::Some(ksp_raw_transaction_lib::assemble_raw_transaction_acquisition(
|
||||
transaction,
|
||||
ksp_store_lib::RawObservationKey::new([signature_byte; 32]),
|
||||
ksp_store_lib::RawObservationKey::new([observation_byte; 32]),
|
||||
provenance,
|
||||
));
|
||||
}
|
||||
@@ -251,3 +290,70 @@ async fn pre_007_store_network_mismatch_is_rejected_before_write() {
|
||||
assert_eq!(port.calls.load(std::sync::atomic::Ordering::Acquire), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn v0_3_13_pre_008_same_canonical_identity_uses_atomic_entity_once_then_additional_observation() {
|
||||
let network = match network("mainnet") {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let port = FakePersistencePort::new(
|
||||
network,
|
||||
PortResponse::Outcome(ksp_store_lib::RawEntityWriteOutcome::Inserted, ksp_store_lib::RawObservationWriteOutcome::Inserted),
|
||||
);
|
||||
let convergence = crate::RawTransactionIngestPersistenceConvergence::new(8);
|
||||
let first = match acquisition_with_observation_key("mainnet", 41, 1) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let second = match acquisition_with_observation_key("mainnet", 41, 2) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let first_outcome = crate::persist_raw_transaction_ingest_converged_acquisition(&port, first, &convergence).await;
|
||||
let second_outcome = crate::persist_raw_transaction_ingest_converged_acquisition(&port, second, &convergence).await;
|
||||
assert!(first_outcome.is_ok());
|
||||
assert!(second_outcome.is_ok());
|
||||
assert_eq!(port.calls.load(std::sync::atomic::Ordering::Acquire), 1);
|
||||
assert_eq!(port.observation_calls.load(std::sync::atomic::Ordering::Acquire), 1);
|
||||
let second_outcome = match second_outcome {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(second_outcome.entity(), crate::RawTransactionIngestEntityPersistence::AlreadyPresent);
|
||||
assert_eq!(second_outcome.observation(), crate::RawTransactionIngestObservationPersistence::Inserted);
|
||||
return;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn v0_3_13_pre_008_replayed_same_observation_is_idempotent_without_raw_resubmission() {
|
||||
let network = match network("mainnet") {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let port = FakePersistencePort::new(
|
||||
network,
|
||||
PortResponse::Outcome(ksp_store_lib::RawEntityWriteOutcome::Inserted, ksp_store_lib::RawObservationWriteOutcome::Inserted),
|
||||
)
|
||||
.with_observation_response(ksp_store_lib::RawObservationWriteOutcome::AlreadyPresent);
|
||||
let convergence = crate::RawTransactionIngestPersistenceConvergence::new(8);
|
||||
let first = match acquisition_with_observation_key("mainnet", 42, 3) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let second = match acquisition_with_observation_key("mainnet", 42, 3) {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let first_result = crate::persist_raw_transaction_ingest_converged_acquisition(&port, first, &convergence).await;
|
||||
assert!(first_result.is_ok());
|
||||
let second_result = crate::persist_raw_transaction_ingest_converged_acquisition(&port, second, &convergence).await;
|
||||
let second_outcome = match second_result {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(port.calls.load(std::sync::atomic::Ordering::Acquire), 1);
|
||||
assert_eq!(port.observation_calls.load(std::sync::atomic::Ordering::Acquire), 1);
|
||||
assert_eq!(second_outcome.observation(), crate::RawTransactionIngestObservationPersistence::AlreadyPresent);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user