use super::*;
use std::fs;
#[test]
fn sstable_corrupt_entry_rejected() {
let path = temp_path("sstable_corrupt_entry");
let entries = vec![Entry {
key: 1,
version: 1,
kind: EntryKind::FullNode,
value: b"hello".to_vec(),
}];
write_sstable(&path, &entries).unwrap();
let mut raw = fs::read(&path).unwrap();
raw[65] ^= 0xFF;
fs::write(&path, &raw).unwrap();
let result = read_sstable(&path);
assert!(
matches!(result, Err(SstableError::Corrupt(_))),
"expected Corrupt error, got {:?}",
result.map(|_| ())
);
fs::remove_file(&path).ok();
}
fn temp_path(name: &str) -> std::path::PathBuf {
let mut dir = std::env::temp_dir();
let stamp = format!(
"{}_{}_{}",
name,
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
);
dir.push(format!("{}.sst", stamp));
dir
}
fn sample_entries(count: usize) -> Vec<Entry> {
(0..count)
.map(|i| Entry {
key: i as u64,
version: (i * 10) as u64,
kind: EntryKind::EdgeDelta,
value: vec![i as u8, (i + 1) as u8],
})
.collect()
}
#[test]
fn sstable_round_trip() {
let path = temp_path("sstable_round_trip");
let entries = vec![
Entry {
key: 5,
version: 1,
kind: EntryKind::FullNode,
value: b"alpha".to_vec(),
},
Entry {
key: 2,
version: 2,
kind: EntryKind::EdgeDelta,
value: b"beta".to_vec(),
},
];
let table = write_sstable(&path, &entries).unwrap();
let loaded = read_sstable(&path).unwrap();
assert_eq!(table.entries, loaded.entries);
assert_eq!(table.fences, loaded.fences);
assert_eq!(table.bloom.bits(), loaded.bloom.bits());
fs::remove_file(path).ok();
}
#[test]
fn bloom_and_fence_metadata() {
let path = temp_path("sstable_bloom_fence");
let entries = sample_entries(130);
let table = write_sstable(&path, &entries).unwrap();
assert!(table.bloom.may_contain(5));
assert!(table.bloom.may_contain(129));
assert_eq!(table.fences.len(), 3);
assert_eq!(table.fences[0].min_key, 0);
assert_eq!(table.fences[0].max_key, 63);
assert_eq!(table.fences[1].min_key, 64);
assert_eq!(table.fences[1].max_key, 127);
assert_eq!(table.fences[2].min_key, 128);
assert_eq!(table.fences[2].max_key, 129);
fs::remove_file(path).ok();
}
#[test]
fn sstable_is_page_aligned() {
let path = temp_path("sstable_page_aligned");
let entries = sample_entries(200);
let table = write_sstable(&path, &entries).unwrap();
assert_eq!(table.fences.len(), 4);
let metadata = fs::metadata(&path).unwrap();
assert_eq!(metadata.len() % PAGE_SIZE_BYTES, 0);
let buffer = std::fs::read(&path).unwrap();
let mut cursor = Cursor::new(buffer);
let header = read_header(&mut cursor).unwrap();
assert_eq!(header.bloom_offset % PAGE_SIZE_BYTES, 0);
assert_eq!(header.fence_offset % PAGE_SIZE_BYTES, 0);
fs::remove_file(path).ok();
}