use super::*;
#[test]
fn analyze_spawn_spec_runs_a_bare_serve() {
let tmp = tempfile::tempdir().expect("tempdir");
let socket = tmp.path().join("sockets").join("trusty-analyze.sock");
let Ok(spec) = analyze_spawn_spec(&socket) else {
eprintln!("skip: trusty-analyze is not installed on this machine");
return;
};
let args: Vec<String> = spec
.args
.iter()
.map(|a| a.to_string_lossy().into_owned())
.collect();
assert_eq!(args[0], "serve", "the child must be a plain serve");
assert_eq!(args[1], "--socket");
assert_eq!(args[2], socket.to_string_lossy());
assert!(
spec.create_dirs
.contains(&socket.parent().expect("parent").to_path_buf()),
"the socket's directory must be created before the child tries to bind it"
);
assert!(
!args.iter().any(|a| a == "--port" || a == "--mcp"),
"no retired transport flag may be passed: {args:?}"
);
}
#[test]
fn analyze_timeouts_leave_room_for_the_flush() {
assert!(
ANALYZE_TIMEOUTS.sigterm_patience > ANALYZE_TIMEOUTS.shutdown_flush,
"the SIGKILL must land after the flush window, never inside it"
);
assert_eq!(ANALYZE_TIMEOUTS.shutdown_flush, ANALYZE_SHUTDOWN_FLUSH);
assert!(
ANALYZE_TIMEOUTS.spawn_probe >= Duration::from_secs(5),
"the budget has to cover opening two redb files on a cold page cache"
);
}
#[test]
fn idle_timeout_parses_its_three_meanings() {
assert_eq!(
analyze_idle_timeout(None),
Some(DEFAULT_ANALYZE_IDLE_TIMEOUT)
);
assert_eq!(
analyze_idle_timeout(Some("")),
Some(DEFAULT_ANALYZE_IDLE_TIMEOUT)
);
assert_eq!(
analyze_idle_timeout(Some("0")),
None,
"0 must mean never exit, not exit immediately"
);
assert_eq!(
analyze_idle_timeout(Some(" 90 ")),
Some(Duration::from_secs(90))
);
assert_eq!(
analyze_idle_timeout(Some("soon")),
Some(DEFAULT_ANALYZE_IDLE_TIMEOUT),
"a typo must not stop the server from starting"
);
assert!(
DEFAULT_ANALYZE_IDLE_TIMEOUT >= Duration::from_secs(5 * 60)
&& DEFAULT_ANALYZE_IDLE_TIMEOUT <= Duration::from_secs(15 * 60),
"the #6350 ruling fixed the default inside a 5–15 minute band"
);
}
#[serial_test::serial]
#[tokio::test]
async fn external_mode_returns_the_socket_without_spawning() {
let tmp = tempfile::tempdir().expect("tempdir");
let socket = tmp.path().join("absent.sock");
let handle = OnDemandAnalyze::at(&socket);
unsafe { std::env::set_var(ANALYZE_EXTERNAL_ENV, "1") };
let path = handle.ensure_running().await;
unsafe { std::env::remove_var(ANALYZE_EXTERNAL_ENV) };
assert_eq!(
path.expect("external mode must succeed without a server"),
socket
);
assert!(
!socket.exists(),
"external mode must not have started anything"
);
}
#[test]
fn the_default_handle_uses_the_shared_socket_path() {
let Ok(expected) = crate::daemon_socket_path(ANALYZE_SERVICE) else {
eprintln!("skip: no resolvable data directory in this environment");
return;
};
let handle = OnDemandAnalyze::new().expect("the path resolved a moment ago");
assert_eq!(handle.socket(), expected);
}