use std::sync::Arc;
use crate::cancel::CancellationToken;
use crate::error::EngineError;
use crate::event::EventSink;
use crate::step::{BatchResult, StepBatch};
use crate::world::World;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EngineId(Arc<str>);
impl EngineId {
pub fn as_str(&self) -> &str {
&self.0
}
}
impl From<&str> for EngineId {
fn from(s: &str) -> Self {
Self(Arc::from(s))
}
}
impl std::fmt::Display for EngineId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Clone, Copy)]
pub struct StepKindSpec {
pub prefix: &'static str,
pub schema: &'static str,
pub validate: Option<PayloadValidator>,
}
pub type PayloadValidator = fn(&str) -> Result<(), PayloadProbeError>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PayloadProbeError {
pub line: usize,
pub column: usize,
pub message: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DoctorResult {
pub status: DoctorStatus,
pub detail: String,
}
impl DoctorResult {
pub fn pass(detail: impl Into<String>) -> Self {
Self {
status: DoctorStatus::Pass,
detail: detail.into(),
}
}
pub fn warn(detail: impl Into<String>) -> Self {
Self {
status: DoctorStatus::Warn,
detail: detail.into(),
}
}
pub fn fail(detail: impl Into<String>) -> Self {
Self {
status: DoctorStatus::Fail,
detail: detail.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum DoctorStatus {
Pass,
Warn,
Fail,
}
pub struct DoctorCheck {
pub name: &'static str,
pub run: fn() -> DoctorResult,
}
impl std::fmt::Debug for DoctorCheck {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DoctorCheck")
.field("name", &self.name)
.finish_non_exhaustive()
}
}
#[derive(Debug, Clone)]
pub struct ScenarioCtx {
pub run_id: Arc<str>,
pub scenario: Arc<str>,
pub artifact: Option<ArtifactRef>,
pub secrets: Arc<std::collections::BTreeMap<String, String>>,
pub http: HttpDefaults,
pub file_root: Option<std::path::PathBuf>,
}
#[derive(Debug, Clone, Copy)]
pub struct HttpDefaults {
pub timeout_ms: u64,
pub follow_location: bool,
}
impl Default for HttpDefaults {
fn default() -> Self {
Self {
timeout_ms: 30_000,
follow_location: false,
}
}
}
#[derive(Debug, Clone)]
pub struct ArtifactRef {
pub slug: Arc<str>,
pub text: Arc<str>,
pub map: Arc<crate::emit::SidecarMap>,
}
pub trait EngineFactory: Send + Sync {
fn id(&self) -> &'static str;
fn step_kinds(&self) -> &'static [StepKindSpec];
fn doctor(&self) -> Vec<DoctorCheck>;
fn open(&self, ctx: &ScenarioCtx) -> Result<Box<dyn EngineSession>, EngineError>;
}
pub trait EngineSession: Send {
fn run_batch(
&mut self,
batch: &StepBatch,
world: &mut World,
events: &EventSink,
cancel: &CancellationToken,
) -> BatchResult;
fn batch_budget(&mut self, _batch: &StepBatch) -> Option<std::time::Duration> {
None
}
fn finish(&mut self) -> Result<(), EngineError>;
}