system_harness/
lib.rs

1#![doc = include_str!("../README.md")]
2//!
3//! # QEMU
4//! 
5//! A [`QemuSystem`](`crate::QemuSystem`) that implements 
6//! [`SystemHarness`](`crate::SystemHarness`) can be instantiated using a 
7//! [`QemuSystemConfig`](`crate::QemuSystemConfig`) that can be deserialized
8//! using serde.
9//!
10//! The top-most mapping should align with the QEMU argument names with the
11//! sub-mappings aligning with the backends and/or properties of the arguments.
12//!
13//! An example QEMU configuration:
14//!```json
15#![doc = include_str!("../tests/data/qemu-config.json")]
16//!```
17//! # Containers
18//!
19//! A [`ContainerSystem`](`crate::ContainerSystem`) that implements 
20//! [`SystemHarness`](`crate::SystemHarness`) can be instantiated using a 
21//! [`ContainerSystemConfig`](`crate::ContainerSystemConfig`) that can be deserialized
22//! using serde.
23//!
24//! An example of a container configuration:
25//!```json
26#![doc = include_str!("../tests/data/container-config.json")]
27//!```
28use std::io::{Read, Write};
29use std::time::SystemTime;
30
31/// System keyboard key
32#[derive(Debug, PartialEq)]
33pub enum Key {
34    Enter,
35}
36
37/// System status
38#[derive(Debug, PartialEq)]
39pub enum Status {
40    Running,
41    Paused,
42    Suspended,
43    Shutdown,
44}
45
46/// Type of event
47#[derive(Debug, PartialEq)]
48pub enum EventKind {
49    Shutdown,
50    Resume,
51    Pause,
52    Suspend,
53}
54
55/// A machine event
56pub struct Event {
57    /// Type of event
58    pub kind: EventKind,
59
60    /// Time event occurred
61    pub timestamp: SystemTime,
62}
63
64/// A trait representing event listener
65pub trait EventSubscriber: Send + Sync + 'static {
66    /// Action to be performed on event
67    fn on_event(&mut self, event: &Event);
68}
69
70/// A trait representing a harnessed system
71pub trait SystemHarness {
72
73    type Terminal: SystemTerminal;
74
75    /// Get a terminal for the system 
76    fn terminal(&self) -> Result<Self::Terminal, Error>;
77
78    /// Pause system
79    fn pause(&mut self) -> Result<(), Error>;
80
81    /// Resume system
82    fn resume(&mut self) -> Result<(), Error>;
83
84    /// Shutdown system
85    fn shutdown(&mut self) -> Result<(), Error>;
86
87    /// Get system status
88    fn status(&mut self) -> Result<Status, Error>;
89
90    /// Check if harness is running
91    fn running(&mut self) -> Result<bool, Error>;
92}
93
94/// A trait representing a harnessed system that should be
95/// treated as a terminal
96pub trait SystemTerminal: Write + Read {
97
98    /// Send key to emulator
99    fn send_key(&mut self, key: Key) -> Result<(), Error>;
100
101    /// Send a command to the terminal
102    fn send_command(&mut self, command: &str) -> Result<(), Error> {
103        self.write(command.as_bytes())?;
104        self.flush()?;
105        self.send_key(Key::Enter)
106    }
107
108}
109
110/// An event publisher
111pub trait EventPublisher {
112    /// Subscribe event listener
113    fn subscribe(&mut self, subscriber: impl EventSubscriber) -> Result<(), Error>;
114}
115
116impl<F> EventSubscriber for F
117where
118    F: FnMut(&Event) + Send + Sync + 'static,
119{
120    fn on_event(&mut self, event: &Event) {
121        (self)(event)
122    }
123}
124
125mod error;
126pub use error::Error;
127pub use error::ErrorKind;
128
129#[cfg(all(target_family = "unix", feature = "container"))]
130mod container;
131#[cfg(all(target_family = "unix", feature = "container"))]
132pub use container::*;
133
134#[cfg(all(target_family = "unix", feature = "qemu"))]
135mod qemu;
136#[cfg(all(target_family = "unix", feature = "qemu"))]
137pub use qemu::*;
138
139#[cfg(test)]
140mod tests {
141
142    use super::*;
143
144    struct FakeEventPublisher(Vec<Box<dyn EventSubscriber>>);
145
146    impl FakeEventPublisher {
147        pub fn publish(&mut self) {
148            let event = Event {
149                kind: EventKind::Shutdown,
150                timestamp: SystemTime::now(),
151            };
152            for subscriber in &mut self.0 {
153                subscriber.on_event(&event);
154            }
155        }
156    }
157
158    impl EventPublisher for FakeEventPublisher {
159        fn subscribe(&mut self, subscriber: impl EventSubscriber) -> Result<(), Error> {
160            self.0.push(Box::new(subscriber));
161            Ok(())
162        }
163    }
164
165    #[test]
166    fn fn_subscribe() {
167        let mut publisher = FakeEventPublisher(Vec::new());
168        publisher.subscribe(|_event: &Event| {}).unwrap();
169        publisher.publish();
170    }
171}