Files
training-software/cms/tests/test_cms.py
Paperclip CTO 01661bf5a8
Some checks failed
CI / lint (push) Successful in 6s
CI / test (push) Failing after 7s
CI / build-container (push) Has been skipped
fix: restore CI by fixing lint, test collection, and notification syntax
2026-05-18 14:53:29 +02:00

179 lines
7.2 KiB
Python

import uuid
from unittest.mock import patch
import pytest
from django.core.files.uploadedfile import SimpleUploadedFile
from rest_framework import status
from rest_framework.test import APIClient
from accounts.tests.factories import AccountUserFactory
from cms.models import ContentBlock, ScanStatus
from cms.upload import UploadValidationError, validate_upload
from .factories import ContentBlockFactory, CourseThemeFactory, MediaAssetFactory, PageFactory
@pytest.fixture
def api_client():
return APIClient()
@pytest.fixture
def auth_client():
user = AccountUserFactory()
client = APIClient()
client.force_authenticate(user=user)
return client, user
# ── Upload validation ──────────────────────────────────────────────────────────
class TestValidateUpload:
def _make_file(self, name, size=1024, content=b"x" * 1024):
return SimpleUploadedFile(name, content)
def test_accepts_allowed_extension(self):
f = self._make_file("photo.jpg")
validate_upload(f) # should not raise
def test_rejects_disallowed_extension(self):
f = self._make_file("script.exe", size=100, content=b"x" * 100)
with pytest.raises(UploadValidationError, match="extension"):
validate_upload(f)
def test_rejects_oversized_file(self):
big = SimpleUploadedFile("big.jpg", b"x" * (101 * 1024 * 1024))
with pytest.raises(UploadValidationError, match="size"):
validate_upload(big)
# ── MediaUploadView ────────────────────────────────────────────────────────────
@pytest.mark.django_db
class TestMediaUploadView:
url = "/api/cms/upload/"
def test_unauthenticated_returns_401(self, api_client):
f = SimpleUploadedFile("img.jpg", b"data", content_type="image/jpeg")
resp = api_client.post(self.url, {"file": f}, format="multipart")
assert resp.status_code == status.HTTP_401_UNAUTHORIZED
def test_upload_creates_asset(self, auth_client):
client, user = auth_client
content = b"fake image data"
f = SimpleUploadedFile("test.jpg", content, content_type="image/jpeg")
with patch("cms.views.save_upload") as mock_save:
asset = MediaAssetFactory(uploaded_by=user)
mock_save.return_value = asset
resp = client.post(self.url, {"file": f, "org_id": str(uuid.uuid4())}, format="multipart")
assert resp.status_code == status.HTTP_201_CREATED
assert "id" in resp.data
def test_missing_file_returns_400(self, auth_client):
client, _ = auth_client
resp = client.post(self.url, {}, format="multipart")
assert resp.status_code == status.HTTP_400_BAD_REQUEST
def test_invalid_file_returns_400(self, auth_client):
client, _ = auth_client
f = SimpleUploadedFile("malware.exe", b"MZ", content_type="application/octet-stream")
resp = client.post(self.url, {"file": f}, format="multipart")
assert resp.status_code == status.HTTP_400_BAD_REQUEST
# ── PageContentBlocksView ──────────────────────────────────────────────────────
@pytest.mark.django_db
class TestPageContentBlocksView:
def test_list_blocks_for_page(self, auth_client):
client, _ = auth_client
page = PageFactory()
b1 = ContentBlockFactory(page=page, order=0)
b2 = ContentBlockFactory(page=page, order=1)
url = f"/api/cms/pages/{page.pk}/blocks/"
resp = client.get(url)
assert resp.status_code == status.HTTP_200_OK
ids = [b["id"] for b in resp.data]
assert str(b1.pk) in ids
assert str(b2.pk) in ids
def test_create_block(self, auth_client):
client, _ = auth_client
page = PageFactory()
url = f"/api/cms/pages/{page.pk}/blocks/"
payload = {"block_type": "richtext", "body": "<p>Hello</p>", "order": 0}
resp = client.post(url, payload, format="json")
assert resp.status_code == status.HTTP_201_CREATED
assert ContentBlock.objects.filter(page=page).count() == 1
def test_create_block_unknown_page_returns_404(self, auth_client):
client, _ = auth_client
url = f"/api/cms/pages/{uuid.uuid4()}/blocks/"
resp = client.post(url, {"block_type": "richtext", "order": 0}, format="json")
assert resp.status_code == status.HTTP_404_NOT_FOUND
# ── ContentBlockDetailView ─────────────────────────────────────────────────────
@pytest.mark.django_db
class TestContentBlockDetailView:
def test_patch_block(self, auth_client):
client, _ = auth_client
block = ContentBlockFactory(body="original")
url = f"/api/cms/blocks/{block.pk}/"
resp = client.patch(url, {"body": "updated"}, format="json")
assert resp.status_code == status.HTTP_200_OK
block.refresh_from_db()
assert block.body == "updated"
def test_delete_block(self, auth_client):
client, _ = auth_client
block = ContentBlockFactory()
url = f"/api/cms/blocks/{block.pk}/"
resp = client.delete(url)
assert resp.status_code == status.HTTP_204_NO_CONTENT
assert not ContentBlock.objects.filter(pk=block.pk).exists()
def test_patch_nonexistent_returns_404(self, auth_client):
client, _ = auth_client
url = f"/api/cms/blocks/{uuid.uuid4()}/"
resp = client.patch(url, {"body": "x"}, format="json")
assert resp.status_code == status.HTTP_404_NOT_FOUND
# ── CourseTheme ────────────────────────────────────────────────────────────────
@pytest.mark.django_db
class TestCourseTheme:
def test_theme_created_with_defaults(self):
theme = CourseThemeFactory()
assert theme.primary_color == "#1a1a1a"
assert theme.logo is None
def test_theme_with_logo(self):
user = AccountUserFactory()
asset = MediaAssetFactory(uploaded_by=user)
theme = CourseThemeFactory(logo=asset)
assert theme.logo == asset
# ── scan_media_asset_task ──────────────────────────────────────────────────────
@pytest.mark.django_db
class TestScanMediaAssetTask:
def test_marks_asset_clean(self):
from cms.tasks import scan_media_asset_task
user = AccountUserFactory()
asset = MediaAssetFactory(uploaded_by=user, scan_status=ScanStatus.PENDING)
result = scan_media_asset_task(str(asset.pk))
asset.refresh_from_db()
assert asset.scan_status == ScanStatus.CLEAN
assert result["scan_status"] == "clean"
def test_missing_asset_returns_error(self):
from cms.tasks import scan_media_asset_task
result = scan_media_asset_task(str(uuid.uuid4()))
assert result["error"] == "not found"