226 lines
7.1 KiB
Python
226 lines
7.1 KiB
Python
|
|
"""Tests for notify toggle helpers and cross-worker settings broadcast."""
|
||
|
|
|
||
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from server.config import settings
|
||
|
|
from server.infrastructure.settings_broadcast import apply_setting_override, publish_setting_change
|
||
|
|
from server.infrastructure.telegram import send_telegram_alert, send_telegram_recovery, send_telegram_system_alert
|
||
|
|
from server.utils.notify_toggles import (
|
||
|
|
notify_attr_enabled,
|
||
|
|
notify_enabled,
|
||
|
|
resource_alert_notify_enabled,
|
||
|
|
resource_recovery_notify_enabled,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize(
|
||
|
|
("value", "expected"),
|
||
|
|
[
|
||
|
|
("true", True),
|
||
|
|
("false", False),
|
||
|
|
("0", False),
|
||
|
|
("off", False),
|
||
|
|
("no", False),
|
||
|
|
(False, False),
|
||
|
|
(True, True),
|
||
|
|
(None, True),
|
||
|
|
],
|
||
|
|
)
|
||
|
|
def test_notify_enabled(value, expected):
|
||
|
|
assert notify_enabled(value) is expected
|
||
|
|
|
||
|
|
|
||
|
|
def test_resource_alert_notify_enabled_respects_cpu_toggle():
|
||
|
|
settings.NOTIFY_ALERT_CPU = "false"
|
||
|
|
settings.NOTIFY_ALERT_MEM = "true"
|
||
|
|
settings.NOTIFY_ALERT_DISK = "true"
|
||
|
|
assert resource_alert_notify_enabled("cpu") is False
|
||
|
|
assert resource_alert_notify_enabled("mem") is True
|
||
|
|
assert resource_alert_notify_enabled("disk") is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_resource_recovery_requires_both_toggles():
|
||
|
|
settings.NOTIFY_RECOVERY = "true"
|
||
|
|
settings.NOTIFY_ALERT_CPU = "false"
|
||
|
|
settings.NOTIFY_ALERT_MEM = "true"
|
||
|
|
settings.NOTIFY_ALERT_DISK = "false"
|
||
|
|
assert resource_recovery_notify_enabled("cpu") is False
|
||
|
|
assert resource_recovery_notify_enabled("mem") is True
|
||
|
|
assert resource_recovery_notify_enabled("disk") is False
|
||
|
|
|
||
|
|
settings.NOTIFY_RECOVERY = "false"
|
||
|
|
assert resource_recovery_notify_enabled("mem") is False
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("metric,attr", [
|
||
|
|
("cpu", "NOTIFY_ALERT_CPU"),
|
||
|
|
("mem", "NOTIFY_ALERT_MEM"),
|
||
|
|
("disk", "NOTIFY_ALERT_DISK"),
|
||
|
|
])
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_send_telegram_alert_skipped_when_metric_disabled(metric, attr):
|
||
|
|
setattr(settings, attr, "false")
|
||
|
|
settings.TELEGRAM_BOT_TOKEN = "123:ABC"
|
||
|
|
settings.TELEGRAM_CHAT_ID = "1"
|
||
|
|
|
||
|
|
with patch("server.infrastructure.telegram.send_telegram", new_callable=AsyncMock) as mock_send:
|
||
|
|
result = await send_telegram_alert("srv-1", metric, 95.0, 1)
|
||
|
|
|
||
|
|
assert result is False
|
||
|
|
mock_send.assert_not_awaited()
|
||
|
|
|
||
|
|
|
||
|
|
def test_apply_db_override_notify_toggle():
|
||
|
|
settings.NOTIFY_ALERT_CPU = "true"
|
||
|
|
assert apply_setting_override("notify_alert_cpu", "false") is True
|
||
|
|
assert settings.NOTIFY_ALERT_CPU == "false"
|
||
|
|
|
||
|
|
|
||
|
|
def test_apply_db_override_unknown_key():
|
||
|
|
assert apply_setting_override("nonexistent_key", "x") is False
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_publish_setting_change():
|
||
|
|
mock_redis = AsyncMock()
|
||
|
|
mock_redis.publish = AsyncMock(return_value=1)
|
||
|
|
|
||
|
|
with patch("server.infrastructure.redis.client.get_redis", return_value=mock_redis):
|
||
|
|
ok = await publish_setting_change("notify_alert_cpu", "false")
|
||
|
|
|
||
|
|
assert ok is True
|
||
|
|
mock_redis.publish.assert_awaited_once()
|
||
|
|
channel, payload = mock_redis.publish.await_args.args
|
||
|
|
assert channel == "nexus:settings"
|
||
|
|
assert '"notify_alert_cpu"' in payload
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_send_telegram_recovery_skipped_when_disabled():
|
||
|
|
settings.NOTIFY_RECOVERY = "false"
|
||
|
|
|
||
|
|
with patch("server.infrastructure.telegram.send_telegram", new_callable=AsyncMock) as mock_send:
|
||
|
|
result = await send_telegram_recovery("srv-1", "cpu", 50.0, 1)
|
||
|
|
|
||
|
|
assert result is False
|
||
|
|
mock_send.assert_not_awaited()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("metric,attr", [
|
||
|
|
("cpu", "NOTIFY_ALERT_CPU"),
|
||
|
|
("mem", "NOTIFY_ALERT_MEM"),
|
||
|
|
("disk", "NOTIFY_ALERT_DISK"),
|
||
|
|
])
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_send_telegram_recovery_skipped_when_metric_alert_disabled(metric, attr):
|
||
|
|
settings.NOTIFY_RECOVERY = "true"
|
||
|
|
setattr(settings, attr, "false")
|
||
|
|
|
||
|
|
with patch("server.infrastructure.telegram.send_telegram", new_callable=AsyncMock) as mock_send:
|
||
|
|
result = await send_telegram_recovery("srv-1", metric, 50.0, 1)
|
||
|
|
|
||
|
|
assert result is False
|
||
|
|
mock_send.assert_not_awaited()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_send_telegram_recovery_allowed_when_cpu_enabled():
|
||
|
|
settings.NOTIFY_RECOVERY = "true"
|
||
|
|
settings.NOTIFY_ALERT_CPU = "true"
|
||
|
|
settings.TELEGRAM_BOT_TOKEN = "123:ABC"
|
||
|
|
settings.TELEGRAM_CHAT_ID = "1"
|
||
|
|
|
||
|
|
with patch("server.infrastructure.telegram.send_telegram", new_callable=AsyncMock) as mock_send:
|
||
|
|
mock_send.return_value = True
|
||
|
|
result = await send_telegram_recovery("srv-1", "cpu", 50.0, 1)
|
||
|
|
|
||
|
|
assert result is True
|
||
|
|
mock_send.assert_awaited_once()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("notify_key", ["NOTIFY_SYSTEM_REDIS", "NOTIFY_SYSTEM_MYSQL"])
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_send_telegram_system_recovery_skipped_when_disabled(notify_key):
|
||
|
|
setattr(settings, notify_key, "false")
|
||
|
|
|
||
|
|
with patch("server.infrastructure.telegram.send_telegram", new_callable=AsyncMock) as mock_send:
|
||
|
|
result = await send_telegram_system_alert(
|
||
|
|
summary="连接已恢复",
|
||
|
|
title="服务恢复",
|
||
|
|
notify_key=notify_key,
|
||
|
|
icon="🟢",
|
||
|
|
)
|
||
|
|
|
||
|
|
assert result is False
|
||
|
|
mock_send.assert_not_awaited()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_send_telegram_system_alert_skipped_when_disabled():
|
||
|
|
settings.NOTIFY_TIME_DRIFT = "false"
|
||
|
|
|
||
|
|
with patch("server.infrastructure.telegram.send_telegram", new_callable=AsyncMock) as mock_send:
|
||
|
|
result = await send_telegram_system_alert(
|
||
|
|
summary="test",
|
||
|
|
notify_key="NOTIFY_TIME_DRIFT",
|
||
|
|
)
|
||
|
|
|
||
|
|
assert result is False
|
||
|
|
mock_send.assert_not_awaited()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_set_setting_publishes_broadcast():
|
||
|
|
from server.api.schemas import SettingUpdatePayload
|
||
|
|
from server.api.settings import set_setting
|
||
|
|
from server.domain.models import Setting
|
||
|
|
|
||
|
|
settings.NOTIFY_ALERT_CPU = "true"
|
||
|
|
admin = MagicMock(username="admin")
|
||
|
|
request = MagicMock()
|
||
|
|
request.client.host = "127.0.0.1"
|
||
|
|
db = MagicMock()
|
||
|
|
mock_setting = Setting(key="notify_alert_cpu", value="false")
|
||
|
|
|
||
|
|
with patch("server.api.settings.SettingRepositoryImpl") as repo_cls, patch(
|
||
|
|
"server.api.settings.AuditLogRepositoryImpl"
|
||
|
|
) as audit_cls, patch(
|
||
|
|
"server.infrastructure.settings_broadcast.publish_setting_change",
|
||
|
|
new_callable=AsyncMock,
|
||
|
|
) as mock_publish:
|
||
|
|
repo = repo_cls.return_value
|
||
|
|
repo.set = AsyncMock(return_value=mock_setting)
|
||
|
|
audit_cls.return_value.create = AsyncMock()
|
||
|
|
|
||
|
|
await set_setting(
|
||
|
|
"notify_alert_cpu",
|
||
|
|
SettingUpdatePayload(value="false"),
|
||
|
|
request,
|
||
|
|
admin,
|
||
|
|
db,
|
||
|
|
)
|
||
|
|
|
||
|
|
assert settings.NOTIFY_ALERT_CPU == "false"
|
||
|
|
mock_publish.assert_awaited_once_with("notify_alert_cpu", "false")
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize(
|
||
|
|
"attr",
|
||
|
|
[
|
||
|
|
"NOTIFY_ALERT_CPU",
|
||
|
|
"NOTIFY_ALERT_MEM",
|
||
|
|
"NOTIFY_ALERT_DISK",
|
||
|
|
"NOTIFY_RECOVERY",
|
||
|
|
"NOTIFY_TIME_DRIFT",
|
||
|
|
"NOTIFY_SYSTEM_REDIS",
|
||
|
|
"NOTIFY_SYSTEM_MYSQL",
|
||
|
|
"NOTIFY_RESTART",
|
||
|
|
"NOTIFY_SCRIPT_COMPLETE",
|
||
|
|
],
|
||
|
|
)
|
||
|
|
def test_all_notify_attrs_disable(attr):
|
||
|
|
setattr(settings, attr, "false")
|
||
|
|
assert notify_attr_enabled(attr) is False
|