Skip to main content

lmn_core/execution/
mod.rs

1pub mod curve;
2pub mod error;
3pub mod fixed;
4
5pub use error::RunError;
6
7use std::path::PathBuf;
8use std::sync::Arc;
9
10use crate::command::{Body, HttpMethod};
11use crate::config::secret::SensitiveString;
12use crate::histogram::{LatencyHistogram, StatusCodeHistogram};
13use crate::http::RequestConfig;
14use crate::load_curve::LoadCurve;
15use crate::response_template::ResponseTemplate;
16use crate::response_template::field::TrackedField;
17use crate::response_template::stats::ResponseStats;
18
19// ── RunMode ───────────────────────────────────────────────────────────────────
20
21/// Indicates which execution strategy produced the run results.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum RunMode {
24    /// Worker-pool fixed-count mode: N long-lived VUs share an atomic request budget.
25    Fixed,
26    /// Time-based dynamic VU mode driven by a `LoadCurve`.
27    Curve,
28}
29
30// ── TemplateStats ─────────────────────────────────────────────────────────────
31
32/// Timing information for request template generation.
33#[derive(Debug, Clone)]
34pub struct TemplateStats {
35    pub generation_duration: std::time::Duration,
36}
37
38// ── StageStats ────────────────────────────────────────────────────────────────
39
40/// Per-stage latency and request counts for curve-mode runs.
41pub struct StageStats {
42    pub latency: LatencyHistogram,
43    pub status_codes: StatusCodeHistogram,
44    pub total_requests: u64,
45    pub total_failures: u64,
46}
47
48// ── CurveStats ────────────────────────────────────────────────────────────────
49
50/// Curve-specific metadata captured at the end of a curve run.
51pub struct CurveStats {
52    pub duration: std::time::Duration,
53    pub stages: Vec<crate::load_curve::Stage>,
54    /// Per-stage histogram data — one entry per stage in the load curve.
55    pub stage_stats: Vec<StageStats>,
56}
57
58// ── RunStats ──────────────────────────────────────────────────────────────────
59
60pub struct RunStats {
61    pub elapsed: std::time::Duration,
62    pub mode: RunMode,
63    pub latency: LatencyHistogram,
64    pub status_codes: StatusCodeHistogram,
65    pub total_requests: u64,
66    pub total_failures: u64,
67    pub template_stats: Option<TemplateStats>,
68    pub response_stats: Option<ResponseStats>,
69    pub curve_stats: Option<CurveStats>,
70}
71
72// ── RequestSpec ───────────────────────────────────────────────────────────────
73
74/// All request-level parameters for a run.
75pub struct RequestSpec {
76    pub host: String,
77    pub method: HttpMethod,
78    pub body: Option<Body>,
79    pub template_path: Option<PathBuf>,
80    pub response_template_path: Option<PathBuf>,
81    /// Custom HTTP headers to send with every request in this run.
82    pub headers: Vec<(String, SensitiveString)>,
83}
84
85// ── ExecutionMode ─────────────────────────────────────────────────────────────
86
87/// Determines the execution strategy for a run.
88pub enum ExecutionMode {
89    /// Classic semaphore-based fixed-count execution.
90    Fixed {
91        request_count: usize,
92        concurrency: usize,
93    },
94    /// Time-based dynamic VU execution driven by a `LoadCurve`.
95    Curve(LoadCurve),
96}
97
98// ── Shared helpers ────────────────────────────────────────────────────────────
99
100pub(crate) fn resolve_tracked_fields(
101    path: Option<PathBuf>,
102) -> Result<Option<Arc<Vec<TrackedField>>>, Box<dyn std::error::Error>> {
103    path.map(|p| {
104        ResponseTemplate::parse(&p)
105            .map(|rt| Arc::new(rt.fields))
106            .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
107    })
108    .transpose()
109}
110
111pub(crate) fn build_request_config(
112    host: String,
113    method: HttpMethod,
114    body: Option<Body>,
115    tracked_fields: Option<Arc<Vec<TrackedField>>>,
116    headers: Vec<(String, SensitiveString)>,
117    concurrency: usize,
118) -> Result<Arc<RequestConfig>, RunError> {
119    let client = reqwest::Client::builder()
120        .pool_max_idle_per_host(concurrency)
121        .build()?;
122    Ok(Arc::new(RequestConfig {
123        client,
124        host: Arc::new(host),
125        method,
126        body: Arc::new(body),
127        tracked_fields,
128        headers: Arc::new(headers),
129    }))
130}