use serial_test::serial;
use terraphim_persistence::DeviceStorage;
use terraphim_service::conversation_service::{ConversationFilter, ConversationService};
use terraphim_types::{ChatMessage, RoleName};
#[tokio::test]
#[serial]
async fn test_create_and_get_conversation() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
let conversation = service
.create_conversation("Test Conversation".to_string(), RoleName::new("Test Role"))
.await
.unwrap();
let loaded = service.get_conversation(&conversation.id).await.unwrap();
assert_eq!(loaded.id, conversation.id);
assert_eq!(loaded.title, "Test Conversation");
assert_eq!(loaded.role, RoleName::new("Test Role"));
}
#[tokio::test]
#[serial]
async fn test_update_conversation() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
let mut conversation = service
.create_conversation("Original Title".to_string(), RoleName::new("Test Role"))
.await
.unwrap();
conversation.add_message(ChatMessage::user("Hello".to_string()));
conversation.add_message(ChatMessage::assistant(
"Hi there!".to_string(),
Some("gpt-4".to_string()),
));
let conversation = service.update_conversation(conversation).await.unwrap();
let loaded = service.get_conversation(&conversation.id).await.unwrap();
assert_eq!(loaded.messages.len(), 2);
assert_eq!(loaded.messages[0].content, "Hello");
assert_eq!(loaded.messages[1].content, "Hi there!");
}
#[tokio::test]
#[serial]
async fn test_list_conversations() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
let initial = service
.list_conversations(ConversationFilter::default())
.await
.unwrap();
let initial_count = initial.len();
service
.create_conversation("Conv 1".to_string(), RoleName::new("Role A"))
.await
.unwrap();
service
.create_conversation("Conv 2".to_string(), RoleName::new("Role B"))
.await
.unwrap();
service
.create_conversation("Conv 3".to_string(), RoleName::new("Role A"))
.await
.unwrap();
let all = service
.list_conversations(ConversationFilter::default())
.await
.unwrap();
assert_eq!(
all.len(),
initial_count + 3,
"Should have 3 new conversations"
);
let filtered = service
.list_conversations(ConversationFilter {
role: Some(RoleName::new("Role A")),
..Default::default()
})
.await
.unwrap();
assert!(
filtered.len() >= 2,
"Should have at least 2 Role A conversations, found {}",
filtered.len()
);
let titles: Vec<_> = filtered.iter().map(|c| c.title.as_str()).collect();
assert!(
titles.contains(&"Conv 1"),
"Conv 1 should be in filtered results"
);
assert!(
titles.contains(&"Conv 3"),
"Conv 3 should be in filtered results"
);
}
#[tokio::test]
#[serial]
async fn test_search_conversations() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
service
.create_conversation(
"Machine Learning Discussion".to_string(),
RoleName::new("AI"),
)
.await
.unwrap();
service
.create_conversation("Rust Programming Tips".to_string(), RoleName::new("Dev"))
.await
.unwrap();
service
.create_conversation("Python Data Science".to_string(), RoleName::new("AI"))
.await
.unwrap();
let results = service.search_conversations("machine").await.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].title, "Machine Learning Discussion");
let results = service.search_conversations("rust").await.unwrap();
assert_eq!(results.len(), 1);
}
#[tokio::test]
#[serial]
async fn test_delete_conversation() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
let conversation = service
.create_conversation("To Delete".to_string(), RoleName::new("Test"))
.await
.unwrap();
let loaded = service.get_conversation(&conversation.id).await;
assert!(loaded.is_ok());
service.delete_conversation(&conversation.id).await.unwrap();
let loaded = service.get_conversation(&conversation.id).await;
assert!(loaded.is_err());
}
#[tokio::test]
#[serial]
async fn test_export_import_conversation() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
let mut conversation = service
.create_conversation("Export Test".to_string(), RoleName::new("Test"))
.await
.unwrap();
conversation.add_message(ChatMessage::user("Test message".to_string()));
conversation.add_message(ChatMessage::assistant(
"Test response".to_string(),
Some("gpt-4".to_string()),
));
let conversation = service.update_conversation(conversation).await.unwrap();
let json = service.export_conversation(&conversation.id).await.unwrap();
assert!(json.contains("Export Test"));
assert!(json.contains("Test message"));
assert!(json.contains("Test response"));
service.delete_conversation(&conversation.id).await.unwrap();
let imported = service.import_conversation(&json).await.unwrap();
assert_eq!(imported.title, "Export Test");
assert_eq!(imported.messages.len(), 2);
assert_eq!(imported.messages[0].content, "Test message");
assert_eq!(imported.messages[1].content, "Test response");
}
#[tokio::test]
#[serial]
async fn test_get_statistics() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
let initial_stats = service.get_statistics().await.unwrap();
let initial_conversations = initial_stats.total_conversations;
let initial_messages = initial_stats.total_messages;
let mut conv1 = service
.create_conversation("Stat Conv 1".to_string(), RoleName::new("StatRole A"))
.await
.unwrap();
conv1.add_message(ChatMessage::user("Message 1".to_string()));
conv1.add_message(ChatMessage::assistant("Response 1".to_string(), None));
service.update_conversation(conv1).await.unwrap();
let mut conv2 = service
.create_conversation("Stat Conv 2".to_string(), RoleName::new("StatRole B"))
.await
.unwrap();
conv2.add_message(ChatMessage::user("Message 2".to_string()));
service.update_conversation(conv2).await.unwrap();
let mut conv3 = service
.create_conversation("Stat Conv 3".to_string(), RoleName::new("StatRole A"))
.await
.unwrap();
conv3.add_message(ChatMessage::user("Message 3".to_string()));
conv3.add_message(ChatMessage::assistant("Response 3".to_string(), None));
conv3.add_message(ChatMessage::user("Message 4".to_string()));
service.update_conversation(conv3).await.unwrap();
let stats = service.get_statistics().await.unwrap();
assert_eq!(
stats.total_conversations,
initial_conversations + 3,
"Should have 3 new conversations"
);
assert_eq!(
stats.total_messages,
initial_messages + 6,
"Should have 6 new messages"
);
assert!(
stats.conversations_by_role.contains_key("StatRole A"),
"StatRole A should be tracked"
);
assert!(
stats.conversations_by_role.contains_key("StatRole B"),
"StatRole B should be tracked"
);
assert_eq!(
*stats.conversations_by_role.get("StatRole A").unwrap(),
2,
"StatRole A should have 2 conversations"
);
assert_eq!(
*stats.conversations_by_role.get("StatRole B").unwrap(),
1,
"StatRole B should have 1 conversation"
);
}
#[tokio::test]
#[serial]
async fn test_conversation_ordering() {
let _ = DeviceStorage::init_memory_only().await.unwrap();
let service = ConversationService::new();
service
.create_conversation("First".to_string(), RoleName::new("Test"))
.await
.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
service
.create_conversation("Second".to_string(), RoleName::new("Test"))
.await
.unwrap();
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
service
.create_conversation("Third".to_string(), RoleName::new("Test"))
.await
.unwrap();
let conversations = service
.list_conversations(ConversationFilter::default())
.await
.unwrap();
assert_eq!(conversations[0].title, "Third");
assert_eq!(conversations[1].title, "Second");
assert_eq!(conversations[2].title, "First");
}