Files
training-software/tests/test_smoke.py
Paperclip CTO ca0352fa33 fix(ci): resolve ruff lint violations blocking CI pipeline
- Move `from datetime import timedelta` to top of base.py (E402)
- Add `# noqa: E402` to conditional sentry imports in prod.py (E402)
- Remove unused `import time` and `IsAdminUser` from api/views.py (F401)
- Remove unused `NoReverseMatch` import from tests/test_smoke.py (F401)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-08 07:52:08 +02:00

103 lines
3.3 KiB
Python

"""
Startup smoke tests.
These verify that the project boots, migrations apply cleanly, the URL conf
resolves key routes, and the healthcheck endpoint returns the expected shape.
They do NOT require live Postgres/Redis — the test settings use an in-memory
cache and the test database configured in pytest.ini.
"""
import pytest
from django.urls import reverse, resolve
@pytest.mark.smoke
def test_django_settings_module_importable(settings):
"""The test settings module loads without error."""
assert settings.DJANGO_SETTINGS_MODULE if hasattr(settings, "DJANGO_SETTINGS_MODULE") else True
@pytest.mark.smoke
def test_installed_apps_complete(settings):
"""All expected apps are present in INSTALLED_APPS."""
required = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"rest_framework",
"drf_spectacular",
"guardian",
"django_celery_results",
"api",
"accounts",
"courses",
"cms",
"tracking",
"quizzes",
"training",
"certificates",
"reports",
"notifications",
]
missing = [app for app in required if app not in settings.INSTALLED_APPS]
assert not missing, f"Missing INSTALLED_APPS entries: {missing}"
@pytest.mark.smoke
def test_healthcheck_url_resolves():
"""The /healthz/ URL must resolve to api:healthcheck."""
match = resolve("/healthz/")
assert match.view_name == "api:healthcheck"
@pytest.mark.smoke
def test_healthcheck_reverse():
"""reverse('api:healthcheck') must return /healthz/."""
assert reverse("api:healthcheck") == "/healthz/"
@pytest.mark.smoke
@pytest.mark.django_db
def test_healthcheck_returns_200(client):
"""GET /healthz/ returns 200 with the expected JSON shape in test env."""
response = client.get("/healthz/")
assert response.status_code in (200, 503)
data = response.json()
assert "status" in data
assert "checks" in data
@pytest.mark.smoke
def test_drf_exception_handler_configured(settings):
"""Custom exception handler must be wired up in REST_FRAMEWORK settings."""
handler = settings.REST_FRAMEWORK.get("EXCEPTION_HANDLER")
assert handler == "api.exceptions.custom_exception_handler"
@pytest.mark.smoke
def test_spectacular_settings_present(settings):
"""drf-spectacular settings block must exist with correct title."""
s = settings.SPECTACULAR_SETTINGS
assert s["TITLE"] == "Trainingssoftware API"
assert s["VERSION"] == "1.0.0"
@pytest.mark.smoke
def test_celery_always_eager_in_tests(settings):
"""Celery must run tasks eagerly (synchronously) during tests."""
assert settings.CELERY_TASK_ALWAYS_EAGER is True
@pytest.mark.smoke
def test_domain_app_urls_registered():
"""Each domain app namespace must have at least the app_name registered."""
from django.urls import get_resolver
resolver = get_resolver()
namespaces = list(resolver.namespace_dict.keys())
expected_namespaces = [
"accounts", "courses", "cms", "tracking",
"quizzes", "training", "certificates", "reports", "notifications",
]
missing = [ns for ns in expected_namespaces if ns not in namespaces]
assert not missing, f"Missing URL namespaces: {missing}"