facett-simview/tests/devserver.rs
//! The dev server over a real socket: the static mount, the job verbs and the Arrow data.
use std::io::{Read as _, Write as _};
use std::net::{TcpListener, TcpStream};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use facett_simview::contract;
use facett_simview::devserver::{DevServer, Mount};
use facett_simview::mock::MockServer;
fn http(port: u16, method: &str, target: &str) -> (u16, String, Vec<u8>) {
let mut s = TcpStream::connect(("127.0.0.1", port)).unwrap();
write!(s, "{method} {target} HTTP/1.1\r\nHost: x\r\nContent-Length: 0\r\n\r\n").unwrap();
let mut buf = Vec::new();
s.read_to_end(&mut buf).unwrap();
let split = buf.windows(4).position(|w| w == b"\r\n\r\n").unwrap();
let head = String::from_utf8_lossy(&buf[..split]).to_string();
let status = head.split_whitespace().nth(1).unwrap().parse().unwrap();
(status, head, buf[split + 4..].to_vec())
}
#[test]
fn the_dev_server_serves_the_page_and_the_contract() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let port = listener.local_addr().unwrap().port();
let here = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let server = DevServer {
mounts: vec![Mount { prefix: String::new(), dir: here.join("tests") }],
mock: Arc::new(Mutex::new(MockServer::new(300))),
};
std::thread::spawn(move || server.serve(listener));
let (s, head, _) = http(port, "GET", "/sim/");
assert_eq!(s, 302);
assert!(head.contains("Location: /sim/?component=simview"), "{head}");
let (s, head, body) = http(port, "GET", "/sim/devserver.rs");
assert_eq!(s, 200);
assert!(String::from_utf8_lossy(&body).contains("the_dev_server_serves_the_page"), "{head}");
assert_eq!(http(port, "GET", "/sim/../Cargo.toml").0, 400, "nothing climbs out of a mount");
let (s, _, body) = http(port, "GET", "/sim/api/nodes.arrow?labels=Person&limit=200000");
assert_eq!(s, 200);
let persons = contract::decode_nodes(&body).unwrap();
assert_eq!(persons.len(), 300);
assert!(persons.iter().all(|p| p.label == "Person" && p.kommun.is_some()));
let (_, _, body) = http(port, "GET", "/sim/api/edges.arrow?types=BOR_PA&limit=50");
let edges = contract::decode_edges(&body).unwrap();
assert_eq!(edges.len(), 50);
assert!(edges.iter().all(|e| e.etype == "BOR_PA"));
let (_, _, body) = http(port, "GET", "/sim/api/ego.arrow?id=3");
assert_eq!(contract::decode_edges(&body).unwrap().len(), 4);
let (_, _, body) = http(port, "GET", "/sim/api/nodes.arrow?ids=3,301");
assert_eq!(contract::decode_nodes(&body).unwrap().len(), 2);
let (_, _, body) = http(port, "GET", "/sim/api/meta.json");
assert_eq!(contract::Meta::parse(&body).unwrap().persons, 300);
assert_eq!(http(port, "POST", "/power/falkordb/permutate").0, 202);
assert_eq!(http(port, "POST", "/power/falkordb/simulate").0, 409, "one job at a time");
let (s, _, body) = http(port, "GET", "/power");
assert_eq!(s, 200);
assert!(contract::Job::parse(&body).unwrap().busy);
assert_eq!(http(port, "POST", "/power/falkordb/explode").0, 404);
}