183 lines
6.2 KiB
Python
183 lines
6.2 KiB
Python
"""通知配置模块测试 — 渠道CRUD + 推送历史"""
|
||
import pytest
|
||
from fastapi.testclient import TestClient
|
||
from sqlalchemy.orm import Session
|
||
from tests.conftest import create_test_user, get_token_for_user, auth_header
|
||
|
||
|
||
class TestNotificationChannels:
|
||
"""通知渠道CRUD测试"""
|
||
|
||
BASE = "/api/cma/notifications"
|
||
|
||
def test_list_channels_empty(self, client: TestClient, db: Session):
|
||
"""空列表"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
resp = client.get(f"{self.BASE}/channels", headers=auth_header(token))
|
||
assert resp.status_code == 200
|
||
assert resp.json()["data"] == []
|
||
|
||
def test_create_wecom_channel(self, client: TestClient, db: Session):
|
||
"""创建企微机器人渠道"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
resp = client.post(
|
||
f"{self.BASE}/channels",
|
||
headers=auth_header(token),
|
||
json={
|
||
"name": "告警群",
|
||
"channel_type": "wecom",
|
||
"config": {"webhook_url": "https://qyapi.weixin.qq.com/webhook/abc"},
|
||
"enabled": True,
|
||
},
|
||
)
|
||
assert resp.status_code == 200
|
||
data = resp.json()
|
||
assert data["name"] == "告警群"
|
||
assert data["channel_type"] == "wecom"
|
||
assert data["enabled"] is True
|
||
|
||
def test_create_mail_channel(self, client: TestClient, db: Session):
|
||
"""创建邮件渠道"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
resp = client.post(
|
||
f"{self.BASE}/channels",
|
||
headers=auth_header(token),
|
||
json={
|
||
"name": "管理邮箱",
|
||
"channel_type": "mail",
|
||
"config": {
|
||
"host": "smtp.qq.com",
|
||
"port": 465,
|
||
"user": "admin@example.com",
|
||
"password": "pass",
|
||
"to": ["admin@example.com"],
|
||
},
|
||
},
|
||
)
|
||
assert resp.status_code == 200
|
||
assert resp.json()["channel_type"] == "mail"
|
||
|
||
def test_update_channel(self, client: TestClient, db: Session):
|
||
"""更新渠道"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
create_resp = client.post(
|
||
f"{self.BASE}/channels",
|
||
headers=auth_header(token),
|
||
json={"name": "旧名称", "channel_type": "wecom", "config": {}},
|
||
)
|
||
ch_id = create_resp.json()["id"]
|
||
|
||
resp = client.put(
|
||
f"{self.BASE}/channels/{ch_id}",
|
||
headers=auth_header(token),
|
||
json={"name": "新名称", "enabled": False},
|
||
)
|
||
assert resp.status_code == 200
|
||
assert resp.json()["name"] == "新名称"
|
||
assert resp.json()["enabled"] is False
|
||
|
||
def test_delete_channel(self, client: TestClient, db: Session):
|
||
"""删除渠道"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
create_resp = client.post(
|
||
f"{self.BASE}/channels",
|
||
headers=auth_header(token),
|
||
json={"name": "待删除", "channel_type": "wecom", "config": {}},
|
||
)
|
||
ch_id = create_resp.json()["id"]
|
||
|
||
resp = client.delete(
|
||
f"{self.BASE}/channels/{ch_id}",
|
||
headers=auth_header(token),
|
||
)
|
||
assert resp.status_code == 200
|
||
assert resp.json()["message"] == "已删除"
|
||
|
||
# 验证已删除
|
||
get_resp = client.get(f"{self.BASE}/channels", headers=auth_header(token))
|
||
assert len(get_resp.json()["data"]) == 0
|
||
|
||
def test_delete_channel_not_found(self, client: TestClient, db: Session):
|
||
"""删除不存在的渠道"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
resp = client.delete(f"{self.BASE}/channels/99999", headers=auth_header(token))
|
||
assert resp.status_code == 404
|
||
|
||
def test_test_channel_network(self, client: TestClient, db: Session):
|
||
"""测试推送(网络可能不通,但不应500)"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
create_resp = client.post(
|
||
f"{self.BASE}/channels",
|
||
headers=auth_header(token),
|
||
json={"name": "测试", "channel_type": "wecom", "config": {"webhook_url": "http://invalid"}, "enabled": True},
|
||
)
|
||
ch_id = create_resp.json()["id"]
|
||
|
||
# 网络不通,但应该返回结果而不是500
|
||
resp = client.post(
|
||
f"{self.BASE}/channels/{ch_id}/test",
|
||
headers=auth_header(token),
|
||
)
|
||
assert resp.status_code == 200
|
||
assert "results" in resp.json()
|
||
|
||
|
||
class TestNotificationLogs:
|
||
"""通知历史测试"""
|
||
|
||
def test_logs_empty(self, client: TestClient, db: Session):
|
||
"""空日志"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
resp = client.get("/api/cma/notifications/logs", headers=auth_header(token))
|
||
assert resp.status_code == 200
|
||
assert resp.json()["total"] == 0
|
||
|
||
def test_logs_with_data(self, client: TestClient, db: Session):
|
||
"""有了日志记录后可查询"""
|
||
from app.models import NotificationLog
|
||
from datetime import datetime
|
||
|
||
# 直接插入日志
|
||
log = NotificationLog(
|
||
alert_id=1, channel="wecom", recipient="测试群",
|
||
title="测试通知", content="测试内容", status="sent", sent_at=datetime.now(),
|
||
)
|
||
db.add(log)
|
||
db.commit()
|
||
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
resp = client.get("/api/cma/notifications/logs", headers=auth_header(token))
|
||
assert resp.status_code == 200
|
||
assert resp.json()["total"] >= 1
|
||
assert len(resp.json()["data"]) >= 1
|
||
|
||
|
||
class TestAlertPush:
|
||
"""手动推送测试"""
|
||
|
||
def test_push_alerts_no_channels(self, client: TestClient, db: Session):
|
||
"""推送端点已移除,预期404"""
|
||
create_test_user(db)
|
||
token = get_token_for_user(client)
|
||
|
||
resp = client.post("/api/cma/notifications/alerts/push", headers=auth_header(token))
|
||
assert resp.status_code == 404, "push端点已移除"
|