use async_trait::async_trait; use speare::{req_res, Ctx, Handle, Node, Process, Request}; use tokio::task; struct Foo; #[async_trait] impl Process for Foo { type Props = (); type Msg = (); type Err = (); async fn init(_: &mut Ctx) -> Result { Ok(Foo) } } struct Bar; #[async_trait] impl Process for Bar { type Props = (); type Msg = (); type Err = (); async fn init(_: &mut Ctx) -> Result { Ok(Bar) } } #[allow(clippy::disallowed_names)] #[tokio::test] async fn node_stops_all_processes_when_dropped() { // Arrange let mut node = Node::default(); let foo = node.spawn::(()); let bar = node.spawn::(()); // Act drop(node); task::yield_now().await; task::yield_now().await; // Assert assert!(!foo.is_alive()); assert!(!bar.is_alive()); } struct Quitter; #[async_trait] impl Process for Quitter { type Props = bool; type Msg = (); type Err = (); async fn init(ctx: &mut Ctx) -> Result { if *ctx.props() { Err(()) } else { Ok(Quitter) } } async fn handle(&mut self, _: Self::Msg, _: &mut Ctx) -> Result<(), Self::Err> { Err(()) } } #[tokio::test] async fn root_process_quits_without_supervision_on_error() { // Arrange let mut node = Node::default(); let quit_on_start = false; let quitter = node.spawn::(quit_on_start); assert!(quitter.is_alive()); // Error on handle // Act quitter.send(()); task::yield_now().await; task::yield_now().await; // Assert assert!(!quitter.is_alive()); // Error on init // Act let quit_on_start = true; let quitter2 = node.spawn::(quit_on_start); task::yield_now().await; task::yield_now().await; // Assert assert!(!quitter2.is_alive()); } struct Parent { foo: Handle<()>, bar: Handle<()>, } #[async_trait] impl Process for Parent { type Props = (); type Msg = Request<(), (Handle<()>, Handle<()>)>; type Err = (); async fn init(ctx: &mut Ctx) -> Result { Ok(Parent { foo: ctx.spawn::(()), bar: ctx.spawn::(()), }) } async fn handle(&mut self, msg: Self::Msg, _: &mut Ctx) -> Result<(), Self::Err> { msg.reply((self.foo.clone(), self.bar.clone())); Ok(()) } } #[allow(clippy::disallowed_names)] #[tokio::test] async fn stopping_a_root_process_stops_all_its_children() { // Arrange let mut node = Node::default(); let parent = node.spawn::(()); let (req, res) = req_res(()); parent.send(req); let (foo, bar) = res.recv().await.unwrap(); assert!(foo.is_alive()); assert!(bar.is_alive()); // Act parent.stop(); task::yield_now().await; task::yield_now().await; // Assert assert!(!foo.is_alive()); assert!(!bar.is_alive()); }