From 18c6d2b0dd77b38f487747aad1fcd1218aa8c356 Mon Sep 17 00:00:00 2001
From: yj <2077506045@qq.com>
Date: 星期三, 27 八月 2025 09:19:57 +0800
Subject: [PATCH] 1. 新增测试群组关键字,测试群组名称包含关键字,在其中发言一律不触发静默。

---
 app/services/friend_ignore_service.py |   16 ++
 /dev/null                             |  177 -----------------------------------
 app/services/silence_service.py       |   41 ++++++++
 config.py                             |    3 
 app/services/message_processor.py     |    4 
 logs/app.log                          |    5 
 6 files changed, 61 insertions(+), 185 deletions(-)

diff --git a/app/services/friend_ignore_service.py b/app/services/friend_ignore_service.py
index 061c771..2b0123f 100644
--- a/app/services/friend_ignore_service.py
+++ b/app/services/friend_ignore_service.py
@@ -8,6 +8,7 @@
 from app.services.redis_queue import redis_queue
 from app.models.database import get_db
 from app.models.contact import Contact
+from app.services.silence_service import silence_service
 from config import settings
 
 
@@ -84,18 +85,20 @@
             logger.error(f"娣诲姞濂藉弸鍒板拷鐣ュ垪琛ㄥ紓甯�: error={str(e)}")
             return False
 
-    def is_friend_ignored(self, w_id: str) -> bool:
+    def is_friend_ignored(self, w_id: str, group_id: Optional[str] = None) -> bool:
         """
         妫�鏌ユ寚瀹歸_id鏄惁搴旇琚拷鐣�
 
         閫昏緫锛�
         1. 濡傛灉濂藉弸蹇界暐鍔熻兘鏈惎鐢紝杩斿洖False锛堜笉蹇界暐锛�
         2. 濡傛灉w_id鍦ㄧ櫧鍚嶅崟涓紝杩斿洖False锛堜笉蹇界暐锛�
-        3. 濡傛灉w_id鍦ㄥ拷鐣ュ垪琛ㄤ腑锛岃繑鍥濼rue锛堝拷鐣ワ級
-        4. 濡傛灉w_id涓嶅湪蹇界暐鍒楄〃涓紝杩斿洖False锛堜笉蹇界暐锛�
+        3. 濡傛灉w_id鍦ㄥ拷鐣ュ垪琛ㄤ腑锛屼絾鎵�鍦ㄧ兢缁勪负娴嬭瘯缇ょ粍锛岃繑鍥濬alse锛堜笉蹇界暐锛�
+        4. 濡傛灉w_id鍦ㄥ拷鐣ュ垪琛ㄤ腑锛岃繑鍥濼rue锛堝拷鐣ワ級
+        5. 濡傛灉w_id涓嶅湪蹇界暐鍒楄〃涓紝杩斿洖False锛堜笉蹇界暐锛�
 
         Args:
             w_id: 鐢ㄦ埛w_id
+            group_id: 缇ょ粍ID锛堝彲閫夛級锛岀敤浜庢鏌ユ槸鍚︿负娴嬭瘯缇ょ粍
 
         Returns:
             濡傛灉搴旇琚拷鐣ヨ繑鍥濼rue锛屽惁鍒欒繑鍥濬alse
@@ -116,8 +119,13 @@
             is_in_ignore_list = redis_queue.redis_client.sismember(self.ignore_list_key, w_id)
 
             if is_in_ignore_list:
+                # 濡傛灉鍦ㄥ拷鐣ュ垪琛ㄤ腑锛屾鏌ユ槸鍚﹀湪娴嬭瘯缇ょ粍涓�
+                if group_id and silence_service.is_test_group(group_id):
+                    logger.info(f"娴嬭瘯缇ょ粍涓殑濂藉弸娑堟伅涓嶈蹇界暐: w_id={w_id}, group_id={group_id}")
+                    return False
+                
                 logger.info(f"w_id鍦ㄥ拷鐣ュ垪琛ㄤ腑锛屽拷鐣ユ秷鎭�: w_id={w_id}")
-
+                
             return is_in_ignore_list
 
         except Exception as e:
diff --git a/app/services/message_processor.py b/app/services/message_processor.py
index 0b26bff..fecc840 100644
--- a/app/services/message_processor.py
+++ b/app/services/message_processor.py
@@ -201,8 +201,8 @@
         from_user = data.get("fromUser")
         from_group = data.get("fromGroup")
 
-        # 妫�鏌ュ彂閫佽�呮槸鍚﹀湪濂藉弸蹇界暐鍒楄〃涓�
-        is_friend_ignored = friend_ignore_service.is_friend_ignored(from_user)
+        # 妫�鏌ュ彂閫佽�呮槸鍚﹀湪濂藉弸蹇界暐鍒楄〃涓紙浼犲叆缇ょ粍ID鐢ㄤ簬娴嬭瘯缇ょ粍妫�鏌ワ級
+        is_friend_ignored = friend_ignore_service.is_friend_ignored(from_user, from_group)
 
         if is_friend_ignored:
             logger.info(
diff --git a/app/services/silence_service.py b/app/services/silence_service.py
index 0161198..10727ae 100644
--- a/app/services/silence_service.py
+++ b/app/services/silence_service.py
@@ -5,8 +5,11 @@
 import time
 from typing import Optional
 from loguru import logger
+from sqlalchemy.orm import Session
 
 from app.services.redis_queue import redis_queue
+from app.models.database import get_db
+from app.models.contact import Contact
 from config import settings
 
 
@@ -25,6 +28,39 @@
         """鑾峰彇缇ょ粍闈欓粯缁撴潫鏃堕棿閿�"""
         return f"{self.silence_end_time_key_prefix}{group_id}"
 
+    def is_test_group(self, group_id: str) -> bool:
+        """
+        妫�鏌ユ寚瀹氱兢缁勬槸鍚︿负娴嬭瘯缇ょ粍
+
+        Args:
+            group_id: 缇ょ粍ID
+
+        Returns:
+            濡傛灉鏄祴璇曠兢缁勮繑鍥濼rue锛屽惁鍒欒繑鍥濬alse
+        """
+        try:
+            # 妫�鏌ユ槸鍚﹂厤缃簡娴嬭瘯缇ょ粍鍏抽敭瀛�
+            if not settings.test_group_keywords:
+                return False
+
+            # 浠庢暟鎹簱鏌ヨ缇ょ粍淇℃伅
+            with next(get_db()) as db:
+                contact = db.query(Contact).filter(Contact.wc_id == group_id).first()
+                if not contact or not contact.nick_name:
+                    return False
+
+                # 妫�鏌ョ兢缁勬樀绉版槸鍚﹀寘鍚换浣曟祴璇曞叧閿瓧
+                nick_name = contact.nick_name
+                for keyword in settings.test_group_keywords:
+                    if keyword in nick_name:
+                        logger.info(f"璇嗗埆鍒版祴璇曠兢缁�: group_id={group_id}, nick_name={nick_name}, keyword={keyword}")
+                        return True
+
+            return False
+        except Exception as e:
+            logger.error(f"妫�鏌ユ祴璇曠兢缁勫紓甯�: group_id={group_id}, error={str(e)}")
+            return False
+
     def activate_silence_mode(self, group_id: str) -> bool:
         """
         婵�娲绘寚瀹氱兢缁勭殑闈欓粯妯″紡
@@ -36,6 +72,11 @@
             婵�娲绘垚鍔熻繑鍥濼rue锛屽け璐ヨ繑鍥濬alse
         """
         try:
+            # 妫�鏌ユ槸鍚︿负娴嬭瘯缇ょ粍锛屽鏋滄槸鍒欎笉婵�娲婚潤榛樻ā寮�
+            if self.is_test_group(group_id):
+                logger.info(f"娴嬭瘯缇ょ粍涓嶆縺娲婚潤榛樻ā寮�: group_id={group_id}")
+                return True
+
             if not settings.silence_mode_enabled:
                 logger.debug("闈欓粯妯″紡鍔熻兘宸茬鐢�")
                 return False
diff --git a/config.py b/config.py
index 7942292..79c1456 100644
--- a/config.py
+++ b/config.py
@@ -118,6 +118,9 @@
 
         # 缁撴潫瀛楃涓查厤缃�
         self.end_str_list = config_data.get("end_str_list", [])
+        
+        # 娴嬭瘯缇ょ粍鍏抽敭瀛楅厤缃�
+        self.test_group_keywords = config_data.get("test_group_keywords", [])
 
     def update_ecloud_w_id(self, new_w_id: str) -> bool:
         """
