diff --git a/Cargo.lock b/Cargo.lock index 544ad06e9..260978db2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4047,6 +4047,16 @@ dependencies = [ "walkdir", ] +[[package]] +name = "ruffle_socket_mock" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + [[package]] name = "ruffle_video" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 5fa831910..b4d9955fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ members = [ "tests", "tests/input-format", + "tests/socket-mock", ] default-members = ["desktop"] resolver = "2" diff --git a/tests/socket-mock/Cargo.toml b/tests/socket-mock/Cargo.toml new file mode 100644 index 000000000..5aeba17bf --- /dev/null +++ b/tests/socket-mock/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ruffle_socket_mock" +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true + +[dependencies] +tracing = { workspace = true} +tracing-subscriber = { workspace = true } +serde = { version = "1.0.152", features = ["derive"] } +serde_json = "1.0.91" \ No newline at end of file diff --git a/tests/socket-mock/src/main.rs b/tests/socket-mock/src/main.rs new file mode 100644 index 000000000..3dca3ca64 --- /dev/null +++ b/tests/socket-mock/src/main.rs @@ -0,0 +1,130 @@ +use std::{net::TcpListener, io::{self, Read, Write}, path::Path, fs::File}; +use serde::{Serialize, Deserialize}; +use serde_json::from_reader; +use tracing_subscriber::filter::{EnvFilter, LevelFilter}; + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "type")] +pub enum SocketEvent { + /// Wait for input data that matches this. + Receive { + expected: Vec, + }, + /// Send data to client. + Send { + payload: Vec, + }, + /// Expect client to disconnect. + WaitForDisconnect, + /// Disconnect the client. + Disconnect, +} + +impl SocketEvent { + pub fn from_file

(path: P) -> Result, io::Error> + where + P: AsRef, + { + let file = File::open(path)?; + + Ok(from_reader(file)?) + } +} + +static POLICY: &'static [u8] = &*b" + + + +\0"; + + +fn main() { + let subscriber = tracing_subscriber::fmt::Subscriber::builder() + .with_env_filter(EnvFilter::builder().with_default_directive(LevelFilter::INFO.into()).from_env_lossy()) + .finish(); + // Ignore error if it's already been set + let _ = tracing::subscriber::set_global_default(subscriber); + + let events = SocketEvent::from_file("socket.json").unwrap(); + let event_count = events.len(); + + let listener = TcpListener::bind("0.0.0.0:8001").unwrap(); + tracing::info!("Listening on {}", listener.local_addr().unwrap()); + let (mut stream, addr) = listener.accept().unwrap(); + tracing::info!("Incoming connection from {}", addr); + + // Handle socket policy stuff. (Required as Flash Player wont want to connect otherwise.) + let mut buffer = [0; 4096]; + let _ = stream.read(&mut buffer); + stream.write_all(POLICY).unwrap(); + tracing::info!("Policy sent successfully!"); + + // Now we listen again as flash reopens socket connection. + let (mut stream, addr) = listener.accept().unwrap(); + tracing::info!("Incoming connection from {}", addr); + + for (index, event) in events.into_iter().enumerate() { + tracing::info!("Running step {}/{}", index + 1, event_count); + + match event { + SocketEvent::Receive { expected } => { + let mut output = vec![]; + + loop { + let mut buffer = [0; 4096]; + + match stream.read(&mut buffer) { + Err(_) | Ok(0) => { + tracing::error!("Expected data, but socket was closed."); + return; + } + Ok(read) => { + if read == 4096 { + output.extend(buffer); + } else { + let data = buffer.into_iter().take(read).collect::>(); + output.extend(data); + break; + } + } + } + } + + if output != expected { + tracing::error!("Received data did not match expected data\nExpected: {:?}\nActual: {:?}", expected, output); + } + }, + SocketEvent::Send { mut payload } => { + while !payload.is_empty() { + match stream.write(&payload) { + Err(_) | Ok(0) => { + tracing::error!("Socket was closed in middle of writing."); + return; + } + Ok(written) => { + let _ = payload.drain(..written); + } + } + } + }, + SocketEvent::WaitForDisconnect => { + let mut buffer = [0; 4096]; + + match stream.read(&mut buffer) { + Err(_) | Ok(0) => { + tracing::info!("Client has closed the connection!"); + return; + } + Ok(_) => { + tracing::error!("Expected client to close connection, but data was sent instead."); + } + } + }, + SocketEvent::Disconnect => { + tracing::info!("Disconnecting client."); + drop(stream); + break; + } + } + } +}