use super::*;
use axum::extract::State;
use axum::Json;
use std::sync::Arc;
#[tokio::test]
async fn pid_slot_forwarder_does_not_leak_tasks() {
use crate::core::registry::IndexRegistry;
use std::sync::atomic::{AtomicU32, Ordering};
let state = Arc::new(SearchAppState::new(IndexRegistry::new()));
let slot1 = Arc::new(AtomicU32::new(42));
state.install_embedderd_pid_slot(Arc::clone(&slot1)).await;
{
let guard = state.embedderd_pid_forwarder_handle.lock().await;
assert!(
guard.is_some(),
"after first install, abort handle must be Some"
);
}
let slot2 = Arc::new(AtomicU32::new(99));
state.install_embedderd_pid_slot(Arc::clone(&slot2)).await;
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
let stored = state.embedderd_pid_slot.load(Ordering::Relaxed);
assert_eq!(
stored, 99,
"embedderd_pid_slot must reflect the second slot's PID after re-install"
);
}
#[tokio::test]
async fn admin_stop_triggers_graceful_shutdown() {
use crate::core::registry::IndexRegistry;
let state = Arc::new(SearchAppState::new(IndexRegistry::new()));
let mut shutdown_rx = state.shutdown_tx.subscribe();
let Json(resp) = admin_stop_handler(State(Arc::clone(&state))).await;
assert_eq!(
resp.get("ok"),
Some(&serde_json::json!(true)),
"admin_stop must return ok:true"
);
let changed =
tokio::time::timeout(std::time::Duration::from_millis(500), shutdown_rx.changed()).await;
assert!(
changed.is_ok(),
"shutdown channel must be signalled within 500 ms"
);
assert!(
*shutdown_rx.borrow(),
"shutdown_tx value must be true after admin_stop"
);
}
#[tokio::test]
async fn validate_root_path_is_non_blocking_and_async() {
use std::path::Path;
let result = super::helpers::validate_root_path(Path::new("")).await;
assert!(result.is_err(), "empty path must be rejected");
let result = super::helpers::validate_root_path(Path::new("relative/path")).await;
assert!(result.is_err(), "relative path must be rejected");
let result =
super::helpers::validate_root_path(Path::new("/this/path/does/not/exist/issue829")).await;
assert!(result.is_err(), "non-existent path must be rejected");
}
#[tokio::test(flavor = "multi_thread")]
async fn file_is_within_root_slow_path_does_not_block_executor() {
use super::helpers::file_is_within_root;
use std::path::Path;
let root = Path::new("/non/existent/root");
let result = file_is_within_root("/non/existent/other/file.rs", root);
assert!(!result, "non-existent root must return false");
let result = file_is_within_root("src/lib.rs", root);
assert!(result, "clean relative path must be accepted");
}