From c17e286db183a5321a19d0004e1148bd87a9d488 Mon Sep 17 00:00:00 2001 From: xiaoxixi Date: Tue, 28 Apr 2026 22:17:02 +0800 Subject: [PATCH] =?UTF-8?q?test(storage):=20=E7=BC=96=E5=86=99=20Storage?= =?UTF-8?q?=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- src/storage/mod.rs | 161 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 337065e..b4c6b0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,4 +33,4 @@ termimad = "0.34" textwrap = "0.16" chrono = "0.4" hostname = "0.3" -sqlx = { version = "0.8", features = ["sqlite", "macros", "chrono"] } +sqlx = { version = "0.8", features = ["sqlite", "macros", "chrono", "runtime-tokio"] } diff --git a/src/storage/mod.rs b/src/storage/mod.rs index 7c59c4c..a5fbd51 100644 --- a/src/storage/mod.rs +++ b/src/storage/mod.rs @@ -361,3 +361,164 @@ impl Storage { unreachable!() } } + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + + async fn create_test_storage() -> (Storage, TempDir) { + let dir = tempfile::tempdir().unwrap(); + let db_path = dir.path().join("test.db"); + let storage = Storage::new(&db_path).await.unwrap(); + (storage, dir) + } + + #[tokio::test] + async fn test_upsert_and_get_session() { + let (storage, _dir) = create_test_storage().await; + + let meta = crate::storage::session::SessionMeta { + id: "cli_chat:sid123:dialog1".to_string(), + channel: "cli_chat".to_string(), + chat_id: "sid123".to_string(), + dialog_id: "dialog1".to_string(), + title: "测试会话".to_string(), + created_at: 1000, + last_active_at: 1000, + message_count: 0, + routing_info: Some(r#"{"type":"cli"}"#.to_string()), + deleted_at: None, + }; + + storage.upsert_session(&meta).await.unwrap(); + + let loaded = storage.get_session(&meta.id).await.unwrap(); + assert_eq!(loaded.title, "测试会话"); + assert_eq!(loaded.channel, "cli_chat"); + } + + #[tokio::test] + async fn test_get_nonexistent_session() { + let (storage, _dir) = create_test_storage().await; + + let result = storage.get_session("nonexistent").await; + assert!(result.is_err()); + matches!(result.unwrap_err(), StorageError::NotFound(_)); + } + + #[tokio::test] + async fn test_list_sessions() { + let (storage, _dir) = create_test_storage().await; + + for i in 0..5 { + let meta = crate::storage::session::SessionMeta { + id: format!("cli_chat:sid123:dialog{}", i), + channel: "cli_chat".to_string(), + chat_id: "sid123".to_string(), + dialog_id: format!("dialog{}", i), + title: format!("会话{}", i), + created_at: i as i64 * 1000, + last_active_at: i as i64 * 1000, + message_count: i, + routing_info: None, + deleted_at: None, + }; + storage.upsert_session(&meta).await.unwrap(); + } + + let sessions = storage.list_sessions("cli_chat", "sid123", 10).await.unwrap(); + assert_eq!(sessions.len(), 5); + // 按 last_active_at DESC 排序 + assert_eq!(sessions[0].dialog_id, "dialog4"); + } + + #[tokio::test] + async fn test_soft_delete() { + let (storage, _dir) = create_test_storage().await; + + let meta = crate::storage::session::SessionMeta { + id: "cli_chat:sid123:dialog1".to_string(), + channel: "cli_chat".to_string(), + chat_id: "sid123".to_string(), + dialog_id: "dialog1".to_string(), + title: "测试".to_string(), + created_at: 1000, + last_active_at: 1000, + message_count: 0, + routing_info: None, + deleted_at: None, + }; + + storage.upsert_session(&meta).await.unwrap(); + storage.soft_delete_session(&meta.id).await.unwrap(); + + let result = storage.get_session(&meta.id).await; + assert!(result.is_err()); + matches!(result.unwrap_err(), StorageError::NotFound(_)); + } + + #[tokio::test] + async fn test_append_and_load_messages() { + let (storage, _dir) = create_test_storage().await; + + let session_meta = crate::storage::session::SessionMeta { + id: "cli_chat:sid123:dialog1".to_string(), + channel: "cli_chat".to_string(), + chat_id: "sid123".to_string(), + dialog_id: "dialog1".to_string(), + title: "测试".to_string(), + created_at: 1000, + last_active_at: 1000, + message_count: 0, + routing_info: None, + deleted_at: None, + }; + storage.upsert_session(&session_meta).await.unwrap(); + + let msg = crate::storage::message::MessageMeta { + id: "msg1".to_string(), + session_id: session_meta.id.clone(), + seq: 1, + role: "user".to_string(), + content: "你好".to_string(), + media_refs: None, + tool_call_id: None, + tool_name: None, + tool_calls: None, + created_at: 1000, + }; + + let seq = storage.append_message(&session_meta.id, &msg).await.unwrap(); + assert_eq!(seq, 1); + + let loaded = storage.load_messages(&session_meta.id, 0).await.unwrap(); + assert_eq!(loaded.len(), 1); + assert_eq!(loaded[0].content, "你好"); + } + + #[tokio::test] + async fn test_touch_session() { + let (storage, _dir) = create_test_storage().await; + + let meta = crate::storage::session::SessionMeta { + id: "cli_chat:sid123:dialog1".to_string(), + channel: "cli_chat".to_string(), + chat_id: "sid123".to_string(), + dialog_id: "dialog1".to_string(), + title: "测试".to_string(), + created_at: 1000, + last_active_at: 1000, + message_count: 0, + routing_info: None, + deleted_at: None, + }; + storage.upsert_session(&meta).await.unwrap(); + + storage.touch_session(&meta.id, 5, 2000).await.unwrap(); + + let loaded = storage.get_session(&meta.id).await.unwrap(); + assert_eq!(loaded.message_count, 5); + assert_eq!(loaded.last_active_at, 2000); + } +}