#![allow(dead_code)]
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
#[cfg(test)]
use proptest::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RequirementLevel {
Must,
Should,
May,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TestCategory {
ChaosDeterminism,
ScenarioReplayability,
SnapshotRestore,
VirtualTime,
OracleConsistency,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ConformanceCase {
pub id: &'static str,
pub section: &'static str,
pub level: RequirementLevel,
pub category: TestCategory,
pub description: &'static str,
}
#[derive(Debug, Serialize)]
pub enum TestResult {
Pass,
Fail { reason: String },
Skipped { reason: String },
}
#[derive(Debug, Clone)]
pub struct MockLabRuntime {
seed: u64,
virtual_time: Duration,
chaos_events: Vec<ChaosEvent>,
scenario_state: ScenarioState,
snapshot_data: Option<RuntimeSnapshot>,
deterministic_rng: MockRng,
oracle_reports: Vec<OracleReport>,
}
#[derive(Debug, Clone)]
pub struct ChaosEvent {
pub event_type: ChaosEventType,
pub target_task: u64,
pub virtual_time: Duration,
pub sequence: u64,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ChaosEventType {
Cancellation,
Delay { duration: Duration },
IoError { error_code: u32 },
WakeupStorm { count: u32 },
BudgetExhaustion,
}
#[derive(Debug, Clone)]
pub struct ScenarioState {
pub scenario_id: String,
pub execution_trace: Vec<TraceEvent>,
pub fault_events: Vec<FaultEvent>,
pub oracle_checks: HashMap<String, bool>,
pub replay_count: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RuntimeSnapshot {
pub timestamp: Duration,
pub task_states: HashMap<u64, TaskState>,
pub region_tree: HashMap<u64, RegionState>,
pub obligation_map: HashMap<u64, ObligationState>,
pub logical_clocks: HashMap<u64, u64>,
pub quiescence_proof: QuiescenceProof,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaskState {
pub task_id: u64,
pub region_id: u64,
pub status: TaskStatus,
pub logical_time: u64,
pub cancellation_token: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TaskStatus {
Scheduled,
Running,
Waiting,
Completed,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegionState {
pub region_id: u64,
pub parent_region: Option<u64>,
pub child_tasks: Vec<u64>,
pub child_regions: Vec<u64>,
pub status: RegionStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RegionStatus {
Active,
Closing,
Closed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObligationState {
pub obligation_id: u64,
pub task_id: u64,
pub obligation_type: ObligationType,
pub status: ObligationStatus,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ObligationType {
Permit,
Acknowledgment,
Lease,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ObligationStatus {
Pending,
Committed,
Aborted,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuiescenceProof {
pub all_regions_closed: bool,
pub no_pending_tasks: bool,
pub all_obligations_resolved: bool,
pub causal_ordering_valid: bool,
}
#[derive(Debug, Clone)]
pub struct TraceEvent {
pub sequence: u64,
pub task_id: u64,
pub event_type: TraceEventType,
pub logical_time: u64,
pub virtual_time: Duration,
}
#[derive(Debug, Clone, PartialEq)]
pub enum TraceEventType {
TaskSpawn,
TaskComplete,
TaskCancel,
RegionCreate,
RegionClose,
ObligationCreate,
ObligationResolve,
ChaosInjection { chaos_type: ChaosEventType },
}
#[derive(Debug, Clone)]
pub struct FaultEvent {
pub fault_id: String,
pub timing: Duration,
pub fault_type: String,
pub target: String,
}
#[derive(Debug, Clone)]
pub struct OracleReport {
pub oracle_name: String,
pub checks_passed: u32,
pub checks_failed: u32,
pub violations: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct MockRng {
seed: u64,
state: u64,
}
impl MockRng {
pub fn new(seed: u64) -> Self {
Self { seed, state: seed }
}
pub fn next(&mut self) -> u64 {
self.state = self.state.wrapping_mul(1103515245).wrapping_add(12345);
self.state
}
pub fn next_f64(&mut self) -> f64 {
(self.next() as f64) / (u64::MAX as f64)
}
pub fn next_bool(&mut self, probability: f64) -> bool {
self.next_f64() < probability
}
}
impl MockLabRuntime {
pub fn new(seed: u64) -> Self {
Self {
seed,
virtual_time: Duration::ZERO,
chaos_events: Vec::new(),
scenario_state: ScenarioState {
scenario_id: "default".to_string(),
execution_trace: Vec::new(),
fault_events: Vec::new(),
oracle_checks: HashMap::new(),
replay_count: 0,
},
snapshot_data: None,
deterministic_rng: MockRng::new(seed),
oracle_reports: Vec::new(),
}
}
pub fn inject_chaos_with_seed(&mut self, chaos_config: &ChaosConfig) -> Vec<ChaosEvent> {
let mut rng = MockRng::new(self.seed);
let mut events = Vec::new();
let mut sequence = 0;
for _ in 0..chaos_config.max_events {
if rng.next_bool(chaos_config.injection_probability) {
let event_type = match rng.next() % 5 {
0 => ChaosEventType::Cancellation,
1 => ChaosEventType::Delay {
duration: Duration::from_millis(rng.next() % 100),
},
2 => ChaosEventType::IoError {
error_code: (rng.next() % 10) as u32,
},
3 => ChaosEventType::WakeupStorm {
count: (rng.next() % 20) as u32 + 1,
},
_ => ChaosEventType::BudgetExhaustion,
};
let event = ChaosEvent {
event_type,
target_task: rng.next() % 100,
virtual_time: self.virtual_time,
sequence,
};
events.push(event.clone());
sequence += 1;
}
}
self.chaos_events.extend(events.clone());
events
}
pub fn verify_chaos_determinism(&self, other: &Self) -> bool {
if self.seed != other.seed {
return false;
}
if self.chaos_events.len() != other.chaos_events.len() {
return false;
}
for (a, b) in self.chaos_events.iter().zip(other.chaos_events.iter()) {
if a.event_type != b.event_type
|| a.target_task != b.target_task
|| a.sequence != b.sequence
{
return false;
}
}
true
}
pub fn run_scenario(&mut self, scenario: &TestScenario) -> ScenarioResult {
self.scenario_state.scenario_id = scenario.id.clone();
self.scenario_state.fault_events = scenario.fault_events.clone();
self.scenario_state.replay_count += 1;
let mut trace_events = Vec::new();
let mut oracle_checks = HashMap::new();
let mut rng = MockRng::new(self.seed);
for (i, fault) in scenario.fault_events.iter().enumerate() {
let trace_event = TraceEvent {
sequence: i as u64,
task_id: rng.next() % 10,
event_type: match fault.fault_type.as_str() {
"cancel" => TraceEventType::TaskCancel,
"delay" => TraceEventType::ChaosInjection {
chaos_type: ChaosEventType::Delay {
duration: fault.timing,
},
},
_ => TraceEventType::TaskSpawn,
},
logical_time: i as u64 * 1000,
virtual_time: fault.timing,
};
trace_events.push(trace_event);
oracle_checks.insert(format!("oracle_{}", i), rng.next_bool(0.9));
}
self.scenario_state.execution_trace = trace_events.clone();
self.scenario_state.oracle_checks = oracle_checks.clone();
ScenarioResult {
scenario_id: scenario.id.clone(),
execution_trace: trace_events,
oracle_checks,
replay_count: self.scenario_state.replay_count,
trace_certificate: self.generate_trace_certificate(),
}
}
pub fn generate_trace_certificate(&self) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
for event in &self.scenario_state.execution_trace {
event.sequence.hash(&mut hasher);
event.task_id.hash(&mut hasher);
event.logical_time.hash(&mut hasher);
match &event.event_type {
TraceEventType::TaskSpawn => 0u8.hash(&mut hasher),
TraceEventType::TaskComplete => 1u8.hash(&mut hasher),
TraceEventType::TaskCancel => 2u8.hash(&mut hasher),
TraceEventType::RegionCreate => 3u8.hash(&mut hasher),
TraceEventType::RegionClose => 4u8.hash(&mut hasher),
TraceEventType::ObligationCreate => 5u8.hash(&mut hasher),
TraceEventType::ObligationResolve => 6u8.hash(&mut hasher),
TraceEventType::ChaosInjection { .. } => 7u8.hash(&mut hasher),
}
}
let mut oracle_checks: Vec<_> = self.scenario_state.oracle_checks.iter().collect();
oracle_checks.sort_by(|(left, _), (right, _)| left.cmp(right));
for (key, value) in oracle_checks {
key.hash(&mut hasher);
value.hash(&mut hasher);
}
format!("trace_cert_{:016x}", hasher.finish())
}
pub fn take_snapshot(&self) -> RuntimeSnapshot {
RuntimeSnapshot {
timestamp: self.virtual_time,
task_states: self.generate_sample_task_states(),
region_tree: self.generate_sample_region_tree(),
obligation_map: self.generate_sample_obligations(),
logical_clocks: self.generate_logical_clocks(),
quiescence_proof: self.validate_quiescence(),
}
}
pub fn restore_from_snapshot(&mut self, snapshot: RuntimeSnapshot) -> Result<(), String> {
if !self.validate_snapshot_integrity(&snapshot) {
return Err("Snapshot integrity validation failed".to_string());
}
self.virtual_time = snapshot.timestamp;
if !snapshot.quiescence_proof.all_regions_closed
|| !snapshot.quiescence_proof.no_pending_tasks
|| !snapshot.quiescence_proof.all_obligations_resolved
{
return Err("Quiescence proof invalid".to_string());
}
self.snapshot_data = Some(snapshot);
Ok(())
}
pub fn verify_round_trip(&self, original_snapshot: &RuntimeSnapshot) -> bool {
match &self.snapshot_data {
Some(restored) => self.compare_snapshots(original_snapshot, restored),
None => false,
}
}
fn validate_snapshot_integrity(&self, snapshot: &RuntimeSnapshot) -> bool {
for (_task_id, task_state) in &snapshot.task_states {
if !snapshot.region_tree.contains_key(&task_state.region_id) {
return false;
}
}
for (_, obligation) in &snapshot.obligation_map {
if !snapshot.task_states.contains_key(&obligation.task_id) {
return false;
}
}
for (region_id, region) in &snapshot.region_tree {
if let Some(parent_id) = region.parent_region {
if parent_id == *region_id {
return false; }
}
}
true
}
fn compare_snapshots(&self, a: &RuntimeSnapshot, b: &RuntimeSnapshot) -> bool {
a.timestamp == b.timestamp
&& a.task_states.len() == b.task_states.len()
&& a.region_tree.len() == b.region_tree.len()
&& a.obligation_map.len() == b.obligation_map.len()
&& a.quiescence_proof.all_regions_closed == b.quiescence_proof.all_regions_closed
}
fn generate_sample_task_states(&self) -> HashMap<u64, TaskState> {
let mut tasks = HashMap::new();
for i in 0..5 {
tasks.insert(
i,
TaskState {
task_id: i,
region_id: i / 2,
status: TaskStatus::Completed,
logical_time: i * 1000,
cancellation_token: None,
},
);
}
tasks
}
fn generate_sample_region_tree(&self) -> HashMap<u64, RegionState> {
let mut regions = HashMap::new();
regions.insert(
0,
RegionState {
region_id: 0,
parent_region: None,
child_tasks: vec![0, 1],
child_regions: vec![1, 2],
status: RegionStatus::Closed,
},
);
regions.insert(
1,
RegionState {
region_id: 1,
parent_region: Some(0),
child_tasks: vec![2, 3],
child_regions: vec![],
status: RegionStatus::Closed,
},
);
regions.insert(
2,
RegionState {
region_id: 2,
parent_region: Some(0),
child_tasks: vec![4],
child_regions: vec![],
status: RegionStatus::Closed,
},
);
regions
}
fn generate_sample_obligations(&self) -> HashMap<u64, ObligationState> {
let mut obligations = HashMap::new();
obligations.insert(
0,
ObligationState {
obligation_id: 0,
task_id: 0,
obligation_type: ObligationType::Permit,
status: ObligationStatus::Committed,
},
);
obligations
}
fn generate_logical_clocks(&self) -> HashMap<u64, u64> {
let mut clocks = HashMap::new();
for i in 0..5 {
clocks.insert(i, i * 1000);
}
clocks
}
fn validate_quiescence(&self) -> QuiescenceProof {
QuiescenceProof {
all_regions_closed: true,
no_pending_tasks: true,
all_obligations_resolved: true,
causal_ordering_valid: true,
}
}
}
#[derive(Debug, Clone)]
pub struct ChaosConfig {
pub max_events: usize,
pub injection_probability: f64,
pub enabled_types: Vec<ChaosEventType>,
}
#[derive(Debug, Clone)]
pub struct TestScenario {
pub id: String,
pub description: String,
pub fault_events: Vec<FaultEvent>,
pub expected_oracles: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ScenarioResult {
pub scenario_id: String,
pub execution_trace: Vec<TraceEvent>,
pub oracle_checks: HashMap<String, bool>,
pub replay_count: u32,
pub trace_certificate: String,
}
const LAB_CONFORMANCE_CASES: &[ConformanceCase] = &[
ConformanceCase {
id: "LAB-CHAOS-01",
section: "chaos.determinism",
level: RequirementLevel::Must,
category: TestCategory::ChaosDeterminism,
description: "Same seed produces identical chaos injection sequences",
},
ConformanceCase {
id: "LAB-CHAOS-02",
section: "chaos.determinism",
level: RequirementLevel::Must,
category: TestCategory::ChaosDeterminism,
description: "Chaos events maintain deterministic ordering across runs",
},
ConformanceCase {
id: "LAB-CHAOS-03",
section: "chaos.cancellation",
level: RequirementLevel::Must,
category: TestCategory::ChaosDeterminism,
description: "Cancellation chaos points are reproducible",
},
ConformanceCase {
id: "LAB-REPLAY-01",
section: "scenario.replayability",
level: RequirementLevel::Must,
category: TestCategory::ScenarioReplayability,
description: "Scenarios execute identically on replay with same seed",
},
ConformanceCase {
id: "LAB-REPLAY-02",
section: "scenario.certificates",
level: RequirementLevel::Must,
category: TestCategory::ScenarioReplayability,
description: "Trace certificates match exactly between runs",
},
ConformanceCase {
id: "LAB-REPLAY-03",
section: "scenario.oracles",
level: RequirementLevel::Must,
category: TestCategory::ScenarioReplayability,
description: "Oracle reports maintain consistency across replay",
},
ConformanceCase {
id: "LAB-SNAPSHOT-01",
section: "snapshot.roundtrip",
level: RequirementLevel::Must,
category: TestCategory::SnapshotRestore,
description: "Snapshot → restore preserves runtime state exactly",
},
ConformanceCase {
id: "LAB-SNAPSHOT-02",
section: "snapshot.quiescence",
level: RequirementLevel::Must,
category: TestCategory::SnapshotRestore,
description: "Restored runtime reaches quiescence correctly",
},
ConformanceCase {
id: "LAB-SNAPSHOT-03",
section: "snapshot.integrity",
level: RequirementLevel::Must,
category: TestCategory::SnapshotRestore,
description: "Task/region/obligation relationships survive round-trip",
},
];
#[cfg(test)]
mod tests {
use super::*;
fn run_conformance_test(case: &ConformanceCase) -> TestResult {
match case.id {
"LAB-CHAOS-01" => test_chaos_determinism_identical_sequences(),
"LAB-CHAOS-02" => test_chaos_determinism_ordering(),
"LAB-CHAOS-03" => test_chaos_cancellation_reproducibility(),
"LAB-REPLAY-01" => test_scenario_replay_identity(),
"LAB-REPLAY-02" => test_trace_certificate_matching(),
"LAB-REPLAY-03" => test_oracle_consistency(),
"LAB-SNAPSHOT-01" => test_snapshot_restore_round_trip(),
"LAB-SNAPSHOT-02" => test_snapshot_quiescence_preservation(),
"LAB-SNAPSHOT-03" => test_snapshot_relationship_integrity(),
_ => TestResult::Skipped {
reason: "No registered lab conformance case for this id".to_string(),
},
}
}
fn test_chaos_determinism_identical_sequences() -> TestResult {
let seed = 42;
let chaos_config = ChaosConfig {
max_events: 10,
injection_probability: 0.8,
enabled_types: vec![
ChaosEventType::Cancellation,
ChaosEventType::Delay {
duration: Duration::from_millis(1),
},
],
};
let mut runtime1 = MockLabRuntime::new(seed);
let mut runtime2 = MockLabRuntime::new(seed);
let events1 = runtime1.inject_chaos_with_seed(&chaos_config);
let events2 = runtime2.inject_chaos_with_seed(&chaos_config);
if runtime1.verify_chaos_determinism(&runtime2) {
TestResult::Pass
} else {
TestResult::Fail {
reason: format!(
"Chaos sequences differ: {} vs {} events",
events1.len(),
events2.len()
),
}
}
}
fn test_chaos_determinism_ordering() -> TestResult {
let seed = 123;
let chaos_config = ChaosConfig {
max_events: 5,
injection_probability: 1.0, enabled_types: vec![ChaosEventType::Cancellation],
};
let mut runtime = MockLabRuntime::new(seed);
let events = runtime.inject_chaos_with_seed(&chaos_config);
for window in events.windows(2) {
if window[0].sequence >= window[1].sequence {
return TestResult::Fail {
reason: "Chaos events not properly ordered by sequence".to_string(),
};
}
}
TestResult::Pass
}
fn test_chaos_cancellation_reproducibility() -> TestResult {
let seed = 789;
let chaos_config = ChaosConfig {
max_events: 3,
injection_probability: 1.0,
enabled_types: vec![ChaosEventType::Cancellation],
};
let mut runtime1 = MockLabRuntime::new(seed);
let mut runtime2 = MockLabRuntime::new(seed);
let events1 = runtime1.inject_chaos_with_seed(&chaos_config);
let events2 = runtime2.inject_chaos_with_seed(&chaos_config);
for (e1, e2) in events1.iter().zip(events2.iter()) {
if e1.target_task != e2.target_task || e1.event_type != e2.event_type {
return TestResult::Fail {
reason: "Cancellation chaos not reproducible across runs".to_string(),
};
}
}
TestResult::Pass
}
fn test_scenario_replay_identity() -> TestResult {
let seed = 456;
let mut runtime = MockLabRuntime::new(seed);
let scenario = TestScenario {
id: "test_scenario".to_string(),
description: "Test scenario for replay".to_string(),
fault_events: vec![
FaultEvent {
fault_id: "fault1".to_string(),
timing: Duration::from_millis(100),
fault_type: "cancel".to_string(),
target: "task1".to_string(),
},
FaultEvent {
fault_id: "fault2".to_string(),
timing: Duration::from_millis(200),
fault_type: "delay".to_string(),
target: "task2".to_string(),
},
],
expected_oracles: vec!["oracle_1".to_string(), "oracle_2".to_string()],
};
let result1 = runtime.run_scenario(&scenario);
let result2 = runtime.run_scenario(&scenario);
if result1.trace_certificate == result2.trace_certificate {
TestResult::Pass
} else {
TestResult::Fail {
reason: "Scenario replay produced different results".to_string(),
}
}
}
fn test_trace_certificate_matching() -> TestResult {
let seed = 999;
let mut runtime1 = MockLabRuntime::new(seed);
let mut runtime2 = MockLabRuntime::new(seed);
let scenario = TestScenario {
id: "cert_test".to_string(),
description: "Certificate test".to_string(),
fault_events: vec![FaultEvent {
fault_id: "cert_fault".to_string(),
timing: Duration::from_millis(50),
fault_type: "cancel".to_string(),
target: "task_cert".to_string(),
}],
expected_oracles: vec!["cert_oracle".to_string()],
};
let result1 = runtime1.run_scenario(&scenario);
let result2 = runtime2.run_scenario(&scenario);
if result1.trace_certificate == result2.trace_certificate {
TestResult::Pass
} else {
TestResult::Fail {
reason: format!(
"Trace certificates don't match: {} vs {}",
result1.trace_certificate, result2.trace_certificate
),
}
}
}
fn test_oracle_consistency() -> TestResult {
let seed = 111;
let mut runtime = MockLabRuntime::new(seed);
let scenario = TestScenario {
id: "oracle_test".to_string(),
description: "Oracle consistency test".to_string(),
fault_events: vec![FaultEvent {
fault_id: "oracle_fault".to_string(),
timing: Duration::from_millis(75),
fault_type: "delay".to_string(),
target: "task_oracle".to_string(),
}],
expected_oracles: vec!["consistency_oracle".to_string()],
};
let result1 = runtime.run_scenario(&scenario);
let result2 = runtime.run_scenario(&scenario);
if result1.oracle_checks == result2.oracle_checks {
TestResult::Pass
} else {
TestResult::Fail {
reason: "Oracle results inconsistent across replays".to_string(),
}
}
}
fn test_snapshot_restore_round_trip() -> TestResult {
let seed = 222;
let runtime = MockLabRuntime::new(seed);
let snapshot = runtime.take_snapshot();
let mut restored_runtime = MockLabRuntime::new(seed);
match restored_runtime.restore_from_snapshot(snapshot.clone()) {
Ok(()) => {
if restored_runtime.verify_round_trip(&snapshot) {
TestResult::Pass
} else {
TestResult::Fail {
reason: "Round-trip verification failed".to_string(),
}
}
}
Err(e) => TestResult::Fail {
reason: format!("Snapshot restoration failed: {}", e),
},
}
}
fn test_snapshot_quiescence_preservation() -> TestResult {
let seed = 333;
let runtime = MockLabRuntime::new(seed);
let snapshot = runtime.take_snapshot();
if snapshot.quiescence_proof.all_regions_closed
&& snapshot.quiescence_proof.no_pending_tasks
&& snapshot.quiescence_proof.all_obligations_resolved
&& snapshot.quiescence_proof.causal_ordering_valid
{
TestResult::Pass
} else {
TestResult::Fail {
reason: "Quiescence proof invalid in snapshot".to_string(),
}
}
}
fn test_snapshot_relationship_integrity() -> TestResult {
let seed = 444;
let runtime = MockLabRuntime::new(seed);
let snapshot = runtime.take_snapshot();
for (task_id, task_state) in &snapshot.task_states {
if !snapshot.region_tree.contains_key(&task_state.region_id) {
return TestResult::Fail {
reason: format!(
"Task {} references non-existent region {}",
task_id, task_state.region_id
),
};
}
}
for (obligation_id, obligation) in &snapshot.obligation_map {
if !snapshot.task_states.contains_key(&obligation.task_id) {
return TestResult::Fail {
reason: format!(
"Obligation {} references non-existent task {}",
obligation_id, obligation.task_id
),
};
}
}
TestResult::Pass
}
#[test]
fn lab_conformance_full_suite() {
let mut pass_count = 0;
let mut fail_count = 0;
let mut skip_count = 0;
for case in LAB_CONFORMANCE_CASES {
let result = run_conformance_test(case);
match result {
TestResult::Pass => {
pass_count += 1;
println!("✓ {}: {}", case.id, case.description);
}
TestResult::Fail { reason } => {
fail_count += 1;
println!("✗ {}: {} - {}", case.id, case.description, reason);
}
TestResult::Skipped { reason } => {
skip_count += 1;
println!("⚠ {}: {} - {}", case.id, case.description, reason);
}
}
}
let total = pass_count + fail_count + skip_count;
println!(
"\nLab Conformance Results: {}/{} passed, {} failed, {} skipped",
pass_count, total, fail_count, skip_count
);
let must_cases: Vec<_> = LAB_CONFORMANCE_CASES
.iter()
.filter(|c| c.level == RequirementLevel::Must)
.collect();
let mut must_failures = 0;
for case in &must_cases {
if let TestResult::Fail { .. } = run_conformance_test(case) {
must_failures += 1;
}
}
assert_eq!(
must_failures, 0,
"{} MUST requirements failed",
must_failures
);
}
proptest! {
#[test]
fn prop_chaos_determinism(seed in 0u64..10000, max_events in 1usize..50) {
let chaos_config = ChaosConfig {
max_events,
injection_probability: 0.5,
enabled_types: vec![ChaosEventType::Cancellation, ChaosEventType::Delay { duration: Duration::from_millis(1) }],
};
let mut runtime1 = MockLabRuntime::new(seed);
let mut runtime2 = MockLabRuntime::new(seed);
runtime1.inject_chaos_with_seed(&chaos_config);
runtime2.inject_chaos_with_seed(&chaos_config);
prop_assert!(runtime1.verify_chaos_determinism(&runtime2));
}
#[test]
fn prop_snapshot_round_trip(seed in 0u64..10000) {
let runtime = MockLabRuntime::new(seed);
let snapshot = runtime.take_snapshot();
let mut restored_runtime = MockLabRuntime::new(seed);
let restore_result = restored_runtime.restore_from_snapshot(snapshot.clone());
prop_assert!(restore_result.is_ok());
prop_assert!(restored_runtime.verify_round_trip(&snapshot));
}
#[test]
fn prop_scenario_replay_consistency(seed in 0u64..10000, fault_count in 1usize..10) {
let mut runtime = MockLabRuntime::new(seed);
let scenario = TestScenario {
id: format!("prop_test_{}", seed),
description: "Property-based test scenario".to_string(),
fault_events: (0..fault_count).map(|i| FaultEvent {
fault_id: format!("fault_{}", i),
timing: Duration::from_millis((i as u64) * 50),
fault_type: "cancel".to_string(),
target: format!("task_{}", i),
}).collect(),
expected_oracles: vec![],
};
let result1 = runtime.run_scenario(&scenario);
let result2 = runtime.run_scenario(&scenario);
prop_assert_eq!(result1.trace_certificate, result2.trace_certificate);
}
}
}