bambuddy/backend/tests/unit/test_pushover_priority.py
maziggy 1555fad539 fix(notifications): send Pushover retry/expire for Emergency priority (#2586)
Pushover rejects priority-2 (Emergency) messages unless they carry retry
and expire. _send_pushover never sent them, so setting priority 2 always
failed with Pushover's "retry and expire are required" error. Now at
priority 2 we send retry/expire (default 60s/3600s, clamped to Pushover's
30-10800s range), surfaced as two provider fields shown only when priority
is 2. Added PushoverConfig schema fields, i18n labels across all locales,
and unit tests.
2026-07-17 10:02:19 +02:00

83 lines
2.9 KiB
Python

"""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