340 lines
10 KiB
Rust
340 lines
10 KiB
Rust
use std::time::Duration;
|
|
|
|
use rand::Rng;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
use tokio::net::{TcpListener, TcpStream};
|
|
use tokio::time;
|
|
|
|
use crate::test::LOCALHOST_IP;
|
|
|
|
pub struct DummyTCPServer(TcpListener);
|
|
|
|
impl DummyTCPServer {
|
|
pub async fn start(port: u16) -> Self {
|
|
let addr = format!("{}:{}", LOCALHOST_IP, port);
|
|
println!("[DUMMY TCP] Listen on {}", addr);
|
|
let listener = TcpListener::bind(addr)
|
|
.await
|
|
.expect("Failed to bind dummy TCP listener!");
|
|
Self(listener)
|
|
}
|
|
|
|
/// Receive chunk of data from following connection
|
|
pub async fn read_next_connection(&self) -> Vec<u8> {
|
|
let (mut conn, _addr) = self
|
|
.0
|
|
.accept()
|
|
.await
|
|
.expect("Could not open next connection!");
|
|
|
|
let mut buff = Vec::with_capacity(100);
|
|
conn.read_to_end(&mut buff).await.unwrap();
|
|
|
|
buff
|
|
}
|
|
|
|
/// Receive chunk of data from following connection
|
|
pub async fn read_then_write_next_connection(&self, to_send: &[u8]) -> Vec<u8> {
|
|
let (mut conn, _addr) = self
|
|
.0
|
|
.accept()
|
|
.await
|
|
.expect("Could not open next connection!");
|
|
|
|
let mut buff: [u8; 100] = [0; 100];
|
|
let size = conn.read(&mut buff).await.unwrap();
|
|
|
|
conn.write_all(to_send).await.unwrap();
|
|
|
|
buff[0..size].to_vec()
|
|
}
|
|
|
|
/// Receive chunk of data from following connection
|
|
pub async fn write_next_connection(&self, to_send: &[u8]) {
|
|
let (mut conn, _addr) = self
|
|
.0
|
|
.accept()
|
|
.await
|
|
.expect("Could not open next connection!");
|
|
|
|
conn.write_all(to_send).await.unwrap()
|
|
}
|
|
|
|
/// Perform complex exchange: receive numbers from client and respond with their square
|
|
pub async fn next_conn_square_operations(&self) {
|
|
let (mut conn, _addr) = self
|
|
.0
|
|
.accept()
|
|
.await
|
|
.expect("Could not open next connection!");
|
|
|
|
let mut buff: [u8; 100] = [0; 100];
|
|
loop {
|
|
let size = conn.read(&mut buff).await.unwrap();
|
|
if size == 0 {
|
|
break;
|
|
}
|
|
|
|
let content = String::from_utf8_lossy(&buff[0..size])
|
|
.to_string()
|
|
.parse::<i64>()
|
|
.unwrap();
|
|
|
|
conn.write_all((content * content).to_string().as_bytes())
|
|
.await
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
pub async fn loop_conn_square_operations(&self) {
|
|
loop {
|
|
self.next_conn_square_operations().await
|
|
}
|
|
}
|
|
|
|
/// Perform complex exchange: receive numbers from client and respond with their value + a given number
|
|
pub async fn next_conn_add_operations(&self, inc: i32) {
|
|
let (mut conn, _addr) = self
|
|
.0
|
|
.accept()
|
|
.await
|
|
.expect("Could not open next connection!");
|
|
|
|
let mut buff: [u8; 100] = [0; 100];
|
|
loop {
|
|
let size = conn.read(&mut buff).await.unwrap();
|
|
if size == 0 {
|
|
break;
|
|
}
|
|
|
|
let content = String::from_utf8_lossy(&buff[0..size])
|
|
.to_string()
|
|
.parse::<i64>()
|
|
.unwrap();
|
|
|
|
conn.write_all((content + inc as i64).to_string().as_bytes())
|
|
.await
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
pub async fn loop_next_conn_add_operations(&self, inc: i32) {
|
|
loop {
|
|
self.next_conn_add_operations(inc).await
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn dummy_tcp_client_read_conn(port: u16) -> Vec<u8> {
|
|
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
.await
|
|
.expect("Failed to connect to dummy TCP server!");
|
|
|
|
let mut buff: [u8; 100] = [0; 100];
|
|
let size = socket.read(&mut buff).await.unwrap();
|
|
|
|
buff[0..size].to_vec()
|
|
}
|
|
|
|
pub async fn dummy_tcp_client_write_then_read_conn(port: u16, data: &[u8]) -> Vec<u8> {
|
|
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
.await
|
|
.expect("Failed to connect to dummy TCP server!");
|
|
|
|
socket.write_all(data).await.unwrap();
|
|
|
|
let mut buff: [u8; 100] = [0; 100];
|
|
let size = socket.read(&mut buff).await.unwrap();
|
|
|
|
buff[0..size].to_vec()
|
|
}
|
|
|
|
pub async fn dummy_tcp_client_write_conn(port: u16, data: &[u8]) {
|
|
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
.await
|
|
.expect("Failed to connect to dummy TCP server!");
|
|
|
|
socket.write_all(data).await.unwrap()
|
|
}
|
|
|
|
pub async fn dummy_tcp_client_square_root_requests(port: u16, num_exchanges: usize) {
|
|
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
.await
|
|
.expect("Failed to connect to dummy TCP server!");
|
|
|
|
let mut rng = rand::thread_rng();
|
|
let mut buff: [u8; 100] = [0; 100];
|
|
|
|
for _ in 0..num_exchanges {
|
|
let num = rng.gen::<i32>() % 100;
|
|
socket.write_all(num.to_string().as_bytes()).await.unwrap();
|
|
|
|
let size = socket.read(&mut buff).await.unwrap();
|
|
|
|
if size == 0 {
|
|
panic!("Got empty response!");
|
|
}
|
|
|
|
let got = String::from_utf8_lossy(&buff[0..size])
|
|
.to_string()
|
|
.parse::<i64>()
|
|
.unwrap();
|
|
println!("{} * {} = {} (based on server response)", num, num, got);
|
|
assert_eq!((num * num) as i64, got);
|
|
}
|
|
}
|
|
|
|
pub async fn dummy_tcp_client_additions_requests(port: u16, inc: i32, num_exchanges: usize) {
|
|
let mut socket = TcpStream::connect(format!("127.0.0.1:{}", port))
|
|
.await
|
|
.expect("Failed to connect to dummy TCP server!");
|
|
|
|
let mut rng = rand::thread_rng();
|
|
let mut buff: [u8; 100] = [0; 100];
|
|
|
|
for _ in 0..num_exchanges {
|
|
let num = rng.gen::<i32>() % 100;
|
|
socket.write_all(num.to_string().as_bytes()).await.unwrap();
|
|
|
|
let size = socket.read(&mut buff).await.unwrap();
|
|
|
|
if size == 0 {
|
|
panic!("Got empty response!");
|
|
}
|
|
|
|
let got = String::from_utf8_lossy(&buff[0..size])
|
|
.to_string()
|
|
.parse::<i64>()
|
|
.unwrap();
|
|
println!("{} + {} = {} (based on server response)", num, inc, got);
|
|
assert_eq!((num + inc) as i64, got);
|
|
}
|
|
}
|
|
|
|
/// Check whether a given port is open or not
|
|
pub async fn is_port_open(port: u16) -> bool {
|
|
match TcpStream::connect(("127.0.0.1", port)).await {
|
|
Ok(_) => true,
|
|
Err(_) => false,
|
|
}
|
|
}
|
|
|
|
/// Wait for a port to become available
|
|
pub async fn wait_for_port(port: u16) {
|
|
for _ in 0..50 {
|
|
if is_port_open(port).await {
|
|
return;
|
|
}
|
|
time::sleep(Duration::from_millis(10)).await;
|
|
}
|
|
|
|
eprintln!("Port {} did not open in time!", port);
|
|
std::process::exit(2);
|
|
}
|
|
|
|
mod test {
|
|
use crate::test::dummy_tcp_sockets::{
|
|
dummy_tcp_client_additions_requests, dummy_tcp_client_read_conn,
|
|
dummy_tcp_client_square_root_requests, dummy_tcp_client_write_conn,
|
|
dummy_tcp_client_write_then_read_conn, DummyTCPServer,
|
|
};
|
|
use crate::test::{get_port_number, PortsAllocation};
|
|
|
|
fn port(index: u16) -> u16 {
|
|
get_port_number(PortsAllocation::DummyTCPServer, index)
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn socket_read_from_server() {
|
|
const DATA: &[u8] = "Hello world!!!".as_bytes();
|
|
|
|
let listener = DummyTCPServer::start(port(0)).await;
|
|
let handle = tokio::spawn(async move {
|
|
listener.write_next_connection(DATA).await;
|
|
});
|
|
let data = dummy_tcp_client_read_conn(port(0)).await;
|
|
assert_eq!(data, DATA);
|
|
|
|
handle.await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn socket_write_to_server() {
|
|
const DATA: &[u8] = "Hello world 2".as_bytes();
|
|
|
|
let listener = DummyTCPServer::start(port(1)).await;
|
|
tokio::spawn(async move {
|
|
dummy_tcp_client_write_conn(port(1), DATA).await;
|
|
});
|
|
let data = listener.read_next_connection().await;
|
|
assert_eq!(data, DATA);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn socket_read_and_write_to_server() {
|
|
const DATA_1: &[u8] = "Hello world 3a".as_bytes();
|
|
const DATA_2: &[u8] = "Hello world 3b".as_bytes();
|
|
|
|
let listener = DummyTCPServer::start(port(2)).await;
|
|
let handle = tokio::spawn(async move {
|
|
println!("client handle");
|
|
let data = dummy_tcp_client_write_then_read_conn(port(2), DATA_1).await;
|
|
assert_eq!(data, DATA_2);
|
|
});
|
|
let h2 = tokio::spawn(async move {
|
|
println!("server handle");
|
|
let data = listener.read_then_write_next_connection(DATA_2).await;
|
|
assert_eq!(data, DATA_1);
|
|
});
|
|
|
|
handle.await.unwrap();
|
|
h2.await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn socket_dummy_root_calculator() {
|
|
let listener = DummyTCPServer::start(port(3)).await;
|
|
let handle = tokio::spawn(async move {
|
|
listener.next_conn_square_operations().await;
|
|
});
|
|
let data = dummy_tcp_client_write_then_read_conn(port(3), "5".as_bytes()).await;
|
|
assert_eq!(data, "25".as_bytes());
|
|
|
|
handle.await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn socket_dummy_root_calculator_multiple() {
|
|
let listener = DummyTCPServer::start(port(4)).await;
|
|
let handle = tokio::spawn(async move {
|
|
listener.next_conn_square_operations().await;
|
|
});
|
|
dummy_tcp_client_square_root_requests(port(4), 10).await;
|
|
|
|
handle.await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn socket_dummy_addition_calculator() {
|
|
let listener = DummyTCPServer::start(port(5)).await;
|
|
let handle = tokio::spawn(async move {
|
|
listener.next_conn_add_operations(4).await;
|
|
});
|
|
let data = dummy_tcp_client_write_then_read_conn(port(5), "5".as_bytes()).await;
|
|
assert_eq!(data, "9".as_bytes());
|
|
|
|
handle.await.unwrap();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn socket_dummy_addition_calculator_multiple() {
|
|
let listener = DummyTCPServer::start(port(6)).await;
|
|
let handle = tokio::spawn(async move {
|
|
listener.next_conn_add_operations(7).await;
|
|
});
|
|
dummy_tcp_client_additions_requests(port(6), 7, 10).await;
|
|
|
|
handle.await.unwrap();
|
|
}
|
|
}
|