pub mod exec;
pub mod ssh;
pub mod tree;
use std::collections::{HashMap, HashSet};
use std::os::unix::io::RawFd;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum WorkerError {
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("worker error: {0}")]
General(String),
#[error("timeout")]
Timeout,
}
pub type Result<T> = std::result::Result<T, WorkerError>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WorkerState {
Pending,
Running,
Done,
Aborted,
}
pub trait EventHandler: Send {
fn on_start(&mut self, worker: &dyn Worker) {
let _ = worker;
}
fn on_read(&mut self, node: &str, fd: RawFd, msg: &[u8]) {
let _ = (node, fd, msg);
}
fn on_close(&mut self, node: &str, rc: i32) {
let _ = (node, rc);
}
fn on_timeout(&mut self, node: &str) {
let _ = node;
}
fn on_error(&mut self, node: &str, error: &WorkerError) {
let _ = (node, error);
}
fn take_buffers(
&mut self,
) -> (
HashMap<String, Vec<Vec<u8>>>,
HashMap<String, Vec<Vec<u8>>>,
HashSet<String>,
) {
(HashMap::new(), HashMap::new(), HashSet::new())
}
}
pub trait Worker: Send {
fn start(&mut self) -> Result<()>;
fn abort(&mut self, kill: bool);
fn state(&self) -> WorkerState;
fn set_handler(&mut self, handler: Box<dyn EventHandler>);
fn read_fds(&self) -> Vec<RawFd>;
fn write_fds(&self) -> Vec<RawFd>;
fn handle_read(&mut self, fd: RawFd) -> Result<()>;
fn handle_write(&mut self, fd: RawFd) -> Result<()>;
fn is_done(&self) -> bool;
fn retcodes(&self) -> &HashMap<String, i32>;
fn num_nodes(&self) -> usize;
fn take_handler(&mut self) -> Option<Box<dyn EventHandler>>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_worker_state_variants() {
assert_eq!(WorkerState::Pending, WorkerState::Pending);
assert_eq!(WorkerState::Running, WorkerState::Running);
assert_eq!(WorkerState::Done, WorkerState::Done);
assert_eq!(WorkerState::Aborted, WorkerState::Aborted);
}
#[test]
fn test_worker_state_debug() {
assert_eq!(format!("{:?}", WorkerState::Pending), "Pending");
assert_eq!(format!("{:?}", WorkerState::Running), "Running");
assert_eq!(format!("{:?}", WorkerState::Done), "Done");
assert_eq!(format!("{:?}", WorkerState::Aborted), "Aborted");
}
#[test]
fn test_worker_state_clone() {
let state = WorkerState::Pending;
let cloned = state.clone();
assert_eq!(state, cloned);
}
#[test]
fn test_worker_state_copy() {
fn take_copy<T: Copy>(_: T) {}
take_copy(WorkerState::Pending);
}
#[test]
fn test_worker_state_partial_eq() {
assert!(WorkerState::Pending == WorkerState::Pending);
assert!(WorkerState::Running != WorkerState::Pending);
}
#[test]
fn test_worker_error_variants() {
let io_err = WorkerError::Io(std::io::Error::new(
std::io::ErrorKind::NotFound,
"not found",
));
let gen_err = WorkerError::General("something went wrong".to_string());
let timeout_err = WorkerError::Timeout;
matches!(io_err, WorkerError::Io(_));
matches!(gen_err, WorkerError::General(_));
matches!(timeout_err, WorkerError::Timeout);
}
#[test]
fn test_worker_error_impls_error() {
use std::error::Error;
let gen_err = WorkerError::General("test".to_string());
assert!(gen_err.source().is_none());
let timeout_err = WorkerError::Timeout;
assert!(timeout_err.source().is_none());
}
#[test]
fn test_worker_error_impls_display() {
let io_err = WorkerError::Io(std::io::Error::new(
std::io::ErrorKind::NotFound,
"file.txt",
));
assert_eq!(io_err.to_string(), "io error: file.txt");
let gen_err = WorkerError::General("test error".to_string());
assert_eq!(gen_err.to_string(), "worker error: test error");
let timeout_err = WorkerError::Timeout;
assert_eq!(timeout_err.to_string(), "timeout");
}
#[test]
fn test_event_handler_default_methods() {
struct TestHandler;
impl EventHandler for TestHandler {}
let handler = TestHandler;
let _ = handler;
}
#[test]
fn test_event_handler_object_safe() {
struct TestHandler;
impl EventHandler for TestHandler {}
let _handler: Box<dyn EventHandler> = Box::new(TestHandler);
}
#[test]
fn test_event_handler_is_send() {
fn assert_send<T: Send>() {}
assert_send::<Box<dyn EventHandler>>();
}
#[test]
fn test_result_type_alias() {
let ok: Result<()> = Ok(());
let err: Result<()> = Err(WorkerError::Timeout);
assert!(ok.is_ok());
assert!(err.is_err());
}
}