Files
dirigent/crates/dirigent_archivist/tests/pagination_test.rs
T
2026-05-08 01:59:04 +02:00

143 lines
6.1 KiB
Rust

//! Pagination tests for dirigent_archivist
//!
//! These tests verify the count_messages and get_messages_range functionality.
#[cfg(test)]
mod pagination_tests {
use chrono::Utc;
use dirigent_archivist::{
backends::JsonlBackend, Archivist, MessageRecord, RegisterConnectorRequest,
RegisterSessionRequest, Result,
};
use std::sync::Arc;
use uuid::Uuid;
/// Build a self-contained coordinator rooted at `archive_root`, backed by
/// a single `JsonlBackend`. Avoids the shared `.archives.json` race that
/// `new_with_single_archive` creates in the tempdir's parent.
async fn mk_archivist(archive_root: std::path::PathBuf) -> Result<Archivist> {
let backend = Arc::new(JsonlBackend::new(archive_root).await?);
Archivist::from_single_backend("main".into(), backend).await
}
#[tokio::test]
async fn test_pagination_count_and_range() -> Result<()> {
let temp_dir = std::env::temp_dir().join(format!("archivist_test_{}", Uuid::now_v7()));
let archivist = mk_archivist(temp_dir.clone()).await?;
// Register connector
let connector_req = RegisterConnectorRequest {
r#type: "OpenCode".to_string(),
title: "Test Connector".to_string(),
client_native_id: "opencode@localhost:12225".to_string(),
custom_uid: None,
metadata: serde_json::json!({}),
fingerprint: None,
};
let connector_response = archivist.register_connector(connector_req, None).await?;
// Register session
let session_req = RegisterSessionRequest {
connector_uid: connector_response.connector_uid,
native_session_id: "native-123".to_string(),
title: Some("Pagination Test".to_string()),
custom_scroll_id: None,
metadata: serde_json::json!({}),
completeness: Default::default(),
parent_scroll_id: None,
is_subagent: false,
continuation: None,
agent_id: None,
subagent_type: None,
spawning_tool_use_id: None,
};
let session_response = archivist.register_session(session_req, None).await?;
let scroll_id = session_response.scroll_id;
// Test empty session
let count = archivist.count_messages(scroll_id, None).await?;
assert_eq!(count, 0, "Empty session should have 0 messages");
let range = archivist.get_messages_range(scroll_id, 0, 10, None).await?;
assert_eq!(range.len(), 0, "Empty session should return empty range");
// Add 25 messages with varying timestamps
let mut messages = Vec::new();
let base_time = Utc::now();
for i in 0..25 {
messages.push(MessageRecord {
version: 1,
message_id: Uuid::now_v7(),
session: scroll_id,
parent_id: None,
ts: base_time + chrono::Duration::seconds(i),
role: if i % 2 == 0 { "user" } else { "assistant" }.to_string(),
author: Some("test".to_string()),
content_md: format!("Message {}", i),
content_parts: None,
attachments: Vec::new(),
metadata: serde_json::json!({}),
});
}
archivist.append_messages(scroll_id, messages, None).await?;
// Test count_messages
let count = archivist.count_messages(scroll_id, None).await?;
assert_eq!(count, 25, "Should count 25 messages");
// Test get_messages_range - first page
let page1 = archivist.get_messages_range(scroll_id, 0, 10, None).await?;
assert_eq!(page1.len(), 10, "First page should have 10 messages");
assert_eq!(page1[0].content_md, "Message 0", "First message should be Message 0");
assert_eq!(page1[9].content_md, "Message 9", "10th message should be Message 9");
// Test get_messages_range - second page
let page2 = archivist.get_messages_range(scroll_id, 10, 10, None).await?;
assert_eq!(page2.len(), 10, "Second page should have 10 messages");
assert_eq!(page2[0].content_md, "Message 10", "11th message should be Message 10");
assert_eq!(page2[9].content_md, "Message 19", "20th message should be Message 19");
// Test get_messages_range - partial last page
let page3 = archivist.get_messages_range(scroll_id, 20, 10, None).await?;
assert_eq!(page3.len(), 5, "Last page should have 5 messages");
assert_eq!(page3[0].content_md, "Message 20", "21st message should be Message 20");
assert_eq!(page3[4].content_md, "Message 24", "25th message should be Message 24");
// Test get_messages_range - offset beyond messages
let page4 = archivist.get_messages_range(scroll_id, 30, 10, None).await?;
assert_eq!(page4.len(), 0, "Offset beyond messages should return empty");
// Verify chronological ordering is maintained in pagination
let all_messages = archivist.get_messages(scroll_id, None).await?;
let first_10_from_all = &all_messages[0..10];
let first_10_from_page = &page1[..];
for i in 0..10 {
assert_eq!(
first_10_from_all[i].message_id,
first_10_from_page[i].message_id,
"Pagination should maintain same order as get_messages()"
);
}
// Clean up
tokio::fs::remove_dir_all(temp_dir).await.ok();
Ok(())
}
#[tokio::test]
async fn test_count_messages_nonexistent_session() -> Result<()> {
let temp_dir = std::env::temp_dir().join(format!("archivist_test_{}", Uuid::now_v7()));
let archivist = mk_archivist(temp_dir.clone()).await?;
// Count messages for non-existent session (should return 0, not error)
let nonexistent_scroll_id = Uuid::now_v7();
let count = archivist.count_messages(nonexistent_scroll_id, None).await?;
assert_eq!(count, 0, "Non-existent session should have 0 messages");
// Clean up
tokio::fs::remove_dir_all(temp_dir).await.ok();
Ok(())
}
}