#![allow(non_snake_case)]
use triviumdb::database::Database;
use triviumdb::storage::wal::WalEntry;
use std::fs::OpenOptions;
use std::io::Write;
const DIM: usize = 2;
fn tmp_db(name: &str) -> String {
std::fs::create_dir_all("test_data").ok();
format!("test_data/sec_{}", name)
}
fn cleanup(path: &str) {
for ext in &["", ".wal", ".vec", ".lock", ".flush_ok"] {
std::fs::remove_file(format!("{}{}", path, ext)).ok();
}
}
#[test]
fn 测试_毒素向量拦截_拒绝NaN与Inf() {
let path = tmp_db("nan_inf");
cleanup(&path);
let mut db = Database::<f32>::open(&path, DIM).unwrap();
assert!(db.insert(&[1.0, 2.0], serde_json::json!({})).is_ok());
let res1 = db.insert(&[f32::NAN, 1.0], serde_json::json!({}));
assert!(res1.is_err(), "应拒绝包含 NaN 的向量");
let res2 = db.insert(&[0.0, f32::INFINITY], serde_json::json!({}));
assert!(res2.is_err(), "应拒绝包含 Infinity 的向量");
let mut tx = db.begin_tx();
tx.insert(&[f32::NEG_INFINITY, 0.0], serde_json::json!({}));
let res3 = tx.commit();
assert!(res3.is_err(), "事务模式中也应拒绝包含 -Infinity 的向量");
cleanup(&path);
}
fn append_raw_wal_entry<T: serde::Serialize>(path: &str, entry: &WalEntry<T>, corrupt_crc: bool) {
let wal_path = format!("{}.wal", path);
let mut file = OpenOptions::new().create(true).append(true).open(&wal_path).unwrap();
let data = bincode::serialize(entry).unwrap();
let mut checksum = crc32fast::hash(&data);
if corrupt_crc {
checksum = checksum.wrapping_add(1); }
let len = data.len() as u32;
file.write_all(&len.to_le_bytes()).unwrap();
file.write_all(&data).unwrap();
file.write_all(&checksum.to_le_bytes()).unwrap();
}
#[test]
fn 测试_WAL丢失TxCommit的幽灵事务_被正确截断并保护后续追加() {
let path = tmp_db("wal_phantom_tx");
cleanup(&path);
append_raw_wal_entry::<f32>(&path, &WalEntry::TxBegin { tx_id: 100 }, false);
append_raw_wal_entry::<f32>(&path, &WalEntry::Insert {
id: 1,
vector: vec![1.0, 1.0],
payload: "{}".to_string()
}, false);
{
let mut db = Database::<f32>::open(&path, DIM).unwrap();
assert_eq!(db.node_count(), 0, "幽灵事务中的数据应被丢弃");
db.insert(&[2.0, 2.0], serde_json::json!({"valid": true})).unwrap();
}
{
let db = Database::<f32>::open(&path, DIM).unwrap();
assert_eq!(db.node_count(), 1, "后续正常追加的数据应该存活");
let payload = db.get_payload(1).unwrap();
assert_eq!(payload["valid"], true);
}
cleanup(&path);
}
#[test]
fn 测试_WAL遇尾部乱码死字节_精确截除防止污染() {
let path = tmp_db("wal_corrupted_tail");
cleanup(&path);
append_raw_wal_entry::<f32>(&path, &WalEntry::Insert {
id: 1, vector: vec![1.0, 1.0], payload: "{}".to_string()
}, false);
{
let wal_path = format!("{}.wal", path);
let mut file = OpenOptions::new().append(true).open(&wal_path).unwrap();
file.write_all(&[0xDE, 0xAD, 0xBE, 0xEF]).unwrap();
}
{
let mut db = Database::<f32>::open(&path, DIM).unwrap();
assert_eq!(db.node_count(), 1, "前半段正常数据应该被恢复");
db.insert(&[3.0, 3.0], serde_json::json!({"safe": "yes"})).unwrap();
}
{
let db = Database::<f32>::open(&path, DIM).unwrap();
assert_eq!(db.node_count(), 2, "乱码被截除,后续的新数据完美恢复");
}
cleanup(&path);
}
#[test]
fn 测试_大规模写入_安全触发Mmap多次扩容() {
let path = tmp_db("mmap_resize_pressure");
cleanup(&path);
let mut db = Database::<f32>::open(&path, DIM).unwrap();
for i in 0..15000 {
db.insert(&[i as f32, i as f32], serde_json::json!({"seq": i})).unwrap();
}
assert_eq!(db.node_count(), 15000, "Mmap 动态扩容(甚至多次翻倍)未导致数据截断");
let p = db.get_payload(15000).unwrap();
assert_eq!(p["seq"], 14999);
cleanup(&path);
}
#[test]
fn 测试_密集图谱_万级笛卡尔积防OOM_LazyEvaluation有效性() {
let path = tmp_db("dense_graph_oom");
cleanup(&path);
let mut db = Database::<f32>::open(&path, DIM).unwrap();
let hub_id = db.insert(&[0.0, 0.0], serde_json::json!({"name": "hub"})).unwrap();
let mut leaf_ids = vec![];
for i in 1..=100 {
let id = db.insert(&[i as f32, 0.0], serde_json::json!({"name": "leaf", "val": i})).unwrap();
leaf_ids.push(id);
}
{
let mut tx = db.begin_tx();
for &leaf in &leaf_ids {
tx.link(leaf, hub_id, "connects", 1.0);
tx.link(hub_id, leaf, "connects", 1.0);
}
tx.commit().unwrap();
}
let results = db.query("MATCH (a)-[:connects]->(b)-[:connects]->(c) RETURN c").unwrap();
assert_eq!(results.len(), 5000, "引擎现在支持默认 LIMIT,没有 LIMIT 的复杂笛卡尔积会在 5000 时优雅平滑截断,不再抛出恐慌错误!");
cleanup(&path);
}
#[test]
fn 测试_跨进程文件锁_强硬阻断双重绑定() {
let path = tmp_db("file_exclusive_lock");
cleanup(&path);
let _db_a = Database::<f32>::open(&path, DIM).unwrap();
let db_b_result = Database::<f32>::open(&path, DIM);
assert!(
db_b_result.is_err(),
"必须阻断!文件已被当前进程内的另一个 Database 句柄(甚至跨进程)独占锁死"
);
let err_msg = db_b_result.err().unwrap().to_string();
assert!(err_msg.contains("already opened by another"), "错误信息不匹配:{}", err_msg);
cleanup(&path);
}
#[test]
fn 测试_巨型恶意载荷拦截_防OOM与日志撑爆() {
let path = tmp_db("giant_payload_rejection");
cleanup(&path);
let mut db = Database::<f32>::open(&path, DIM).unwrap();
let giant_string = "A".repeat(10 * 1024 * 1024);
let giant_payload = serde_json::json!({ "story": giant_string });
let res = db.insert(&[0.1, 0.2], giant_payload.clone());
assert!(res.is_err(), "10MB 超大直写必须被拦截");
assert!(res.unwrap_err().to_string().contains("exceeds maximum allowed limit (8MB)"));
let mut tx = db.begin_tx();
tx.insert(&[0.9, 0.8], giant_payload.clone());
let tx_res = tx.commit();
assert!(
tx_res.is_err(),
"事务提交并未被拦截"
);
let err_str = tx_res.unwrap_err().to_string();
assert!(
err_str.contains("exceeds maximum allowed limit (8MB)"),
"不在预期的错误范围内: {}", err_str
);
let giant_vector = vec![0.5_f32; 100_000];
let vec_res = db.insert(&giant_vector, serde_json::json!({"status": "evil"}));
assert!(vec_res.is_err(), "超大维度向量必须被拦截");
assert!(vec_res.unwrap_err().to_string().contains("dimension mismatch"));
db.insert(&[1.0, 1.0], serde_json::json!({"status": "ok"})).unwrap();
assert_eq!(db.node_count(), 1, "恶意载荷彻底被拦截且未污染任何游标,正常写入不受影响");
cleanup(&path);
}