#[cfg(test)]
mod tests {
use crate::wal::tests::helpers::*;
use crate::wal::{Wal, WalError};
use std::sync::Arc;
use std::thread;
use tempfile::TempDir;
#[test]
fn max_record_size_rejects_oversized_record() {
init_tracing();
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let wal: Wal<MemTableRecord> = Wal::open(&path, Some(32)).unwrap();
let small = MemTableRecord {
key: b"k".to_vec(),
value: Some(b"v".to_vec()),
timestamp: 1,
deleted: false,
};
wal.append(&small).unwrap();
let large = MemTableRecord {
key: vec![b'X'; 100],
value: Some(vec![b'Y'; 100]),
timestamp: 2,
deleted: false,
};
let err = wal.append(&large).unwrap_err();
assert!(
matches!(err, WalError::RecordTooLarge(_)),
"Expected RecordTooLarge, got: {:?}",
err
);
let records = collect_iter(&wal).unwrap();
assert_eq!(records.len(), 1);
assert_eq!(records[0].key, b"k");
}
#[test]
fn open_nonexistent_directory_fails() {
init_tracing();
let tmp = TempDir::new().unwrap();
let bad_path = tmp.path().join("nonexistent_dir").join("000000.log");
let result = Wal::<MemTableRecord>::open(&bad_path, None);
assert!(result.is_err());
let err = result.unwrap_err();
assert!(
matches!(err, WalError::Io(_)),
"Expected Io error, got: {:?}",
err
);
}
#[test]
fn empty_wal_replay_yields_nothing() {
init_tracing();
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let wal: Wal<MemTableRecord> = Wal::open(&path, None).unwrap();
let records = collect_iter(&wal).unwrap();
assert!(
records.is_empty(),
"Expected 0 records, got {}",
records.len()
);
}
#[test]
fn concurrent_append_all_records_survive() {
init_tracing();
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let wal: Arc<Wal<MemTableRecord>> = Arc::new(Wal::open(&path, None).unwrap());
let num_threads = 4;
let records_per_thread = 50;
let handles: Vec<_> = (0..num_threads)
.map(|t| {
let wal_clone = Arc::clone(&wal);
thread::spawn(move || {
for i in 0..records_per_thread {
let rec = MemTableRecord {
key: format!("t{}_k{}", t, i).into_bytes(),
value: Some(format!("t{}_v{}", t, i).into_bytes()),
timestamp: (t * 1000 + i) as u64,
deleted: false,
};
wal_clone.append(&rec).unwrap();
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
let records = collect_iter(&wal).unwrap();
assert_eq!(
records.len(),
num_threads * records_per_thread,
"Expected {} records, got {}",
num_threads * records_per_thread,
records.len()
);
}
}