c62d8daea8
Move all 29 workspace members from packages/<name>/ to crates/<name>/. Updates: workspace Cargo.toml (members + path deps), justfile, root CLAUDE.md, scripts/build/CARGO_INSTALL.md, docs/architecture/crates.md (renamed from packages.md), structural references in docs/architecture and docs/configuration, per-crate CLAUDE.md self-references. Historical plans, reports, and building/ docs are left untouched. No behavior change; just check-all stays green and fermata tests pass.
279 lines
9.1 KiB
Rust
279 lines
9.1 KiB
Rust
//! Integration tests for fixture loading and validation.
|
|
|
|
use dirigate::fixture::{load_and_validate, load_fixture, load_fixtures_from_dir, validate_fixture};
|
|
use std::path::PathBuf;
|
|
|
|
fn test_fixture_path(name: &str) -> PathBuf {
|
|
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
.join("tests")
|
|
.join("fixtures")
|
|
.join(name)
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_valid_basic_fixture() {
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_fixture(&path).await.expect("Failed to load fixture");
|
|
|
|
assert_eq!(fixture.version, "0.1");
|
|
assert_eq!(fixture.sessions.len(), 1);
|
|
assert_eq!(fixture.sessions[0].id, "session-1");
|
|
assert_eq!(fixture.sessions[0].title, "Basic Test Session");
|
|
assert_eq!(fixture.sessions[0].participants.len(), 2);
|
|
assert_eq!(fixture.sessions[0].messages.len(), 2);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_valid_complex_fixture() {
|
|
let path = test_fixture_path("valid_complex.yaml");
|
|
let fixture = load_fixture(&path).await.expect("Failed to load fixture");
|
|
|
|
assert_eq!(fixture.version, "0.1");
|
|
assert_eq!(fixture.sessions.len(), 2);
|
|
|
|
// Check first session
|
|
let session1 = &fixture.sessions[0];
|
|
assert_eq!(session1.id, "session-chat");
|
|
assert_eq!(session1.participants.len(), 3);
|
|
assert_eq!(session1.messages.len(), 4);
|
|
|
|
// Check message metadata
|
|
let msg3 = &session1.messages[2];
|
|
assert!(msg3.metadata.is_some());
|
|
|
|
// Check second session with behavior override
|
|
let session2 = &fixture.sessions[1];
|
|
assert_eq!(session2.id, "session-debug");
|
|
assert!(session2.behavior.is_some());
|
|
|
|
// Check responders config
|
|
assert_eq!(fixture.responders.keyword_map.len(), 2);
|
|
assert!(fixture.responders.random.is_some());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_valid_basic_fixture() {
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_fixture(&path).await.expect("Failed to load fixture");
|
|
|
|
// Should validate successfully
|
|
validate_fixture(&fixture).expect("Fixture validation failed");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_valid_complex_fixture() {
|
|
let path = test_fixture_path("valid_complex.yaml");
|
|
let fixture = load_fixture(&path).await.expect("Failed to load fixture");
|
|
|
|
// Should validate successfully
|
|
validate_fixture(&fixture).expect("Fixture validation failed");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_and_validate_valid() {
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load and validate");
|
|
|
|
assert_eq!(fixture.version, "0.1");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_invalid_version() {
|
|
let path = test_fixture_path("invalid_version.yaml");
|
|
let fixture = load_fixture(&path).await.expect("Failed to load fixture");
|
|
|
|
let result = validate_fixture(&fixture);
|
|
assert!(result.is_err());
|
|
|
|
let err = result.unwrap_err();
|
|
assert!(err.to_string().contains("Invalid version"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_and_validate_invalid_version() {
|
|
let path = test_fixture_path("invalid_version.yaml");
|
|
let result = load_and_validate(&path).await;
|
|
|
|
assert!(result.is_err());
|
|
let err = result.unwrap_err();
|
|
assert!(err.to_string().contains("Invalid version"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_duplicate_session_ids() {
|
|
let path = test_fixture_path("invalid_duplicate_session.yaml");
|
|
let fixture = load_fixture(&path).await.expect("Failed to load fixture");
|
|
|
|
let result = validate_fixture(&fixture);
|
|
assert!(result.is_err());
|
|
|
|
let err = result.unwrap_err();
|
|
assert!(err.to_string().contains("Duplicate session ID"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_bad_yaml() {
|
|
let path = test_fixture_path("invalid_bad_yaml.yaml");
|
|
let result = load_fixture(&path).await;
|
|
|
|
assert!(result.is_err());
|
|
let err = result.unwrap_err();
|
|
assert!(err.to_string().contains("Failed to parse YAML"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_validate_bad_timestamp() {
|
|
let path = test_fixture_path("invalid_bad_timestamp.yaml");
|
|
let fixture = load_fixture(&path).await.expect("Failed to load fixture");
|
|
|
|
let result = validate_fixture(&fixture);
|
|
assert!(result.is_err());
|
|
|
|
let err = result.unwrap_err();
|
|
assert!(err.to_string().contains("invalid ISO8601 timestamp"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_nonexistent_file() {
|
|
let path = test_fixture_path("does_not_exist.yaml");
|
|
let result = load_fixture(&path).await;
|
|
|
|
assert!(result.is_err());
|
|
let err = result.unwrap_err();
|
|
assert!(err.to_string().contains("Failed to read file"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_fixtures_from_directory() {
|
|
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
.join("tests")
|
|
.join("fixtures");
|
|
|
|
let fixtures = load_fixtures_from_dir(&dir).await.expect("Failed to load fixtures from directory");
|
|
|
|
// Should load the 2 valid fixtures, skipping the invalid ones
|
|
assert_eq!(fixtures.len(), 2);
|
|
|
|
// Verify we got the right fixtures
|
|
let ids: Vec<_> = fixtures.iter()
|
|
.flat_map(|f| f.sessions.iter().map(|s| s.id.as_str()))
|
|
.collect();
|
|
|
|
assert!(ids.contains(&"session-1") || ids.contains(&"session-chat"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_load_fixtures_from_empty_directory() {
|
|
// Create a temporary empty directory
|
|
let temp_dir = std::env::temp_dir().join("dirigent_test_empty");
|
|
tokio::fs::create_dir_all(&temp_dir).await.ok();
|
|
|
|
let fixtures = load_fixtures_from_dir(&temp_dir).await.expect("Failed to load from empty directory");
|
|
|
|
// Should return empty vector, not error
|
|
assert_eq!(fixtures.len(), 0);
|
|
|
|
// Cleanup
|
|
tokio::fs::remove_dir_all(&temp_dir).await.ok();
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_message_parent_references() {
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
// Check that parent_id references are valid
|
|
let session = &fixture.sessions[0];
|
|
let msg2 = &session.messages[1];
|
|
|
|
assert_eq!(msg2.parent_id, Some("msg-1".to_string()));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_session_behavior_overrides() {
|
|
let path = test_fixture_path("valid_complex.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
// Second session should have behavior overrides
|
|
let session2 = &fixture.sessions[1];
|
|
assert!(session2.behavior.is_some());
|
|
|
|
let behavior = session2.behavior.as_ref().unwrap();
|
|
assert!(behavior.responder.is_some());
|
|
assert!(behavior.streaming.is_some());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_participant_kinds() {
|
|
use dirigate::fixture::ParticipantKind;
|
|
|
|
let path = test_fixture_path("valid_complex.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
let session = &fixture.sessions[0];
|
|
let participant_kinds: Vec<_> = session.participants.iter()
|
|
.map(|p| &p.kind)
|
|
.collect();
|
|
|
|
assert!(participant_kinds.contains(&&ParticipantKind::User));
|
|
assert!(participant_kinds.contains(&&ParticipantKind::Assistant));
|
|
assert!(participant_kinds.contains(&&ParticipantKind::System));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_message_roles() {
|
|
use dirigate::fixture::MessageRole;
|
|
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
let messages = &fixture.sessions[0].messages;
|
|
assert_eq!(messages[0].role, MessageRole::User);
|
|
assert_eq!(messages[1].role, MessageRole::Assistant);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_responder_strategies() {
|
|
use dirigate::fixture::ResponderStrategy;
|
|
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
assert_eq!(fixture.responders.default_strategy, ResponderStrategy::Echo);
|
|
|
|
let path2 = test_fixture_path("valid_complex.yaml");
|
|
let fixture2 = load_and_validate(&path2).await.expect("Failed to load fixture");
|
|
|
|
assert_eq!(fixture2.responders.default_strategy, ResponderStrategy::Keywords);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_streaming_configuration() {
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
assert!(fixture.streaming.enabled);
|
|
assert_eq!(fixture.streaming.tokens_per_chunk, 5);
|
|
assert_eq!(fixture.streaming.chunk_interval_ms, 100);
|
|
assert_eq!(fixture.streaming.jitter_ms, Some(20));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_keyword_map() {
|
|
let path = test_fixture_path("valid_basic.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
assert_eq!(fixture.responders.keyword_map.get("hello"), Some(&"Hi there!".to_string()));
|
|
assert_eq!(fixture.responders.keyword_map.get("help"), Some(&"I can assist you with various tasks.".to_string()));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_random_config() {
|
|
let path = test_fixture_path("valid_complex.yaml");
|
|
let fixture = load_and_validate(&path).await.expect("Failed to load fixture");
|
|
|
|
let random_config = fixture.responders.random.as_ref().expect("Missing random config");
|
|
assert_eq!(random_config.seed, 42);
|
|
assert_eq!(random_config.corpus.len(), 3);
|
|
}
|