Start to write tests

This commit is contained in:
Pierre HUBERT 2022-09-14 17:36:16 +02:00
parent b6be982295
commit 70cb99a0a0
9 changed files with 223 additions and 5 deletions

92
Cargo.lock generated
View File

@ -349,6 +349,12 @@ dependencies = [
"alloc-stdlib", "alloc-stdlib",
] ]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.2.1" version = "1.2.1"
@ -585,9 +591,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577" checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab",
] ]
[[package]] [[package]]
@ -1022,6 +1030,9 @@ dependencies = [
"rand", "rand",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded",
"tokio",
"tokio-tungstenite",
"uuid", "uuid",
] ]
@ -1074,6 +1085,17 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "sha-1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]] [[package]]
name = "sha1" name = "sha1"
version = "0.10.1" version = "0.10.1"
@ -1151,6 +1173,26 @@ version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thiserror"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.13" version = "0.3.13"
@ -1195,14 +1237,39 @@ dependencies = [
"libc", "libc",
"memchr", "memchr",
"mio", "mio",
"num_cpus",
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",
"tokio-macros",
"winapi", "winapi",
] ]
[[package]]
name = "tokio-macros"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-tungstenite"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite",
]
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.3" version = "0.7.3"
@ -1238,6 +1305,25 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "tungstenite"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0"
dependencies = [
"base64",
"byteorder",
"bytes",
"http",
"httparse",
"log",
"rand",
"sha-1",
"thiserror",
"url",
"utf-8",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.15.0" version = "1.15.0"
@ -1277,6 +1363,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.1.2" version = "1.1.2"

View File

@ -18,3 +18,9 @@ actix-web-actors = "4.1.0"
actix-rt = "2.7.0" actix-rt = "2.7.0"
uuid = { version = "1.1.2", features = ["v4"] } uuid = { version = "1.1.2", features = ["v4"] }
rand = "0.8.5" rand = "0.8.5"
[dev-dependencies]
tokio = { version = "1", features = ["full"] }
#reqwest = { version = "0.11.11", default-features = false, features = ["json", "rustls-tls"] }
tokio-tungstenite = "0.17.2"
serde_urlencoded = "0.7.1"

25
src/bot_client.rs Normal file
View File

@ -0,0 +1,25 @@
use std::error::Error;
use tokio::net::TcpStream;
use tokio_tungstenite::tungstenite::handshake::client::Response;
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
use crate::data::GameRules;
pub async fn run_client(server: &str, rules: &GameRules) -> Result<(), Box<dyn Error>> {
let url = format!(
"{}/play/bot?{}",
server.replace("http", "ws"),
serde_urlencoded::to_string(rules).unwrap()
);
log::debug!("Connecting to {}...", url);
let (socket, _) = match tokio_tungstenite::connect_async(url).await {
Ok(s) => s,
Err(e) => {
log::error!("Failed to establish WebSocket connection! {:?}", e);
return Err(Box::new(e));
}
};
Ok(())
}

View File

@ -1,4 +1,6 @@
pub mod args; pub mod args;
#[cfg(test)]
pub mod bot_client;
pub mod consts; pub mod consts;
pub mod data; pub mod data;
pub mod game; pub mod game;
@ -6,3 +8,5 @@ pub mod human_player;
pub mod human_player_ws; pub mod human_player_ws;
pub mod random_bot; pub mod random_bot;
pub mod server; pub mod server;
#[cfg(test)]
mod test;

View File

@ -8,7 +8,5 @@ use sea_battle_backend::server::start_server;
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let args: Args = Args::parse(); start_server(Args::parse()).await
start_server(&args).await
} }

View File

@ -39,7 +39,7 @@ async fn start_bot_play(
resp resp
} }
pub async fn start_server(args: &Args) -> std::io::Result<()> { pub async fn start_server(args: Args) -> std::io::Result<()> {
let args_clone = args.clone(); let args_clone = args.clone();
HttpServer::new(move || { HttpServer::new(move || {

39
src/test/client.rs Normal file
View File

@ -0,0 +1,39 @@
use crate::args::Args;
use crate::bot_client;
use crate::data::GameRules;
use crate::server::start_server;
use crate::test::network_utils::wait_for_port;
use crate::test::TestPort;
use tokio::task;
#[tokio::test]
async fn invalid_port() {
let _ = env_logger::builder().is_test(true).try_init();
bot_client::run_client(
&TestPort::ClientInvalidPort.as_url(),
&GameRules::random_players_rules(),
)
.await
.unwrap_err();
}
#[tokio::test]
async fn invalid_rules() {
let _ = env_logger::builder().is_test(true).try_init();
let local_set = task::LocalSet::new();
local_set
.run_until(async move {
let mut rules = GameRules::random_players_rules();
rules.map_width = 0;
task::spawn_local(start_server(Args::for_test(TestPort::ClientInvalidRules)));
wait_for_port(TestPort::ClientInvalidRules.port()).await;
bot_client::run_client(&TestPort::ClientInvalidRules.as_url(), &rules)
.await
.unwrap_err();
})
.await;
}

29
src/test/mod.rs Normal file
View File

@ -0,0 +1,29 @@
use crate::args::Args;
#[derive(Copy, Clone)]
enum TestPort {
ClientInvalidPort = 20000,
ClientInvalidRules,
}
impl TestPort {
pub fn port(&self) -> u16 {
(*self as u32) as u16
}
pub fn as_url(&self) -> String {
format!("http://127.0.0.1:{}", self.port())
}
}
impl Args {
fn for_test(port: TestPort) -> Self {
Self {
listen_address: format!("127.0.0.1:{}", port.port()),
cors: None,
}
}
}
mod client;
mod network_utils;

25
src/test/network_utils.rs Normal file
View File

@ -0,0 +1,25 @@
use std::time::Duration;
use tokio::net::TcpStream;
use tokio::time;
/// 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);
}