97 lines
3.3 KiB
Rust
97 lines
3.3 KiB
Rust
//! End-to-end control-plane test: boots the full sidecar (UDP + control socket
|
|
//! + SFU loop) in-process and speaks the JSON-lines protocol like PHP does.
|
|
|
|
use std::io::{BufRead, BufReader, Write};
|
|
use std::net::IpAddr;
|
|
use std::os::unix::net::UnixStream;
|
|
use std::path::PathBuf;
|
|
use std::thread;
|
|
use std::time::{Duration, Instant};
|
|
|
|
use blax_webrtc_sfu::server::{self, Config};
|
|
|
|
fn start_sidecar(socket: PathBuf) -> thread::JoinHandle<()> {
|
|
let config = Config {
|
|
socket,
|
|
udp_ip: IpAddr::from([127, 0, 0, 1]),
|
|
udp_port: 0,
|
|
public_ip: None,
|
|
};
|
|
thread::spawn(move || server::run(config).expect("sidecar to run"))
|
|
}
|
|
|
|
fn connect(socket: &PathBuf) -> UnixStream {
|
|
let deadline = Instant::now() + Duration::from_secs(5);
|
|
loop {
|
|
if let Ok(stream) = UnixStream::connect(socket) {
|
|
return stream;
|
|
}
|
|
assert!(Instant::now() < deadline, "control socket never came up");
|
|
thread::sleep(Duration::from_millis(20));
|
|
}
|
|
}
|
|
|
|
fn roundtrip(reader: &mut impl BufRead, writer: &mut impl Write, req: &str) -> serde_json::Value {
|
|
writeln!(writer, "{req}").unwrap();
|
|
writer.flush().unwrap();
|
|
let mut line = String::new();
|
|
reader.read_line(&mut line).unwrap();
|
|
serde_json::from_str(&line).unwrap_or_else(|e| panic!("bad reply {line:?}: {e}"))
|
|
}
|
|
|
|
#[test]
|
|
fn control_protocol_end_to_end() {
|
|
let socket = std::env::temp_dir().join(format!("blax-sfu-test-{}.sock", std::process::id()));
|
|
let _ = std::fs::remove_file(&socket);
|
|
let sidecar = start_sidecar(socket.clone());
|
|
|
|
let stream = connect(&socket);
|
|
let mut reader = BufReader::new(stream.try_clone().unwrap());
|
|
let mut writer = stream;
|
|
|
|
// ping
|
|
let reply = roundtrip(&mut reader, &mut writer, r#"{"id":1,"cmd":"ping"}"#);
|
|
assert_eq!(reply["id"], 1);
|
|
assert_eq!(reply["ok"], true);
|
|
|
|
// empty stats
|
|
let reply = roundtrip(&mut reader, &mut writer, r#"{"id":2,"cmd":"stats"}"#);
|
|
assert_eq!(reply["ok"], true);
|
|
assert_eq!(reply["rooms"], serde_json::json!([]));
|
|
|
|
// add_peer with a garbage offer errors cleanly
|
|
let reply = roundtrip(
|
|
&mut reader,
|
|
&mut writer,
|
|
r#"{"id":3,"cmd":"add_peer","room":"r1","peer":"p1","offer":"not sdp"}"#,
|
|
);
|
|
assert_eq!(reply["ok"], false);
|
|
assert!(
|
|
reply["error"].as_str().unwrap().contains("offer"),
|
|
"unexpected error: {reply}"
|
|
);
|
|
|
|
// unknown peer errors cleanly
|
|
let reply = roundtrip(
|
|
&mut reader,
|
|
&mut writer,
|
|
r#"{"id":4,"cmd":"mute_peer","room":"r1","peer":"ghost","muted":true}"#,
|
|
);
|
|
assert_eq!(reply["ok"], false);
|
|
assert!(reply["error"].as_str().unwrap().contains("no such peer"));
|
|
|
|
// malformed json → error with id 0, connection stays usable
|
|
let reply = roundtrip(&mut reader, &mut writer, r#"{"id":5,"cmd":"nope"}"#);
|
|
assert_eq!(reply["ok"], false);
|
|
|
|
let reply = roundtrip(&mut reader, &mut writer, r#"{"id":6,"cmd":"ping"}"#);
|
|
assert_eq!(reply["ok"], true);
|
|
|
|
// shutdown stops the loop and removes the socket file
|
|
let reply = roundtrip(&mut reader, &mut writer, r#"{"id":7,"cmd":"shutdown"}"#);
|
|
assert_eq!(reply["ok"], true);
|
|
|
|
sidecar.join().expect("sidecar thread to finish");
|
|
assert!(!socket.exists(), "socket file cleaned up on shutdown");
|
|
}
|