Dirigent Protocol Tests
This directory contains comprehensive tests for the Dirigent protocol and OpenCode adapter.
Test Files
protocol_tests.rs
Core protocol translation tests that verify OpenCode events are correctly translated to Dirigent protocol events.
Coverage:
- Session creation and updates
- User and assistant messages
- Message parts (text, thinking, tool)
- Event stream parsing
- Protocol serialization/deserialization
Run: cargo test --test protocol_tests
deduplication_tests.rs
Tests for the stateful adapter's deduplication logic, ensuring no duplicate messages or parts appear in the UI.
Coverage:
- Duplicate
MessageStartedfiltering - Duplicate
MessageCompletedfiltering - Part completion signal (
delta: null) filtering - Different part types not being filtered
- Streaming part updates working correctly
- Full tit-tat conversation flow
- Adapter state independence
Run: cargo test --test deduplication_tests
session_list_tests.rs
Tests for parsing OpenCode session list responses.
Coverage:
- Session list array parsing
- Empty session list handling
- Single session deserialization
- Optional fields handling
- Timestamp parsing validation
Run: cargo test --test session_list_tests
Fixtures
fixtures/sample_events.jsonl
Sample OpenCode SSE events in JSONL format (one event per line). Used for parsing validation and event stream testing.
fixtures/opencode_session_response.json
Real OpenCode session list response. Used for session deserialization tests.
Source: Copied from /docs/building/opencode_session_response.json
Running All Tests
# Run all protocol tests
cargo test --package dirigent_protocol
# Run with output
cargo test --package dirigent_protocol -- --nocapture
# Run specific test
cargo test --package dirigent_protocol test_tit_tat_flow
# Run tests matching pattern
cargo test --package dirigent_protocol duplicate
Adding New Tests
For OpenCode Event Translation
Add to protocol_tests.rs:
#[test]
fn test_translate_new_feature() {
let adapter = OpenCodeAdapter::new();
// Create OpenCode event
let oc_event = oc::Event::YourEvent { ... };
// Translate
let result = adapter.translate_event(oc_event);
// Assert
assert!(result.is_ok());
match result.unwrap() {
Event::YourDirigentEvent(data) => {
assert_eq!(data.field, expected_value);
}
_ => panic!("Expected YourDirigentEvent"),
}
}
For Deduplication Logic
Add to deduplication_tests.rs:
#[test]
fn test_new_deduplication_rule() {
let adapter = OpenCodeAdapter::new();
// Send first event
let result1 = adapter.translate_event(first_event);
assert!(result1.is_ok());
// Send duplicate event
let result2 = adapter.translate_event(duplicate_event);
assert!(result2.is_err());
assert!(matches!(result2.unwrap_err(), TranslationError::Duplicate));
}
For New Fixtures
- Place fixture file in
tests/fixtures/ - Use
include_str!to load it:let fixture = include_str!("fixtures/your_file.json");
Test Principles
Stateful Adapter Pattern
⚠️ IMPORTANT: The adapter maintains state, so:
// ✅ CORRECT: One adapter for entire event stream
let adapter = OpenCodeAdapter::new();
for event in events {
adapter.translate_event(event);
}
// ❌ WRONG: New adapter each time (loses state!)
for event in events {
let adapter = OpenCodeAdapter::new();
adapter.translate_event(event);
}
Testing Duplicates
When testing deduplication:
- Send the first event → should succeed
- Send the duplicate event → should fail with
TranslationError::Duplicate - Always use the SAME adapter instance
Real-World Fixtures
Fixtures should come from actual OpenCode API responses when possible:
- Captures real-world edge cases
- Ensures compatibility with API changes
- Documents actual behavior
CI Integration
These tests run automatically on:
- Every commit (via
cargo test) - Pull requests
- Before releases
Status: All tests should pass before merging.
Coverage Report
# Install tarpaulin for coverage
cargo install cargo-tarpaulin
# Generate coverage report
cargo tarpaulin --package dirigent_protocol --out Html
Related Documentation
- SSE Deduplication - How deduplication works
- SSE Event Flow Analysis - OpenCode event patterns
- Protocol Abstraction Plan - Adapter architecture
Test Statistics
Last Updated: 2025-11-01
- Total Tests: 24
- Deduplication Tests: 7
- Session Tests: 5
- Protocol Tests: 12
- All Passing: ✅
Troubleshooting
Test Fails with "argument #1 of type &OpenCodeAdapter is missing"
Problem: You're calling OpenCodeAdapter::translate_event(event) as a static method.
Solution: Create an adapter instance first:
let adapter = OpenCodeAdapter::new();
let result = adapter.translate_event(event);
Test Fails with "pattern does not mention field part_id"
Problem: The MessagePartAdded event now includes a part_id field.
Solution: Update your pattern match:
// Before
Event::MessagePartAdded { message_id, part, delta } => { ... }
// After
Event::MessagePartAdded { message_id, part_id: _, part, delta } => { ... }
Deduplication Test Unexpectedly Passes
Problem: You're creating a new adapter for each event.
Solution: Create ONE adapter and reuse it:
let adapter = OpenCodeAdapter::new();
adapter.translate_event(event1); // First time
adapter.translate_event(event1); // Should be duplicate!