sync from monorepo @ 2452e92e

This commit is contained in:
2026-05-08 01:59:04 +02:00
commit b03dc15371
459 changed files with 129586 additions and 0 deletions
@@ -0,0 +1,89 @@
//! 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);
}