tests: Add experimental socket_mock tool

This is used to help to create/test socket.json files against real Flash Player to verify behavior.
This commit is contained in:
sleepycatcoding 2023-07-21 18:10:27 +03:00 committed by Nathan Adams
parent a7c6a8bb77
commit 88626b7212
4 changed files with 155 additions and 0 deletions

10
Cargo.lock generated
View File

@ -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"

View File

@ -25,6 +25,7 @@ members = [
"tests",
"tests/input-format",
"tests/socket-mock",
]
default-members = ["desktop"]
resolver = "2"

View File

@ -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"

View File

@ -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<u8>,
},
/// Send data to client.
Send {
payload: Vec<u8>,
},
/// Expect client to disconnect.
WaitForDisconnect,
/// Disconnect the client.
Disconnect,
}
impl SocketEvent {
pub fn from_file<P>(path: P) -> Result<Vec<Self>, io::Error>
where
P: AsRef<Path>,
{
let file = File::open(path)?;
Ok(from_reader(file)?)
}
}
static POLICY: &'static [u8] = &*b"<?xml version=\"1.0\"?>
<!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">
<cross-domain-policy>
<allow-access-from domain=\"*\" to-ports=\"*\"/>
</cross-domain-policy>\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::<Vec<_>>();
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;
}
}
}
}