use std::{fmt::Display, time::Duration};
use rtest::{Context, TestError};
use rtest_derive::{rtest, run, Resource};
use shop::{ItemId, UserId};
use thiserror::Error;
mod carts;
mod items;
mod multiple;
mod shop;
mod users;
#[derive(Debug, Error)]
pub enum WebserverSetupError {
#[error("cant start webserver: {0}")]
Start(std::io::Error),
}
impl TestError for WebserverSetupError {}
#[derive(Debug, Error)]
pub enum WebserverTestError {
#[error("reqwest sending error: {0}")]
Reqwest(reqwest::Error),
#[error("response parsing error: {0}")]
Response(reqwest::Error),
}
impl TestError for WebserverTestError {}
#[derive(Resource)]
struct Webserver {
child: std::process::Child,
port: u16,
}
impl Webserver {
fn req<T: Display>(&self, method: reqwest::Method, end_url: T) -> reqwest::RequestBuilder {
let client = reqwest::Client::new();
client.request(method, format!("http://localhost:{}/{}", self.port, end_url))
}
}
impl Drop for Webserver {
fn drop(&mut self) {
std::thread::sleep(Duration::from_millis(200));
self.child.kill().unwrap();
}
}
#[rtest]
fn start_server() -> Result<Webserver, WebserverSetupError> {
use rand::Rng;
let mut rng = rand::thread_rng();
let args: Vec<String> = std::env::args().collect();
let port = 3000 + rng.gen::<u8>() as u16;
let child = std::process::Command::new(&args[0])
.arg("webserver")
.arg(port.to_string())
.spawn()
.map_err(WebserverSetupError::Start)?;
std::thread::sleep(Duration::from_millis(500));
Ok(Webserver { child, port })
}
#[derive(Resource)]
struct WebserverWithItems {
webserver: Webserver,
book_id: ItemId,
cookie_id: ItemId,
}
#[derive(Resource)]
struct WebserverWithUsers {
webserver: Webserver,
book_id: ItemId,
cookie_id: ItemId,
ava_id: UserId,
john_id: UserId,
}
pub fn main() -> std::process::ExitCode {
let args: Vec<String> = std::env::args().collect();
if args.len() == 3 && args[1] == "webserver" {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let port = args[2].parse::<u16>().expect("Invalid Port provided as 2nd argument");
runtime.block_on(shop::run(port));
0.into()
} else {
let runconfig = rtest::RunConfig {
context: Context::default(),
runtime_builder: std::sync::Arc::new(Box::new(|| {
let mut builder = tokio::runtime::Builder::new_current_thread();
builder.enable_all();
builder
})),
};
run!(runconfig)
}
}