1#![doc = include_str!("../README.md")]
2#![doc = include_str!("../tests/data/qemu-config.json")]
16#![doc = include_str!("../tests/data/container-config.json")]
27use std::io::{Read, Write};
29use std::time::SystemTime;
30
31#[derive(Debug, PartialEq)]
33pub enum Key {
34 Enter,
35}
36
37#[derive(Debug, PartialEq)]
39pub enum Status {
40 Running,
41 Paused,
42 Suspended,
43 Shutdown,
44}
45
46#[derive(Debug, PartialEq)]
48pub enum EventKind {
49 Shutdown,
50 Resume,
51 Pause,
52 Suspend,
53}
54
55pub struct Event {
57 pub kind: EventKind,
59
60 pub timestamp: SystemTime,
62}
63
64pub trait EventSubscriber: Send + Sync + 'static {
66 fn on_event(&mut self, event: &Event);
68}
69
70pub trait SystemHarness {
72
73 type Terminal: SystemTerminal;
74
75 fn terminal(&self) -> Result<Self::Terminal, Error>;
77
78 fn pause(&mut self) -> Result<(), Error>;
80
81 fn resume(&mut self) -> Result<(), Error>;
83
84 fn shutdown(&mut self) -> Result<(), Error>;
86
87 fn status(&mut self) -> Result<Status, Error>;
89
90 fn running(&mut self) -> Result<bool, Error>;
92}
93
94pub trait SystemTerminal: Write + Read {
97
98 fn send_key(&mut self, key: Key) -> Result<(), Error>;
100
101 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
110pub trait EventPublisher {
112 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}