netsky-db 0.1.7

netsky observability database
Documentation
use std::process::Command;
use std::time::Duration;

use chrono::Utc;
use netsky_db::Db;

const CHILD_ENV: &str = "NETSKY_DB_CONCURRENT_CHILD";
const PATH_ENV: &str = "NETSKY_DB_CONCURRENT_PATH";
const WRITES_ENV: &str = "NETSKY_DB_CONCURRENT_WRITES";

#[test]
fn eight_process_cli_writes_have_zero_lock_errors() {
    let dir = tempfile::tempdir().expect("tempdir");
    let path = dir.path().join("meta.db");
    let db = Db::open_path(&path).expect("open");
    db.migrate().expect("migrate");

    let exe = std::env::current_exe().expect("current exe");
    let procs = 8;
    let writes = 4;
    let mut children = Vec::new();
    for writer in 0..procs {
        children.push(
            Command::new(&exe)
                .arg("--exact")
                .arg("concurrent_child")
                .arg("--nocapture")
                .env(CHILD_ENV, writer.to_string())
                .env(PATH_ENV, &path)
                .env(WRITES_ENV, writes.to_string())
                .output()
                .expect("spawn child"),
        );
    }

    for (idx, output) in children.into_iter().enumerate() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        assert!(output.status.success(), "child {idx} failed: {stderr}");
        assert!(
            !stderr.contains("Database already open") && !stderr.contains("database is locked"),
            "child {idx} lock stderr: {stderr}"
        );
    }

    let db = Db::open_path(&path).expect("reopen");
    let out = db
        .query("SELECT COUNT(*) AS count FROM cli_invocations")
        .expect("query count");
    assert!(out.contains(&(procs * writes).to_string()), "{out}");
}

#[test]
fn concurrent_child() {
    let Ok(writer) = std::env::var(CHILD_ENV) else {
        return;
    };
    let path = std::env::var(PATH_ENV).expect("path env");
    let writes = std::env::var(WRITES_ENV)
        .expect("writes env")
        .parse::<usize>()
        .expect("writes");
    let db = Db::open_path(path).expect("open child db");
    db.migrate().expect("migrate child db");
    for i in 0..writes {
        let argv = format!(r#"["writer-{writer}", "{i}"]"#);
        db.record_cli(
            Utc::now(),
            "netsky",
            &argv,
            Some(0),
            Some(Duration::from_millis(1).as_millis() as i64),
            "concurrent-test",
        )
        .expect("record cli");
    }
}