laravel-webrtc/rust/tests/control.rs

97 lines
3.3 KiB
Rust
Raw Normal View History

//! 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");
}