use std::net::{SocketAddr, TcpListener, TcpStream};
use super::super::WebSocketListener;
use super::BoundWebSocket;
use crate::ServerError;
use crate::config::types::WebSocketConfig;
use crate::server::connection::ConnectionSupervisor;
type TestResult = Result<(), Box<dyn std::error::Error>>;
fn config(listen_address: SocketAddr) -> WebSocketConfig {
WebSocketConfig {
listen_address,
path: "/liminal".to_owned(),
allowed_origins: Vec::new(),
allowed_origin_ports: Vec::new(),
ping_interval_ms: None,
}
}
pub(in crate::server) fn upgrade_on_a_thread(
address: SocketAddr,
) -> Result<std::thread::JoinHandle<Result<u16, String>>, std::io::Error> {
let stream = TcpStream::connect(address)?;
Ok(std::thread::spawn(move || {
let (socket, response) =
tungstenite::client::client(format!("ws://{address}/liminal"), stream)
.map_err(|error| error.to_string())?;
drop(socket);
Ok(response.status().as_u16())
}))
}
#[test]
fn a_client_upgrading_before_accepting_is_upgraded_once_it_starts() -> TestResult {
let bound = BoundWebSocket::bind(&config("127.0.0.1:0".parse()?))?;
let client = upgrade_on_a_thread(bound.local_addr())?;
let supervisor = ConnectionSupervisor::new()?;
let listener = WebSocketListener::accept_on(bound, supervisor.clone())?;
let status = client
.join()
.map_err(|_| "the upgrading client panicked")??;
assert_eq!(status, 101, "the early client is upgraded");
listener.shutdown()?;
supervisor.shutdown();
Ok(())
}
#[test]
fn an_address_in_use_refuses_at_the_bind() -> TestResult {
let taken = TcpListener::bind("127.0.0.1:0")?;
let address = taken.local_addr()?;
let refused = BoundWebSocket::bind(&config(address));
assert!(
matches!(refused, Err(ServerError::ListenerBind { address: failed, .. }) if failed == address),
"{refused:?}"
);
Ok(())
}
#[test]
fn the_bound_address_resolves_an_ephemeral_port() -> TestResult {
let bound = BoundWebSocket::bind(&config("127.0.0.1:0".parse()?))?;
assert_ne!(bound.local_addr().port(), 0, "{bound:?}");
Ok(())
}