|
|
@@ -0,0 +1,83 @@
|
|
|
+"""Tests for Pushover emergency-priority (2) retry/expire handling (#2586).
|
|
|
+
|
|
|
+Pushover rejects a priority-2 (Emergency) message unless it also carries
|
|
|
+``retry`` and ``expire``. These tests pin that we send those params at
|
|
|
+priority 2 (clamped to Pushover's legal 30..10800 range) and omit them at
|
|
|
+every other priority.
|
|
|
+"""
|
|
|
+
|
|
|
+import httpx
|
|
|
+import pytest
|
|
|
+
|
|
|
+from backend.app.services.notification_service import NotificationService
|
|
|
+
|
|
|
+
|
|
|
+class _CaptureClient:
|
|
|
+ """Minimal stand-in for httpx.AsyncClient that records the posted data."""
|
|
|
+
|
|
|
+ def __init__(self):
|
|
|
+ self.is_closed = False
|
|
|
+ self.last_data: dict | None = None
|
|
|
+
|
|
|
+ async def post(self, url, data=None, files=None):
|
|
|
+ self.last_data = data
|
|
|
+ return httpx.Response(200, json={"status": 1})
|
|
|
+
|
|
|
+
|
|
|
+@pytest.fixture
|
|
|
+def service_with_capture():
|
|
|
+ service = NotificationService()
|
|
|
+ client = _CaptureClient()
|
|
|
+ service._http_client = client # bypass real HTTP
|
|
|
+ return service, client
|
|
|
+
|
|
|
+
|
|
|
+BASE_CONFIG = {"user_key": "u" * 30, "app_token": "a" * 30}
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_priority_2_includes_retry_and_expire(service_with_capture):
|
|
|
+ service, client = service_with_capture
|
|
|
+ ok, _ = await service._send_pushover({**BASE_CONFIG, "priority": 2, "retry": 90, "expire": 7200}, "T", "M")
|
|
|
+ assert ok
|
|
|
+ assert client.last_data["priority"] == 2
|
|
|
+ assert client.last_data["retry"] == 90
|
|
|
+ assert client.last_data["expire"] == 7200
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_priority_2_uses_defaults_when_unset(service_with_capture):
|
|
|
+ service, client = service_with_capture
|
|
|
+ ok, _ = await service._send_pushover({**BASE_CONFIG, "priority": 2}, "T", "M")
|
|
|
+ assert ok
|
|
|
+ assert client.last_data["retry"] == 60
|
|
|
+ assert client.last_data["expire"] == 3600
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_priority_2_clamps_to_pushover_limits(service_with_capture):
|
|
|
+ service, client = service_with_capture
|
|
|
+ ok, _ = await service._send_pushover({**BASE_CONFIG, "priority": 2, "retry": 5, "expire": 999999}, "T", "M")
|
|
|
+ assert ok
|
|
|
+ assert client.last_data["retry"] == 30 # min 30
|
|
|
+ assert client.last_data["expire"] == 10800 # max 10800
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_priority_2_tolerates_string_values(service_with_capture):
|
|
|
+ service, client = service_with_capture
|
|
|
+ ok, _ = await service._send_pushover({**BASE_CONFIG, "priority": "2", "retry": "120", "expire": "1800"}, "T", "M")
|
|
|
+ assert ok
|
|
|
+ assert client.last_data["priority"] == 2
|
|
|
+ assert client.last_data["retry"] == 120
|
|
|
+ assert client.last_data["expire"] == 1800
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.asyncio
|
|
|
+@pytest.mark.parametrize("priority", [-2, -1, 0, 1])
|
|
|
+async def test_non_emergency_priority_omits_retry_and_expire(service_with_capture, priority):
|
|
|
+ service, client = service_with_capture
|
|
|
+ ok, _ = await service._send_pushover({**BASE_CONFIG, "priority": priority, "retry": 90, "expire": 7200}, "T", "M")
|
|
|
+ assert ok
|
|
|
+ assert "retry" not in client.last_data
|
|
|
+ assert "expire" not in client.last_data
|