# Storage testing Use the deterministic runtime's storage backend for storage tests. It permits reproducible I/O, crashes, corruption, and recovery without real disk access. ## Basic operations ```rust #[test] fn test_storage_operations() { let runner = deterministic::Runner::default(); runner.start(|context| async move { let (blob, _) = context .open("partition_name", &0u64.to_be_bytes()) .await .expect("open blob"); blob.write_at(0, vec![1, 2, 3, 4]).await.expect("write"); let data = blob.read_at(0, 4).await.expect("read").coalesce(); assert_eq!(data.as_ref(), &[1, 2, 3, 4]); blob.sync().await.expect("sync"); }); } ``` ## Recovery and corruption Persist data, drop the database, and initialize it again to test clean recovery. To simulate an interrupted write, resize a blob after writing it; to simulate corruption, overwrite a checksum or truncate data. Reinitialize and verify that replay recovers to the last valid item. ```rust let (blob, size) = context.open(&partition, &name).await.unwrap(); blob.resize(size - 1).await.unwrap(); blob.sync().await.unwrap(); let journal = Journal::init(context, cfg).await.unwrap(); assert_eq!(journal.size().await.unwrap(), expected_size); ``` ## What to cover - Empty and single-item stores, maximum sizes, and offset overflow. - Restart after a clean sync and after an unclean shutdown. - Truncated, corrupted, and missing data. - Multiple readers or writers and blob pruning. - Metrics for tracked, synced, and pruned data. - Hash-based conformance tests for intentionally stable storage formats. Errors from mutable operations, including `put`, `delete`, and `sync`, are unrecoverable. A caller must not use that database again after such an error.