mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-11-11 17:16:43 -05:00
Backend tests
This commit is contained in:
parent
36fae88016
commit
1510a7550e
182
src/documents/tests/test_api_share_link_bundles.py
Normal file
182
src/documents/tests/test_api_share_link_bundles.py
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils import timezone
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
|
from documents.models import ShareLink
|
||||||
|
from documents.models import ShareLinkBundle
|
||||||
|
from documents.tasks import cleanup_expired_share_link_bundles
|
||||||
|
from documents.tests.factories import DocumentFactory
|
||||||
|
from documents.tests.utils import DirectoriesMixin
|
||||||
|
|
||||||
|
|
||||||
|
class ShareLinkBundleAPITests(DirectoriesMixin, APITestCase):
|
||||||
|
ENDPOINT = "/api/share_link_bundles/"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.user = User.objects.create_superuser(username="bundle_admin")
|
||||||
|
self.client.force_authenticate(self.user)
|
||||||
|
self.document = DocumentFactory.create()
|
||||||
|
|
||||||
|
@mock.patch("documents.views.build_share_link_bundle.delay")
|
||||||
|
def test_create_bundle_triggers_build_job(self, delay_mock):
|
||||||
|
payload = {
|
||||||
|
"document_ids": [self.document.pk],
|
||||||
|
"file_version": ShareLink.FileVersion.ARCHIVE,
|
||||||
|
"expiration_days": 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.client.post(self.ENDPOINT, payload, format="json")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
bundle = ShareLinkBundle.objects.get(pk=response.data["id"])
|
||||||
|
self.assertEqual(bundle.documents.count(), 1)
|
||||||
|
self.assertEqual(bundle.status, ShareLinkBundle.Status.PENDING)
|
||||||
|
delay_mock.assert_called_once_with(bundle.pk)
|
||||||
|
|
||||||
|
def test_create_bundle_rejects_missing_documents(self):
|
||||||
|
payload = {
|
||||||
|
"document_ids": [9999],
|
||||||
|
"file_version": ShareLink.FileVersion.ARCHIVE,
|
||||||
|
"expiration_days": 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.client.post(self.ENDPOINT, payload, format="json")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
self.assertIn("document_ids", response.data)
|
||||||
|
|
||||||
|
@mock.patch("documents.views.build_share_link_bundle.delay")
|
||||||
|
def test_rebuild_bundle_resets_state(self, delay_mock):
|
||||||
|
bundle = ShareLinkBundle.objects.create(
|
||||||
|
slug="rebuild-slug",
|
||||||
|
file_version=ShareLink.FileVersion.ARCHIVE,
|
||||||
|
status=ShareLinkBundle.Status.FAILED,
|
||||||
|
)
|
||||||
|
bundle.documents.set([self.document])
|
||||||
|
bundle.last_error = "Something went wrong"
|
||||||
|
bundle.size_bytes = 100
|
||||||
|
bundle.file_path = "path/to/file.zip"
|
||||||
|
bundle.save()
|
||||||
|
|
||||||
|
response = self.client.post(f"{self.ENDPOINT}{bundle.pk}/rebuild/")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
bundle.refresh_from_db()
|
||||||
|
self.assertEqual(bundle.status, ShareLinkBundle.Status.PENDING)
|
||||||
|
self.assertEqual(bundle.last_error, "")
|
||||||
|
self.assertIsNone(bundle.size_bytes)
|
||||||
|
self.assertEqual(bundle.file_path, "")
|
||||||
|
delay_mock.assert_called_once_with(bundle.pk)
|
||||||
|
|
||||||
|
def test_rebuild_bundle_rejects_processing_status(self):
|
||||||
|
bundle = ShareLinkBundle.objects.create(
|
||||||
|
slug="processing-slug",
|
||||||
|
file_version=ShareLink.FileVersion.ARCHIVE,
|
||||||
|
status=ShareLinkBundle.Status.PROCESSING,
|
||||||
|
)
|
||||||
|
bundle.documents.set([self.document])
|
||||||
|
|
||||||
|
response = self.client.post(f"{self.ENDPOINT}{bundle.pk}/rebuild/")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
self.assertIn("detail", response.data)
|
||||||
|
|
||||||
|
def test_download_ready_bundle_streams_file(self):
|
||||||
|
bundle_file = Path(self.dirs.media_dir) / "bundles" / "ready.zip"
|
||||||
|
bundle_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
bundle_file.write_bytes(b"binary-zip-content")
|
||||||
|
|
||||||
|
bundle = ShareLinkBundle.objects.create(
|
||||||
|
slug="readyslug",
|
||||||
|
file_version=ShareLink.FileVersion.ARCHIVE,
|
||||||
|
status=ShareLinkBundle.Status.READY,
|
||||||
|
file_path=str(bundle_file),
|
||||||
|
)
|
||||||
|
bundle.documents.set([self.document])
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(f"/share/{bundle.slug}/")
|
||||||
|
content = b"".join(response.streaming_content)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEqual(response["Content-Type"], "application/zip")
|
||||||
|
self.assertEqual(content, b"binary-zip-content")
|
||||||
|
self.assertIn("attachment;", response["Content-Disposition"])
|
||||||
|
|
||||||
|
def test_download_pending_bundle_returns_202(self):
|
||||||
|
bundle = ShareLinkBundle.objects.create(
|
||||||
|
slug="pendingslug",
|
||||||
|
file_version=ShareLink.FileVersion.ARCHIVE,
|
||||||
|
status=ShareLinkBundle.Status.PENDING,
|
||||||
|
)
|
||||||
|
bundle.documents.set([self.document])
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(f"/share/{bundle.slug}/")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
||||||
|
|
||||||
|
@mock.patch("documents.views.build_share_link_bundle.delay")
|
||||||
|
def test_download_missing_file_triggers_rebuild(self, delay_mock):
|
||||||
|
bundle = ShareLinkBundle.objects.create(
|
||||||
|
slug="missingfileslug",
|
||||||
|
file_version=ShareLink.FileVersion.ARCHIVE,
|
||||||
|
status=ShareLinkBundle.Status.READY,
|
||||||
|
file_path=str(Path(self.dirs.media_dir) / "does-not-exist.zip"),
|
||||||
|
)
|
||||||
|
bundle.documents.set([self.document])
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(f"/share/{bundle.slug}/")
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
||||||
|
bundle.refresh_from_db()
|
||||||
|
self.assertEqual(bundle.status, ShareLinkBundle.Status.PENDING)
|
||||||
|
delay_mock.assert_called_once_with(bundle.pk)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareLinkBundleTaskTests(DirectoriesMixin, APITestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.document = DocumentFactory.create()
|
||||||
|
|
||||||
|
def test_cleanup_expired_share_link_bundles(self):
|
||||||
|
expired_path = Path(self.dirs.media_dir) / "expired.zip"
|
||||||
|
expired_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
expired_path.write_bytes(b"expired")
|
||||||
|
|
||||||
|
active_path = Path(self.dirs.media_dir) / "active.zip"
|
||||||
|
active_path.write_bytes(b"active")
|
||||||
|
|
||||||
|
expired_bundle = ShareLinkBundle.objects.create(
|
||||||
|
slug="expired-bundle",
|
||||||
|
file_version=ShareLink.FileVersion.ARCHIVE,
|
||||||
|
status=ShareLinkBundle.Status.READY,
|
||||||
|
expiration=timezone.now() - timedelta(days=1),
|
||||||
|
file_path=str(expired_path),
|
||||||
|
)
|
||||||
|
expired_bundle.documents.set([self.document])
|
||||||
|
|
||||||
|
active_bundle = ShareLinkBundle.objects.create(
|
||||||
|
slug="active-bundle",
|
||||||
|
file_version=ShareLink.FileVersion.ARCHIVE,
|
||||||
|
status=ShareLinkBundle.Status.READY,
|
||||||
|
expiration=timezone.now() + timedelta(days=1),
|
||||||
|
file_path=str(active_path),
|
||||||
|
)
|
||||||
|
active_bundle.documents.set([self.document])
|
||||||
|
|
||||||
|
cleanup_expired_share_link_bundles()
|
||||||
|
|
||||||
|
self.assertFalse(ShareLinkBundle.objects.filter(pk=expired_bundle.pk).exists())
|
||||||
|
self.assertTrue(ShareLinkBundle.objects.filter(pk=active_bundle.pk).exists())
|
||||||
|
self.assertFalse(expired_path.exists())
|
||||||
|
self.assertTrue(active_path.exists())
|
||||||
Loading…
x
Reference in New Issue
Block a user