#![allow(clippy::unwrap_used, clippy::expect_used)]
use anyhow::Result;
use modkit::{RunnableCapability, lifecycle as lifecycle_attr, lifecycle::*};
use std::time::Duration;
use tokio_util::sync::CancellationToken;
struct ReadyAware;
#[lifecycle_attr(method = "run_with_ready", stop_timeout = "200ms", await_ready = true)]
impl ReadyAware {
pub async fn run_with_ready(
&self,
cancel: CancellationToken,
ready: ReadySignal,
) -> Result<()> {
tokio::time::sleep(Duration::from_millis(20)).await;
ready.notify();
cancel.cancelled().await;
Ok(())
}
}
struct AutoNotify;
#[lifecycle_attr(method = "run_no_ready", await_ready = true)]
impl AutoNotify {
pub async fn run_no_ready(&self, cancel: CancellationToken) -> Result<()> {
cancel.cancelled().await;
Ok(())
}
}
#[tokio::test]
async fn stays_starting_until_ready_signal() {
let m = ReadyAware.into_module();
let parent = CancellationToken::new();
m.start(parent.clone()).await.unwrap();
assert_eq!(m.status(), Status::Starting);
tokio::time::sleep(Duration::from_millis(40)).await;
assert_eq!(m.status(), Status::Running);
parent.cancel();
m.stop(CancellationToken::new()).await.unwrap();
assert_eq!(m.status(), Status::Stopped);
}
#[tokio::test]
async fn auto_notify_when_no_ready_param() {
let m = AutoNotify.into_module();
let parent = CancellationToken::new();
m.start(parent.clone()).await.unwrap();
tokio::time::sleep(Duration::from_millis(5)).await;
assert!(matches!(m.status(), Status::Running | Status::Starting));
parent.cancel();
m.stop(CancellationToken::new()).await.unwrap();
assert_eq!(m.status(), Status::Stopped);
}
#[tokio::test]
async fn drop_cleans_up_background_task() {
let parent = CancellationToken::new();
let handle = tokio::spawn(async move {
let m = AutoNotify.into_module();
m.start(parent.clone()).await.unwrap();
m
});
let m = handle.await.unwrap();
drop(m);
}