//! Smoke tests for the StemeDB simulation. //! //! These tests validate that the simulation infrastructure works correctly //! and can be run in CI. They exercise the core simulation loop and verify //! that the Spine (WAL + Ingestor + KV Store), Cortex (Query + Lenses), //! and Ballot Box (Votes + VoteAwareConsensusLens) correctly process data. use stemedb_sim::{ run_simulation, AgentSpec, ErrorKind, SimulationConfig, SimulationResult, StrategyType, }; /// Verify the default simulation configuration succeeds. /// /// This is the primary smoke test - if this passes, Spine, Cortex, and Ballot Box are working. #[tokio::test] async fn smoke_default_simulation_succeeds() { let config = SimulationConfig::default(); let result = run_simulation(config).await.expect("Simulation setup should not fail"); assert!(result.is_success(), "Default simulation should succeed. Errors: {:?}", result.errors); // All Arena 1 tests should pass assert!(result.recency_test_passed, "Recency lens test should pass"); assert!(result.lifecycle_test_passed, "Lifecycle filtering test should pass"); assert!(result.audit_test_passed, "Query audit test should pass"); // All Arena 2 tests should pass assert!(result.vote_consensus_test_passed, "Vote consensus test should pass"); assert!(result.troll_resistance_test_passed, "Troll resistance test should pass"); assert!(result.votes_written >= 6, "Should have written at least 6 votes"); // All Arena 3 tests should pass assert!(result.mv_integration_test_passed, "MV integration test should pass"); assert!(result.fast_path_test_passed, "Fast-path test should pass"); assert!(result.mv_freshness_test_passed, "MV freshness test should pass"); assert!(result.views_materialized >= 1, "Should have materialized at least 1 view"); } /// Verify simulation works with increased load. #[tokio::test] async fn smoke_high_volume_simulation() { let config = SimulationConfig { agents: vec![ AgentSpec { count: 4, strategy: StrategyType::Scientist }, AgentSpec { count: 3, strategy: StrategyType::Troll }, AgentSpec { count: 3, strategy: StrategyType::Believer }, ], tick_count: 50, ingestion_wait_ms: 1000, // More time for larger workload }; let result = run_simulation(config).await.expect("Simulation setup should not fail"); assert!( result.is_success(), "High-volume simulation should succeed. Errors: {:?}", result.errors ); // Strategy-driven: agents may assert, vote, query, or skip per tick assert!(result.assertions_written >= 16, "Should have arena test assertions + base"); // All Arena 1 + 2 + 3 tests should pass assert!(result.recency_test_passed); assert!(result.lifecycle_test_passed); assert!(result.audit_test_passed); assert!(result.vote_consensus_test_passed); assert!(result.troll_resistance_test_passed); assert!(result.mv_integration_test_passed); assert!(result.fast_path_test_passed); assert!(result.mv_freshness_test_passed); } /// Verify simulation result accessors work correctly. #[test] fn test_simulation_result_is_success() { // Success case: all assertions verified, no errors, all tests pass let success = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; assert!(success.is_success()); // Note: mismatched assertions_written != assertions_verified is allowed // because Arena 2 tests write additional test assertions. let with_mismatch = SimulationResult { assertions_written: 10, assertions_verified: 8, queries_executed: 10, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; // This is now allowed - mismatched counts don't fail assert!(with_mismatch.is_success()); // Failure case: has errors let with_errors = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![stemedb_sim::SimulationError { tick: 5, kind: ErrorKind::VerificationFailure, message: "Test error".to_string(), }], agent_count: 3, tick_count: 10, }; assert!(!with_errors.is_success()); // Failure case: recency test failed let recency_failed = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: false, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; assert!(!recency_failed.is_success()); // Failure case: lifecycle test failed let lifecycle_failed = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: false, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; assert!(!lifecycle_failed.is_success()); // Failure case: audit test failed let audit_failed = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: false, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; assert!(!audit_failed.is_success()); // Failure case: vote consensus test failed let vote_consensus_failed = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: false, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; assert!(!vote_consensus_failed.is_success()); // Failure case: troll resistance test failed let troll_resistance_failed = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: false, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; assert!(!troll_resistance_failed.is_success()); } /// Verify summary formatting. #[test] fn test_simulation_result_summary_format() { let success = SimulationResult { assertions_written: 10, assertions_verified: 10, queries_executed: 12, votes_written: 6, recency_test_passed: true, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: true, mv_integration_test_passed: true, fast_path_test_passed: true, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 3, errors: vec![], agent_count: 3, tick_count: 10, }; let summary = success.summary(); assert!(summary.contains("✅"), "Success should show checkmark"); assert!(summary.contains("10"), "Should show assertion count"); assert!(summary.contains("6"), "Should show vote count"); assert!(summary.contains("recency=✓"), "Should show recency passed"); assert!(summary.contains("lifecycle=✓"), "Should show lifecycle passed"); assert!(summary.contains("audit=✓"), "Should show audit passed"); assert!(summary.contains("vote_consensus=✓"), "Should show vote consensus passed"); assert!(summary.contains("troll_resist=✓"), "Should show troll resistance passed"); assert!(summary.contains("mv_integ=✓"), "Should show MV integration passed"); assert!(summary.contains("fast_path=✓"), "Should show fast-path passed"); assert!(summary.contains("mv_fresh=✓"), "Should show MV freshness passed"); let failure = SimulationResult { assertions_written: 10, assertions_verified: 8, queries_executed: 10, votes_written: 6, recency_test_passed: false, lifecycle_test_passed: true, audit_test_passed: true, vote_consensus_test_passed: true, troll_resistance_test_passed: false, mv_integration_test_passed: true, fast_path_test_passed: false, mv_freshness_test_passed: true, persona_test_passed: true, strategy_metrics: vec![], views_materialized: 2, errors: vec![stemedb_sim::SimulationError { tick: 5, kind: ErrorKind::VerificationFailure, message: "Test".to_string(), }], agent_count: 3, tick_count: 10, }; let summary = failure.summary(); assert!(summary.contains("❌"), "Failure should show X"); assert!(summary.contains("1 error"), "Should show error count"); assert!(summary.contains("recency=✗"), "Should show recency failed"); assert!(summary.contains("troll_resist=✗"), "Should show troll resistance failed"); assert!(summary.contains("fast_path=✗"), "Should show fast-path failed"); } /// Verify all error kinds are representable. #[test] fn test_error_kinds_are_complete() { // This test documents all error kinds - if a new one is added, // this test should be updated to cover it. let kinds = [ ErrorKind::WriteFailure, ErrorKind::VerificationFailure, ErrorKind::SignatureInvalid, ErrorKind::StorageCorruption, ErrorKind::SerializationFailure, ErrorKind::QueryFailure, ErrorKind::LensResolutionFailure, ErrorKind::AuditFailure, ErrorKind::VoteWriteFailure, ErrorKind::VoteConsensusFailure, ErrorKind::MaterializerFailure, ]; for kind in kinds { let error = stemedb_sim::SimulationError { tick: 0, kind, message: format!("{:?} test", kind) }; // Verify Debug trait works let debug_str = format!("{:?}", error); assert!(!debug_str.is_empty()); } } /// Verify minimum viable configuration works. /// Note: Minimal simulation requires at least 3 agents for voting tests. #[tokio::test] async fn smoke_minimal_simulation() { let config = SimulationConfig { agents: vec![ AgentSpec { count: 1, strategy: StrategyType::Scientist }, AgentSpec { count: 1, strategy: StrategyType::Troll }, AgentSpec { count: 1, strategy: StrategyType::Believer }, ], tick_count: 1, ingestion_wait_ms: 300, }; let result = run_simulation(config).await.expect("Simulation setup should not fail"); assert!(result.is_success(), "Minimal simulation should succeed: {:?}", result.errors); // Strategy-driven: agents may assert, vote, query, or skip per tick assert!(result.assertions_written >= 14, "Should have arena test assertions + base"); assert_eq!(result.agent_count, 3); assert_eq!(result.tick_count, 1); // All Arena 1 + 2 + 3 tests should pass assert!(result.recency_test_passed); assert!(result.lifecycle_test_passed); assert!(result.audit_test_passed); assert!(result.vote_consensus_test_passed); assert!(result.troll_resistance_test_passed); assert!(result.mv_integration_test_passed); assert!(result.fast_path_test_passed); assert!(result.mv_freshness_test_passed); }