Add sandbox and daemon mock to utils mod

This commit is contained in:
edouard 2022-09-05 12:19:00 +02:00
parent 928294b32e
commit ebc239733c
4 changed files with 150 additions and 0 deletions

View File

@ -3,3 +3,4 @@ pub mod daemon;
pub mod installer; pub mod installer;
pub mod loader; pub mod loader;
pub mod ui; pub mod ui;
pub mod utils;

93
gui/src/utils/mock.rs Normal file
View File

@ -0,0 +1,93 @@
use crate::daemon::{client::Client, DaemonError};
use minisafe::config::Config;
use serde::{de::DeserializeOwned, Serialize};
use serde_json::{json, Value};
use std::fmt::Debug;
use std::sync::{
mpsc::{channel, Receiver, Sender},
Mutex,
};
use std::thread;
#[derive(Debug)]
pub struct DaemonClient {
transport: Mutex<(Sender<Value>, Receiver<Result<Value, DaemonError>>)>,
}
impl Client for DaemonClient {
type Error = DaemonError;
fn request<S: Serialize + Debug, D: DeserializeOwned + Debug>(
&self,
method: &str,
params: Option<S>,
) -> Result<D, Self::Error> {
let req = json!({"method": method, "params": params});
let connection = self.transport.lock().expect("Failed to unlock");
connection
.0
.send(req)
.expect("Mock client failed to send request");
connection
.1
.recv()
.expect("Mock client failed to receive response")
.map(|value| serde_json::from_value(value).unwrap())
}
}
pub struct Daemon {
requests: Vec<(Option<Value>, Result<Value, DaemonError>)>,
}
impl Daemon {
pub fn new(requests: Vec<(Option<Value>, Result<Value, DaemonError>)>) -> Self {
Self { requests }
}
pub fn run(self) -> DaemonClient {
let (client_sender, daemon_receiver) = channel();
let (daemon_sender, client_receiver) = channel();
thread::spawn(move || {
let mut requests = self.requests.into_iter();
while let Ok(msg) = daemon_receiver.recv() {
let request = requests
.next()
.expect("Mock Daemon must have all requests mocked in the right order");
if let Some(body) = request.0 {
assert_eq!(body, msg);
}
daemon_sender
.send(request.1)
.expect("Mock daemon failed to send response")
}
// close the daemon -> client channel after
// the client -> daemon channel is closed.
// (client -> daemon channel is closed when DaemonClient is dropped)
drop(daemon_sender);
// Readable with `cargo test -- --nocapture`
println!("The daemon has stopped!");
});
DaemonClient {
transport: Mutex::new((client_sender, client_receiver)),
}
}
}
pub fn fake_daemon_config() -> Config {
toml::from_str(
r#"
data_dir = "/home/edouard/code/revault/demo/minisafe/datadir"
main_descriptor = "wsh(or_d(pk(tpubDCbK3Ysvk8HjcF6mPyrgMu3KgLiaaP19RjKpNezd8GrbAbNg6v5BtWLaCt8FNm6QkLseopKLf5MNYQFtochDTKHdfgG6iqJ8cqnLNAwtXuP/*),and_v(v:pkh(tpubDDtb2WPYwEWw2WWDV7reLV348iJHw2HmhzvPysKKrJw3hYmvrd4jasyoioVPdKGQqjyaBMEvTn1HvHWDSVqQ6amyyxRZ5YjpPBBGjJ8yu8S/*),older(100))))#459t6xxr"
[bitcoin_config]
network = "regtest"
poll_interval_secs = 30
[bitcoind_config]
addr = "127.0.0.1:9001"
cookie_path = "/home/edouard/code/revault/demo/minisafe/regtest/bcdir1/regtest/.cookie"
"#
).unwrap()
}

5
gui/src/utils/mod.rs Normal file
View File

@ -0,0 +1,5 @@
#[cfg(test)]
pub mod sandbox;
#[cfg(test)]
pub mod mock;

51
gui/src/utils/sandbox.rs Normal file
View File

@ -0,0 +1,51 @@
use std::sync::Arc;
use iced_native::command::Action;
use crate::{
app::{cache::Cache, message::Message, state::State},
daemon::Daemon,
};
pub struct Sandbox<S: State> {
state: S,
}
impl<S: State + Send + 'static> Sandbox<S> {
pub fn new(state: S) -> Self {
return Self { state };
}
pub fn state(&self) -> &S {
&self.state
}
pub async fn update(
mut self,
daemon: Arc<dyn Daemon + Sync + Send>,
cache: &Cache,
message: Message,
) -> Self {
let cmd = self.state.update(daemon.clone(), cache, message);
for action in cmd.actions() {
if let Action::Future(f) = action {
let msg = f.await;
let _cmd = self.state.update(daemon.clone(), cache, msg);
}
}
self
}
pub async fn load(mut self, daemon: Arc<dyn Daemon + Sync + Send>, cache: &Cache) -> Self {
let cmd = self.state.load(daemon.clone());
for action in cmd.actions() {
if let Action::Future(f) = action {
let msg = f.await;
self = self.update(daemon.clone(), cache, msg).await;
}
}
self
}
}