Initial commit: SMS Forwarder project with Docker support

This commit is contained in:
zack
2025-07-17 19:30:35 +08:00
commit 152e136673
29 changed files with 3583 additions and 0 deletions

1
tests/__init__.py Normal file
View File

@ -0,0 +1 @@
"""测试包."""

57
tests/test_main.py Normal file
View File

@ -0,0 +1,57 @@
"""主应用测试."""
import pytest
from fastapi.testclient import TestClient
from sms_forwarder.main import app
client = TestClient(app)
def test_root():
"""测试根路径."""
response = client.get("/")
assert response.status_code == 200
data = response.json()
assert "message" in data
assert "version" in data
def test_health_check():
"""测试健康检查."""
response = client.get("/health")
assert response.status_code == 200
data = response.json()
assert data["status"] == "healthy"
assert "timestamp" in data
def test_status():
"""测试状态接口."""
response = client.get("/status")
assert response.status_code == 200
data = response.json()
assert "version" in data
assert "uptime" in data
assert "notifications_sent" in data
assert "notifications_failed" in data
def test_notify_without_auth():
"""测试未认证的通知请求."""
response = client.post("/notify", json={
"api_key": "invalid-key",
"message": {
"sender": "test",
"content": "test message"
}
})
assert response.status_code == 401
def test_notify_invalid_data():
"""测试无效数据的通知请求."""
response = client.post("/notify", json={
"invalid": "data"
})
assert response.status_code == 422

105
tests/test_notifier.py Normal file
View File

@ -0,0 +1,105 @@
"""通知模块测试."""
import pytest
from unittest.mock import MagicMock, patch
from sms_forwarder.models import SMSMessage
from sms_forwarder.notifier import NotificationManager
@pytest.fixture
def notification_manager():
"""通知管理器测试夹具."""
with patch("sms_forwarder.notifier.get_config") as mock_get_config:
# 模拟配置
mock_config = MagicMock()
mock_config.notifications.services = [
MagicMock(name="test", url="test://test", enabled=True)
]
mock_config.notifications.templates.sms.title = "SMS: {sender}"
mock_config.notifications.templates.sms.body = "From: {sender}\nContent: {content}\nTime: {timestamp}"
mock_config.notifications.templates.system.title = "System"
mock_config.notifications.templates.system.body = "{message}"
mock_get_config.return_value = mock_config
manager = NotificationManager()
# 模拟 Apprise 对象
manager.apprise_obj = MagicMock()
manager.apprise_obj.__len__.return_value = 1
yield manager
def test_send_sms_notification_success(notification_manager):
"""测试成功发送短信通知."""
notification_manager.apprise_obj.notify.return_value = True
sms = SMSMessage(
sender="Test Sender",
content="Test Message"
)
result = notification_manager.send_sms_notification(sms)
assert result is True
assert notification_manager.stats["sent"] == 1
assert notification_manager.stats["failed"] == 0
notification_manager.apprise_obj.notify.assert_called_once()
def test_send_sms_notification_failure(notification_manager):
"""测试发送短信通知失败."""
notification_manager.apprise_obj.notify.return_value = False
sms = SMSMessage(
sender="Test Sender",
content="Test Message"
)
result = notification_manager.send_sms_notification(sms)
assert result is False
assert notification_manager.stats["sent"] == 0
assert notification_manager.stats["failed"] == 1
notification_manager.apprise_obj.notify.assert_called_once()
def test_send_system_notification(notification_manager):
"""测试发送系统通知."""
notification_manager.apprise_obj.notify.return_value = True
result = notification_manager.send_system_notification("Test System Message")
assert result is True
assert notification_manager.stats["sent"] == 1
notification_manager.apprise_obj.notify.assert_called_once()
def test_no_services_available(notification_manager):
"""测试没有可用服务时的行为."""
# 模拟没有可用服务
notification_manager.apprise_obj.__len__.return_value = 0
sms = SMSMessage(
sender="Test Sender",
content="Test Message"
)
result = notification_manager.send_sms_notification(sms)
assert result is False
assert notification_manager.stats["failed"] == 1
# 应该不会调用 notify
notification_manager.apprise_obj.notify.assert_not_called()
def test_get_stats(notification_manager):
"""测试获取统计信息."""
notification_manager.stats = {"sent": 5, "failed": 2}
stats = notification_manager.get_stats()
assert stats == {"sent": 5, "failed": 2}
# 确保返回的是副本
assert stats is not notification_manager.stats