sqlitegraph 2.2.2

Embedded graph database with full ACID transactions, HNSW vector search, dual backend support, and comprehensive graph algorithms library
Documentation
use std::{
    fs,
    path::PathBuf,
    sync::{Mutex, OnceLock},
};

use sqlitegraph::bench_gates::{
    BenchGateResult, BenchMetric, BenchThreshold, check_thresholds, compare_to_baseline,
    load_previous_runs, record_bench_run, set_bench_file_path,
};

fn set_bench_file(test_name: &str) -> PathBuf {
    let path = std::env::temp_dir().join(format!("sqlitegraph_{test_name}.json"));
    let _ = fs::remove_file(&path);
    set_bench_file_path(path.clone());
    path
}

fn test_lock() -> std::sync::MutexGuard<'static, ()> {
    static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
    LOCK.get_or_init(|| Mutex::new(()))
        .lock()
        .expect("bench lock")
}

fn metric(name: &str, ops: f64) -> BenchMetric {
    BenchMetric {
        name: name.into(),
        ops_per_sec: ops,
        bytes_per_sec: 0.0,
        notes: String::new(),
    }
}

#[test]
fn test_record_and_reload_roundtrip() {
    let _guard = test_lock();
    let path = set_bench_file("record_roundtrip");
    record_bench_run("bench_round", metric("bench_round", 100.0)).unwrap();
    let runs = load_previous_runs().unwrap();
    assert_eq!(runs.len(), 1);
    assert_eq!(runs[0].name, "bench_round");
    fs::remove_file(path).ok();
}

#[test]
fn test_threshold_passes() {
    let _guard = test_lock();
    let path = set_bench_file("threshold_pass");
    record_bench_run("bench_thr", metric("bench_thr", 250.0)).unwrap();
    let threshold = BenchThreshold {
        name: "bench_thr".into(),
        min_ops_per_sec: 200.0,
        max_ms: 5.0,
    };
    let result = check_thresholds("bench_thr", threshold).unwrap();
    assert!(matches!(result, BenchGateResult::Pass));
    fs::remove_file(path).ok();
}

#[test]
fn test_threshold_fails() {
    let _guard = test_lock();
    let path = set_bench_file("threshold_fail");
    record_bench_run("bench_thr", metric("bench_thr", 50.0)).unwrap();
    let threshold = BenchThreshold {
        name: "bench_thr".into(),
        min_ops_per_sec: 100.0,
        max_ms: 5.0,
    };
    let result = check_thresholds("bench_thr", threshold).unwrap();
    assert!(matches!(result, BenchGateResult::Fail { .. }));
    fs::remove_file(path).ok();
}

#[test]
fn test_baseline_comparison_improved() {
    let _guard = test_lock();
    let path = set_bench_file("baseline_improved");
    record_bench_run("bench_cmp", metric("bench_cmp", 100.0)).unwrap();
    let comparison = compare_to_baseline("bench_cmp", metric("bench_cmp", 125.0)).unwrap();
    assert!(comparison.improved);
    assert!(comparison.delta_ops_per_sec > 0.0);
    fs::remove_file(path).ok();
}

#[test]
fn test_baseline_comparison_regressed() {
    let _guard = test_lock();
    let path = set_bench_file("baseline_regressed");
    record_bench_run("bench_cmp", metric("bench_cmp", 120.0)).unwrap();
    let comparison = compare_to_baseline("bench_cmp", metric("bench_cmp", 80.0)).unwrap();
    assert!(!comparison.improved);
    assert!(comparison.delta_ops_per_sec < 0.0);
    fs::remove_file(path).ok();
}