//! Integration test: importer trait progress events fire in expected order. //! //! Drives a full `ChatGptImporter::import` against a fixture and asserts on //! the `ImportProgressEvent` sequence observed on the paired receiver. use std::sync::Arc; use tempfile::TempDir; use dirigent_archivist::{ backends::JsonlBackend, coordinator::Archivist, import::{ ImportConfig, ImportProgressEvent, ImportProgressSink, ImportTarget, ImporterRegistry, }, }; #[tokio::test] async fn progress_event_sequence_is_well_formed() { // 1. Setup an in-memory archivist (JsonlBackend in tempdir). let dir = TempDir::new().unwrap(); let backend = Arc::new(JsonlBackend::new(dir.path().to_path_buf()).await.unwrap()); let archivist = Archivist::from_single_backend("main".into(), backend) .await .unwrap(); let archivist = Arc::new(archivist); // 2. Use the chatgpt fixture — a minimal conversations.json with a // user + assistant message pair. let fixture = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../dirigent_chatgpt/tests/fixtures/minimal.json"); assert!( fixture.exists(), "chatgpt fixture missing at {}", fixture.display() ); let cfg = ImportConfig { source: "chatgpt".into(), params: { let mut m = std::collections::BTreeMap::new(); m.insert("path".into(), serde_json::json!(fixture.display().to_string())); m }, }; // 3. Run the import with a channel sink. let registry = ImporterRegistry::default(); let importer = registry.get("chatgpt").expect("chatgpt registered"); let (sink, mut rx) = ImportProgressSink::channel(); let archivist_for_job = archivist.clone(); let job = tokio::spawn(async move { importer .import(&cfg, &*archivist_for_job, ImportTarget::default(), sink) .await }); // 4. Collect all events until the sender side is dropped. let mut events = Vec::new(); while let Some(evt) = rx.recv().await { events.push(evt); } let stats = job.await.unwrap().expect("import"); // 5. Assertions on the event sequence. // Must contain at least one SessionStarted before any SessionFinished. let started_idx = events .iter() .position(|e| matches!(e, ImportProgressEvent::SessionStarted { .. })); let finished_idx = events .iter() .position(|e| matches!(e, ImportProgressEvent::SessionFinished { .. })); assert!(started_idx.is_some(), "expected a SessionStarted event"); assert!(finished_idx.is_some(), "expected a SessionFinished event"); assert!( started_idx.unwrap() < finished_idx.unwrap(), "SessionStarted must precede SessionFinished" ); // Stats shows at least 2 messages written (chatgpt fixture has a user // + assistant pair). assert!( stats.messages_written >= 2, "expected messages to be written, got stats {:?}", stats ); assert_eq!(stats.sessions_imported, 1); }