Files
ChuBlog/chusql-storage/tests/wal_test.rs
T

119 lines
3.1 KiB
Rust
Raw Normal View History

use chusql_storage::protocol::Row;
use chusql_storage::wal::{Wal, WalOp};
use serde_json::json;
fn row(pairs: &[(&str, serde_json::Value)]) -> Row {
let mut m = Row::new();
for (k, v) in pairs {
m.insert((*k).to_string(), v.clone());
}
m
}
#[test]
fn append_and_read_insert() {
let dir = tempfile::tempdir().unwrap();
let wal = Wal::new(dir.path().join("wal.log"));
let op = WalOp::Insert {
table: "users".into(),
row: row(&[("id", json!(1)), ("name", json!("Alice"))]),
key: Some(1),
};
wal.append(&op).unwrap();
let back = wal.read().unwrap().unwrap();
assert_eq!(back, op);
}
#[test]
fn append_and_read_replace_all() {
let dir = tempfile::tempdir().unwrap();
let wal = Wal::new(dir.path().join("wal.log"));
let op = WalOp::ReplaceAll {
table: "users".into(),
rows: vec![
row(&[("id", json!(1)), ("name", json!("Alice"))]),
row(&[("id", json!(2)), ("name", json!("Bob"))]),
],
};
wal.append(&op).unwrap();
let back = wal.read().unwrap().unwrap();
assert_eq!(back, op);
}
#[test]
fn missing_file_returns_none() {
let dir = tempfile::tempdir().unwrap();
let wal = Wal::new(dir.path().join("wal.log"));
assert!(wal.read().unwrap().is_none());
}
#[test]
fn empty_file_returns_none() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("wal.log");
std::fs::write(&path, b"").unwrap();
let wal = Wal::new(&path);
assert!(wal.read().unwrap().is_none());
}
#[test]
fn clear_truncates() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("wal.log");
let wal = Wal::new(&path);
wal.append(&WalOp::Insert {
table: "t".into(),
row: row(&[("id", json!(1))]),
key: None,
})
.unwrap();
assert!(wal.read().unwrap().is_some());
wal.clear().unwrap();
assert!(wal.read().unwrap().is_none());
assert_eq!(std::fs::metadata(&path).unwrap().len(), 0);
}
#[test]
fn truncated_tail_is_ignored() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("wal.log");
let wal = Wal::new(&path);
wal.append(&WalOp::Insert {
table: "users".into(),
row: row(&[("id", json!(1)), ("name", json!("Alice"))]),
key: Some(1),
})
.unwrap();
// 砍掉最后 5 个字节,模拟"写一半断电"
let full = std::fs::read(&path).unwrap();
std::fs::write(&path, &full[..full.len() - 5]).unwrap();
// 读回来应该当作"没有这条"
assert!(wal.read().unwrap().is_none());
}
#[test]
fn overwrite_on_second_append_is_visible() {
// 简化版一次只允许一条,append 两次会叠在文件里——
// 但正常路径下 clear 先跑,所以实际不会叠加。
// 这个测试只验证 read 能解析最前面那一条。
let dir = tempfile::tempdir().unwrap();
let wal = Wal::new(dir.path().join("wal.log"));
wal.append(&WalOp::Insert {
table: "t".into(),
row: row(&[("id", json!(1))]),
key: None,
})
.unwrap();
let first = wal.read().unwrap().unwrap();
assert!(matches!(first, WalOp::Insert { .. }));
}