use std::time::Duration;
use super::engine::SimulationEngine;
use super::error::SimulationError;
use super::report::SimulationReport;
pub struct LiveSimulation {
engine: SimulationEngine,
duration: Duration,
}
impl LiveSimulation {
pub fn new(engine: SimulationEngine, duration: Duration) -> Self {
Self { engine, duration }
}
pub fn duration(&self) -> Duration {
self.duration
}
pub fn engine(&self) -> &SimulationEngine {
&self.engine
}
pub async fn run(&self) -> Result<SimulationReport, SimulationError> {
tokio::time::sleep(self.duration).await;
Ok(SimulationReport {
total_events: 0,
denied: 0,
allowed: 0,
approval_required: 0,
budget_impact_usd: None,
flagged_outcomes: Vec::new(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use std::sync::Arc;
use crate::PolicyEngine;
fn make_live_sim(duration: Duration) -> LiveSimulation {
let policy_yaml = r#"
tier: low
rules:
- id: allow-all
description: Allow everything
match:
actions: ["*"]
effect: allow
audit: true
"#;
let mut tmp = tempfile::NamedTempFile::new().unwrap();
tmp.write_all(policy_yaml.as_bytes()).unwrap();
tmp.flush().unwrap();
let (tx, _rx) = tokio::sync::broadcast::channel(16);
let engine = PolicyEngine::load_from_file(tmp.path(), tx).unwrap();
let sim_engine = SimulationEngine::new(Arc::new(engine));
LiveSimulation::new(sim_engine, duration)
}
#[test]
fn accessors() {
let sim = make_live_sim(Duration::from_secs(5));
assert_eq!(sim.duration(), Duration::from_secs(5));
let _ = sim.engine().engine();
}
#[tokio::test]
async fn run_returns_empty_report() {
let sim = make_live_sim(Duration::from_millis(10));
let report = sim.run().await.unwrap();
assert_eq!(report.total_events, 0);
assert_eq!(report.allowed, 0);
assert_eq!(report.denied, 0);
assert_eq!(report.approval_required, 0);
assert!(report.flagged_outcomes.is_empty());
}
}