use dirigent_archivist::{ coordinator::Archivist, error::ArchivistBootError, registry::{ArchivesConfig, BackendRegistry}, }; fn parse(toml_src: &str) -> ArchivesConfig { toml::from_str(toml_src).unwrap() } #[tokio::test] async fn boot_with_one_jsonl_archive() { let dir = tempfile::tempdir().unwrap(); let cfg = parse(&format!( r#" [[archives]] name = "main" type = "jsonl" [archives.params] path = "{}" "#, dir.path().to_string_lossy().replace('\\', "/") )); let registry = BackendRegistry::with_jsonl(); let _archivist = Archivist::from_config(cfg, ®istry, None).await.unwrap(); } #[tokio::test] async fn boot_empty_config_is_ephemeral() { let cfg: ArchivesConfig = toml::from_str("").unwrap(); let registry = BackendRegistry::with_jsonl(); let archivist = Archivist::from_config(cfg, ®istry, None).await.unwrap(); let archives = archivist.list_archives().await.unwrap(); assert!(archives.is_empty()); } #[tokio::test] async fn boot_unknown_type_errors() { let cfg = parse( r#" [[archives]] name = "x" type = "nope" [archives.params] "#, ); let registry = BackendRegistry::with_jsonl(); let result = Archivist::from_config(cfg, ®istry, None).await; match result { Ok(_) => panic!("expected UnknownType error"), Err(err) => assert!( matches!(err, ArchivistBootError::UnknownType { .. }), "expected UnknownType, got {err:?}" ), } } #[tokio::test] async fn boot_no_primary_errors() { let cfg = parse( r#" [[archives]] name = "mirror" type = "jsonl" failure_mode = "best_effort" [archives.params] path = "/tmp/whatever" "#, ); let registry = BackendRegistry::with_jsonl(); let result = Archivist::from_config(cfg, ®istry, None).await; match result { Ok(_) => panic!("expected Validation error"), Err(err) => assert!( matches!(err, ArchivistBootError::Validation(_)), "expected Validation, got {err:?}" ), } } #[tokio::test] async fn boot_duplicate_name_errors() { let dir = tempfile::tempdir().unwrap(); let cfg = parse(&format!( r#" [[archives]] name = "main" type = "jsonl" [archives.params] path = "{p}" [[archives]] name = "main" type = "jsonl" [archives.params] path = "{p}" "#, p = dir.path().to_string_lossy().replace('\\', "/"), )); let registry = BackendRegistry::with_jsonl(); let result = Archivist::from_config(cfg, ®istry, None).await; match result { Ok(_) => panic!("expected Validation error"), Err(err) => assert!( matches!(err, ArchivistBootError::Validation(_)), "expected Validation, got {err:?}" ), } } #[test] fn example_toml_parses() { // Load the full dirigent.toml.example and parse just the [[archives]] // section as `ArchivesConfig`. Confirms the example's archive syntax is // valid Phase 3 schema. let src = std::fs::read_to_string( std::path::Path::new(env!("CARGO_MANIFEST_DIR")) .join("../../dirigent.toml.example"), ) .expect("dirigent.toml.example present at workspace root"); // Parse the whole file as a TOML value, then try to deserialize the // full document into `ArchivesConfig`. Any `archives` subtable gets picked up; // other top-level fields (connectors, matrix, ...) are ignored because // `ArchivesConfig` only has `entries: Vec` via // `#[serde(rename = "archives")]`. let cfg: ArchivesConfig = toml::from_str(&src).expect("ArchivesConfig from full example"); cfg.validate().expect("example config validates"); assert!(!cfg.entries.is_empty(), "example must declare at least one archive"); }