From 760ad2e5f87a31d7588d932c40c09149a2c00924 Mon Sep 17 00:00:00 2001 From: shay7sev Date: Thu, 22 Jan 2026 17:41:59 +0800 Subject: [PATCH] feat(test): add tests --- .env.example | 1 + src/model.rs | 16 ++++++++++++ tests/db_test.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++ tests/file_test.rs | 47 +++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 .env.example create mode 100644 tests/db_test.rs create mode 100644 tests/file_test.rs diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ab8c0e4 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +DATABASE_URL=postgres://user:password@ip:port/db \ No newline at end of file diff --git a/src/model.rs b/src/model.rs index ce3b371..102494c 100644 --- a/src/model.rs +++ b/src/model.rs @@ -36,3 +36,19 @@ pub struct LogRecord { pub module: String, pub trace_id: Option, } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_level_ordering() { + assert!(LogLevel::ERROR > LogLevel::INFO); + assert!(LogLevel::DEBUG < LogLevel::FATAL); + } + + #[test] + fn test_level_display() { + assert_eq!(LogLevel::INFO.to_string(), "INFO"); + } +} diff --git a/tests/db_test.rs b/tests/db_test.rs new file mode 100644 index 0000000..995df8f --- /dev/null +++ b/tests/db_test.rs @@ -0,0 +1,61 @@ +use std::env; + +use chrono::Utc; +// tests/db_test.rs +use dotenv::dotenv; +use rust_logger::model::{LogLevel, LogRecord}; +use rust_logger::outputs::LogOutput; +use rust_logger::outputs::postgres::PostgresOutput; +use sqlx::postgres::PgPoolOptions; + +#[sqlx::test] // sqlx 提供的强大宏,自动为每个测试创建一个临时数据库 +async fn test_postgres_write() { + dotenv().ok(); + let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&db_url) + .await + .unwrap(); + // 1. 准备表结构 (需要在测试库里建表) + sqlx::query( + r#" + CREATE TABLE IF NOT EXISTS app_logs ( + id BIGSERIAL PRIMARY KEY, + service_name VARCHAR(50), + log_level VARCHAR(10), + message TEXT, + module VARCHAR(100), + created_at TIMESTAMPTZ, + trace_id VARCHAR(64) + ) + "#, + ) + .execute(&pool) + .await + .unwrap(); + + // 2. 初始化 Output + let output = PostgresOutput::new(pool.clone()); + + // 3. 写入日志 + // ... 构造 record ... + let record = LogRecord { + service_name: "db_test".into(), + timestamp: Utc::now(), + level: LogLevel::INFO, + message: "Hello Integration Test Db".into(), + module: "tests".into(), + trace_id: Some("123-abc".into()), + }; + output.write(&record).await; + + // 4. 验证是否写入 + let count: i64 = + sqlx::query_scalar("SELECT count(*) FROM app_logs WHERE service_name = 'db_test'") + .fetch_one(&pool) + .await + .unwrap(); + + assert!(count > 1); +} diff --git a/tests/file_test.rs b/tests/file_test.rs new file mode 100644 index 0000000..9abd8e2 --- /dev/null +++ b/tests/file_test.rs @@ -0,0 +1,47 @@ +// tests/file_test.rs +use chrono::Utc; +use rust_logger::model::{LogLevel, LogRecord}; +use rust_logger::outputs::LogOutput; +use rust_logger::outputs::file::FileOutput; +use std::fs; +use std::path::Path; + +#[tokio::test] // 使用 tokio 的测试宏 +async fn test_file_output_write() { + let dir = "test_logs"; + let prefix = "test-service"; + + // 1. 清理环境 (确保之前跑剩下的文件删掉) + if Path::new(dir).exists() { + fs::remove_dir_all(dir).unwrap(); + } + + // 2. 初始化 Output + let output = FileOutput::new(dir, prefix) + .await + .expect("Failed to create output"); + + // 3. 构造一条假日志 + let record = LogRecord { + service_name: "file_test".into(), + timestamp: Utc::now(), + level: LogLevel::INFO, + message: "Hello Integration Test File".into(), + module: "tests".into(), + trace_id: Some("123-abc".into()), + }; + + // 4. 写入 + output.write(&record).await; + + // 5. 验证文件是否存在且内容正确 + let mut entries = fs::read_dir(dir).unwrap(); + let entry = entries.next().unwrap().unwrap(); + let content = fs::read_to_string(entry.path()).unwrap(); + + assert!(content.contains("Hello Integration Test")); + assert!(content.contains("[INFO]")); + + // 6. 清理 + fs::remove_dir_all(dir).unwrap(); +}