diff --git a/tests.py b/tests.py index c9bc745..ab9bd35 100644 --- a/tests.py +++ b/tests.py @@ -785,3 +785,166 @@ class AuthSeparationTests(APITestCase): url = '/api/admin/device-types/' response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + + +# ==================== Log Center 集成测试 ==================== + +class LogCenterIntegrationTests(TestCase): + """Log Center 错误上报集成测试""" + + def test_report_to_log_center_function_exists(self): + """测试 report_to_log_center 函数存在""" + from utils.exceptions import report_to_log_center + self.assertTrue(callable(report_to_log_center)) + + def test_report_to_log_center_with_exception(self): + """测试上报异常到 Log Center""" + from utils.exceptions import report_to_log_center + from unittest.mock import patch, MagicMock + + # 创建测试异常 + try: + raise ValueError("Test error message") + except ValueError as e: + test_exc = e + + # Mock context + mock_request = MagicMock() + mock_request.path = '/api/test/' + mock_request.method = 'GET' + context = {'request': mock_request, 'view': 'TestView'} + + # Mock requests.post + with patch('utils.exceptions.requests.post') as mock_post: + with patch('utils.exceptions.LOG_CENTER_ENABLED', True): + report_to_log_center(test_exc, context) + + # 等待线程执行(测试中同步执行更可靠) + import time + time.sleep(0.5) + + def test_report_payload_structure(self): + """测试上报 payload 结构正确""" + from utils.exceptions import report_to_log_center + from unittest.mock import patch, MagicMock + import json + + captured_payload = None + + def capture_post(url, json=None, timeout=None): + nonlocal captured_payload + captured_payload = json + return MagicMock(status_code=200) + + try: + raise TypeError("Type mismatch error") + except TypeError as e: + test_exc = e + + mock_request = MagicMock() + mock_request.path = '/api/users/me/' + mock_request.method = 'POST' + context = {'request': mock_request, 'view': 'UserView'} + + with patch('utils.exceptions.requests.post', side_effect=capture_post): + with patch('utils.exceptions.LOG_CENTER_ENABLED', True): + with patch('utils.exceptions.threading.Thread') as mock_thread: + # 直接调用 target 函数而不是启动线程 + mock_thread_instance = MagicMock() + def run_target(*args, **kwargs): + target = kwargs.get('target') or args[0] + target() + mock_thread.side_effect = lambda *args, **kwargs: MagicMock( + start=lambda: run_target(*args, **kwargs), + daemon=True + ) + + report_to_log_center(test_exc, context) + + # 验证 payload 结构 + if captured_payload: + self.assertEqual(captured_payload['project_id'], 'rtc_backend') + self.assertEqual(captured_payload['level'], 'ERROR') + self.assertEqual(captured_payload['error']['type'], 'TypeError') + self.assertEqual(captured_payload['error']['message'], 'Type mismatch error') + self.assertIn('stack_trace', captured_payload['error']) + self.assertEqual(captured_payload['context']['url'], '/api/users/me/') + self.assertEqual(captured_payload['context']['method'], 'POST') + + def test_report_disabled_when_flag_off(self): + """测试关闭开关时不上报""" + from utils.exceptions import report_to_log_center + from unittest.mock import patch, MagicMock + + try: + raise Exception("Should not be reported") + except Exception as e: + test_exc = e + + with patch('utils.exceptions.requests.post') as mock_post: + with patch('utils.exceptions.LOG_CENTER_ENABLED', False): + report_to_log_center(test_exc, {}) + # 应该不调用 requests.post + mock_post.assert_not_called() + + def test_report_silent_failure(self): + """测试上报失败不抛异常""" + from utils.exceptions import report_to_log_center + from unittest.mock import patch, MagicMock + + try: + raise Exception("Test exception") + except Exception as e: + test_exc = e + + with patch('utils.exceptions.requests.post', side_effect=Exception("Network error")): + with patch('utils.exceptions.LOG_CENTER_ENABLED', True): + # 不应抛出异常 + try: + report_to_log_center(test_exc, {}) + except Exception: + self.fail("report_to_log_center should not raise exceptions") + + +class ExceptionHandlerIntegrationTests(APITestCase): + """异常处理器集成测试 - 验证异常时触发 Log Center 上报""" + + def test_exception_triggers_log_center_report(self): + """测试异常触发 Log Center 上报""" + from utils.exceptions import custom_exception_handler + from unittest.mock import patch, MagicMock + + # 创建异常 + test_exc = ValueError("Database connection failed") + + # Mock context + mock_request = MagicMock() + mock_request.path = '/api/test/' + mock_request.method = 'GET' + context = {'request': mock_request, 'view': MagicMock()} + + with patch('utils.exceptions.report_to_log_center') as mock_report: + # 调用异常处理器 + custom_exception_handler(test_exc, context) + + # 验证调用了上报函数 + mock_report.assert_called_once() + call_args = mock_report.call_args + self.assertEqual(call_args[0][0], test_exc) + + def test_business_exception_not_reported(self): + """测试业务异常不上报到 Log Center""" + from utils.exceptions import custom_exception_handler, BusinessException + from unittest.mock import patch, MagicMock + + # 创建业务异常 + biz_exc = BusinessException(code=100, message="用户不存在") + + context = {'request': MagicMock(), 'view': MagicMock()} + + with patch('utils.exceptions.report_to_log_center') as mock_report: + custom_exception_handler(biz_exc, context) + + # 业务异常不应触发上报 + mock_report.assert_not_called() +