#[cfg(test)]
mod tests {
use crate::wal::Wal;
use std::fs;
use tempfile::TempDir;
#[test]
fn rotate_next_increments_seq() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mut wal: Wal<u64> = Wal::open(&path, None).unwrap();
let seq1 = wal.wal_seq();
let seq2 = wal.rotate_next().expect("rotate failed");
assert_eq!(seq2, seq1 + 1);
assert_eq!(wal.wal_seq(), seq1 + 1);
let mut files: Vec<String> = fs::read_dir(tmp.path())
.unwrap()
.map(|e| e.unwrap().file_name().to_string_lossy().to_string())
.collect();
files.sort();
assert!(
files.contains(&"000000.log".to_string()),
"Missing 000000.log after rotate"
);
assert!(
files.contains(&"000001.log".to_string()),
"Missing 000001.log after rotate"
);
}
#[test]
fn multi_rotation_persists_all_data() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("000000.log");
let mut wal: Wal<u64> = Wal::open(&path, None).unwrap();
let mut input_data = Vec::new();
let rotations = 3; let writes_per_rotation = 10;
for _ in 0..=rotations {
for _ in 0..writes_per_rotation {
let value = input_data.len() as u64;
input_data.push(value);
wal.append(&value).expect("append failed");
}
wal.rotate_next().expect("rotation failed");
}
let mut files: Vec<String> = fs::read_dir(tmp.path())
.unwrap()
.map(|e| e.unwrap().file_name().to_string_lossy().to_string())
.filter(|f| f.ends_with(".log"))
.collect();
files.sort();
let expected: Vec<String> = (0..=rotations + 1)
.map(|seq| format!("{seq:06}.log"))
.collect();
assert_eq!(files, expected, "Unexpected set of WAL files");
let mut replayed = Vec::new();
for seq in 0..=rotations + 1 {
let p = tmp.path().join(format!("{seq:06}.log"));
if !p.exists() {
panic!("Missing WAL file: {}", p.display());
}
let wal_reader: Wal<u64> =
Wal::open(&p, None).expect("Failed to reopen WAL for replay");
let iter = wal_reader.replay_iter().expect("Failed to get replay_iter");
for record in iter {
let record = record.expect("Record decode error");
replayed.push(record);
}
}
assert_eq!(
replayed, input_data,
"Replayed WAL contents do not match original input"
);
}
#[test]
fn open_fails_if_file_was_renamed() {
use std::fs;
let tmp = TempDir::new().unwrap();
let original_path = tmp.path().join("000000.log");
let wal: Wal<u64> = Wal::open(&original_path, None).unwrap();
let original_seq = wal.wal_seq();
assert_eq!(original_seq, 0);
let renamed_path = tmp.path().join("000005.log");
fs::rename(&original_path, &renamed_path).expect("Failed to rename WAL file");
let files: Vec<_> = fs::read_dir(tmp.path())
.unwrap()
.map(|e| e.unwrap().file_name().to_string_lossy().to_string())
.collect();
assert_eq!(files.len(), 1);
assert_eq!(files[0], "000005.log");
let result = Wal::<u64>::open(&renamed_path, None);
assert!(
result.is_err(),
"Wal::open() should reject renamed WAL due to sequence mismatch"
);
}
}