1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use futures::channel::oneshot;
use futures::FutureExt;
use serde::Deserialize;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use warp::Filter;
mod device;
mod error;
mod output;
mod snapshot;
pub use device::Device;
pub use error::Error;
pub use output::Output;
pub use snapshot::Metadata;
pub struct Disposable(Option<oneshot::Sender<mpsc::Sender<()>>>);
#[derive(Debug, Deserialize)]
pub enum Message {
Snapshot {
test_name: String,
snapshot_name: String,
},
OpenURL(String),
}
impl Drop for Disposable {
fn drop(&mut self) {
if let Some(sender) = self.0.take() {
let (tx, rx) = mpsc::channel();
let _ = sender.send(tx);
rx.recv().unwrap();
}
}
}
fn handler(device: Device) -> impl warp::Filter<Extract = impl warp::Reply> + Clone {
let output = Arc::new(Mutex::new(Output::new("target/polyhorn-snapshots")));
warp::path!("polyhorn" / "tests" / String)
.and(warp::post())
.and(warp::body::json())
.map(move |_id, message: Message| {
match message {
Message::OpenURL(url) => {
device.open_url(&url).unwrap();
}
Message::Snapshot {
test_name,
snapshot_name,
} => {
let screenshot = device.screenshot().unwrap();
output.lock().unwrap().store(
snapshot::Metadata {
test_name: Some(test_name),
snapshot_name: Some(snapshot_name),
..device.metadata()
},
screenshot,
);
}
}
"Ok"
})
}
pub fn serve(device: Device) -> (SocketAddr, Disposable) {
let (sender, receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let mut runtime = tokio::runtime::Runtime::new().unwrap();
runtime.block_on(async move {
let (drop_sender, drop_receiver) = oneshot::channel();
let server = warp::serve(handler(device));
let (addr, runloop) =
server.bind_ephemeral(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0));
sender.send((addr, Disposable(Some(drop_sender)))).unwrap();
let mut drop_receiver = drop_receiver.fuse();
let mut runloop = runloop.fuse();
futures::select! {
tx = drop_receiver => {
std::mem::drop(runloop);
tx.unwrap().send(()).unwrap();
},
_ = runloop => {}
};
});
});
receiver.recv().unwrap()
}