DispelEvilBot/tests/test_admin_admins.py

162 lines
5.4 KiB
Python

"""Тесты раздела «Админы»: добавление, роли, включение и удаление."""
from __future__ import annotations
from datetime import UTC, datetime
from typing import Any
import pytest
from fastapi.testclient import TestClient
from common.repositories import admins_repo
ADMIN_1: dict[str, Any] = {
"telegram_id": 1,
"username": "admin",
"role": "admin",
"enabled": True,
"created_at": datetime(2026, 1, 1, tzinfo=UTC),
"last_login_at": datetime(2026, 10, 25, 12, 0, tzinfo=UTC),
}
ADMIN_2: dict[str, Any] = {
"telegram_id": 2,
"username": "second",
"role": "moderator",
"enabled": True,
"created_at": datetime(2026, 1, 1, tzinfo=UTC),
"last_login_at": None,
}
@pytest.fixture
def fake_admins(monkeypatch: pytest.MonkeyPatch) -> dict[str, Any]:
state: dict[str, Any] = {"admins": [ADMIN_1, ADMIN_2]}
async def list_admins() -> list[dict[str, Any]]:
return state["admins"]
async def upsert_admin(telegram_id: int, username: str | None, role: str) -> None:
state["upsert"] = (telegram_id, username, role)
async def set_admin_role(telegram_id: int, role: str) -> bool:
state["role"] = (telegram_id, role)
return True
async def set_admin_enabled(telegram_id: int, enabled: bool) -> bool:
state["enabled"] = (telegram_id, enabled)
return True
async def delete_admin(telegram_id: int) -> bool:
state["deleted"] = telegram_id
return True
monkeypatch.setattr(admins_repo, "list_admins", list_admins)
monkeypatch.setattr(admins_repo, "upsert_admin", upsert_admin)
monkeypatch.setattr(admins_repo, "set_admin_role", set_admin_role)
monkeypatch.setattr(admins_repo, "set_admin_enabled", set_admin_enabled)
monkeypatch.setattr(admins_repo, "delete_admin", delete_admin)
return state
def _csrf(client: TestClient, csrf_token) -> str:
return csrf_token(client.get("/admins").text)
def test_admins_list(fake_admins: dict[str, Any], client_factory) -> None:
response = client_factory().get("/admins")
assert response.status_code == 200
assert "second" in response.text
assert "(вы)" in response.text
def test_add_admin(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post(
"/admins",
data={"telegram_id": "12345", "username": "@third", "role": "moderator", "csrf_token": token},
)
assert response.status_code == 200
assert "Администратор добавлен" in response.text
assert fake_admins["upsert"] == (12345, "third", "moderator")
def test_add_admin_rejects_bad_id(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post("/admins", data={"telegram_id": "abc", "role": "admin", "csrf_token": token})
assert response.status_code == 400
assert "Telegram-ID должен быть числом" in response.text
assert "upsert" not in fake_admins
def test_change_role(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post("/admins/2/role", data={"role": "admin", "csrf_token": token})
assert response.status_code == 200
assert "Роль обновлена" in response.text
assert fake_admins["role"] == (2, "admin")
def test_cannot_toggle_self(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post("/admins/1/toggle", data={"csrf_token": token})
assert response.status_code == 400
assert "самого себя" in response.text
assert "enabled" not in fake_admins
def test_toggle_admin(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post("/admins/2/toggle", data={"csrf_token": token})
assert response.status_code == 200
assert "Доступ обновлён" in response.text
assert fake_admins["enabled"] == (2, False)
def test_cannot_delete_self(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post("/admins/1/delete", data={"csrf_token": token})
assert response.status_code == 400
assert "удалить самого себя" in response.text
def test_cannot_delete_last_admin(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
fake_admins["admins"] = [ADMIN_2]
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post("/admins/2/delete", data={"csrf_token": token})
assert response.status_code == 400
assert "последнего администратора" in response.text
assert "deleted" not in fake_admins
def test_delete_admin(fake_admins: dict[str, Any], client_factory, csrf_token) -> None:
client: TestClient = client_factory()
token = _csrf(client, csrf_token)
response = client.post("/admins/2/delete", data={"csrf_token": token})
assert response.status_code == 200
assert "Администратор удалён" in response.text
assert fake_admins["deleted"] == 2