The first start tried the default languages once; a DNS failure at that moment left them missing for good. Languages asked for are now kept as pending in state.json and retried in the background (30 s, doubling to 15 min) until they are in, across restarts; an install from the admin panel joins the same queue. A state from before this, with nothing installed, counts as an unfinished first start. The admin panel shows what is waiting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
"""Email translation's languages in the admin panel (app/api/admin.py), with
|
|
the translator service replaced by a stand-in."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from app import translation
|
|
from tests.api.test_admin_users import World, world # noqa: F401 — the fixture
|
|
|
|
|
|
@pytest.fixture
|
|
def service(monkeypatch: pytest.MonkeyPatch) -> dict[str, list[str]]:
|
|
state: dict[str, list[str]] = {"installed": ["en", "pl"], "calls": []}
|
|
|
|
async def status() -> dict[str, object]:
|
|
return {
|
|
"installed": list(state["installed"]),
|
|
"installing": {"de": {"done": 10, "total": 40}} if "de" in state["calls"] else {},
|
|
"available": ["en", "pl", "de", "hu"],
|
|
"errors": {},
|
|
}
|
|
|
|
async def install(code: str) -> None:
|
|
state["calls"].append(code)
|
|
|
|
async def remove(code: str) -> None:
|
|
state["installed"].remove(code)
|
|
|
|
monkeypatch.setattr(translation, "enabled", lambda: True)
|
|
monkeypatch.setattr(translation, "status", status)
|
|
monkeypatch.setattr(translation, "install", install)
|
|
monkeypatch.setattr(translation, "remove", remove)
|
|
return state
|
|
|
|
|
|
async def test_admin_installs_and_removes_languages(
|
|
world: World, # noqa: F811
|
|
service: dict[str, list[str]],
|
|
) -> None:
|
|
async with await world.client(await world.user(admin=True)) as c:
|
|
got = (await c.get("/api/admin/translation")).json()
|
|
assert got["reachable"] and got["installed"] == ["en", "pl"]
|
|
assert got["available"] == ["en", "pl", "de", "hu"]
|
|
|
|
got = (await c.post("/api/admin/translation/languages/de")).json()
|
|
assert service["calls"] == ["de"]
|
|
assert got["installing"] == {"de": {"done": 10, "total": 40}}
|
|
|
|
got = (await c.delete("/api/admin/translation/languages/pl")).json()
|
|
assert got["installed"] == ["en"]
|
|
|
|
assert (await c.post("/api/admin/translation/languages/x;rm")).status_code == 422
|
|
|
|
|
|
async def test_only_admins(world: World, service: dict[str, list[str]]) -> None: # noqa: F811
|
|
async with await world.client(await world.user()) as c:
|
|
assert (await c.get("/api/admin/translation")).status_code == 403
|
|
assert (await c.post("/api/admin/translation/languages/de")).status_code == 403
|
|
assert service["calls"] == []
|
|
|
|
|
|
async def test_unreachable_service_is_reported(
|
|
world: World, # noqa: F811
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
async def down() -> dict[str, object]:
|
|
raise translation.TranslationError("down")
|
|
|
|
monkeypatch.setattr(translation, "enabled", lambda: True)
|
|
monkeypatch.setattr(translation, "status", down)
|
|
async with await world.client(await world.user(admin=True)) as c:
|
|
got = (await c.get("/api/admin/translation")).json()
|
|
assert got == {
|
|
"enabled": True,
|
|
"reachable": False,
|
|
"installed": [],
|
|
"installing": {},
|
|
"pending": [],
|
|
"available": [],
|
|
"errors": {},
|
|
}
|