use crate::{
Error, ErrorOrigin,
db::{DatabaseBootstrapError, MemoryBootstrapAdmissionError},
};
use ic_memory::{
AllocationValidationError, BootstrapAdmissionError, MemoryAllocationPoolError,
MemoryDeclarationError, RuntimeAdoptionError, RuntimeBootstrapError, RuntimeConstructionError,
RuntimeOpenError, StableKey,
};
use icydb_diagnostic_code::{DiagnosticFactTag, ErrorCode};
fn public(cause: RuntimeBootstrapError<MemoryBootstrapAdmissionError>) -> Error {
Error::from(DatabaseBootstrapError::from(cause))
}
fn grant() -> MemoryAllocationPoolError {
MemoryAllocationPoolError::ExcludedSlot { id: 42 }
}
fn historical() -> BootstrapAdmissionError {
BootstrapAdmissionError::Pool(grant())
}
#[test]
fn memory_bootstrap_grant_wrappers_preserve_bounded_slot_evidence() {
for cause in [
RuntimeBootstrapError::Resolution(ic_memory::MemoryResolutionError::Pool(grant())),
RuntimeBootstrapError::Resolution(ic_memory::MemoryResolutionError::UnmanagedAllocation {
id: 42,
}),
] {
let error = public(cause);
assert_eq!(
error.code(),
ErrorCode::RUNTIME_BOUNDARY_MEMORY_ALLOCATION_RESOLUTION_FAILED
);
assert_eq!(
error.core_facts().unwrap(),
[(DiagnosticFactTag::ActualMemoryId, 42)]
);
assert_eq!(error.origin(), ErrorOrigin::Runtime);
}
for cause in [
RuntimeBootstrapError::Admission(historical()),
RuntimeBootstrapError::AdmissionPolicy(MemoryBootstrapAdmissionError::HistoricalJournal(
historical(),
)),
] {
let error = public(cause);
assert_eq!(
error.code(),
ErrorCode::RUNTIME_BOUNDARY_MEMORY_HISTORICAL_JOURNAL_UNAVAILABLE
);
assert_eq!(
error.core_facts().unwrap(),
[(DiagnosticFactTag::ActualMemoryId, 42)]
);
}
}
#[test]
fn memory_bootstrap_roles_and_invalid_declarations_keep_their_identity() {
for store in [None, Some("main".to_string())] {
let count = if store.is_some() { 4 } else { 3 };
let error = public(RuntimeBootstrapError::AdmissionPolicy(
MemoryBootstrapAdmissionError::IncompleteRoles {
namespace: "main".into(),
store,
},
));
assert_eq!(
error.code(),
ErrorCode::RUNTIME_BOUNDARY_MEMORY_ALLOCATION_ROLES_INCOMPLETE
);
assert_eq!(
error.core_facts().unwrap(),
[(DiagnosticFactTag::ExpectedCount, count)]
);
}
for cause in [
RuntimeBootstrapError::AdmissionPolicy(MemoryBootstrapAdmissionError::UnsupportedKey(
"icydb.main.invalid.v1".into(),
)),
RuntimeBootstrapError::Validation(AllocationValidationError::Policy(
MemoryBootstrapAdmissionError::InvalidDeclaration(
"icydb.main.commit.control.v1".into(),
),
)),
RuntimeBootstrapError::Resolution(ic_memory::MemoryResolutionError::Declarations(
MemoryDeclarationError::DuplicateRequest {
stable_key: StableKey::parse("icydb.main.commit.control.v1").unwrap(),
},
)),
] {
let error = public(cause);
assert_eq!(
error.code(),
ErrorCode::RUNTIME_BOUNDARY_MEMORY_DECLARATION_INVALID
);
assert!(error.facts().is_empty());
}
}
#[test]
fn memory_adoption_requirement_drift_is_a_public_conflict() {
for cause in [
RuntimeAdoptionError::UnknownAuthority {
authority: "icydb.main".into(),
},
RuntimeAdoptionError::AuthorityMismatch {
stable_key: "icydb.main.commit.control.v1".into(),
committed_authority: "host.other".into(),
requested_authority: "icydb.main".into(),
},
RuntimeAdoptionError::Open(RuntimeOpenError::StableKeyNotCommitted(
"icydb.main.commit.control.v1".into(),
)),
] {
let error = Error::from(DatabaseBootstrapError::from(cause));
assert_eq!(
error.code(),
ErrorCode::RUNTIME_BOUNDARY_MEMORY_DECLARATION_SNAPSHOT_MISMATCH
);
assert_eq!(error.class(), icydb_diagnostic_code::ErrorClass::Conflict);
assert!(error.facts().is_empty());
}
}
#[test]
fn memory_bootstrap_internal_failures_retain_internal_classification() {
for cause in [
RuntimeBootstrapError::StableCellLedgerWriteTooLarge {
value_size: usize::MAX,
},
RuntimeBootstrapError::LedgerGrowth(ic_memory::RuntimeGrowError::ReentrantAccess),
] {
let error = public(cause);
assert_eq!(error.code(), ErrorCode::RUNTIME_INTERNAL);
assert_eq!(error.class(), icydb_diagnostic_code::ErrorClass::Internal);
assert_eq!(error.origin(), ErrorOrigin::Runtime);
assert!(error.facts().is_empty());
}
let error = Error::from(DatabaseBootstrapError::from(RuntimeAdoptionError::Open(
RuntimeOpenError::NotBootstrapped,
)));
assert_eq!(error.code(), ErrorCode::RUNTIME_INTERNAL);
}
#[test]
fn memory_construction_and_binding_failures_keep_typed_public_classification() {
let error = Error::from(DatabaseBootstrapError::from(
RuntimeConstructionError::BucketSizeMismatch {
persisted: 128,
requested: 16,
},
));
assert_eq!(
error.code(),
ErrorCode::RUNTIME_BOUNDARY_MEMORY_BUCKET_SIZE_MISMATCH
);
assert_eq!(
error.core_facts().unwrap(),
[
(DiagnosticFactTag::Expected, 16),
(DiagnosticFactTag::Actual, 128),
]
);
for cause in [
crate::db::MemoryRuntimeBindingError::NotBootstrapped,
crate::db::MemoryRuntimeBindingError::AlreadyBound,
] {
assert_eq!(
Error::from(DatabaseBootstrapError::from(cause)).code(),
ErrorCode::RUNTIME_INTERNAL
);
}
}