use std::time::Duration;
use serenity::model::id::MessageId;
use tokio::sync::oneshot;
use crate::channels::discord::group_bubble::BubbleSlot;
async fn parked_birth(
slot: &std::sync::Arc<BubbleSlot>,
) -> (oneshot::Receiver<()>, tokio::task::JoinHandle<()>) {
let (claimed_tx, claimed_rx) = oneshot::channel();
let holder = {
let slot = slot.clone();
tokio::spawn(async move {
let _claim = slot.birth_claim().await;
let _ = claimed_tx.send(());
tokio::time::sleep(Duration::from_secs(30)).await;
slot.store(MessageId::new(9)).await;
})
};
(claimed_rx, holder)
}
#[tokio::test]
async fn governor_sleep_does_not_hold_turn_group() {
let slot = std::sync::Arc::new(BubbleSlot::new());
let (claimed, holder) = parked_birth(&slot).await;
claimed.await.expect("birth task took the claim");
let read = tokio::time::timeout(Duration::from_millis(250), slot.read()).await;
assert!(
read.is_ok(),
"settle path waited on an in-flight bubble birth: the id lock is still held across the governor sleep"
);
assert_eq!(read.unwrap(), None, "no bubble has been born yet");
holder.abort();
}
#[tokio::test]
async fn a_parked_birth_does_not_block_the_settle_store() {
let slot = std::sync::Arc::new(BubbleSlot::new());
let (claimed, holder) = parked_birth(&slot).await;
claimed.await.expect("birth task took the claim");
let stored =
tokio::time::timeout(Duration::from_millis(250), slot.store(MessageId::new(4242))).await;
assert!(
stored.is_ok(),
"store waited on an in-flight bubble birth: the id lock is still held across the governor sleep"
);
assert_eq!(slot.read().await, Some(MessageId::new(4242)));
holder.abort();
}
#[tokio::test]
async fn a_second_birth_waits_for_the_first() {
let slot = std::sync::Arc::new(BubbleSlot::new());
let (claimed, holder) = parked_birth(&slot).await;
claimed.await.expect("birth task took the claim");
let second = tokio::time::timeout(Duration::from_millis(120), slot.birth_claim()).await;
assert!(
second.is_err(),
"a second birth ran while the first was in flight: two bubbles for one turn"
);
holder.abort();
let third = tokio::time::timeout(Duration::from_millis(500), slot.birth_claim()).await;
assert!(
third.is_ok(),
"birth claim stayed stuck after the holder left"
);
}
#[tokio::test]
async fn a_later_tool_event_appends_to_the_born_bubble() {
let slot = BubbleSlot::new();
assert_eq!(slot.read().await, None);
slot.store(MessageId::new(77)).await;
assert_eq!(slot.read().await, Some(MessageId::new(77)));
let handle = slot.mid_handle();
assert_eq!(*handle.lock().await, Some(MessageId::new(77)));
}