Files
vidconf/backend/tests/test_admin_api.py
Max Ronzhin 84b06f78f1 test(email): контактный адрес, Reply-To и тестовая отправка письма
Покрытие валидации/сохранения contact_email, простановки Reply-To в
письмах регистрации/приглашений/саммари при включённом и выключенном
контактном адресе, и эндпоинта тестовой отправки (успех, дефолтный
получатель, сбой транспорта без утечки логина/пароля).
2026-07-27 00:35:53 +03:00

761 lines
28 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Интеграционные тесты `/api/v1/admin/*` («Админ-API», блок C).
Покрывает: 403 не-админу на все эндпоинты; CRUD конференций (реюз
`ConferenceService`); PATCH пользователя (роль/блокировка), запрет
самоизменения (409); заблокированный пользователь получает 401 на защищённых
эндпоинтах; ручная рассылка приглашений ставит задачу (мок продюсера);
`PUT /admin/settings` с недоступным уровнем AI → 400; частичный PUT настроек.
"""
import uuid
from datetime import UTC, datetime, timedelta
from pathlib import Path
from unittest.mock import MagicMock
import httpx
import pytest
from sqlalchemy.ext.asyncio import AsyncSession
import api.admin as admin_module
from core.config import get_settings
from core.security import create_access_token, hash_password
from models.conference import Conference
from models.team import Team
from models.user import User
from services import ai_levels
from services.conference_ids import generate_number, generate_slug
from services.email import EmailSendError
FUTURE = datetime.now(UTC) + timedelta(days=3)
async def _make_user(session: AsyncSession, *, role: str = "user") -> User:
user = User(
email=f"{uuid.uuid4()}@example.com",
name_user="Admin API Tester",
password_hash=hash_password("password123"),
email_verified=True,
role=role,
)
session.add(user)
await session.flush()
return user
def _auth_headers(user: User) -> dict[str, str]:
token = create_access_token(user.id, user.role)
return {"Authorization": f"Bearer {token}"}
async def _make_conference(
session: AsyncSession, *, owner_id: uuid.UUID | None = None, **overrides: object
) -> Conference:
defaults: dict[str, object] = {
"number": generate_number(),
"slug": generate_slug(),
"owner_id": owner_id,
"status": "scheduled",
"scheduled_at": FUTURE,
}
defaults.update(overrides)
conference = Conference(**defaults)
session.add(conference)
await session.flush()
return conference
# --- 403 не-админу -----------------------------------------------------------------
async def test_all_admin_endpoints_forbidden_for_non_admin(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
user = await _make_user(db_session)
conference = await _make_conference(db_session, owner_id=user.id)
other_user = await _make_user(db_session)
await db_session.commit()
headers = _auth_headers(user)
requests = [
("GET", "/api/v1/admin/conferences", None),
("PATCH", f"/api/v1/admin/conferences/{conference.id}", {"title": "x"}),
("DELETE", f"/api/v1/admin/conferences/{conference.id}", None),
("POST", f"/api/v1/admin/conferences/{conference.id}/invitations", {}),
("GET", "/api/v1/admin/users", None),
("GET", f"/api/v1/admin/users/{other_user.id}", None),
("PATCH", f"/api/v1/admin/users/{other_user.id}", {"role": "admin"}),
("GET", "/api/v1/admin/settings", None),
("PUT", "/api/v1/admin/settings", {}),
("POST", "/api/v1/admin/settings/test-email", {}),
]
for method, path, body in requests:
response = await client.request(method, path, json=body, headers=headers)
assert response.status_code == 403, f"{method} {path} -> {response.status_code}"
async def test_admin_endpoints_require_authentication(client: httpx.AsyncClient) -> None:
response = await client.get("/api/v1/admin/conferences")
assert response.status_code == 401
# --- Конференции ---------------------------------------------------------------------
async def test_list_conferences_returns_all(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
owner = await _make_user(db_session)
conference = await _make_conference(db_session, owner_id=owner.id, title="Sync")
await db_session.commit()
response = await client.get("/api/v1/admin/conferences", headers=_auth_headers(admin))
assert response.status_code == 200, response.text
body = response.json()
ids = [item["id"] for item in body["items"]]
assert str(conference.id) in ids
assert body["total"] >= 1
item = next(item for item in body["items"] if item["id"] == str(conference.id))
assert item["owner_name"] == owner.name_user
assert item["owner_email"] == owner.email
async def test_list_conferences_owner_fields_are_null_without_owner(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
conference = await _make_conference(db_session, owner_id=None, title="Ownerless")
await db_session.commit()
response = await client.get("/api/v1/admin/conferences", headers=_auth_headers(admin))
assert response.status_code == 200, response.text
item = next(item for item in response.json()["items"] if item["id"] == str(conference.id))
assert item["owner_name"] is None
assert item["owner_email"] is None
async def test_list_conferences_filters_by_status_and_query(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
owner = await _make_user(db_session)
await _make_conference(db_session, owner_id=owner.id, title="Findable Sync", status="scheduled")
await _make_conference(db_session, owner_id=owner.id, title="Other", status="ended")
await db_session.commit()
response = await client.get(
"/api/v1/admin/conferences",
params={"status": "scheduled", "q": "Findable"},
headers=_auth_headers(admin),
)
assert response.status_code == 200
titles = [item["title"] for item in response.json()["items"]]
assert titles == ["Findable Sync"]
async def test_patch_conference_by_admin_returns_200(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
owner = await _make_user(db_session)
conference = await _make_conference(db_session, owner_id=owner.id, title="Original")
await db_session.commit()
response = await client.patch(
f"/api/v1/admin/conferences/{conference.id}",
json={"title": "Renamed by admin"},
headers=_auth_headers(admin),
)
assert response.status_code == 200, response.text
body = response.json()
assert body["title"] == "Renamed by admin"
assert body["owner_name"] == owner.name_user
assert body["owner_email"] == owner.email
async def test_patch_unknown_conference_returns_404(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.patch(
f"/api/v1/admin/conferences/{uuid.uuid4()}",
json={"title": "x"},
headers=_auth_headers(admin),
)
assert response.status_code == 404
async def test_delete_conference_by_admin_returns_204(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
owner = await _make_user(db_session)
conference = await _make_conference(db_session, owner_id=owner.id, status="scheduled")
await db_session.commit()
response = await client.delete(
f"/api/v1/admin/conferences/{conference.id}", headers=_auth_headers(admin)
)
assert response.status_code == 204
async def test_delete_active_conference_by_admin_returns_409(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
owner = await _make_user(db_session)
conference = await _make_conference(
db_session, owner_id=owner.id, status="active", scheduled_at=None
)
await db_session.commit()
response = await client.delete(
f"/api/v1/admin/conferences/{conference.id}", headers=_auth_headers(admin)
)
assert response.status_code == 409
async def test_send_invitations_enqueues_task(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
admin = await _make_user(db_session, role="admin")
owner = await _make_user(db_session)
conference = await _make_conference(db_session, owner_id=owner.id)
await db_session.commit()
mock_enqueue = MagicMock()
monkeypatch.setattr(admin_module, "enqueue_invitations", mock_enqueue)
response = await client.post(
f"/api/v1/admin/conferences/{conference.id}/invitations",
json={"emails": ["custom@example.com"]},
headers=_auth_headers(admin),
)
assert response.status_code == 202, response.text
mock_enqueue.assert_called_once_with(conference.id, emails=["custom@example.com"])
async def test_send_invitations_unknown_conference_returns_404(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
monkeypatch.setattr(admin_module, "enqueue_invitations", MagicMock())
response = await client.post(
f"/api/v1/admin/conferences/{uuid.uuid4()}/invitations",
json={},
headers=_auth_headers(admin),
)
assert response.status_code == 404
# --- Создание пользователя администратором ---------------------------------------------
async def test_create_user_returns_201_and_login_works(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
email = f"{uuid.uuid4()}@example.com"
response = await client.post(
"/api/v1/admin/users",
json={"name_user": "Новый пользователь", "email": email, "password": "password123"},
headers=_auth_headers(admin),
)
assert response.status_code == 201, response.text
body = response.json()
assert body["email"] == email
assert body["name_user"] == "Новый пользователь"
assert body["role"] == "user"
assert body["email_verified"] is True
login = await client.post(
"/api/v1/auth/token", data={"username": email, "password": "password123"}
)
assert login.status_code == 200, login.text
assert "access_token" in login.json()
async def test_create_user_with_team_id(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
team = Team(name=f"Team {uuid.uuid4()}")
db_session.add(team)
await db_session.flush()
await db_session.commit()
email = f"{uuid.uuid4()}@example.com"
response = await client.post(
"/api/v1/admin/users",
json={
"name_user": "С командой",
"email": email,
"password": "password123",
"team_id": str(team.id),
},
headers=_auth_headers(admin),
)
assert response.status_code == 201, response.text
assert response.json()["team_id"] == str(team.id)
async def test_create_user_unknown_team_returns_404(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.post(
"/api/v1/admin/users",
json={
"name_user": "Без команды",
"email": f"{uuid.uuid4()}@example.com",
"password": "password123",
"team_id": str(uuid.uuid4()),
},
headers=_auth_headers(admin),
)
assert response.status_code == 404
assert response.json()["detail"] == "team_not_found"
async def test_create_user_duplicate_email_returns_409(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
existing = await _make_user(db_session)
await db_session.commit()
response = await client.post(
"/api/v1/admin/users",
json={
"name_user": "Дубль",
"email": existing.email,
"password": "password123",
},
headers=_auth_headers(admin),
)
assert response.status_code == 409
assert response.json()["detail"] == "email_already_registered"
async def test_create_user_forbidden_for_non_admin(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
user = await _make_user(db_session)
await db_session.commit()
response = await client.post(
"/api/v1/admin/users",
json={
"name_user": "Not allowed",
"email": f"{uuid.uuid4()}@example.com",
"password": "password123",
},
headers=_auth_headers(user),
)
assert response.status_code == 403
# --- Пользователи ----------------------------------------------------------------------
async def test_list_users_returns_all(client: httpx.AsyncClient, db_session: AsyncSession) -> None:
admin = await _make_user(db_session, role="admin")
other = await _make_user(db_session)
await db_session.commit()
response = await client.get("/api/v1/admin/users", headers=_auth_headers(admin))
assert response.status_code == 200
items = response.json()["items"]
ids = [item["id"] for item in items]
assert str(admin.id) in ids
assert str(other.id) in ids
assert all("email_verified" in item for item in items)
async def test_patch_user_role_and_block(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
target = await _make_user(db_session)
await db_session.commit()
response = await client.patch(
f"/api/v1/admin/users/{target.id}",
json={"role": "admin", "is_blocked": True},
headers=_auth_headers(admin),
)
assert response.status_code == 200, response.text
body = response.json()
assert body["role"] == "admin"
assert body["is_blocked"] is True
assert body["email_verified"] is True
async def test_get_user_returns_profile_card(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
"""Карточка профиля из таблицы пользователей — те же поля, что `/users/me`."""
admin = await _make_user(db_session, role="admin")
target = await _make_user(db_session)
await db_session.commit()
response = await client.get(f"/api/v1/admin/users/{target.id}", headers=_auth_headers(admin))
assert response.status_code == 200, response.text
body = response.json()
assert body["id"] == str(target.id)
assert body["name_user"] == target.name_user
assert body["avatar_url"] is None
assert body["team_name"] is None
async def test_get_unknown_user_returns_404(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.get(f"/api/v1/admin/users/{uuid.uuid4()}", headers=_auth_headers(admin))
assert response.status_code == 404
async def test_patch_user_updates_name(client: httpx.AsyncClient, db_session: AsyncSession) -> None:
admin = await _make_user(db_session, role="admin")
target = await _make_user(db_session)
await db_session.commit()
response = await client.patch(
f"/api/v1/admin/users/{target.id}",
json={"name_user": "Renamed By Admin"},
headers=_auth_headers(admin),
)
assert response.status_code == 200, response.text
assert response.json()["name_user"] == "Renamed By Admin"
async def test_upload_user_avatar_by_admin(
client: httpx.AsyncClient,
db_session: AsyncSession,
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("MEDIA_ROOT", str(tmp_path))
get_settings.cache_clear()
try:
admin = await _make_user(db_session, role="admin")
target = await _make_user(db_session)
await db_session.commit()
response = await client.post(
f"/api/v1/admin/users/{target.id}/avatar",
headers=_auth_headers(admin),
files={"file": ("avatar.png", b"\x89PNG\r\n\x1a\n" + b"\x00" * 32, "image/png")},
)
assert response.status_code == 200, response.text
assert response.json()["avatar_url"] is not None
finally:
get_settings.cache_clear()
async def test_upload_user_avatar_forbidden_for_non_admin(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
user = await _make_user(db_session)
target = await _make_user(db_session)
await db_session.commit()
response = await client.post(
f"/api/v1/admin/users/{target.id}/avatar",
headers=_auth_headers(user),
files={"file": ("avatar.png", b"\x89PNG\r\n\x1a\n" + b"\x00" * 32, "image/png")},
)
assert response.status_code == 403
async def test_patch_self_returns_409(client: httpx.AsyncClient, db_session: AsyncSession) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.patch(
f"/api/v1/admin/users/{admin.id}",
json={"is_blocked": True},
headers=_auth_headers(admin),
)
assert response.status_code == 409
async def test_blocked_user_gets_401_on_protected_endpoint(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
target = await _make_user(db_session)
await db_session.commit()
target_headers = _auth_headers(target)
block_response = await client.patch(
f"/api/v1/admin/users/{target.id}",
json={"is_blocked": True},
headers=_auth_headers(admin),
)
assert block_response.status_code == 200
response = await client.get("/api/v1/users/me", headers=target_headers)
assert response.status_code == 401
async def test_patch_unknown_user_returns_404(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.patch(
f"/api/v1/admin/users/{uuid.uuid4()}",
json={"is_blocked": True},
headers=_auth_headers(admin),
)
assert response.status_code == 404
# --- Настройки --------------------------------------------------------------------------
async def test_get_settings_includes_ai_levels(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Плумбинг `detect_ai_levels` через API — не тест самого детекта (см.
`test_ai_levels.py`): железо теста-«пресета 3» смоделировано env-переменными
(RAM хватает на `min`, но не на `medium`; GPU нет — `max` недоступен), файлы
моделей считаются скачанными (изолируем тест от реального диска)."""
monkeypatch.setattr(ai_levels, "_model_downloaded", lambda _path: True)
monkeypatch.setattr(admin_module, "transcription_queue_served", lambda: False)
monkeypatch.setenv("HW_RAM_MB", "16384")
monkeypatch.delenv("HW_GPU_NAME", raising=False)
get_settings.cache_clear()
try:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.get("/api/v1/admin/settings", headers=_auth_headers(admin))
assert response.status_code == 200, response.text
body = response.json()
levels = {item["level"]: item["available"] for item in body["ai_levels"]}
assert levels["min"] is True
assert levels["medium"] is False
assert levels["max"] is False
finally:
get_settings.cache_clear()
async def test_get_settings_transcription_queue_served_reflects_worker_presence(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
"""`transcription_queue_served`
в ответе `GET /admin/settings` для обоих исходов детекта воркера (замокан
на уровне сервисной функции — сам детект Celery inspect покрыт
`test_task_producers.py`)."""
admin = await _make_user(db_session, role="admin")
await db_session.commit()
monkeypatch.setattr(admin_module, "transcription_queue_served", lambda: True)
served = await client.get("/api/v1/admin/settings", headers=_auth_headers(admin))
assert served.status_code == 200, served.text
assert served.json()["transcription_queue_served"] is True
monkeypatch.setattr(admin_module, "transcription_queue_served", lambda: False)
not_served = await client.get("/api/v1/admin/settings", headers=_auth_headers(admin))
assert not_served.status_code == 200, not_served.text
assert not_served.json()["transcription_queue_served"] is False
async def test_put_settings_partial_update(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(admin_module, "transcription_queue_served", lambda: False)
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.put(
"/api/v1/admin/settings",
json={"chat_enabled": False, "display_timezone": "Asia/Yekaterinburg"},
headers=_auth_headers(admin),
)
assert response.status_code == 200, response.text
body = response.json()
assert body["chat_enabled"] is False
assert body["display_timezone"] == "Asia/Yekaterinburg"
assert body["ai_level"] == "min"
assert body["transcription_queue_served"] is False
async def test_put_settings_unavailable_ai_level_returns_400(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.put(
"/api/v1/admin/settings",
json={"ai_level": "medium"},
headers=_auth_headers(admin),
)
assert response.status_code == 400
async def test_put_settings_contact_email_enable_and_persist(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(admin_module, "transcription_queue_served", lambda: False)
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.put(
"/api/v1/admin/settings",
json={"contact_email_enabled": True, "contact_email": "Contact@VidConf.RU"},
headers=_auth_headers(admin),
)
assert response.status_code == 200, response.text
body = response.json()
assert body["contact_email_enabled"] is True
assert body["contact_email"] == "contact@vidconf.ru"
reloaded = await client.get("/api/v1/admin/settings", headers=_auth_headers(admin))
assert reloaded.json()["contact_email"] == "contact@vidconf.ru"
async def test_put_settings_contact_email_invalid_returns_400(
client: httpx.AsyncClient, db_session: AsyncSession
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.put(
"/api/v1/admin/settings",
json={"contact_email_enabled": True, "contact_email": "not an email"},
headers=_auth_headers(admin),
)
assert response.status_code == 400
# --- Тестовое письмо ----------------------------------------------------------------
async def test_send_test_email_defaults_to_admin_email(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Без явного `to` тестовое письмо уходит на email текущего администратора."""
admin = await _make_user(db_session, role="admin")
await db_session.commit()
sent: dict[str, object] = {}
class _FakeBackend:
async def send(self, **kwargs: object) -> None:
sent.update(kwargs)
monkeypatch.setattr(admin_module, "create_email_backend", lambda settings: _FakeBackend())
response = await client.post(
"/api/v1/admin/settings/test-email", json={}, headers=_auth_headers(admin)
)
assert response.status_code == 200, response.text
body = response.json()
assert body["success"] is True
assert sent["to"] == admin.email
async def test_send_test_email_to_explicit_recipient(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
sent: dict[str, object] = {}
class _FakeBackend:
async def send(self, **kwargs: object) -> None:
sent.update(kwargs)
monkeypatch.setattr(admin_module, "create_email_backend", lambda settings: _FakeBackend())
response = await client.post(
"/api/v1/admin/settings/test-email",
json={"to": "other@example.com"},
headers=_auth_headers(admin),
)
assert response.status_code == 200, response.text
assert sent["to"] == "other@example.com"
async def test_send_test_email_uses_contact_email_as_reply_to(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
await client.put(
"/api/v1/admin/settings",
json={"contact_email_enabled": True, "contact_email": "contact@vidconf.example"},
headers=_auth_headers(admin),
)
sent: dict[str, object] = {}
class _FakeBackend:
async def send(self, **kwargs: object) -> None:
sent.update(kwargs)
monkeypatch.setattr(admin_module, "create_email_backend", lambda settings: _FakeBackend())
response = await client.post(
"/api/v1/admin/settings/test-email", json={}, headers=_auth_headers(admin)
)
assert response.status_code == 200, response.text
assert sent["reply_to"] == "contact@vidconf.example"
async def test_send_test_email_reports_transport_failure_without_leaking_secrets(
client: httpx.AsyncClient, db_session: AsyncSession, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Сбой транспорта — понятный текст ошибки; хост/порт видны, логин/пароль — нет."""
monkeypatch.setenv("EMAIL_BACKEND", "smtp")
monkeypatch.setenv("SMTP_HOST", "smtp.example.com")
monkeypatch.setenv("SMTP_PORT", "2525")
monkeypatch.setenv("SMTP_USERNAME", "secret-user")
monkeypatch.setenv("SMTP_PASSWORD", "super-secret-password")
get_settings.cache_clear()
class _FailingBackend:
async def send(self, **kwargs: object) -> None:
raise EmailSendError("временный сбой SMTP: сервер недоступен", retryable=True)
monkeypatch.setattr(admin_module, "create_email_backend", lambda settings: _FailingBackend())
try:
admin = await _make_user(db_session, role="admin")
await db_session.commit()
response = await client.post(
"/api/v1/admin/settings/test-email", json={}, headers=_auth_headers(admin)
)
assert response.status_code == 200, response.text
body = response.json()
assert body["success"] is False
assert "сбой SMTP" in body["message"]
assert body["smtp_host"] == "smtp.example.com"
assert body["smtp_port"] == 2525
assert "secret-user" not in response.text
assert "super-secret-password" not in response.text
finally:
get_settings.cache_clear()