diff --git a/logs/app.log b/logs/app.log
index 22941d3..dc08815 100644
--- a/logs/app.log
+++ b/logs/app.log
@@ -1,2 +1,3 @@
-2025-08-22 16:15:05 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
-2025-08-22 16:34:15 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-08-26 15:35:24 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-08-26 15:55:13 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
+2025-08-26 16:08:41 | INFO | __main__:<module>:132 - 鍚姩E浜戠瀹�-DifyAI瀵规帴鏈嶅姟
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index 7188324..0000000
--- a/tests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# 娴嬭瘯鍖呭垵濮嬪寲鏂囦欢
diff --git a/tests/test_api.py b/tests/test_api.py
deleted file mode 100644
index 7791983..0000000
--- a/tests/test_api.py
+++ /dev/null
@@ -1,102 +0,0 @@
-"""
-API鎺ュ彛娴嬭瘯
-"""
-import pytest
-from fastapi.testclient import TestClient
-from unittest.mock import patch
-from main import app
-
-
-client = TestClient(app)
-
-
-class TestCallbackAPI:
-    """鍥炶皟API娴嬭瘯绫�"""
-    
-    def test_health_check(self):
-        """娴嬭瘯鍋ュ悍妫�鏌ユ帴鍙�"""
-        response = client.get("/api/v1/health")
-        assert response.status_code == 200
-        data = response.json()
-        assert data["status"] == "healthy"
-    
-    @patch('app.services.message_processor.message_processor')
-    @patch('app.workers.message_worker.message_worker')
-    def test_callback_success(self, mock_worker, mock_processor):
-        """娴嬭瘯鍥炶皟鎺ュ彛鎴愬姛"""
-        mock_processor.enqueue_callback_message.return_value = True
-        
-        callback_data = {
-            "account": "17200000000",
-            "messageType": "80001",
-            "wcId": "wxid_phyyedw9xap22",
-            "data": {
-                "content": "娴嬭瘯娑堟伅",
-                "fromGroup": "25411981800@chatroom",
-                "fromUser": "wxid_ynu1tgjz156j22",
-                "memberCount": 8,
-                "msgId": 1685074592,
-                "newMsgId": 1497474118261484795,
-                "self": False,
-                "timestamp": 1640772092,
-                "toUser": "wxid_phyyedw9xap22",
-                "wId": "12491ae9-62aa-4f7a-83e6-9db4e9f28e3c"
-            }
-        }
-        
-        response = client.post("/api/v1/callback", json=callback_data)
-        
-        assert response.status_code == 200
-        data = response.json()
-        assert data["success"] is True
-        assert data["message"] == "娑堟伅宸叉垚鍔熷姞鍏ュ鐞嗛槦鍒�"
-        
-        mock_processor.enqueue_callback_message.assert_called_once()
-        mock_worker.process_user_queue.assert_called_once_with("wxid_ynu1tgjz156j22")
-    
-    @patch('app.services.message_processor.message_processor')
-    def test_callback_failure(self, mock_processor):
-        """娴嬭瘯鍥炶皟鎺ュ彛澶辫触"""
-        mock_processor.enqueue_callback_message.return_value = False
-        
-        callback_data = {
-            "account": "17200000000",
-            "messageType": "80001",
-            "wcId": "wxid_phyyedw9xap22",
-            "data": {
-                "content": "娴嬭瘯娑堟伅",
-                "fromGroup": "25411981800@chatroom",
-                "fromUser": "wxid_ynu1tgjz156j22",
-                "self": False
-            }
-        }
-        
-        response = client.post("/api/v1/callback", json=callback_data)
-        
-        assert response.status_code == 200
-        data = response.json()
-        assert data["success"] is False
-        assert data["message"] == "娑堟伅澶勭悊澶辫触"
-    
-    def test_callback_invalid_data(self):
-        """娴嬭瘯鏃犳晥鏁版嵁"""
-        invalid_data = {
-            "messageType": "80001"
-            # 缂哄皯蹇呰瀛楁
-        }
-        
-        response = client.post("/api/v1/callback", json=invalid_data)
-        assert response.status_code == 422  # 楠岃瘉閿欒
-    
-    def test_root_endpoint(self):
-        """娴嬭瘯鏍硅矾寰�"""
-        response = client.get("/")
-        assert response.status_code == 200
-        data = response.json()
-        assert data["message"] == "E浜戠瀹�-DifyAI瀵规帴鏈嶅姟"
-        assert data["version"] == "1.0.0"
-        assert data["status"] == "running"
-
-
-if __name__ == "__main__":
-    pytest.main([__file__])
diff --git a/tests/test_dify_streaming.py b/tests/test_dify_streaming.py
deleted file mode 100644
index 8fa8630..0000000
--- a/tests/test_dify_streaming.py
+++ /dev/null
@@ -1,174 +0,0 @@
-"""
-娴嬭瘯Dify娴佸紡妯″紡鍔熻兘
-"""
-
-import pytest
-import json
-from unittest.mock import Mock, patch, MagicMock
-from app.services.dify_client import DifyClient
-from config import settings
-
-
-class TestDifyStreaming:
-    """娴嬭瘯Dify娴佸紡妯″紡"""
-
-    def setup_method(self):
-        """娴嬭瘯鍓嶈缃�"""
-        self.client = DifyClient()
-
-    def test_process_stream_response_success(self):
-        """娴嬭瘯鎴愬姛澶勭悊娴佸紡鍝嶅簲"""
-        # 妯℃嫙娴佸紡鍝嶅簲鏁版嵁
-        stream_data = [
-            "data: {\"event\": \"message\", \"task_id\": \"test-task\", \"id\": \"test-msg\", \"conversation_id\": \"test-conv\", \"answer\": \"Hello\", \"created_at\": 1705398420}",
-            "data: {\"event\": \"message\", \"task_id\": \"test-task\", \"id\": \"test-msg\", \"conversation_id\": \"test-conv\", \"answer\": \" World\", \"created_at\": 1705398420}",
-            "data: {\"event\": \"message_end\", \"metadata\": {\"usage\": {\"total_tokens\": 10}}, \"usage\": {\"total_tokens\": 10}}",
-        ]
-
-        # 鍒涘缓妯℃嫙鍝嶅簲瀵硅薄
-        mock_response = Mock()
-        mock_response.iter_lines.return_value = stream_data
-
-        # 娴嬭瘯澶勭悊娴佸紡鍝嶅簲
-        result = self.client._process_stream_response(mock_response, "test_user")
-
-        # 楠岃瘉缁撴灉
-        assert result is not None
-        assert result["answer"] == "Hello World"
-        assert result["conversation_id"] == "test-conv"
-        assert result["task_id"] == "test-task"
-        assert result["usage"]["total_tokens"] == 10
-
-    def test_process_stream_response_error(self):
-        """娴嬭瘯澶勭悊娴佸紡鍝嶅簲閿欒"""
-        # 妯℃嫙閿欒鍝嶅簲鏁版嵁
-        stream_data = [
-            "data: {\"event\": \"error\", \"message\": \"API璋冪敤澶辫触\", \"code\": \"500\"}",
-        ]
-
-        # 鍒涘缓妯℃嫙鍝嶅簲瀵硅薄
-        mock_response = Mock()
-        mock_response.iter_lines.return_value = stream_data
-
-        # 娴嬭瘯澶勭悊娴佸紡鍝嶅簲
-        result = self.client._process_stream_response(mock_response, "test_user")
-
-        # 楠岃瘉缁撴灉
-        assert result is None
-
-    def test_process_stream_response_incomplete(self):
-        """娴嬭瘯澶勭悊涓嶅畬鏁寸殑娴佸紡鍝嶅簲"""
-        # 妯℃嫙涓嶅畬鏁村搷搴旀暟鎹紙缂哄皯message_end浜嬩欢锛�
-        stream_data = [
-            "data: {\"event\": \"message\", \"task_id\": \"test-task\", \"id\": \"test-msg\", \"conversation_id\": \"test-conv\", \"answer\": \"Hello\", \"created_at\": 1705398420}",
-        ]
-
-        # 鍒涘缓妯℃嫙鍝嶅簲瀵硅薄
-        mock_response = Mock()
-        mock_response.iter_lines.return_value = stream_data
-
-        # 娴嬭瘯澶勭悊娴佸紡鍝嶅簲
-        result = self.client._process_stream_response(mock_response, "test_user")
-
-        # 楠岃瘉缁撴灉 - 鍗充娇娌℃湁message_end浜嬩欢锛屽彧瑕佹湁鍐呭鍜宑onversation_id涔熷簲璇ヨ繑鍥炵粨鏋�
-        assert result is not None
-        assert result["answer"] == "Hello"
-        assert result["conversation_id"] == "test-conv"
-
-    @patch('app.services.dify_client.settings')
-    def test_send_message_uses_streaming_when_enabled(self, mock_settings):
-        """娴嬭瘯褰撳惎鐢ㄦ祦寮忔ā寮忔椂浣跨敤娴佸紡鍙戦��"""
-        # 璁剧疆閰嶇疆涓哄惎鐢ㄦ祦寮忔ā寮�
-        mock_settings.dify_streaming_enabled = True
-        
-        # 妯℃嫙娴佸紡鍙戦�佹柟娉�
-        with patch.object(self.client, 'send_chat_message_stream') as mock_stream:
-            mock_stream.return_value = {"answer": "test response", "conversation_id": "test-conv"}
-            
-            result = self.client.send_message("test query", "test_user")
-            
-            # 楠岃瘉璋冪敤浜嗘祦寮忔柟娉�
-            mock_stream.assert_called_once_with("test query", "test_user", None, None)
-            assert result["answer"] == "test response"
-
-    @patch('app.services.dify_client.settings')
-    def test_send_message_uses_blocking_when_disabled(self, mock_settings):
-        """娴嬭瘯褰撶鐢ㄦ祦寮忔ā寮忔椂浣跨敤闃诲鍙戦��"""
-        # 璁剧疆閰嶇疆涓虹鐢ㄦ祦寮忔ā寮�
-        mock_settings.dify_streaming_enabled = False
-        
-        # 妯℃嫙闃诲鍙戦�佹柟娉�
-        with patch.object(self.client, 'send_chat_message') as mock_blocking:
-            mock_blocking.return_value = {"answer": "test response", "conversation_id": "test-conv"}
-            
-            result = self.client.send_message("test query", "test_user")
-            
-            # 楠岃瘉璋冪敤浜嗛樆濉炴柟娉�
-            mock_blocking.assert_called_once_with("test query", "test_user", None, None)
-            assert result["answer"] == "test response"
-
-    @patch('app.services.dify_client.settings')
-    def test_send_message_force_streaming_override(self, mock_settings):
-        """娴嬭瘯寮哄埗娴佸紡妯″紡瑕嗙洊閰嶇疆"""
-        # 璁剧疆閰嶇疆涓虹鐢ㄦ祦寮忔ā寮�
-        mock_settings.dify_streaming_enabled = False
-        
-        # 妯℃嫙娴佸紡鍙戦�佹柟娉�
-        with patch.object(self.client, 'send_chat_message_stream') as mock_stream:
-            mock_stream.return_value = {"answer": "test response", "conversation_id": "test-conv"}
-            
-            # 寮哄埗浣跨敤娴佸紡妯″紡
-            result = self.client.send_message("test query", "test_user", force_streaming=True)
-            
-            # 楠岃瘉璋冪敤浜嗘祦寮忔柟娉曪紙瑕嗙洊浜嗛厤缃級
-            mock_stream.assert_called_once_with("test query", "test_user", None, None)
-            assert result["answer"] == "test response"
-
-    def test_process_stream_response_with_ping_events(self):
-        """娴嬭瘯澶勭悊鍖呭惈ping浜嬩欢鐨勬祦寮忓搷搴�"""
-        # 妯℃嫙鍖呭惈ping浜嬩欢鐨勫搷搴旀暟鎹�
-        stream_data = [
-            "data: {\"event\": \"ping\"}",
-            "data: {\"event\": \"message\", \"task_id\": \"test-task\", \"id\": \"test-msg\", \"conversation_id\": \"test-conv\", \"answer\": \"Hello\", \"created_at\": 1705398420}",
-            "data: {\"event\": \"ping\"}",
-            "data: {\"event\": \"message\", \"task_id\": \"test-task\", \"id\": \"test-msg\", \"conversation_id\": \"test-conv\", \"answer\": \" World\", \"created_at\": 1705398420}",
-            "data: {\"event\": \"message_end\", \"metadata\": {\"usage\": {\"total_tokens\": 10}}}",
-        ]
-
-        # 鍒涘缓妯℃嫙鍝嶅簲瀵硅薄
-        mock_response = Mock()
-        mock_response.iter_lines.return_value = stream_data
-
-        # 娴嬭瘯澶勭悊娴佸紡鍝嶅簲
-        result = self.client._process_stream_response(mock_response, "test_user")
-
-        # 楠岃瘉缁撴灉锛坧ing浜嬩欢搴旇琚拷鐣ワ級
-        assert result is not None
-        assert result["answer"] == "Hello World"
-        assert result["conversation_id"] == "test-conv"
-
-    def test_process_stream_response_with_invalid_json(self):
-        """娴嬭瘯澶勭悊鍖呭惈鏃犳晥JSON鐨勬祦寮忓搷搴�"""
-        # 妯℃嫙鍖呭惈鏃犳晥JSON鐨勫搷搴旀暟鎹�
-        stream_data = [
-            "data: {\"event\": \"message\", \"task_id\": \"test-task\", \"id\": \"test-msg\", \"conversation_id\": \"test-conv\", \"answer\": \"Hello\", \"created_at\": 1705398420}",
-            "data: invalid json data",
-            "data: {\"event\": \"message\", \"task_id\": \"test-task\", \"id\": \"test-msg\", \"conversation_id\": \"test-conv\", \"answer\": \" World\", \"created_at\": 1705398420}",
-            "data: {\"event\": \"message_end\"}",
-        ]
-
-        # 鍒涘缓妯℃嫙鍝嶅簲瀵硅薄
-        mock_response = Mock()
-        mock_response.iter_lines.return_value = stream_data
-
-        # 娴嬭瘯澶勭悊娴佸紡鍝嶅簲
-        result = self.client._process_stream_response(mock_response, "test_user")
-
-        # 楠岃瘉缁撴灉锛堟棤鏁圝SON搴旇琚烦杩囷級
-        assert result is not None
-        assert result["answer"] == "Hello World"
-        assert result["conversation_id"] == "test-conv"
-
-
-if __name__ == "__main__":
-    pytest.main([__file__])
diff --git a/tests/test_friend_ignore_service.py b/tests/test_friend_ignore_service.py
deleted file mode 100644
index 6bc92a7..0000000
--- a/tests/test_friend_ignore_service.py
+++ /dev/null
@@ -1,258 +0,0 @@
-"""
-濂藉弸蹇界暐鏈嶅姟娴嬭瘯
-"""
-
-import pytest
-from unittest.mock import Mock, patch
-from app.services.friend_ignore_service import FriendIgnoreService
-
-
-class TestFriendIgnoreService:
-    """濂藉弸蹇界暐鏈嶅姟娴嬭瘯绫�"""
-    
-    def setup_method(self):
-        """娴嬭瘯鍓嶅噯澶�"""
-        self.service = FriendIgnoreService()
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_add_friends_to_ignore_list_success(self, mock_redis_queue):
-        """娴嬭瘯鎴愬姛娣诲姞濂藉弸鍒板拷鐣ュ垪琛�"""
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        
-        friends = ["wxid_test1", "wxid_test2", "wxid_test3"]
-        
-        result = self.service.add_friends_to_ignore_list(friends)
-        
-        # 楠岃瘉缁撴灉
-        assert result is True
-        
-        # 楠岃瘉Redis鎿嶄綔琚皟鐢�
-        mock_redis_client.delete.assert_called_once_with(self.service.ignore_list_key)
-        mock_redis_client.sadd.assert_called_once_with(self.service.ignore_list_key, *friends)
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_add_friends_to_ignore_list_empty(self, mock_redis_queue):
-        """娴嬭瘯娣诲姞绌哄ソ鍙嬪垪琛�"""
-        result = self.service.add_friends_to_ignore_list([])
-        
-        # 楠岃瘉缁撴灉
-        assert result is True
-        
-        # 楠岃瘉Redis鎿嶄綔鏈璋冪敤
-        mock_redis_queue.redis_client.delete.assert_not_called()
-        mock_redis_queue.redis_client.sadd.assert_not_called()
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_is_friend_ignored_true(self, mock_redis_queue):
-        """娴嬭瘯妫�鏌ュソ鍙嬪湪蹇界暐鍒楄〃涓�"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.sismember.return_value = True
-        
-        result = self.service.is_friend_ignored("wxid_test1")
-        
-        assert result is True
-        mock_redis_client.sismember.assert_called_once_with(self.service.ignore_list_key, "wxid_test1")
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_is_friend_ignored_false(self, mock_redis_queue):
-        """娴嬭瘯妫�鏌ュソ鍙嬩笉鍦ㄥ拷鐣ュ垪琛ㄤ腑"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.sismember.return_value = False
-        
-        result = self.service.is_friend_ignored("wxid_test1")
-        
-        assert result is False
-        mock_redis_client.sismember.assert_called_once_with(self.service.ignore_list_key, "wxid_test1")
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_get_ignore_list(self, mock_redis_queue):
-        """娴嬭瘯鑾峰彇蹇界暐鍒楄〃"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        expected_set = {"wxid_test1", "wxid_test2"}
-        mock_redis_client.smembers.return_value = expected_set
-        
-        result = self.service.get_ignore_list()
-        
-        assert result == expected_set
-        mock_redis_client.smembers.assert_called_once_with(self.service.ignore_list_key)
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_remove_friend_from_ignore_list(self, mock_redis_queue):
-        """娴嬭瘯浠庡拷鐣ュ垪琛ㄧЩ闄ゅソ鍙�"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.srem.return_value = 1  # 琛ㄧず鎴愬姛绉婚櫎
-        
-        result = self.service.remove_friend_from_ignore_list("wxid_test1")
-        
-        assert result is True
-        mock_redis_client.srem.assert_called_once_with(self.service.ignore_list_key, "wxid_test1")
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_clear_ignore_list(self, mock_redis_queue):
-        """娴嬭瘯娓呯┖蹇界暐鍒楄〃"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        
-        result = self.service.clear_ignore_list()
-        
-        assert result is True
-        mock_redis_client.delete.assert_called_once_with(self.service.ignore_list_key)
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_get_ignore_list_count(self, mock_redis_queue):
-        """娴嬭瘯鑾峰彇蹇界暐鍒楄〃鏁伴噺"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.scard.return_value = 5
-        
-        result = self.service.get_ignore_list_count()
-        
-        assert result == 5
-        mock_redis_client.scard.assert_called_once_with(self.service.ignore_list_key)
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_add_friends_exception_handling(self, mock_redis_queue):
-        """娴嬭瘯娣诲姞濂藉弸鏃剁殑寮傚父澶勭悊"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.sadd.side_effect = Exception("Redis error")
-        
-        result = self.service.add_friends_to_ignore_list(["wxid_test1"])
-        
-        assert result is False
-    
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_is_friend_ignored_exception_handling(self, mock_redis_queue):
-        """娴嬭瘯妫�鏌ュソ鍙嬫椂鐨勫紓甯稿鐞�"""
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.sismember.side_effect = Exception("Redis error")
-        
-        result = self.service.is_friend_ignored("wxid_test1")
-
-        assert result is False
-
-    @patch('app.services.friend_ignore_service.settings')
-    @patch('app.services.friend_ignore_service.redis_queue')
-    @patch('app.services.friend_ignore_service.get_db')
-    def test_is_friend_ignored_whitelist(self, mock_get_db, mock_redis_queue, mock_settings):
-        """娴嬭瘯鐧藉悕鍗曞姛鑳�"""
-        # 妯℃嫙閰嶇疆
-        mock_settings.friend_ignore_enabled = True
-        mock_settings.friend_ignore_whitelist = ["娴嬭瘯鐢ㄦ埛1", "娴嬭瘯鐢ㄦ埛2"]
-
-        # 妯℃嫙鏁版嵁搴撴煡璇�
-        mock_db = Mock()
-        mock_get_db.return_value.__next__.return_value.__enter__.return_value = mock_db
-        mock_get_db.return_value.__next__.return_value.__exit__.return_value = None
-
-        # 妯℃嫙鑱旂郴浜烘煡璇㈢粨鏋� - 鏍规嵁鏄电О杩斿洖涓嶅悓鐨勮仈绯讳汉
-        def mock_query_side_effect(*args, **kwargs):
-            mock_query = Mock()
-            mock_filter = Mock()
-            mock_query.filter.return_value = mock_filter
-
-            # 鏍规嵁鏌ヨ鏉′欢杩斿洖涓嶅悓鐨勭粨鏋�
-            def mock_first():
-                # 杩欓噷绠�鍖栧鐞嗭紝鍋囪鏌ヨ"娴嬭瘯鐢ㄦ埛1"鏃惰繑鍥瀢xid_whitelist1
-                mock_contact = Mock()
-                mock_contact.wc_id = "wxid_whitelist1"
-                return mock_contact
-
-            mock_filter.first = mock_first
-            return mock_query
-
-        mock_db.query.side_effect = mock_query_side_effect
-
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.sismember.return_value = True  # 鍦ㄥ拷鐣ュ垪琛ㄤ腑
-
-        # 娴嬭瘯鐧藉悕鍗曠敤鎴凤紙鍗充娇鍦ㄥ拷鐣ュ垪琛ㄤ腑涔熶笉搴旇琚拷鐣ワ級
-        result = self.service.is_friend_ignored("wxid_whitelist1")
-        assert result is False
-
-        # 娴嬭瘯闈炵櫧鍚嶅崟鐢ㄦ埛锛堝湪蹇界暐鍒楄〃涓簲璇ヨ蹇界暐锛�
-        result = self.service.is_friend_ignored("wxid_normal_user")
-        assert result is True
-
-    @patch('app.services.friend_ignore_service.settings')
-    def test_is_friend_ignored_disabled(self, mock_settings):
-        """娴嬭瘯鍔熻兘绂佺敤鏃剁殑琛屼负"""
-        mock_settings.friend_ignore_enabled = False
-        mock_settings.friend_ignore_whitelist = []
-
-        result = self.service.is_friend_ignored("wxid_test1")
-        assert result is False
-
-    @patch('app.services.friend_ignore_service.settings')
-    @patch('app.services.friend_ignore_service.redis_queue')
-    @patch('app.services.friend_ignore_service.get_db')
-    def test_get_ignore_status_info(self, mock_get_db, mock_redis_queue, mock_settings):
-        """娴嬭瘯鑾峰彇璇︾粏鐘舵�佷俊鎭�"""
-        mock_settings.friend_ignore_enabled = True
-        mock_settings.friend_ignore_whitelist = ["娴嬭瘯鐢ㄦ埛1"]
-
-        # 妯℃嫙鏁版嵁搴撴煡璇�
-        mock_db = Mock()
-        mock_get_db.return_value.__enter__.return_value = mock_db
-        mock_get_db.return_value.__exit__.return_value = None
-
-        # 妯℃嫙鑱旂郴浜烘煡璇㈢粨鏋�
-        mock_contact = Mock()
-        mock_contact.wc_id = "wxid_whitelist1"
-        mock_db.query.return_value.filter.return_value.first.return_value = mock_contact
-
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.sismember.return_value = True
-
-        # 娴嬭瘯鐧藉悕鍗曠敤鎴�
-        result = self.service.get_ignore_status_info("wxid_whitelist1")
-        assert result["w_id"] == "wxid_whitelist1"
-        assert result["in_whitelist"] is True
-        assert result["final_ignored"] is False
-        assert "鐧藉悕鍗�" in result["reason"]
-        assert result["whitelist_nicknames"] == ["娴嬭瘯鐢ㄦ埛1"]
-
-        # 娴嬭瘯鏅�氱敤鎴�
-        result = self.service.get_ignore_status_info("wxid_normal_user")
-        assert result["w_id"] == "wxid_normal_user"
-        assert result["in_whitelist"] is False
-        assert result["in_ignore_list"] is True
-        assert result["final_ignored"] is True
-
-    @patch('app.services.friend_ignore_service.FriendIgnoreService._get_whitelist_wids')
-    @patch('app.services.friend_ignore_service.settings')
-    @patch('app.services.friend_ignore_service.redis_queue')
-    def test_is_friend_ignored_nickname_whitelist(self, mock_redis_queue, mock_settings, mock_get_whitelist_wids):
-        """娴嬭瘯鏄电О鐧藉悕鍗曞姛鑳�"""
-        # 妯℃嫙閰嶇疆
-        mock_settings.friend_ignore_enabled = True
-        mock_settings.friend_ignore_whitelist = ["娴嬭瘯鐢ㄦ埛1", "娴嬭瘯鐢ㄦ埛2"]
-
-        # 妯℃嫙鐧藉悕鍗晈_id杞崲缁撴灉
-        mock_get_whitelist_wids.return_value = ["wxid_whitelist1", "wxid_whitelist2"]
-
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.sismember.return_value = True  # 鍦ㄥ拷鐣ュ垪琛ㄤ腑
-
-        # 娴嬭瘯鐧藉悕鍗曠敤鎴凤紙鍗充娇鍦ㄥ拷鐣ュ垪琛ㄤ腑涔熶笉搴旇琚拷鐣ワ級
-        result = self.service.is_friend_ignored("wxid_whitelist1")
-        assert result is False
-
-        # 娴嬭瘯闈炵櫧鍚嶅崟鐢ㄦ埛锛堝湪蹇界暐鍒楄〃涓簲璇ヨ蹇界暐锛�
-        result = self.service.is_friend_ignored("wxid_normal_user")
-        assert result is True
-
-        # 楠岃瘉鏂规硶琚皟鐢�
-        assert mock_get_whitelist_wids.call_count >= 2
diff --git a/tests/test_message_aggregator.py b/tests/test_message_aggregator.py
deleted file mode 100644
index 42a7a27..0000000
--- a/tests/test_message_aggregator.py
+++ /dev/null
@@ -1,405 +0,0 @@
-"""
-娑堟伅鑱氬悎鏈嶅姟娴嬭瘯
-"""
-
-import time
-import threading
-import pytest
-from unittest.mock import patch, MagicMock
-from app.services.message_aggregator import MessageAggregatorService, PendingMessage, MessageAggregation
-
-
-class TestMessageAggregatorService:
-    """娑堟伅鑱氬悎鏈嶅姟娴嬭瘯绫�"""
-    
-    def setup_method(self):
-        """娴嬭瘯鍓嶅噯澶�"""
-        self.aggregator = MessageAggregatorService()
-        # 璁剧疆杈冪煭鐨勮秴鏃舵椂闂寸敤浜庢祴璇�
-        self.aggregator.aggregation_timeout = 2
-        self.aggregator.aggregation_enabled = True
-    
-    def teardown_method(self):
-        """娴嬭瘯鍚庢竻鐞�"""
-        self.aggregator.stop()
-    
-    def test_should_aggregate_message_valid(self):
-        """娴嬭瘯鏈夋晥娑堟伅鐨勮仛鍚堝垽鏂�"""
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        result = self.aggregator.should_aggregate_message(message_data)
-        assert result is True
-    
-    def test_should_aggregate_message_disabled(self):
-        """娴嬭瘯鑱氬悎鍔熻兘绂佺敤鏃剁殑鍒ゆ柇"""
-        self.aggregator.aggregation_enabled = False
-        
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        result = self.aggregator.should_aggregate_message(message_data)
-        assert result is False
-    
-    def test_should_aggregate_message_wrong_type(self):
-        """娴嬭瘯閿欒娑堟伅绫诲瀷鐨勮仛鍚堝垽鏂�"""
-        message_data = {
-            "messageType": "80002",  # 闈炵兢鑱婃秷鎭�
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        result = self.aggregator.should_aggregate_message(message_data)
-        assert result is False
-    
-    def test_should_aggregate_message_self_message(self):
-        """娴嬭瘯鑷繁鍙戦�佺殑娑堟伅鐨勮仛鍚堝垽鏂�"""
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": True  # 鑷繁鍙戦�佺殑娑堟伅
-            }
-        }
-        
-        result = self.aggregator.should_aggregate_message(message_data)
-        assert result is False
-    
-    def test_should_aggregate_message_missing_fields(self):
-        """娴嬭瘯缂哄皯蹇呰瀛楁鐨勬秷鎭殑鑱氬悎鍒ゆ柇"""
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                # 缂哄皯 fromGroup
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        result = self.aggregator.should_aggregate_message(message_data)
-        assert result is False
-    
-    def test_add_message_to_aggregation_no_aggregation(self):
-        """娴嬭瘯涓嶉渶瑕佽仛鍚堢殑娑堟伅"""
-        self.aggregator.aggregation_enabled = False
-        
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        should_process, aggregated_data = self.aggregator.add_message_to_aggregation(message_data)
-        
-        assert should_process is True
-        assert aggregated_data == message_data
-    
-    def test_add_message_to_aggregation_first_message(self):
-        """娴嬭瘯娣诲姞绗竴鏉℃秷鎭埌鑱氬悎"""
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "绗竴鏉℃秷鎭�",
-                "self": False
-            }
-        }
-        
-        should_process, aggregated_data = self.aggregator.add_message_to_aggregation(message_data)
-        
-        assert should_process is False
-        assert aggregated_data is None
-        
-        # 妫�鏌ヨ仛鍚堢姸鎬�
-        status = self.aggregator.get_aggregation_status()
-        assert status["active_aggregations"] == 1
-        assert "group123@chatroom:wxid_test123" in status["aggregations"]
-    
-    def test_add_message_to_aggregation_multiple_messages(self):
-        """娴嬭瘯娣诲姞澶氭潯娑堟伅鍒拌仛鍚�"""
-        message_data_1 = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "绗竴鏉℃秷鎭�",
-                "self": False
-            }
-        }
-        
-        message_data_2 = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "绗簩鏉℃秷鎭�",
-                "self": False
-            }
-        }
-        
-        # 娣诲姞绗竴鏉℃秷鎭�
-        should_process_1, _ = self.aggregator.add_message_to_aggregation(message_data_1)
-        assert should_process_1 is False
-        
-        # 娣诲姞绗簩鏉℃秷鎭�
-        should_process_2, _ = self.aggregator.add_message_to_aggregation(message_data_2)
-        assert should_process_2 is False
-        
-        # 妫�鏌ヨ仛鍚堢姸鎬�
-        status = self.aggregator.get_aggregation_status()
-        aggregation_info = status["aggregations"]["group123@chatroom:wxid_test123"]
-        assert aggregation_info["message_count"] == 2
-    
-    @patch('app.services.message_processor.message_processor')
-    def test_process_aggregated_messages_timeout(self, mock_message_processor):
-        """娴嬭瘯鑱氬悎娑堟伅瓒呮椂澶勭悊"""
-        mock_message_processor.process_single_message.return_value = True
-        
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        # 娣诲姞娑堟伅鍒拌仛鍚�
-        should_process, _ = self.aggregator.add_message_to_aggregation(message_data)
-        assert should_process is False
-        
-        # 绛夊緟瓒呮椂澶勭悊
-        time.sleep(2.5)
-        
-        # 楠岃瘉娑堟伅澶勭悊鍣ㄨ璋冪敤
-        mock_message_processor.process_single_message.assert_called_once()
-        
-        # 妫�鏌ヨ仛鍚堝凡琚竻鐞�
-        status = self.aggregator.get_aggregation_status()
-        assert status["active_aggregations"] == 0
-    
-    def test_get_aggregation_status(self):
-        """娴嬭瘯鑾峰彇鑱氬悎鐘舵��"""
-        # 鍒濆鐘舵��
-        status = self.aggregator.get_aggregation_status()
-        assert status["enabled"] is True
-        assert status["timeout"] == 2
-        assert status["active_aggregations"] == 0
-        assert status["aggregations"] == {}
-        
-        # 娣诲姞娑堟伅鍚庣殑鐘舵��
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        self.aggregator.add_message_to_aggregation(message_data)
-        
-        status = self.aggregator.get_aggregation_status()
-        assert status["active_aggregations"] == 1
-        assert "group123@chatroom:wxid_test123" in status["aggregations"]
-        
-        aggregation_info = status["aggregations"]["group123@chatroom:wxid_test123"]
-        assert aggregation_info["from_user"] == "wxid_test123"
-        assert aggregation_info["from_group"] == "group123@chatroom"
-        assert aggregation_info["message_count"] == 1
-    
-    @patch('app.services.message_processor.message_processor')
-    def test_force_process_aggregation(self, mock_message_processor):
-        """娴嬭瘯寮哄埗澶勭悊鑱氬悎娑堟伅"""
-        mock_message_processor.process_single_message.return_value = True
-        
-        message_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        # 娣诲姞娑堟伅鍒拌仛鍚�
-        self.aggregator.add_message_to_aggregation(message_data)
-        
-        # 寮哄埗澶勭悊鑱氬悎
-        result = self.aggregator.force_process_aggregation("wxid_test123", "group123@chatroom")
-        assert result is True
-        
-        # 楠岃瘉娑堟伅澶勭悊鍣ㄨ璋冪敤
-        mock_message_processor.process_single_message.assert_called_once()
-        
-        # 妫�鏌ヨ仛鍚堝凡琚竻鐞�
-        status = self.aggregator.get_aggregation_status()
-        assert status["active_aggregations"] == 0
-    
-    def test_force_process_aggregation_not_found(self):
-        """娴嬭瘯寮哄埗澶勭悊涓嶅瓨鍦ㄧ殑鑱氬悎"""
-        result = self.aggregator.force_process_aggregation("wxid_test123", "group123@chatroom")
-        assert result is False
-
-
-class TestPendingMessage:
-    """寰呰仛鍚堟秷鎭祴璇曠被"""
-    
-    def test_pending_message_creation(self):
-        """娴嬭瘯寰呰仛鍚堟秷鎭垱寤�"""
-        message_data = {"test": "data"}
-        timestamp = time.time()
-        
-        pending_message = PendingMessage(
-            message_data=message_data,
-            timestamp=timestamp,
-            content="娴嬭瘯鍐呭",
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        
-        assert pending_message.message_data == message_data
-        assert pending_message.timestamp == timestamp
-        assert pending_message.content == "娴嬭瘯鍐呭"
-        assert pending_message.from_user == "wxid_test123"
-        assert pending_message.from_group == "group123@chatroom"
-
-
-class TestMessageAggregation:
-    """娑堟伅鑱氬悎瀵硅薄娴嬭瘯绫�"""
-    
-    def test_message_aggregation_creation(self):
-        """娴嬭瘯娑堟伅鑱氬悎瀵硅薄鍒涘缓"""
-        aggregation = MessageAggregation(
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        
-        assert aggregation.from_user == "wxid_test123"
-        assert aggregation.from_group == "group123@chatroom"
-        assert len(aggregation.messages) == 0
-        assert aggregation.first_message_time == 0.0
-        assert aggregation.last_message_time == 0.0
-        assert aggregation.timer is None
-    
-    def test_add_message(self):
-        """娴嬭瘯娣诲姞娑堟伅鍒拌仛鍚�"""
-        aggregation = MessageAggregation(
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        
-        timestamp = time.time()
-        pending_message = PendingMessage(
-            message_data={"test": "data"},
-            timestamp=timestamp,
-            content="娴嬭瘯鍐呭",
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        
-        aggregation.add_message(pending_message)
-        
-        assert len(aggregation.messages) == 1
-        assert aggregation.first_message_time == timestamp
-        assert aggregation.last_message_time == timestamp
-    
-    def test_get_aggregated_content(self):
-        """娴嬭瘯鑾峰彇鑱氬悎鍚庣殑鍐呭"""
-        aggregation = MessageAggregation(
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        
-        # 娣诲姞澶氭潯娑堟伅
-        for i in range(3):
-            pending_message = PendingMessage(
-                message_data={"test": f"data{i}"},
-                timestamp=time.time() + i,
-                content=f"娑堟伅{i+1}",
-                from_user="wxid_test123",
-                from_group="group123@chatroom"
-            )
-            aggregation.add_message(pending_message)
-        
-        aggregated_content = aggregation.get_aggregated_content()
-        assert aggregated_content == "娑堟伅1\n娑堟伅2\n娑堟伅3"
-    
-    def test_get_latest_message_data(self):
-        """娴嬭瘯鑾峰彇鏈�鏂版秷鎭暟鎹�"""
-        aggregation = MessageAggregation(
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        
-        # 娣诲姞澶氭潯娑堟伅
-        for i in range(3):
-            pending_message = PendingMessage(
-                message_data={"test": f"data{i}", "timestamp": i},
-                timestamp=time.time() + i,
-                content=f"娑堟伅{i+1}",
-                from_user="wxid_test123",
-                from_group="group123@chatroom"
-            )
-            aggregation.add_message(pending_message)
-        
-        latest_data = aggregation.get_latest_message_data()
-        assert latest_data["test"] == "data2"  # 鏈�鍚庝竴鏉℃秷鎭�
-        assert latest_data["timestamp"] == 2
-    
-    def test_clear(self):
-        """娴嬭瘯娓呯┖鑱氬悎鏁版嵁"""
-        aggregation = MessageAggregation(
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        
-        # 娣诲姞娑堟伅
-        pending_message = PendingMessage(
-            message_data={"test": "data"},
-            timestamp=time.time(),
-            content="娴嬭瘯鍐呭",
-            from_user="wxid_test123",
-            from_group="group123@chatroom"
-        )
-        aggregation.add_message(pending_message)
-        
-        # 璁剧疆瀹氭椂鍣�
-        aggregation.timer = threading.Timer(1, lambda: None)
-        
-        # 娓呯┖
-        aggregation.clear()
-        
-        assert len(aggregation.messages) == 0
-        assert aggregation.first_message_time == 0.0
-        assert aggregation.last_message_time == 0.0
-        assert aggregation.timer is None
diff --git a/tests/test_message_processor.py b/tests/test_message_processor.py
deleted file mode 100644
index e149ce8..0000000
--- a/tests/test_message_processor.py
+++ /dev/null
@@ -1,259 +0,0 @@
-"""
-娑堟伅澶勭悊鍣ㄦ祴璇�
-"""
-import pytest
-from unittest.mock import Mock, patch
-from app.services.message_processor import MessageProcessor
-
-
-class TestMessageProcessor:
-    """娑堟伅澶勭悊鍣ㄦ祴璇曠被"""
-    
-    def setup_method(self):
-        """娴嬭瘯鍓嶅噯澶�"""
-        self.processor = MessageProcessor()
-    
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    def test_is_valid_group_message_success(self, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯鏈夋晥缇よ亰娑堟伅楠岃瘉"""
-        mock_silence_service.is_silence_active.return_value = False
-        mock_friend_ignore_service.is_friend_ignored.return_value = False
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is True
-    
-    def test_is_valid_group_message_wrong_type(self):
-        """娴嬭瘯閿欒娑堟伅绫诲瀷"""
-        callback_data = {
-            "messageType": "80002",  # 闈炵兢鑱婃秷鎭�
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-    
-    def test_is_valid_group_message_self_sent(self):
-        """娴嬭瘯鑷繁鍙戦�佺殑娑堟伅"""
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": True  # 鑷繁鍙戦�佺殑娑堟伅
-            }
-        }
-        
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-    
-    def test_is_valid_group_message_missing_fields(self):
-        """娴嬭瘯缂哄皯蹇呰瀛楁"""
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                # 缂哄皯 fromGroup 鍜� content
-                "self": False
-            }
-        }
-        
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    def test_is_valid_group_message_friend_ignored(self, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯濂藉弸鍦ㄥ拷鐣ュ垪琛ㄤ腑鐨勬秷鎭�"""
-        mock_silence_service.is_silence_active.side_effect = [False, False]  # 涓ゆ妫�鏌ラ兘杩斿洖False
-        mock_silence_service.activate_silence_mode.return_value = True
-        mock_friend_ignore_service.is_friend_ignored.return_value = True
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-        mock_friend_ignore_service.is_friend_ignored.assert_called_once_with("wxid_test123")
-
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    def test_is_valid_group_message_friend_not_ignored(self, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯濂藉弸涓嶅湪蹇界暐鍒楄〃涓殑娑堟伅"""
-        mock_silence_service.is_silence_active.return_value = False
-        mock_friend_ignore_service.is_friend_ignored.return_value = False
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is True
-        mock_friend_ignore_service.is_friend_ignored.assert_called_once_with("wxid_test123")
-
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    def test_is_valid_group_message_silence_active(self, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯缇ょ粍闈欓粯妯″紡婵�娲绘椂鐨勬秷鎭鐞嗭紙闈炲拷鐣ュソ鍙嬶級"""
-        mock_friend_ignore_service.is_friend_ignored.return_value = False
-        mock_silence_service.is_silence_active.return_value = True
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-        mock_silence_service.is_silence_active.assert_called_once_with("group123@chatroom")
-
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    def test_is_valid_group_message_friend_ignored_activate_silence(self, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯濂藉弸琚拷鐣ユ椂婵�娲婚潤榛樻ā寮�"""
-        mock_silence_service.is_silence_active.side_effect = [False, False]  # 绗竴娆℃鏌ユ湭婵�娲伙紝绗簩娆℃鏌ュ拷鐣ュソ鍙嬫椂涔熸湭婵�娲�
-        mock_silence_service.activate_silence_mode.return_value = True
-        mock_friend_ignore_service.is_friend_ignored.return_value = True
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-        mock_silence_service.activate_silence_mode.assert_called_once_with("group123@chatroom")
-
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    def test_is_valid_group_message_friend_ignored_extend_silence(self, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯濂藉弸琚拷鐣ユ椂寤堕暱缇ょ粍闈欓粯妯″紡"""
-        mock_silence_service.is_silence_active.return_value = True  # 缇ょ粍闈欓粯妯″紡宸叉縺娲�
-        mock_silence_service.extend_silence_mode.return_value = True
-        mock_friend_ignore_service.is_friend_ignored.return_value = True
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-        mock_silence_service.extend_silence_mode.assert_called_once_with("group123@chatroom")
-
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    def test_is_valid_group_message_friend_ignored_in_silence_mode(self, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯缇ょ粍闈欓粯妯″紡涓嬪ソ鍙嬫秷鎭粛鑳藉埛鏂版椂闀�"""
-        # 妯℃嫙缇ょ粍闈欓粯妯″紡宸叉縺娲荤殑鎯呭喌
-        mock_friend_ignore_service.is_friend_ignored.return_value = True
-        mock_silence_service.is_silence_active.return_value = True
-        mock_silence_service.extend_silence_mode.return_value = True
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_ignored_friend",
-                "fromGroup": "group123@chatroom",
-                "content": "琚拷鐣ュソ鍙嬪湪缇ょ粍闈欓粯妯″紡涓嬬殑娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.is_valid_group_message(callback_data)
-        assert result is False
-
-        # 楠岃瘉濂藉弸蹇界暐妫�鏌ヨ璋冪敤
-        mock_friend_ignore_service.is_friend_ignored.assert_called_once_with("wxid_ignored_friend")
-        # 楠岃瘉缇ょ粍闈欓粯妯″紡鏃堕棿琚欢闀�
-        mock_silence_service.extend_silence_mode.assert_called_once_with("group123@chatroom")
-    
-    @patch('app.services.message_processor.silence_service')
-    @patch('app.services.message_processor.friend_ignore_service')
-    @patch('app.services.message_processor.redis_queue')
-    def test_enqueue_callback_message_success(self, mock_redis_queue, mock_friend_ignore_service, mock_silence_service):
-        """娴嬭瘯娑堟伅鍏ラ槦鎴愬姛"""
-        mock_silence_service.is_silence_active.return_value = False
-        mock_friend_ignore_service.is_friend_ignored.return_value = False
-        mock_redis_queue.enqueue_message.return_value = True
-
-        callback_data = {
-            "messageType": "80001",
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-
-        result = self.processor.enqueue_callback_message(callback_data)
-
-        assert result is True
-        mock_redis_queue.enqueue_message.assert_called_once_with("wxid_test123", callback_data)
-    
-    @patch('app.services.message_processor.redis_queue')
-    def test_enqueue_callback_message_invalid(self, mock_redis_queue):
-        """娴嬭瘯鏃犳晥娑堟伅鍏ラ槦"""
-        callback_data = {
-            "messageType": "80002",  # 鏃犳晥娑堟伅绫诲瀷
-            "data": {
-                "fromUser": "wxid_test123",
-                "fromGroup": "group123@chatroom",
-                "content": "娴嬭瘯娑堟伅",
-                "self": False
-            }
-        }
-        
-        result = self.processor.enqueue_callback_message(callback_data)
-        
-        assert result is False
-        mock_redis_queue.enqueue_message.assert_not_called()
-
-
-if __name__ == "__main__":
-    pytest.main([__file__])
diff --git a/tests/test_online_status_monitor.py b/tests/test_online_status_monitor.py
deleted file mode 100644
index c9368aa..0000000
--- a/tests/test_online_status_monitor.py
+++ /dev/null
@@ -1,168 +0,0 @@
-"""
-鍦ㄧ嚎鐘舵�佺洃鎺у姛鑳芥祴璇�
-"""
-
-import pytest
-import time
-from unittest.mock import Mock, patch
-from app.services.ecloud_client import ecloud_client
-from app.services.email_service import email_service
-from app.services.sms_service import sms_service
-from app.workers.online_status_worker import online_status_worker
-
-
-class TestOnlineStatusMonitor:
-    """鍦ㄧ嚎鐘舵�佺洃鎺ф祴璇�"""
-
-    def test_ecloud_query_online_wechat_list(self):
-        """娴嬭瘯鏌ヨ鍦ㄧ嚎寰俊鍒楄〃"""
-        # 妯℃嫙鏈夊湪绾垮井淇$殑鎯呭喌
-        with patch.object(ecloud_client.session, 'post') as mock_post:
-            mock_response = Mock()
-            mock_response.json.return_value = {
-                "code": "1000",
-                "message": "鎴愬姛",
-                "data": [
-                    {
-                        "wcId": "wxid_test123",
-                        "wId": "test-w-id-123"
-                    }
-                ]
-            }
-            mock_post.return_value = mock_response
-            
-            result = ecloud_client.query_online_wechat_list()
-            assert result is not None
-            assert len(result) == 1
-            assert result[0]["wcId"] == "wxid_test123"
-
-        # 妯℃嫙娌℃湁鍦ㄧ嚎寰俊鐨勬儏鍐�
-        with patch.object(ecloud_client.session, 'post') as mock_post:
-            mock_response = Mock()
-            mock_response.json.return_value = {
-                "code": "1000",
-                "message": "鎴愬姛",
-                "data": []
-            }
-            mock_post.return_value = mock_response
-            
-            result = ecloud_client.query_online_wechat_list()
-            assert result is not None
-            assert len(result) == 0
-
-    def test_sms_service_generate_sign(self):
-        """娴嬭瘯鐭俊鏈嶅姟绛惧悕鐢熸垚"""
-        # 浣跨敤鏂囨。涓殑绀轰緥鏁版嵁
-        sms_service.username = "test"
-        sms_service.password = "123"
-        timestamp = 1596254400000
-        
-        sign = sms_service._generate_sign(timestamp)
-        expected_sign = "e315cf297826abdeb2092cc57f29f0bf"
-        
-        assert sign == expected_sign
-
-    def test_email_service_disabled(self):
-        """娴嬭瘯閭欢鏈嶅姟绂佺敤鐘舵��"""
-        with patch('config.settings.email_enabled', False):
-            result = email_service.send_notification("娴嬭瘯涓婚", "娴嬭瘯鍐呭")
-            assert result is True  # 绂佺敤鏃跺簲璇ヨ繑鍥濼rue
-
-    def test_sms_service_disabled(self):
-        """娴嬭瘯鐭俊鏈嶅姟绂佺敤鐘舵��"""
-        with patch('config.settings.sms_enabled', False):
-            result = sms_service.send_notification("娴嬭瘯鍐呭")
-            assert result is True  # 绂佺敤鏃跺簲璇ヨ繑鍥濼rue
-
-    def test_online_status_worker_disabled(self):
-        """娴嬭瘯鍦ㄧ嚎鐘舵�佹娴嬪伐浣滆繘绋嬬鐢ㄧ姸鎬�"""
-        with patch('config.settings.online_status_enabled', False):
-            # 鍒涘缓鏂扮殑宸ヤ綔杩涚▼瀹炰緥杩涜娴嬭瘯
-            from app.workers.online_status_worker import OnlineStatusWorker
-            test_worker = OnlineStatusWorker()
-            
-            test_worker.start()
-            assert test_worker.running is False
-            assert test_worker.worker_thread is None
-
-    def test_online_status_worker_status(self):
-        """娴嬭瘯鑾峰彇宸ヤ綔杩涚▼鐘舵��"""
-        status = online_status_worker.get_status()
-
-        assert "running" in status
-        assert "enabled" in status
-        assert "check_interval_minutes" in status
-        assert "last_notification_time" in status
-        assert "notification_cooldown_minutes" in status
-
-        assert isinstance(status["running"], bool)
-        assert isinstance(status["enabled"], bool)
-        assert isinstance(status["check_interval_minutes"], (int, float))
-        assert isinstance(status["notification_cooldown_minutes"], (int, float))
-
-    def test_dynamic_w_id_update(self):
-        """娴嬭瘯鍔ㄦ�亀_id鏇存柊鍔熻兘"""
-        from config import settings
-
-        # 淇濆瓨鍘熷w_id
-        original_w_id = settings.get_current_w_id()
-
-        try:
-            # 娴嬭瘯鏇存柊w_id
-            new_w_id = "test-new-w-id-123"
-            success = settings.update_ecloud_w_id(new_w_id)
-
-            # 楠岃瘉鏇存柊鎴愬姛
-            assert success is True
-            assert settings.get_current_w_id() == new_w_id
-
-            # 娴嬭瘯鐩稿悓w_id涓嶄細閲嶅鏇存柊
-            success = settings.update_ecloud_w_id(new_w_id)
-            assert success is True
-
-        finally:
-            # 鎭㈠鍘熷w_id
-            settings.update_ecloud_w_id(original_w_id)
-
-    def test_w_id_update_in_online_status_check(self):
-        """娴嬭瘯鍦ㄧ嚎鐘舵�佹娴嬩腑鐨剋_id鏇存柊"""
-        from app.workers.online_status_worker import OnlineStatusWorker
-
-        # 鍒涘缓娴嬭瘯宸ヤ綔杩涚▼瀹炰緥
-        test_worker = OnlineStatusWorker()
-
-        # 妯℃嫙w_id鏇存柊
-        test_w_id = "test-w-id-456"
-        test_worker._update_w_id_if_needed(test_w_id)
-
-        # 杩欓噷涓昏娴嬭瘯鏂规硶涓嶄細鎶涘嚭寮傚父
-        # 瀹為檯鐨剋_id鏇存柊閫昏緫鍦╯ettings涓凡缁忔祴璇曡繃浜�
-
-    def test_startup_contact_sync_logic(self):
-        """娴嬭瘯鍚姩鏃惰仈绯讳汉鍚屾閫昏緫"""
-        # 娴嬭瘯娌℃湁鍦ㄧ嚎寰俊鏃剁殑澶勭悊閫昏緫
-        with patch.object(ecloud_client, 'query_online_wechat_list') as mock_query:
-            # 妯℃嫙鏌ヨ澶辫触
-            mock_query.return_value = None
-            # 杩欑鎯呭喌涓嬪簲璇ヨ烦杩囪仈绯讳汉鍚屾锛屼笉浼氭姏鍑哄紓甯�
-
-            # 妯℃嫙娌℃湁鍦ㄧ嚎寰俊
-            mock_query.return_value = []
-            # 杩欑鎯呭喌涓嬩篃搴旇璺宠繃鑱旂郴浜哄悓姝�
-
-            # 妯℃嫙鏈夊湪绾垮井淇�
-            mock_query.return_value = [{"wcId": "test_wc_id", "wId": "test_w_id"}]
-            # 杩欑鎯呭喌涓嬩細灏濊瘯鍚屾鑱旂郴浜�
-
-    def test_email_service_connection_handling(self):
-        """娴嬭瘯閭欢鏈嶅姟杩炴帴澶勭悊"""
-        # 娴嬭瘯閭欢鏈嶅姟鐨勮繛鎺ュ拰鍏抽棴閫昏緫
-        # 涓昏纭繚涓嶄細鍥犱负杩炴帴鍏抽棴寮傚父鑰屽奖鍝嶅彂閫佺粨鏋�
-
-        # 杩欓噷涓昏娴嬭瘯鏂规硶缁撴瀯锛屽疄闄呯殑SMTP娴嬭瘯闇�瑕佺湡瀹炵殑閭欢鏈嶅姟鍣�
-        assert hasattr(email_service, 'send_email')
-        assert hasattr(email_service, 'test_connection')
-
-
-if __name__ == "__main__":
-    pytest.main([__file__])
diff --git a/tests/test_silence_service.py b/tests/test_silence_service.py
deleted file mode 100644
index 181f9f2..0000000
--- a/tests/test_silence_service.py
+++ /dev/null
@@ -1,177 +0,0 @@
-"""
-闈欓粯妯″紡鏈嶅姟娴嬭瘯
-"""
-
-import time
-import pytest
-from unittest.mock import Mock, patch
-
-from app.services.silence_service import SilenceService
-
-
-class TestSilenceService:
-    """闈欓粯妯″紡鏈嶅姟娴嬭瘯绫�"""
-
-    def setup_method(self):
-        """娴嬭瘯鍓嶅噯澶�"""
-        self.service = SilenceService()
-
-    @patch('app.services.silence_service.settings')
-    @patch('app.services.silence_service.redis_queue')
-    def test_activate_silence_mode_success(self, mock_redis_queue, mock_settings):
-        """娴嬭瘯鎴愬姛婵�娲荤兢缁勯潤榛樻ā寮�"""
-        # 妯℃嫙閰嶇疆
-        mock_settings.silence_mode_enabled = True
-        mock_settings.silence_duration_minutes = 10
-
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.setex.return_value = True
-
-        # 娴嬭瘯婵�娲荤兢缁勯潤榛樻ā寮�
-        group_id = "test_group@chatroom"
-        result = self.service.activate_silence_mode(group_id)
-
-        assert result is True
-        # 楠岃瘉Redis璋冪敤
-        assert mock_redis_client.setex.call_count == 2  # 璁剧疆涓や釜閿�
-
-    @patch('app.services.silence_service.settings')
-    def test_activate_silence_mode_disabled(self, mock_settings):
-        """娴嬭瘯闈欓粯妯″紡鍔熻兘绂佺敤鏃剁殑琛屼负"""
-        mock_settings.silence_mode_enabled = False
-
-        group_id = "test_group@chatroom"
-        result = self.service.activate_silence_mode(group_id)
-        assert result is False
-
-    @patch('app.services.silence_service.settings')
-    @patch('app.services.silence_service.redis_queue')
-    def test_is_silence_active(self, mock_redis_queue, mock_settings):
-        """娴嬭瘯妫�鏌ラ潤榛樻ā寮忔槸鍚︽縺娲�"""
-        mock_settings.silence_mode_enabled = True
-        
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        
-        # 娴嬭瘯闈欓粯妯″紡婵�娲荤姸鎬�
-        mock_redis_client.exists.return_value = True
-        group_id = "test_group@chatroom"
-        result = self.service.is_silence_active(group_id)
-        assert result is True
-
-        # 娴嬭瘯闈欓粯妯″紡鏈縺娲荤姸鎬�
-        mock_redis_client.exists.return_value = False
-        result = self.service.is_silence_active(group_id)
-        assert result is False
-
-    @patch('app.services.silence_service.settings')
-    def test_is_silence_active_disabled(self, mock_settings):
-        """娴嬭瘯鍔熻兘绂佺敤鏃剁殑闈欓粯妯″紡妫�鏌�"""
-        mock_settings.silence_mode_enabled = False
-        
-        group_id = "test_group@chatroom"
-        result = self.service.is_silence_active(group_id)
-        assert result is False
-
-    @patch('app.services.silence_service.settings')
-    @patch('app.services.silence_service.redis_queue')
-    def test_get_silence_remaining_time(self, mock_redis_queue, mock_settings):
-        """娴嬭瘯鑾峰彇闈欓粯妯″紡鍓╀綑鏃堕棿"""
-        mock_settings.silence_mode_enabled = True
-        
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        
-        # 妯℃嫙闈欓粯妯″紡婵�娲�
-        mock_redis_client.exists.return_value = True
-        
-        # 妯℃嫙缁撴潫鏃堕棿锛堝綋鍓嶆椂闂� + 300绉掞級
-        future_time = time.time() + 300
-        mock_redis_client.get.return_value = str(future_time)
-        
-        group_id = "test_group@chatroom"
-        result = self.service.get_silence_remaining_time(group_id)
-        assert result is not None
-        assert result > 0
-        assert result <= 300
-
-    @patch('app.services.silence_service.settings')
-    @patch('app.services.silence_service.redis_queue')
-    def test_get_silence_remaining_time_inactive(self, mock_redis_queue, mock_settings):
-        """娴嬭瘯闈欓粯妯″紡鏈縺娲绘椂鑾峰彇鍓╀綑鏃堕棿"""
-        mock_settings.silence_mode_enabled = True
-        
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.exists.return_value = False
-        
-        group_id = "test_group@chatroom"
-        result = self.service.get_silence_remaining_time(group_id)
-        assert result is None
-
-    @patch('app.services.silence_service.settings')
-    @patch('app.services.silence_service.redis_queue')
-    def test_deactivate_silence_mode(self, mock_redis_queue, mock_settings):
-        """娴嬭瘯鎵嬪姩鍋滅敤闈欓粯妯″紡"""
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.delete.return_value = True
-        
-        result = self.service.deactivate_silence_mode()
-        assert result is True
-        
-        # 楠岃瘉鍒犻櫎浜嗕袱涓敭
-        assert mock_redis_client.delete.call_count == 2
-
-    @patch('app.services.silence_service.settings')
-    @patch('app.services.silence_service.redis_queue')
-    def test_extend_silence_mode(self, mock_redis_queue, mock_settings):
-        """娴嬭瘯寤堕暱闈欓粯妯″紡"""
-        mock_settings.silence_mode_enabled = True
-        mock_settings.silence_duration_minutes = 10
-        
-        # 妯℃嫙Redis鎿嶄綔
-        mock_redis_client = Mock()
-        mock_redis_queue.redis_client = mock_redis_client
-        mock_redis_client.setex.return_value = True
-        
-        group_id = "test_group@chatroom"
-        result = self.service.extend_silence_mode(group_id)
-        assert result is True
-
-    @patch('app.services.silence_service.settings')
-    def test_get_silence_status(self, mock_settings):
-        """娴嬭瘯鑾峰彇闈欓粯妯″紡鐘舵��"""
-        mock_settings.silence_mode_enabled = True
-        mock_settings.silence_duration_minutes = 10
-        
-        with patch.object(self.service, 'is_silence_active', return_value=False):
-            status = self.service.get_silence_status()
-            
-            assert status["enabled"] is True
-            assert status["active"] is False
-            assert status["duration_minutes"] == 10
-            assert status["remaining_seconds"] is None
-            assert status["remaining_minutes"] is None
-
-    @patch('app.services.silence_service.settings')
-    def test_get_silence_status_active(self, mock_settings):
-        """娴嬭瘯鑾峰彇婵�娲荤姸鎬佺殑闈欓粯妯″紡鐘舵��"""
-        mock_settings.silence_mode_enabled = True
-        mock_settings.silence_duration_minutes = 10
-        
-        with patch.object(self.service, 'is_silence_active', return_value=True), \
-             patch.object(self.service, 'get_silence_remaining_time', return_value=300):
-            
-            status = self.service.get_silence_status()
-            
-            assert status["enabled"] is True
-            assert status["active"] is True
-            assert status["remaining_seconds"] == 300
-            assert status["remaining_minutes"] == 5.0

--
Gitblit v1.9.1