feat(supervisor): ChildHandle trait + MockChild
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{Mutex, oneshot};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait ChildHandle: Send + 'static {
|
||||
fn pid(&self) -> u32;
|
||||
async fn wait(&mut self) -> std::io::Result<Option<i32>>;
|
||||
fn terminate(&mut self) -> std::io::Result<()>;
|
||||
fn kill(&mut self) -> std::io::Result<()>;
|
||||
}
|
||||
|
||||
pub struct MockChild {
|
||||
pid: u32,
|
||||
exit_rx: Arc<Mutex<oneshot::Receiver<Option<i32>>>>,
|
||||
terminate_tx: Option<oneshot::Sender<()>>,
|
||||
kill_tx: Option<oneshot::Sender<()>>,
|
||||
}
|
||||
|
||||
pub struct MockChildController {
|
||||
pub exit_tx: Option<oneshot::Sender<Option<i32>>>,
|
||||
pub terminate_rx: oneshot::Receiver<()>,
|
||||
pub kill_rx: oneshot::Receiver<()>,
|
||||
}
|
||||
|
||||
impl MockChild {
|
||||
pub fn new(pid: u32) -> (Self, MockChildController) {
|
||||
let (exit_tx, exit_rx) = oneshot::channel();
|
||||
let (terminate_tx, terminate_rx) = oneshot::channel();
|
||||
let (kill_tx, kill_rx) = oneshot::channel();
|
||||
let child = Self {
|
||||
pid,
|
||||
exit_rx: Arc::new(Mutex::new(exit_rx)),
|
||||
terminate_tx: Some(terminate_tx),
|
||||
kill_tx: Some(kill_tx),
|
||||
};
|
||||
let ctl = MockChildController {
|
||||
exit_tx: Some(exit_tx),
|
||||
terminate_rx,
|
||||
kill_rx,
|
||||
};
|
||||
(child, ctl)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ChildHandle for MockChild {
|
||||
fn pid(&self) -> u32 {
|
||||
self.pid
|
||||
}
|
||||
|
||||
async fn wait(&mut self) -> std::io::Result<Option<i32>> {
|
||||
let mut rx = self.exit_rx.lock().await;
|
||||
match (&mut *rx).await {
|
||||
Ok(code) => Ok(code),
|
||||
Err(_) => Err(std::io::Error::other("exit_tx dropped")),
|
||||
}
|
||||
}
|
||||
|
||||
fn terminate(&mut self) -> std::io::Result<()> {
|
||||
if let Some(tx) = self.terminate_tx.take() {
|
||||
let _ = tx.send(());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn kill(&mut self) -> std::io::Result<()> {
|
||||
if let Some(tx) = self.kill_tx.take() {
|
||||
let _ = tx.send(());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn mock_child_exit() {
|
||||
let (mut child, mut ctl) = MockChild::new(123);
|
||||
assert_eq!(child.pid(), 123);
|
||||
ctl.exit_tx.take().unwrap().send(Some(0)).unwrap();
|
||||
assert_eq!(child.wait().await.unwrap(), Some(0));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mock_child_terminate() {
|
||||
let (mut child, mut ctl) = MockChild::new(1);
|
||||
child.terminate().unwrap();
|
||||
ctl.terminate_rx.try_recv().unwrap();
|
||||
}
|
||||
}
|
||||
@@ -1 +1,5 @@
|
||||
//! Process-supervision primitives for the xy daemon.
|
||||
|
||||
pub mod child;
|
||||
|
||||
pub use child::{ChildHandle, MockChild, MockChildController};
|
||||
|
||||
Reference in New Issue
Block a user