use crate::lifecycle::{LifecycleError, answered, free_address, hold};
use alux_ext::ext;
use alux_http::{HttpServerAlg, HttpServerSetup};
use core::time::Duration;
use std::time::Instant;
use tokio::task::LocalSet;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Closing {
asking_for: &'static str,
ending: bool,
}
impl Closing {
pub const fn new(asking_for: &'static str, ending: bool) -> Self {
Self { asking_for, ending }
}
pub const fn asking_for(self) -> &'static str {
self.asking_for
}
pub const fn ending(self) -> bool {
self.ending
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Handover {
NoRequest,
RequestOk,
RequestHeld(&'static str),
}
#[ext(name = MeasureLifecycleExt)]
pub impl<This> This
where
This: HttpServerAlg,
This::Error: Into<LifecycleError>,
{
async fn time_closing<Compile>(mut self, mut compile: Compile, closing: Closing, rounds: u64) -> Duration
where
Compile: FnMut() -> Self::Program,
{
LocalSet::new()
.run_until(async move {
let bind = free_address().expect("an address nothing holds");
let mut timed = Duration::ZERO;
for _ in 0..rounds {
let Ok(mut open) = self.open(HttpServerSetup::new(bind, compile())).await else {
panic!("the server opens");
};
let held = hold(bind, closing.asking_for()).await.expect("a request the server is serving");
let round = Instant::now();
assert!(self.close(&mut open).await.is_ok(), "the open server closes");
if closing.ending() {
assert!(self.end(&mut open).await.is_ok(), "the closed server ends");
}
timed += round.elapsed();
drop(held);
drop(open);
}
timed
})
.await
}
async fn time_handover<Compile>(mut self, mut compile: Compile, load: Handover, rounds: u64) -> Duration
where
Compile: FnMut() -> Self::Program,
{
LocalSet::new()
.run_until(async move {
let bind = free_address().expect("an address nothing holds");
let Ok(mut open) = self.open(HttpServerSetup::new(bind, compile())).await else {
panic!("the first server opens");
};
let mut holding = Vec::new();
let mut timed = Duration::ZERO;
for _ in 0..rounds {
if let Handover::RequestHeld(asking_for) = load {
holding.push(hold(bind, asking_for).await.expect("a request the server is serving"));
}
let round = Instant::now();
if load == Handover::RequestOk {
answered(bind).await.expect("the open server answers");
}
assert!(self.close(&mut open).await.is_ok(), "the open server closes");
let Ok(next) = self.open(HttpServerSetup::new(bind, compile())).await else {
panic!("the next server opens");
};
open = next;
timed += round.elapsed();
}
assert!(self.end(&mut open).await.is_ok(), "the last server ends");
timed
})
.await
}
}