use super::*;
use alloc::boxed::Box;
use core::num::{NonZeroU32, NonZeroU64};
struct Worker;
impl Pipe for Worker {
type In<'message> = Box<[u8]>;
type Out<'message> = ();
}
#[test]
fn impossible_column_capacity_preserves_the_creation_failure() -> Result<(), &'static str> {
let capacity = Capacity::new(NonZeroU32::MIN.saturating_add(2_048));
let Err(error) = ContinuationLedger::<[u8; (isize::MAX as usize) / 1_024]>::try_new(capacity)
else {
return Err("unrepresentable columns were allocated");
};
assert_eq!(
error.failure(),
ContinuationLedgerCreationFailure::StorageUnavailable
);
assert!(matches!(
error._source,
WarpTableCreationError::ColumnsUnavailable { .. }
));
Ok(())
}
#[test]
fn exhausted_identifier_outcome_preserves_address_input_and_deadline() -> Result<(), &'static str> {
let ledger =
ContinuationLedger::try_new(Capacity::new(NonZeroU32::MIN)).map_err(|_| "ledger")?;
let return_to = Box::new(37_u8);
let address = core::ptr::from_ref(return_to.as_ref());
let input = Box::<[u8]>::from([3, 7, 9]);
let bytes = input.as_ptr();
let after = crate::TimeoutAfter::microseconds(NonZeroU64::MIN.saturating_add(12));
let outcome = ledger.admission_outcome::<Worker>(
WarpTableInsertOutcome::IdentifiersExhausted {
rejected: PendingContinuation { return_to },
},
Owed::new(input, after),
);
let ContinuationAdmissionOutcome::Refused {
return_to,
result: Err(ContinuationFailure::Unavailable { reason, rejected }),
} = outcome
else {
return Err("exhaustion did not return owned work");
};
assert_eq!(reason, ContinuationUnavailable::IdentifiersExhausted);
assert_eq!(*return_to, 37);
assert_eq!(core::ptr::from_ref(return_to.as_ref()), address);
let (input, returned_after) = rejected.into_parts();
assert_eq!(input.as_ref(), &[3, 7, 9]);
assert_eq!(input.as_ptr(), bytes);
assert_eq!(returned_after, after);
assert!(ledger.is_empty());
Ok(())
}
#[test]
fn late_arm_refusal_preserves_owned_work_after_expiry() -> Result<(), &'static str> {
let mut ledger =
ContinuationLedger::try_new(Capacity::new(NonZeroU32::MIN)).map_err(|_| "ledger")?;
let input = Box::<[u8]>::from([1, 2, 3]);
let bytes = input.as_ptr();
let after = crate::TimeoutAfter::microseconds(NonZeroU64::MIN.saturating_add(7));
let ContinuationAdmissionOutcome::Admitted { admission } =
ledger.admit::<Worker>(37_u8, Owed::new(input, after))
else {
return Err("admission");
};
let token = admission.timer_token();
let ContinuationExpirationOutcome::Expired {
return_to,
expiration,
} = ledger.expire(token)
else {
return Err("expiry");
};
assert_eq!(return_to, 37);
assert_eq!(expiration.token(), token);
let reason = crate::TimerArmRefusal::AtCapacity {
maximum_deadlines: 9,
};
let output = crate::TimerOut::ArmRefused {
token,
after,
reason,
}
.into_arm_outcome()
.map_err(|_| "arm output")?;
let crate::ContinuationArmOutcome::Refused { refusal } = admission
.settle_timer_arm(output)
.map_err(|_| "arm mismatch")?
else {
return Err("refusal");
};
let ContinuationRefusalOutcome::Stale { refusal } = ledger.refuse(refusal) else {
return Err("expired work was resolved twice");
};
assert_eq!(refusal.reason(), reason);
assert_eq!(refusal.id.value(), token.value());
let (returned, returned_after) = refusal.owed.into_parts();
assert_eq!(returned.as_ptr(), bytes);
assert_eq!(returned.as_ref(), &[1, 2, 3]);
assert_eq!(returned_after, after);
assert!(ledger.is_empty());
Ok(())
}