#![allow(non_snake_case)]
use std::fs::OpenOptions;
use std::io::Write;
use triviumdb::database::Database;
use triviumdb::storage::wal::WalEntry;
const DIM: usize = 2;
fn tmp_db(name: &str) -> String {
let dir = std::env::temp_dir().join("triviumdb_test");
std::fs::create_dir_all(&dir).ok();
dir.join(format!("sec_{}", name))
.to_string_lossy()
.to_string()
}
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
.tql("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.contains("Database locked"),
"错误信息不匹配:{}",
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("Payload too large"));
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("Payload too large"),
"不在预期的错误范围内: {}",
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);
}