add regression test and play vs production
This commit is contained in:
parent
c13f2d553b
commit
27d60845b5
48
Cargo.lock
generated
48
Cargo.lock
generated
@ -219,6 +219,31 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
@ -911,6 +936,26 @@ dependencies = [
|
|||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -1693,6 +1738,9 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "xtask"
|
name = "xtask"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rayon",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yansi"
|
name = "yansi"
|
||||||
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
rayon = "1.10"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
|
io::{stderr, Write},
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
process::{Child, Command},
|
process::{Child, Command},
|
||||||
@ -7,6 +8,8 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
type DynError = Box<dyn std::error::Error>;
|
type DynError = Box<dyn std::error::Error>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -21,6 +24,8 @@ fn try_main() -> Result<(), DynError> {
|
|||||||
match task.as_deref() {
|
match task.as_deref() {
|
||||||
Some("local") => local()?,
|
Some("local") => local()?,
|
||||||
Some("local2") => local2()?,
|
Some("local2") => local2()?,
|
||||||
|
Some("vs_production" | "vs_prod") => vs_production()?,
|
||||||
|
Some("regression") => regression()?,
|
||||||
Some("docker") => docker()?,
|
Some("docker") => docker()?,
|
||||||
_ => print_help(),
|
_ => print_help(),
|
||||||
}
|
}
|
||||||
@ -31,8 +36,10 @@ fn print_help() {
|
|||||||
eprintln!(
|
eprintln!(
|
||||||
"Tasks:
|
"Tasks:
|
||||||
|
|
||||||
local runs the snake on a local game
|
local runs the snake on a local game
|
||||||
local2 runs the snake twice on a local game
|
local2 runs the snake twice on a local game
|
||||||
|
vs_production | vs_prod runs the snake against the active server
|
||||||
|
regression runs the snake against the active server multiple times
|
||||||
|
|
||||||
docker package docker image and upload to docker.mkaenner.de/snake
|
docker package docker image and upload to docker.mkaenner.de/snake
|
||||||
"
|
"
|
||||||
@ -40,7 +47,7 @@ docker package docker image and upload to docker.mkaenner.de/snake
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn local() -> Result<(), DynError> {
|
fn local() -> Result<(), DynError> {
|
||||||
let mut snake = run_snake(8000)?;
|
let mut snake = run_snake(8000, None)?;
|
||||||
|
|
||||||
let game = Command::new("./battlesnake-cli")
|
let game = Command::new("./battlesnake-cli")
|
||||||
.current_dir(project_root())
|
.current_dir(project_root())
|
||||||
@ -65,14 +72,7 @@ fn local() -> Result<(), DynError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn local2() -> Result<(), DynError> {
|
fn local2() -> Result<(), DynError> {
|
||||||
let mut snake1 = run_snake(8000)?;
|
let mut snake = run_snake(8000, None)?;
|
||||||
let mut snake2 = match run_snake(8001) {
|
|
||||||
Ok(snake) => snake,
|
|
||||||
Err(e) => {
|
|
||||||
let _ = snake1.kill();
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let game = Command::new("./battlesnake-cli")
|
let game = Command::new("./battlesnake-cli")
|
||||||
.current_dir(project_root())
|
.current_dir(project_root())
|
||||||
@ -89,22 +89,134 @@ fn local2() -> Result<(), DynError> {
|
|||||||
"--name",
|
"--name",
|
||||||
"local test2",
|
"local test2",
|
||||||
"--url",
|
"--url",
|
||||||
"http://localhost:8001",
|
"http://localhost:8000",
|
||||||
"-g",
|
"-g",
|
||||||
"duel",
|
"duel",
|
||||||
"--browser",
|
"--browser",
|
||||||
])
|
])
|
||||||
.status();
|
.status();
|
||||||
|
|
||||||
game.and(snake1.kill()).and(snake2.kill())?;
|
game.and(snake.kill())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_snake(port: u16) -> Result<Child, DynError> {
|
fn vs_production() -> Result<(), DynError> {
|
||||||
let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
|
let mut snake = run_snake(8000, None)?;
|
||||||
let mut snake = Command::new(cargo)
|
|
||||||
|
let game = Command::new("./battlesnake-cli")
|
||||||
.current_dir(project_root())
|
.current_dir(project_root())
|
||||||
.env("PORT", port.to_string())
|
.args([
|
||||||
|
"play",
|
||||||
|
"-W",
|
||||||
|
"11",
|
||||||
|
"-H",
|
||||||
|
"11",
|
||||||
|
"--name",
|
||||||
|
"local",
|
||||||
|
"--url",
|
||||||
|
"http://localhost:8000",
|
||||||
|
"--name",
|
||||||
|
"production",
|
||||||
|
"--url",
|
||||||
|
"https://snake.mkaenner.de",
|
||||||
|
"-g",
|
||||||
|
"duel",
|
||||||
|
])
|
||||||
|
.output();
|
||||||
|
|
||||||
|
let game = snake.kill().and(game)?;
|
||||||
|
if !game.status.success() {
|
||||||
|
eprintln!("game output: {}", String::from_utf8(game.stderr)?);
|
||||||
|
eprintln!("game status: {}", game.status);
|
||||||
|
Err("failed to play the game".into())
|
||||||
|
} else {
|
||||||
|
const WIN_PHRASE: &[u8] = b"local was the winner.\n";
|
||||||
|
let won =
|
||||||
|
&game.stderr[(game.stderr.len() - WIN_PHRASE.len())..game.stderr.len()] == WIN_PHRASE;
|
||||||
|
if won {
|
||||||
|
println!("The local snake has won");
|
||||||
|
} else {
|
||||||
|
println!("The production snake has won");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn regression() -> Result<(), DynError> {
|
||||||
|
let mut snake = run_snake(8000, Some("error"))?;
|
||||||
|
|
||||||
|
let res = try_regression();
|
||||||
|
|
||||||
|
snake.kill()?;
|
||||||
|
let (won, games) = res?;
|
||||||
|
println!(
|
||||||
|
"\nThe local snake has won {won}/{games} games ({}%)",
|
||||||
|
won * 100 / games
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_regression() -> Result<(usize, usize), DynError> {
|
||||||
|
const GAMES: usize = 1000;
|
||||||
|
// use only 4 threads so we don't ddos the server
|
||||||
|
rayon::ThreadPoolBuilder::new()
|
||||||
|
.num_threads(4)
|
||||||
|
.build_global()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let won_count = (0..GAMES)
|
||||||
|
.into_par_iter()
|
||||||
|
.map(|_| -> Option<usize> {
|
||||||
|
eprint!(".");
|
||||||
|
// let _ = stderr().flush();
|
||||||
|
let game = Command::new("./battlesnake-cli")
|
||||||
|
.current_dir(project_root())
|
||||||
|
.args([
|
||||||
|
"play",
|
||||||
|
"-W",
|
||||||
|
"11",
|
||||||
|
"-H",
|
||||||
|
"11",
|
||||||
|
"--name",
|
||||||
|
"local",
|
||||||
|
"--url",
|
||||||
|
"http://localhost:8000",
|
||||||
|
"--name",
|
||||||
|
"production",
|
||||||
|
"--url",
|
||||||
|
"https://snake.mkaenner.de",
|
||||||
|
"-g",
|
||||||
|
"duel",
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.ok()?;
|
||||||
|
if !game.status.success() {
|
||||||
|
eprintln!("game output: {}", String::from_utf8(game.stderr).ok()?);
|
||||||
|
eprintln!("game status: {}", game.status);
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
const WIN_PHRASE: &[u8] = b"local was the winner.\n";
|
||||||
|
let won = &game.stderr[(game.stderr.len() - WIN_PHRASE.len())..game.stderr.len()]
|
||||||
|
== WIN_PHRASE;
|
||||||
|
Some(usize::from(won))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
Ok((won_count, GAMES))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_snake(port: u16, log: Option<&str>) -> Result<Child, DynError> {
|
||||||
|
let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
|
||||||
|
let mut snake = Command::new(cargo);
|
||||||
|
snake
|
||||||
|
.current_dir(project_root())
|
||||||
|
.env("PORT", port.to_string());
|
||||||
|
if let Some(log) = log {
|
||||||
|
snake.env("RUST_LOG", log);
|
||||||
|
}
|
||||||
|
let mut snake = snake
|
||||||
.args(
|
.args(
|
||||||
["run", "--bin", "battlesnake"]
|
["run", "--bin", "battlesnake"]
|
||||||
.map(str::to_string)
|
.map(str::to_string)
|
||||||
|
Loading…
Reference in New Issue
Block a user