#![cfg(unix)]
use nwep::{Address, Client, Compression, Identity, Method, Server, Status};
use std::os::fd::RawFd;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
fn now_ms() -> i64 {
Instant::now().elapsed().as_millis() as i64
}
fn spawn_server() -> (
nwep::NodeId,
[u8; 32],
u16,
Arc<AtomicBool>,
std::thread::JoinHandle<()>,
) {
let id = Identity::generate().unwrap();
let node = *id.node_id();
let pubkey = *id.public_key();
let (tx, rx) = mpsc::channel();
let stop = Arc::new(AtomicBool::new(false));
let stop_t = stop.clone();
let handle = std::thread::spawn(move || {
let server = Server::builder()
.identity(id)
.bind(Address::loopback(0))
.on_request(|req, res| match req.path() {
Some("/hi") => res.ok(b"hi-body"),
_ => res.not_found(),
})
.build()
.unwrap();
tx.send(server.local_port()).unwrap();
while !stop_t.load(Ordering::Relaxed) {
server.tick(now_ms()).unwrap();
std::thread::sleep(Duration::from_millis(1));
}
});
let port = rx.recv_timeout(Duration::from_secs(3)).unwrap();
(node, pubkey, port, stop, handle)
}
#[test]
fn introspection_on_a_live_connection() {
let (node, server_pubkey, port, stop, server_thread) = spawn_server();
let client = Client::builder()
.identity(Identity::generate().unwrap())
.connect(&node, &Address::loopback(port))
.unwrap();
assert!(client.is_alive());
assert_ne!(client.compression(), Compression::Unknown);
assert_eq!(client.peer_pubkey().unwrap(), server_pubkey);
let resp = client.send(Method::Read, "/hi", &[]).unwrap();
assert_eq!(resp.body(), b"hi-body");
resp.verify(&client.peer_pubkey().unwrap(), "/hi", 0)
.unwrap();
let m = client.metrics();
assert!(m.alive);
assert_eq!(m.requests_inflight, 0);
drop(client);
stop.store(true, Ordering::Relaxed);
server_thread.join().unwrap();
}
fn poll_readable(fd: RawFd, timeout_ms: u32) {
let mut pfd = libc::pollfd {
fd,
events: libc::POLLIN,
revents: 0,
};
unsafe {
libc::poll(&mut pfd, 1, timeout_ms as libc::c_int);
}
}
#[test]
fn a_hand_driven_client_loop_completes_a_request() {
let (node, _pubkey, port, stop, server_thread) = spawn_server();
let client = Client::builder()
.identity(Identity::generate().unwrap())
.connect(&node, &Address::loopback(port))
.unwrap();
for _ in 0..10 {
client.tick(now_ms()).unwrap();
let to = client.next_timeout(now_ms()).unwrap_or(20).min(20);
poll_readable(client.fd(), to);
if !client.is_alive() {
break;
}
}
assert!(
client.is_alive(),
"the connection survived the manual ticks"
);
assert!(client.fd() >= 0);
let resp = client.send(Method::Read, "/hi", &[]).unwrap();
assert_eq!(resp.status(), Some(Status::Ok));
assert_eq!(resp.body(), b"hi-body");
drop(client);
stop.store(true, Ordering::Relaxed);
server_thread.join().unwrap();
}