feat: P0/P1/P2全部功能 — 四层泳道/视角切换/KPI看板/预警/差异反打/预算/知识面板/回顾会/情景预测/Excel导入/角色权限

This commit is contained in:
Hermes CI Fix
2026-07-12 17:46:08 +08:00
parent cdf00efd69
commit ee25d5fa1d
8871 changed files with 1778433 additions and 0 deletions
+183
View File
@@ -0,0 +1,183 @@
"""通知配置模块测试 — 渠道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):
"""没有渠道 → 推送0条"""
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 == 200
assert resp.json()["pushed"] == 0