//! Shared test utilities for HTTP integration tests. #![allow(clippy::expect_used)] #![allow(dead_code)] use ed25519_dalek::{Signer, SigningKey}; use rand::rngs::OsRng; use serde_json::json; use std::sync::Arc; use stemedb_api::AppState; use stemedb_ingest::Ingestor; use stemedb_storage::HybridStore; use stemedb_wal::Journal; use tokio::sync::Mutex; /// Test environment that keeps temp directories alive for the test duration. pub struct TestEnvironment { pub _temp_dir: tempfile::TempDir, pub state: AppState, } /// Test environment with full ingestor for roundtrip tests. pub struct TestEnvironmentWithIngestor { pub _temp_dir: tempfile::TempDir, pub state: AppState, pub ingestor: Ingestor, } /// Helper to create a test environment with temporary directories. pub async fn create_test_env() -> TestEnvironment { let temp_dir = tempfile::tempdir().expect("failed to create temp dir"); let wal_dir = temp_dir.path().join("wal"); let db_dir = temp_dir.path().join("db"); std::fs::create_dir_all(&wal_dir).expect("failed to create wal dir"); std::fs::create_dir_all(&db_dir).expect("failed to create db dir"); let write_journal = Journal::open(&wal_dir).expect("failed to open write journal"); let read_journal = Journal::open(&wal_dir).expect("failed to open read journal"); let store = Arc::new(HybridStore::open(&db_dir).expect("failed to open store")); let state = AppState::new(write_journal, read_journal, store); TestEnvironment { _temp_dir: temp_dir, state } } /// Helper to create a test environment with a running ingestor for roundtrip tests. /// /// Note: We need to share the same store between AppState and Ingestor. pub async fn create_test_env_with_ingestor() -> TestEnvironmentWithIngestor { let temp_dir = tempfile::tempdir().expect("failed to create temp dir"); let wal_dir = temp_dir.path().join("wal"); let db_dir = temp_dir.path().join("db"); std::fs::create_dir_all(&wal_dir).expect("failed to create wal dir"); std::fs::create_dir_all(&db_dir).expect("failed to create db dir"); // Create shared store let store = Arc::new(HybridStore::open(&db_dir).expect("failed to open store")); // Journal for ingestor (reading) - WAL allows multiple readers let journal_for_ingestor = Arc::new(Mutex::new(Journal::open(&wal_dir).expect("failed to open journal for ingestor"))); // Create ingestor with shared store let ingestor = Ingestor::new(journal_for_ingestor, store.clone()) .await .expect("failed to create ingestor"); // Create AppState with write and read journals let write_journal = Journal::open(&wal_dir).expect("failed to open write journal"); let read_journal = Journal::open(&wal_dir).expect("failed to open read journal"); let state = AppState::new(write_journal, read_journal, store); TestEnvironmentWithIngestor { _temp_dir: temp_dir, state, ingestor } } /// Helper to sign a message using Ed25519. #[allow(dead_code)] pub fn sign_message(message: &str) -> ([u8; 32], [u8; 64]) { let mut csprng = OsRng; let signing_key = SigningKey::generate(&mut csprng); let verifying_key = signing_key.verifying_key(); let signature = signing_key.sign(message.as_bytes()); (verifying_key.to_bytes(), signature.to_bytes()) } /// Create a properly signed assertion for testing. pub fn create_signed_assertion_json( subject: &str, predicate: &str, value: f64, ) -> serde_json::Value { let mut csprng = OsRng; let signing_key = SigningKey::generate(&mut csprng); let verifying_key = signing_key.verifying_key(); let message = format!("{}:{}", subject, predicate); let signature = signing_key.sign(message.as_bytes()); let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .map(|d| d.as_secs()) .unwrap_or(0); json!({ "subject": subject, "predicate": predicate, "object": {"type": "Number", "value": value}, "confidence": 0.95, "source_class": "Expert", "lifecycle": "Proposed", "signatures": [{ "agent_id": hex::encode(verifying_key.to_bytes()), "signature": hex::encode(signature.to_bytes()), "timestamp": timestamp }], "source_hash": "0".repeat(64), "timestamp": timestamp }) }