use std::sync::Arc;
use std::sync::Mutex;
use uuid::Uuid;
use crate::brain::agent::QueuedUserMessage;
use crate::brain::agent::service::MessageEnqueueCallback;
use crate::brain::agent::service::background_tasks::register_session_route;
use crate::brain::agent::service::restart_recovery::{
clear_parked_for_test, deliver_or_park, flush_parked, parked_count,
};
type Seen = Arc<Mutex<Vec<(Uuid, String)>>>;
static TEST_LOCK: Mutex<()> = Mutex::new(());
fn serialized() -> std::sync::MutexGuard<'static, ()> {
let guard = TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
clear_parked_for_test();
guard
}
fn recorder() -> (MessageEnqueueCallback, Seen) {
let seen: Arc<Mutex<Vec<(Uuid, String)>>> = Arc::new(Mutex::new(Vec::new()));
let sink = Arc::clone(&seen);
let cb: MessageEnqueueCallback = Arc::new(move |id: Uuid, msg: QueuedUserMessage| {
if let Ok(mut v) = sink.lock() {
v.push((id, msg.display_text));
}
});
(cb, seen)
}
fn msg(text: &str) -> QueuedUserMessage {
QueuedUserMessage {
context_text: text.to_string(),
display_text: text.to_string(),
}
}
#[test]
fn a_report_with_no_route_parks_instead_of_going_out() {
let _guard = serialized();
let session = Uuid::new_v4();
let delivered = deliver_or_park(session, msg("interrupted"));
assert!(!delivered, "nothing claims this session yet");
assert_eq!(parked_count(), 1);
}
#[test]
fn registering_a_route_hands_over_what_was_parked() {
let _guard = serialized();
let session = Uuid::new_v4();
deliver_or_park(session, msg("interrupted"));
let (cb, seen) = recorder();
register_session_route(session, cb);
let seen = seen.lock().unwrap();
assert_eq!(seen.len(), 1, "the channel gets what it missed");
assert_eq!(seen[0].0, session);
assert_eq!(seen[0].1, "interrupted");
assert_eq!(parked_count(), 0);
}
#[test]
fn a_route_that_already_exists_receives_immediately() {
let _guard = serialized();
let session = Uuid::new_v4();
let (cb, seen) = recorder();
register_session_route(session, cb);
let delivered = deliver_or_park(session, msg("later report"));
assert!(delivered);
assert_eq!(parked_count(), 0, "nothing needed parking");
assert_eq!(seen.lock().unwrap().len(), 1);
}
#[test]
fn one_sessions_route_does_not_drain_anothers_reports() {
let _guard = serialized();
let mine = Uuid::new_v4();
let theirs = Uuid::new_v4();
deliver_or_park(mine, msg("mine"));
deliver_or_park(theirs, msg("theirs"));
let (cb, seen) = recorder();
register_session_route(mine, cb);
let seen = seen.lock().unwrap();
assert_eq!(seen.len(), 1);
assert_eq!(seen[0].1, "mine");
assert_eq!(parked_count(), 1, "the other session's report still waits");
}
#[test]
fn the_flush_delivers_locally_rather_than_losing_the_report() {
let _guard = serialized();
let orphan = Uuid::new_v4();
deliver_or_park(orphan, msg("nobody claimed me"));
let (local, seen) = recorder();
let flushed = flush_parked(&local);
assert_eq!(flushed, 1);
assert_eq!(parked_count(), 0);
let seen = seen.lock().unwrap();
assert_eq!(seen[0].0, orphan);
assert_eq!(seen[0].1, "nobody claimed me");
}
#[test]
fn flushing_with_nothing_parked_is_a_no_op() {
let _guard = serialized();
let (local, seen) = recorder();
assert_eq!(flush_parked(&local), 0);
assert!(seen.lock().unwrap().is_empty());
}