use super::failure::Failure;
use crate::serve::receipt_fragments::{Assembler, minimum_cap};
use haematite::{ApiError, BatchFailure, DatabaseError, LeafLogError, ObserverError};
use std::error::Error;
type TestResult = Result<(), Box<dyn Error>>;
fn batch_error() -> Result<DatabaseError, Box<dyn Error>> {
let failure = BatchFailure::new(crate::serve::receipt_wire_tests::fixture()?)?;
Ok(DatabaseError::BatchFailed(Box::new(failure)))
}
#[test]
fn original_typed_wrappers_retain_complete_receipt_and_full_cause() -> TestResult {
let failures = [
Failure::database(batch_error()?),
Failure::api(ApiError::Storage(batch_error()?)),
Failure::leaf_log(LeafLogError::Storage(batch_error()?)),
Failure::observer(ObserverError::Config(batch_error()?)),
Failure::observer(ObserverError::Api(ApiError::Storage(batch_error()?))),
];
let cap = u32::try_from(minimum_cap()?)?;
for failure in failures {
let source = Error::source(&failure).ok_or("failure has no source")?;
let original = source.to_string();
let cloned = failure.clone();
let cloned_source = Error::source(&cloned).ok_or("clone has no source")?;
assert_eq!(cloned_source.to_string(), original);
let encoded = failure.seal()?.ok_or("typed failure sealed no receipt")?;
let mut assembler = Assembler::new("typed", cap)?;
let mut complete = None;
for frame in encoded.frames("typed", cap)? {
if let Some(receipt) = assembler.accept(&frame)? {
assert!(complete.is_none());
complete = Some(receipt);
}
}
let complete = complete.ok_or("assembler never completed the receipt")?;
assert_eq!(complete.bytes(), encoded.bytes());
let receipt = complete.receipt().ok_or("packet has no receipt")?;
assert_eq!(receipt.outcomes.len(), 5);
let refusal = complete.refusal().ok_or("packet has no refusal")?;
assert_eq!(refusal.message, failure.message);
let cause = refusal.cause.as_ref().ok_or("refusal carries no cause")?;
assert_eq!(cause.message, original);
assert!(cause.database.is_some());
let kept_source = Error::source(&failure).ok_or("failure lost its source")?;
assert_eq!(kept_source.to_string(), original);
}
Ok(())
}
#[test]
fn diagnostic_has_no_fabricated_receipt_or_original_database_cause() -> TestResult {
let failure = Failure::new("invalid_document", "invalid JSON before effects");
assert!(failure.seal()?.is_none());
assert!(Error::source(&failure).is_none());
Ok(())
}
#[test]
fn actual_barrier_kind_and_complete_received_message_remain_owned() -> TestResult {
let error = haematite::BranchCommitError::Barrier("original received barrier".repeat(4096));
let message = error.to_string();
let failure = Failure::branch_commit(error);
let source = Error::source(&failure).ok_or("barrier has no source")?;
assert_eq!(source.to_string(), message);
let cap = u32::try_from(minimum_cap()?)?;
let encoded = failure.seal()?.ok_or("barrier failure sealed no packet")?;
let frames = encoded.frames("barrier", cap)?;
assert!(frames.len() > 2);
let mut assembler = Assembler::new("barrier", cap)?;
let mut complete = None;
for frame in frames {
if let Some(receipt) = assembler.accept(&frame)? {
complete = Some(receipt);
}
}
let complete = complete.ok_or("assembler never completed the packet")?;
assert!(complete.receipt().is_none());
let refusal = complete.refusal().ok_or("packet has no refusal")?;
let cause = refusal.cause.as_ref().ok_or("refusal carries no cause")?;
assert_eq!(cause.message, message);
Ok(())
}