iridium-db 0.3.0

A high-performance vector-graph hybrid storage and indexing engine
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;

use crate::features::client::{embedded_driver, DriverConfig};

use super::{serve, ServiceConfig, ServiceTlsMode};

fn temp_data_dir(prefix: &str) -> PathBuf {
    let mut dir = std::env::temp_dir();
    dir.push(format!(
        "{}_{}_{}",
        prefix,
        std::process::id(),
        std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .expect("time")
            .as_nanos()
    ));
    std::fs::create_dir_all(&dir).expect("create temp dir");
    dir
}

fn seed_query_fixture(data_dir: &Path) {
    let driver =
        embedded_driver(DriverConfig::embedded_data_dir(data_dir.to_path_buf())).expect("driver");
    driver.ingest_node(1, 1, &[2, 3]).expect("seed node");
}

fn read_response(stream: &mut TcpStream) -> String {
    let mut out = String::new();
    stream.read_to_string(&mut out).expect("read response");
    out
}

#[test]
fn service_config_validation_reports_warnings_for_weak_security() {
    let report = ServiceConfig {
        listen_address: "127.0.0.1:7001".to_string(),
        data_dir: PathBuf::from("/tmp/iridium-service"),
        telemetry_endpoint: "stdout".to_string(),
        tls_mode: ServiceTlsMode::Disabled,
        admin_token: None,
        max_requests: 1,
    }
    .validate();

    assert!(report.compatible);
    assert_eq!(report.profile_id, "single-node-service-v0-1");
    assert!(report
        .warnings
        .iter()
        .any(|warning| warning.contains("tls_mode=disabled")));
    assert!(report
        .warnings
        .iter()
        .any(|warning| warning.contains("admin_token is unset")));
}

#[test]
fn service_serve_exposes_health_query_and_admin_routes() {
    let data_dir = temp_data_dir("iridium-service");
    seed_query_fixture(&data_dir);
    let listener = TcpListener::bind("127.0.0.1:0").expect("bind probe");
    let addr = listener.local_addr().expect("addr");
    drop(listener);

    let config = ServiceConfig {
        listen_address: addr.to_string(),
        data_dir: data_dir.clone(),
        telemetry_endpoint: "stdout".to_string(),
        tls_mode: ServiceTlsMode::OperatorOptional,
        admin_token: Some("secret-token".to_string()),
        max_requests: 4,
    };

    let thread_config = config.clone();
    let handle = thread::spawn(move || serve(&thread_config));
    std::thread::sleep(Duration::from_millis(50));

    let mut live = TcpStream::connect(addr).expect("connect live");
    live.write_all(b"GET /livez HTTP/1.1\r\nHost: localhost\r\n\r\n")
        .expect("write live");
    let live_text = read_response(&mut live);
    assert!(live_text.contains("200 OK"));
    assert!(live_text.contains("live"));

    let mut query = TcpStream::connect(addr).expect("connect query");
    query
        .write_all(
            b"GET /v1/query?q=MATCH+%28n%29+RETURN+n+LIMIT+1 HTTP/1.1\r\nHost: localhost\r\n\r\n",
        )
        .expect("write query");
    let query_text = read_response(&mut query);
    assert!(query_text.contains("200 OK"));
    assert!(query_text.contains("\"rows\""));

    let mut unauthorized = TcpStream::connect(addr).expect("connect unauthorized");
    unauthorized
        .write_all(b"GET /admin/status HTTP/1.1\r\nHost: localhost\r\n\r\n")
        .expect("write unauthorized");
    let unauthorized_text = read_response(&mut unauthorized);
    assert!(unauthorized_text.contains("401 Unauthorized"));

    let mut stop = TcpStream::connect(addr).expect("connect stop");
    stop.write_all(
        b"GET /admin/lifecycle?action=stop HTTP/1.1\r\nHost: localhost\r\nAuthorization: Bearer secret-token\r\n\r\n",
    )
    .expect("write stop");
    let stop_text = read_response(&mut stop);
    assert!(stop_text.contains("200 OK"));
    assert!(stop_text.contains("\"action\": \"stop\""));

    handle.join().expect("join").expect("serve");
}