alux_http_conformance/
measure.rs1use crate::lifecycle::{LifecycleError, answered, free_address, hold};
8use alux_ext::ext;
9use alux_http::{HttpServerAlg, HttpServerSetup};
10use core::time::Duration;
11use std::time::Instant;
12use tokio::task::LocalSet;
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub struct Closing {
17 asking_for: &'static str,
18 ending: bool,
19}
20
21impl Closing {
22 pub const fn new(asking_for: &'static str, ending: bool) -> Self {
24 Self { asking_for, ending }
25 }
26
27 pub const fn asking_for(self) -> &'static str {
29 self.asking_for
30 }
31
32 pub const fn ending(self) -> bool {
34 self.ending
35 }
36}
37
38#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub enum Handover {
41 NoRequest,
43 RequestOk,
45 RequestHeld(&'static str),
47}
48
49#[ext(name = MeasureLifecycleExt)]
51pub impl<This> This
52where
53 This: HttpServerAlg,
54 This::Error: Into<LifecycleError>,
55{
56 async fn time_closing<Compile>(mut self, mut compile: Compile, closing: Closing, rounds: u64) -> Duration
65 where
66 Compile: FnMut() -> Self::Program,
67 {
68 LocalSet::new()
69 .run_until(async move {
70 let bind = free_address().expect("an address nothing holds");
71 let mut timed = Duration::ZERO;
72 for _ in 0..rounds {
73 let Ok(mut open) = self.open(HttpServerSetup::new(bind, compile())).await else {
74 panic!("the server opens");
75 };
76 let held = hold(bind, closing.asking_for()).await.expect("a request the server is serving");
77
78 let round = Instant::now();
79 assert!(self.close(&mut open).await.is_ok(), "the open server closes");
80 if closing.ending() {
81 assert!(self.end(&mut open).await.is_ok(), "the closed server ends");
82 }
83 timed += round.elapsed();
84
85 drop(held);
86 drop(open);
87 }
88
89 timed
90 })
91 .await
92 }
93
94 async fn time_handover<Compile>(mut self, mut compile: Compile, load: Handover, rounds: u64) -> Duration
99 where
100 Compile: FnMut() -> Self::Program,
101 {
102 LocalSet::new()
103 .run_until(async move {
104 let bind = free_address().expect("an address nothing holds");
105 let Ok(mut open) = self.open(HttpServerSetup::new(bind, compile())).await else {
106 panic!("the first server opens");
107 };
108
109 let mut holding = Vec::new();
110 let mut timed = Duration::ZERO;
111 for _ in 0..rounds {
112 if let Handover::RequestHeld(asking_for) = load {
113 holding.push(hold(bind, asking_for).await.expect("a request the server is serving"));
114 }
115
116 let round = Instant::now();
117 if load == Handover::RequestOk {
118 answered(bind).await.expect("the open server answers");
119 }
120 assert!(self.close(&mut open).await.is_ok(), "the open server closes");
121 let Ok(next) = self.open(HttpServerSetup::new(bind, compile())).await else {
122 panic!("the next server opens");
123 };
124 open = next;
125 timed += round.elapsed();
126 }
127
128 assert!(self.end(&mut open).await.is_ok(), "the last server ends");
129
130 timed
131 })
132 .await
133 }
134}