143 lines
6.1 KiB
Rust
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(())
|
|
}
|
|
}
|