311 lines
12 KiB
Python
311 lines
12 KiB
Python
from django.conf import settings
|
|
from django.contrib.auth.models import Group, Permission
|
|
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
|
from django.core.files.base import ContentFile
|
|
from django.db import transaction
|
|
from django.test import TestCase, TransactionTestCase
|
|
from django.test.utils import override_settings
|
|
|
|
from wagtail.documents import (
|
|
get_document_model,
|
|
get_document_model_string,
|
|
models,
|
|
signal_handlers,
|
|
)
|
|
from wagtail.images.tests.utils import get_test_image_file
|
|
from wagtail.models import Collection, GroupCollectionPermission
|
|
from wagtail.test.testapp.models import CustomDocument, ReimportedDocumentModel
|
|
from wagtail.test.utils import WagtailTestUtils
|
|
|
|
|
|
class TestDocumentQuerySet(TransactionTestCase):
|
|
fixtures = ["test_empty.json"]
|
|
|
|
def test_search_method(self):
|
|
# Make a test document
|
|
document = models.Document.objects.create(title="Test document")
|
|
|
|
# Search for it
|
|
results = models.Document.objects.search("Test")
|
|
self.assertEqual(list(results), [document])
|
|
|
|
def test_operators(self):
|
|
aaa_document = models.Document.objects.create(title="AAA Test document")
|
|
zzz_document = models.Document.objects.create(title="ZZZ Test document")
|
|
|
|
results = models.Document.objects.search("aaa test", operator="and")
|
|
self.assertEqual(list(results), [aaa_document])
|
|
|
|
results = models.Document.objects.search("aaa test", operator="or")
|
|
sorted_results = sorted(results, key=lambda doc: doc.title)
|
|
self.assertEqual(sorted_results, [aaa_document, zzz_document])
|
|
|
|
def test_custom_ordering(self):
|
|
aaa_document = models.Document.objects.create(title="AAA Test document")
|
|
zzz_document = models.Document.objects.create(title="ZZZ Test document")
|
|
|
|
results = models.Document.objects.order_by("title").search(
|
|
"Test", order_by_relevance=False
|
|
)
|
|
self.assertEqual(list(results), [aaa_document, zzz_document])
|
|
results = models.Document.objects.order_by("-title").search(
|
|
"Test", order_by_relevance=False
|
|
)
|
|
self.assertEqual(list(results), [zzz_document, aaa_document])
|
|
|
|
|
|
class TestDocumentPermissions(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
# Create some user accounts for testing permissions
|
|
self.user = self.create_user(
|
|
username="user", email="user@email.com", password="password"
|
|
)
|
|
self.owner = self.create_user(
|
|
username="owner", email="owner@email.com", password="password"
|
|
)
|
|
self.editor = self.create_user(
|
|
username="editor", email="editor@email.com", password="password"
|
|
)
|
|
self.editor.groups.add(Group.objects.get(name="Editors"))
|
|
self.administrator = self.create_superuser(
|
|
username="administrator",
|
|
email="administrator@email.com",
|
|
password="password",
|
|
)
|
|
|
|
# Owner user must have the add_document permission
|
|
self.adders_group = Group.objects.create(name="Document adders")
|
|
GroupCollectionPermission.objects.create(
|
|
group=self.adders_group,
|
|
collection=Collection.get_first_root_node(),
|
|
permission=Permission.objects.get(codename="add_document"),
|
|
)
|
|
self.owner.groups.add(self.adders_group)
|
|
|
|
# Create a document for running tests on
|
|
self.document = models.Document.objects.create(
|
|
title="Test document", uploaded_by_user=self.owner
|
|
)
|
|
|
|
def test_administrator_can_edit(self):
|
|
self.assertTrue(self.document.is_editable_by_user(self.administrator))
|
|
|
|
def test_editor_can_edit(self):
|
|
self.assertTrue(self.document.is_editable_by_user(self.editor))
|
|
|
|
def test_owner_can_edit(self):
|
|
self.assertTrue(self.document.is_editable_by_user(self.owner))
|
|
|
|
def test_user_cant_edit(self):
|
|
self.assertFalse(self.document.is_editable_by_user(self.user))
|
|
|
|
|
|
class TestDocumentFilenameProperties(TestCase):
|
|
def setUp(self):
|
|
self.document = models.Document(title="Test document")
|
|
self.document.file.save(
|
|
"sample_name.doc",
|
|
ContentFile("A boring example document"),
|
|
)
|
|
|
|
self.pdf_document = models.Document(title="Test document")
|
|
self.pdf_document.file.save(
|
|
"sample_name.pdf",
|
|
ContentFile("A boring example document"),
|
|
)
|
|
|
|
self.extensionless_document = models.Document(title="Test document")
|
|
self.extensionless_document.file.save(
|
|
"sample_name",
|
|
ContentFile("A boring example document"),
|
|
)
|
|
|
|
def test_filename(self):
|
|
self.assertEqual("sample_name.doc", self.document.filename)
|
|
self.assertEqual("sample_name.pdf", self.pdf_document.filename)
|
|
self.assertEqual("sample_name", self.extensionless_document.filename)
|
|
|
|
def test_file_extension(self):
|
|
self.assertEqual("doc", self.document.file_extension)
|
|
self.assertEqual("pdf", self.pdf_document.file_extension)
|
|
self.assertEqual("", self.extensionless_document.file_extension)
|
|
|
|
def test_content_type(self):
|
|
self.assertEqual("application/msword", self.document.content_type)
|
|
self.assertEqual("application/pdf", self.pdf_document.content_type)
|
|
self.assertEqual(
|
|
"application/octet-stream", self.extensionless_document.content_type
|
|
)
|
|
|
|
def test_file_hash(self):
|
|
self.assertEqual(
|
|
self.document.get_file_hash(), "7d8c4778b182e4f3bd442408c64a6e22a4b0ed85"
|
|
)
|
|
self.assertEqual(
|
|
self.pdf_document.get_file_hash(),
|
|
"7d8c4778b182e4f3bd442408c64a6e22a4b0ed85",
|
|
)
|
|
self.assertEqual(
|
|
self.extensionless_document.get_file_hash(),
|
|
"7d8c4778b182e4f3bd442408c64a6e22a4b0ed85",
|
|
)
|
|
|
|
def test_content_disposition(self):
|
|
self.assertEqual(
|
|
"""attachment; filename=sample_name.doc; filename*=UTF-8''sample_name.doc""",
|
|
self.document.content_disposition,
|
|
)
|
|
self.assertEqual("inline", self.pdf_document.content_disposition)
|
|
self.assertEqual(
|
|
"""attachment; filename=sample_name; filename*=UTF-8''sample_name""",
|
|
self.extensionless_document.content_disposition,
|
|
)
|
|
|
|
def tearDown(self):
|
|
# delete the FieldFile directly because the TestCase does not commit
|
|
# transactions to trigger transaction.on_commit() in the signal handler
|
|
self.document.file.delete()
|
|
self.pdf_document.file.delete()
|
|
self.extensionless_document.file.delete()
|
|
|
|
|
|
class TestFilesDeletedForDefaultModels(TransactionTestCase):
|
|
"""
|
|
Because we expect file deletion to only happen once a transaction is
|
|
successfully committed, we must run these tests using TransactionTestCase
|
|
per the following documentation:
|
|
|
|
Django's TestCase class wraps each test in a transaction and rolls back that
|
|
transaction after each test, in order to provide test isolation. This means
|
|
that no transaction is ever actually committed, thus your on_commit()
|
|
callbacks will never be run. If you need to test the results of an
|
|
on_commit() callback, use a TransactionTestCase instead.
|
|
https://docs.djangoproject.com/en/1.10/topics/db/transactions/#use-in-tests
|
|
"""
|
|
|
|
fixtures = ["test_empty.json"]
|
|
|
|
def test_document_file_deleted_oncommit(self):
|
|
with transaction.atomic():
|
|
document = get_document_model().objects.create(
|
|
title="Test Image", file=get_test_image_file()
|
|
)
|
|
filename = document.file.name
|
|
|
|
self.assertTrue(document.file.storage.exists(filename))
|
|
document.delete()
|
|
self.assertTrue(document.file.storage.exists(filename))
|
|
self.assertFalse(document.file.storage.exists(filename))
|
|
|
|
|
|
@override_settings(WAGTAILDOCS_EXTENSIONS=["pdf"])
|
|
class TestDocumentValidateExtensions(TestCase):
|
|
def setUp(self):
|
|
self.document_invalid = models.Document.objects.create(
|
|
title="Test document", file="test.doc"
|
|
)
|
|
self.document_valid = models.Document.objects.create(
|
|
title="Test document", file="test.pdf"
|
|
)
|
|
|
|
def test_create_doc_invalid_extension(self):
|
|
"""
|
|
Checks if the uploaded document has the expected extensions
|
|
mentioned in settings.WAGTAILDOCS_EXTENSIONS
|
|
|
|
This is caught in form.error and should be raised during model
|
|
creation when called full_clean. This specific testcase invalid
|
|
file extension is passed
|
|
"""
|
|
with self.assertRaises(ValidationError) as e:
|
|
self.document_invalid.full_clean()
|
|
expected_message = (
|
|
"File extension “doc” is not allowed. Allowed extensions are: pdf."
|
|
)
|
|
self.assertEqual(e.exception.message_dict["file"][0], expected_message)
|
|
|
|
def test_create_doc_valid_extension(self):
|
|
"""
|
|
Checks if the uploaded document has the expected extensions
|
|
mentioned in settings.WAGTAILDOCS_EXTENSIONS
|
|
|
|
This is caught in form.error and should be raised during
|
|
model creation when called full_clean. In this specific
|
|
testcase invalid file extension is passed.
|
|
"""
|
|
try:
|
|
self.document_valid.full_clean()
|
|
except ValidationError:
|
|
self.fail("Validation error is raised even when valid file name is passed")
|
|
|
|
def tearDown(self):
|
|
self.document_invalid.file.delete()
|
|
self.document_valid.file.delete()
|
|
|
|
|
|
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.CustomDocument")
|
|
class TestFilesDeletedForCustomModels(TestFilesDeletedForDefaultModels):
|
|
def setUp(self):
|
|
# Required to create root collection because the TransactionTestCase
|
|
# does not make initial data loaded in migrations available and
|
|
# serialized_rollback=True causes other problems in the test suite.
|
|
# ref: https://docs.djangoproject.com/en/1.10/topics/testing/overview/#rollback-emulation
|
|
Collection.objects.get_or_create(
|
|
name="Root",
|
|
path="0001",
|
|
depth=1,
|
|
numchild=0,
|
|
)
|
|
|
|
#: Sadly signal receivers only get connected when starting django.
|
|
#: We will re-attach them here to mimic the django startup behaviour
|
|
#: and get the signals connected to our custom model..
|
|
signal_handlers.register_signal_handlers()
|
|
|
|
def test_document_model(self):
|
|
cls = get_document_model()
|
|
self.assertEqual(
|
|
f"{cls._meta.app_label}.{cls.__name__}", "tests.CustomDocument"
|
|
)
|
|
|
|
|
|
class TestGetDocumentModel(WagtailTestUtils, TestCase):
|
|
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.CustomDocument")
|
|
def test_custom_get_document_model(self):
|
|
"""Test get_document_model with a custom document model"""
|
|
self.assertIs(get_document_model(), CustomDocument)
|
|
|
|
def test_get_document_model_at_import_time(self):
|
|
self.assertEqual(ReimportedDocumentModel, models.Document)
|
|
|
|
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.CustomDocument")
|
|
def test_custom_get_document_model_string(self):
|
|
"""Test get_document_model_string with a custom document model"""
|
|
self.assertEqual(get_document_model_string(), "tests.CustomDocument")
|
|
|
|
@override_settings()
|
|
def test_standard_get_document_model(self):
|
|
"""Test get_document_model with no WAGTAILDOCS_DOCUMENT_MODEL"""
|
|
del settings.WAGTAILDOCS_DOCUMENT_MODEL
|
|
from wagtail.documents.models import Document
|
|
|
|
self.assertIs(get_document_model(), Document)
|
|
|
|
@override_settings()
|
|
def test_standard_get_document_model_string(self):
|
|
"""Test get_document_model_string with no WAGTAILDOCS_DOCUMENT_MODEL"""
|
|
del settings.WAGTAILDOCS_DOCUMENT_MODEL
|
|
self.assertEqual(get_document_model_string(), "wagtaildocs.Document")
|
|
|
|
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="tests.UnknownModel")
|
|
def test_unknown_get_document_model(self):
|
|
"""Test get_document_model with an unknown model"""
|
|
with self.assertRaises(ImproperlyConfigured):
|
|
get_document_model()
|
|
|
|
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL="invalid-string")
|
|
def test_invalid_get_document_model(self):
|
|
"""Test get_document_model with an invalid model string"""
|
|
with self.assertRaises(ImproperlyConfigured):
|
|
get_document_model()
|