diff options
Diffstat (limited to 'alphabetlearning/resources/tests')
-rw-r--r-- | alphabetlearning/resources/tests/__init__.py | 0 | ||||
-rw-r--r-- | alphabetlearning/resources/tests/test_file_processing.py | 134 | ||||
-rw-r--r-- | alphabetlearning/resources/tests/test_forms.py | 74 | ||||
-rw-r--r-- | alphabetlearning/resources/tests/test_models.py | 120 | ||||
-rw-r--r-- | alphabetlearning/resources/tests/test_views.py | 190 | ||||
-rw-r--r-- | alphabetlearning/resources/tests/testdata/seven_page.pdf | bin | 0 -> 153396 bytes | |||
-rw-r--r-- | alphabetlearning/resources/tests/testdata/test_small_file.pdf | bin | 0 -> 14147 bytes | |||
-rw-r--r-- | alphabetlearning/resources/tests/testdata/two_page.pdf | bin | 0 -> 186265 bytes |
8 files changed, 518 insertions, 0 deletions
diff --git a/alphabetlearning/resources/tests/__init__.py b/alphabetlearning/resources/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/alphabetlearning/resources/tests/__init__.py diff --git a/alphabetlearning/resources/tests/test_file_processing.py b/alphabetlearning/resources/tests/test_file_processing.py new file mode 100644 index 0000000..e09a135 --- /dev/null +++ b/alphabetlearning/resources/tests/test_file_processing.py @@ -0,0 +1,134 @@ +from pathlib import Path + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.core.files.uploadedfile import InMemoryUploadedFile +from django.core.files.uploadedfile import SimpleUploadedFile +from django.core.files.uploadedfile import TemporaryUploadedFile +from django.test import TestCase +from django.urls import reverse + +from .. import services +from ..utils import _get_pdf_collection_type + + +def test_detect_snapshotted_pdf_collection(): + single_pdf_single_page = [["toss"]] + single_pdf_multi_page = [["toss2", "toss8"]] + multi_pdf_single_page = [["toss"], ["toss2"]] + multi_pdf_multi_page = [["toss", "toss2"], ["toss", "toss2"]] + + assert _get_pdf_collection_type(single_pdf_single_page) == "SINGLE_PDF_SINGLE_PAGE" + assert _get_pdf_collection_type(single_pdf_multi_page) == "SINGLE_PDF_MULTI_PAGE" + assert _get_pdf_collection_type(multi_pdf_single_page) == "MULTI_PDF_SINGLE_PAGE" + assert _get_pdf_collection_type(multi_pdf_multi_page) == "MULTI_PDF_MULTI_PAGE" + + +class PDFFileUploadTestCase(TestCase): + def setUp(self): + self.url = reverse("resources:create_resource") + self.test_file_path = Path( + settings.BASE_DIR / "alphabetlearning" / "resources/tests/testdata/test_small_file.pdf" + ) + + # Create a test user + self.email = "testuser@example.com" + self.password = "testpassword" + self.user = get_user_model().objects.create_user( + email=self.email, + password=self.password, + ) + + def test_file_upload(self): + """ + Test that a file can be uploaded successfully using our create_resource view. + """ + self.client.login( + email=self.email, + password=self.password, + ) # Log in the test user + + with open(self.test_file_path, "rb") as file: + uploaded_file = SimpleUploadedFile( + "test_file.pdf", + file.read(), + content_type="application/pdf", + ) + + response = self.client.post(self.url, {"pdf_files": [uploaded_file]}) + + # Check if the response is OK + self.assertEqual(response.status_code, 200) + + def test_file_upload_with_upload_handlers(self): + """ + This test does not test my code but the behavior of the Django file upload handlers. + """ + self.client.login( + email=self.email, + password=self.password, + ) # Log in the test user + + with open(self.test_file_path, "rb") as file: + uploaded_file = SimpleUploadedFile( + "test_file.pdf", + file.read(), + content_type="application/pdf", + ) + + response = self.client.post(self.url, {"pdf_files": [uploaded_file]}) + + self.assertEqual(response.status_code, 200) + + # Check if the uploaded file was handled by MemoryFileUploadHandler or TemporaryFileUploadHandler + uploaded_files = response.wsgi_request.FILES.getlist("pdf_files") + self.assertEqual(len(uploaded_files), 1) + + # We should expect an instance of InMemoryUploadedFile here because test_small_file.pdf is less than 2.5 MB + self.assertIsInstance( + uploaded_files[0], + (SimpleUploadedFile, TemporaryUploadedFile, InMemoryUploadedFile), + ) + + def test_uploaded_pdf_file_metadata(self): + """ + This test does not test my application code, but rather tests the + behavior of the Django file upload handlers. + """ + self.client.login( + email=self.email, + password=self.password, + ) # Log in the test user + + with open(self.test_file_path, "rb") as file: + uploaded_file = SimpleUploadedFile( + "test_file.pdf", + file.read(), + content_type="application/pdf", + ) + + response = self.client.post(self.url, {"pdf_files": [uploaded_file]}) + + self.assertEqual( + response.status_code, + 200, + ) + + # Extract metadata from the uploaded file + pdf_metadata_from_path = services.get_pdf_metadata_from_path(self.test_file_path) + + # Get the number of pages in the PDF - is 4 + self.assertEqual(pdf_metadata_from_path.n_pages, 4) + + # Get the file size in bytes + self.assertGreater(pdf_metadata_from_path.file_size, 0) + + self.assertLess( + pdf_metadata_from_path.file_size, + 5 * 1024 * 1024, + ) # Assuming a maximum file size of 5 MB + + # self.assertTrue(services.export_pdf_pages_as_images_temp_dir(self.test_file_path)) + # capture the output of the export_pdf_pages_as_images_temp_dir function coroutine + files = list(services.export_pages_as_images(self.test_file_path)) + self.assertEqual(len(files), 4) diff --git a/alphabetlearning/resources/tests/test_forms.py b/alphabetlearning/resources/tests/test_forms.py new file mode 100644 index 0000000..aebc110 --- /dev/null +++ b/alphabetlearning/resources/tests/test_forms.py @@ -0,0 +1,74 @@ +import pytest +from django.core.files.uploadedfile import SimpleUploadedFile +from django.db import IntegrityError +from django.test import TestCase +from django.utils.datastructures import MultiValueDict + +from alphabetlearning.resources.factories import ResourceModelFactory +from alphabetlearning.resources.forms import ResourceCreateForm +from alphabetlearning.resources.models import ResourceCategory +from alphabetlearning.resources.models import ResourceType + + +class ResourceCreateFormTest(TestCase): + def setUp(self): + self.resource_type = ResourceType.objects.create(name="Test Resource Type") + self.resource_category = ResourceCategory.objects.create(name="Test Resource Category") + self.form_data = { + "name": "Test Resource", + "description": "Test Description", + "card_description": "Test Card Description", + "resource_type": self.resource_type.id, + "age_range": "Reception (4-5yrs)", + "curriculum": "English", + "feature_slot": 1, + "main_resource_category": self.resource_category.id, + } + self.pdf_files = [ + # use the correct PDF file header - this should pass validation + SimpleUploadedFile( + f"file{i}.pdf", + b"\x25\x50\x44\x46\x2d", + content_type="application/pdf", + ) + for i in range(11) + ] + self.thumbnail_files = [ + # use the correct JPG file header - this should pass validation + SimpleUploadedFile( + f"thumbnail{i}.jpg", + b"\xff\xd8\xff\xdb", + content_type="image/jpeg", + ) + # 5 is the max number currently set in ALLOWED_THUMBNAILS + for i in range(5) + ] + # This needs to be a MultiValueDict for the test to mimic production code + # see clean_pdf_files - self.files.getlist() + self.form_files = MultiValueDict( + {"pdf_files": self.pdf_files, "thumbnail_files": self.thumbnail_files}, + ) + + def test_form_valid(self): + form = ResourceCreateForm(data=self.form_data, files=self.form_files) + assert form.is_valid() + + @pytest.mark.django_db() + def test_featured_slots_must_be_unique(self): + r1 = ResourceModelFactory(feature_slot=1) + with pytest.raises(IntegrityError): + ResourceModelFactory(feature_slot=1) + + @pytest.mark.django_db() + def test_featured_slots_allowable(self): + form_data = { + "name": "Test Resource", + "description": "Test Description", + "resource_type": self.resource_type.id, + "age_range": "5-7", + "curriculum": "English", + "feature_slot": 4, + "main_resource_category": self.resource_category.id, + } + form = ResourceCreateForm(data=form_data, files=self.form_files) + assert not form.is_valid() diff --git a/alphabetlearning/resources/tests/test_models.py b/alphabetlearning/resources/tests/test_models.py new file mode 100644 index 0000000..0fd589a --- /dev/null +++ b/alphabetlearning/resources/tests/test_models.py @@ -0,0 +1,120 @@ +import unittest +from unittest.mock import patch + +import pytest +from django.db import IntegrityError +from django.test import TestCase + +from alphabetlearning.resources.factories import PDFPageSnapshotModelFactory +from alphabetlearning.resources.factories import ResourceModelFactory +from alphabetlearning.resources.models import PDFPageSnapshot +from alphabetlearning.resources.models import PDFResource +from alphabetlearning.resources.models import Resource +from alphabetlearning.resources.models import ResourceCategory +from alphabetlearning.resources.models import ResourceType +from alphabetlearning.resources.views import ResourceInfo +from alphabetlearning.resources.views import _extract_metadata_from_resource + + +@pytest.mark.django_db() +def test_resource_model(resources): + r1 = resources[0] + pdf_on_rw = r1.pdf_resources.first() + pdf_page_snapshot = PDFPageSnapshotModelFactory(pdf_file=pdf_on_rw) + + assert Resource.objects.filter(id=r1.id).exists() + assert any("test_" in name for name in r1.get_pdf_file_names()) + assert len(r1.get_pdf_file_names()) == 3 + assert "pdf_page_snapshot_" in r1.get_pdf_snapshot_file_names()[0] + + +@pytest.mark.django_db() +def test_can_add_feature_slots_to_resource(): + r = ResourceModelFactory() + r.feature_slot = 1 + r.save() + assert r.feature_slot == 1 + + +@pytest.mark.django_db() +def test_resource_slot_int_must_be_unique(): + """ + Test that a resource feature slot must be unique. + """ + r1 = ResourceModelFactory() + r2 = ResourceModelFactory() + r1.feature_slot = 1 + r1.save() + r2.feature_slot = 1 + with pytest.raises(IntegrityError): + r2.save() + + +class ResourceModelTest(TestCase): + def test_string_representation(self): + resource = Resource(name="Test Resource") + assert str(resource) == "Test Resource" + + +@unittest.skip("Skipping this test for now as it is broken") +class TestExtractMetadata(TestCase): + @patch("resources.views.get_presigned_obj_url") + def test_extract_metadata_from_resource(self, mock_get_url): + # Create mock instances of ResourceType and ResourceCategory + mock_resource_type = ResourceType.objects.create(name="Test Type") + mock_main_category = ResourceCategory.objects.create(name="Test Main Category") + + mock_resource = Resource( + name="Test Resource", + thumbnail_filenames=["thumb.jpg", "thumb2.jpg"], + created_at="2022-01-01", + updated_at="2022-01-02", + resource_type=mock_resource_type, + main_resource_category=mock_main_category, + age_range="5-7", + ) + mock_get_url.return_value = "https://example.com/url" + result = _extract_metadata_from_resource(mock_resource) + self.assertIsInstance(result, ResourceInfo) + assert result.name == "Test Resource" + assert result.pdf_filenames == "test.pdf" + assert result.thumbnail_filenames in ["thumb.jpg", "thumb2.jpg"] + assert result.created == "2022-01-01" + assert result.updated == "2022-01-02" + + +@unittest.skip("These tests will not run because they rely upon the view to get file size, etc.") +class TestPDFResourceModel(TestCase): + def setUp(self): + self.resource_type = ResourceType.objects.create(name="Test Resource Type") + self.resource_category = ResourceCategory.objects.create(name="Test Resource Category") + self.resource = Resource.objects.create( + name="Test Resource", + resource_type=self.resource_type, + main_resource_category=self.resource_category, + age_range="5-7", + curriculum="English", + description="Test Description", + ) + self.pdf_resource = PDFResource.objects.create( + resource=self.resource, + file_name="resources/tests/testdata/test_small_file.pdf", + ) + self.pdf_page_snapshot = PDFPageSnapshot.objects.create( + name="Test Thumbnail Image", + file_name="test_resource_1.jpg", + pdf_file=self.pdf_resource, + ) + + def test_pdf_resource_string_representation(self): + self.assertEqual(str(self.resource), "Test Resource") + + def test_get_pdf_snapshot_filenames(self): + self.assertEqual(self.pdf_resource.snapshot_file_names(), ["test_resource_1.jpg"]) + + +@pytest.mark.django_db() +def test_get_urls_of_resource_snapshot_images(resource): + assert len(resource.thumbnail_filenames) == 3 + # crude but it does the job; concatenating a list of URLS into one long sting... + assert "https://ams3.digitaloceanspaces.com" in "".join(resource.thumbnail_urls()) diff --git a/alphabetlearning/resources/tests/test_views.py b/alphabetlearning/resources/tests/test_views.py new file mode 100644 index 0000000..b57e79d --- /dev/null +++ b/alphabetlearning/resources/tests/test_views.py @@ -0,0 +1,190 @@ +import unittest +from pathlib import Path + +import pytest +from django.conf import settings +from django.contrib.auth import get_user_model +from django.contrib.auth.models import User +from django.core.files.uploadedfile import SimpleUploadedFile +from django.test import RequestFactory +from django.test import TestCase +from django.urls import reverse + +from alphabetlearning.resources import services +from alphabetlearning.resources.forms import ResourceCreateForm +from alphabetlearning.resources.models import ResourceCategory +from alphabetlearning.resources.models import ResourceType +from alphabetlearning.resources.views import create_resource + +pytestmark = pytest.mark.django_db + + +def test_create_featured_resource_view(client): + url = reverse("resources:create_featured") + response = client.get(url) + assert response.status_code == 302 + + +def test_create_resource_view(client): + url = reverse("resources:create_resource") + response = client.get(url) + assert response.status_code == 302 + + +@pytest.mark.django_db +def test_create_resource_has_form(client): + User = get_user_model() + user = User.objects.create_user(email="testuser@example.com", password="12345") + client.login(email="testuser@example.com", password="12345") + + url = reverse("resources:create_resource") + response = client.get(url) + assert response.status_code == 200 + assert "form" in response.context + assert isinstance(response.context["form"], ResourceCreateForm) + + +class PDFFileUploadTestCase(TestCase): + def setUp(self): + self.url = reverse("resources:create_resource") + self.two_page_pdf = Path( + settings.BASE_DIR / "alphabetlearning" / "resources/tests/testdata/two_page.pdf" + ) + self.seven_page_pdf = Path( + settings.BASE_DIR / "alphabetlearning" / "resources/tests/testdata/seven_page.pdf" + ) + + # Create a test user + self.email = "testuser@example.com" + self.password = "testpassword" + self.user = get_user_model().objects.create_user( + email=self.email, + password=self.password, + ) + + # Log in the test user + self.client.login(email=self.email, password=self.password) + + # Open the test files and create SimpleUploadedFile objects + with open(self.two_page_pdf, "rb") as file: + self.uploaded_two_page_pdf = SimpleUploadedFile( + "two_page.pdf", + file.read(), + content_type="application/pdf", + ) + with open(self.seven_page_pdf, "rb") as file: + self.uploaded_seven_page_pdf = SimpleUploadedFile( + "seven_page.pdf", + file.read(), + content_type="application/pdf", + ) + + def tearDown(self): + # Close the SimpleUploadedFile objects + self.uploaded_two_page_pdf.close() + self.uploaded_seven_page_pdf.close() + + def test_file_upload_is_pdf(self): + """ + Test that a file can be uploaded successfully using our create_resource view. + """ + response = self.client.post( + self.url, + {"pdf_files": [self.uploaded_two_page_pdf, self.uploaded_seven_page_pdf]}, + ) + + two_page_metadata = services.get_pdf_metadata_from_path(self.two_page_pdf) + seven_page_metadata = services.get_pdf_metadata_from_path(self.seven_page_pdf) + image_files_two_pager = list(services.export_pages_as_images(self.two_page_pdf)) + image_files_seven_pager = list( + services.export_pages_as_images(self.seven_page_pdf), + ) + + self.assertEqual(two_page_metadata.n_pages, 2) + self.assertEqual(seven_page_metadata.n_pages, 7) + self.assertGreater(two_page_metadata.file_size, 0) + self.assertGreater(seven_page_metadata.file_size, 0) + self.assertEqual(len(image_files_two_pager), 2) + self.assertEqual(len(image_files_seven_pager), 7) + self.assertEqual(response.status_code, 200) + + +@unittest.skip("Currently not able to mock S3 API at this point") +class TestCreateResourceUsingResourceFactory(TestCase): + def setUp(self): + self.factory = RequestFactory() + self.user = User.objects.create_user( + username="testuser", + password="testpassword", + ) + self.two_page_pdf = "resources/tests/testdata/two_page.pdf" + self.seven_page_pdf = "resources/tests/testdata/seven_page.pdf" + + # Create resource type + self.resource_type = ResourceType.objects.create(name="Test Resource Type") + + # Create resource categories + self.main_resource_category = ResourceCategory.objects.create( + name="Test Main Category", + ) + self.additional_resource_category = ResourceCategory.objects.create( + name="Test Additional Category", + ) + + def test_post_pdf(self): + # Open the test files and create SimpleUploadedFile objects + with open(self.two_page_pdf, "rb") as file: + uploaded_two_page_pdf = SimpleUploadedFile( + "two_page.pdf", + file.read(), + content_type="application/pdf", + ) + with open(self.seven_page_pdf, "rb") as file: + uploaded_seven_page_pdf = SimpleUploadedFile( + "seven_page.pdf", + file.read(), + content_type="application/pdf", + ) + + # Create a thumbnail file (you can use a dummy file for testing) + thumbnail_file = SimpleUploadedFile( + "thumbnail.jpg", + b"thumbnail_content", + content_type="image/jpeg", + ) + + # Prepare the form data + form_data = { + "name": "Test Resource", + "description": "Test Description", + "resource_type": self.resource_type.id, + "age_range": "5-7", + "curriculum": "English", + "main_resource_category": self.main_resource_category.id, + "additional_resource_category": self.additional_resource_category.id, + "pdf_files": [uploaded_two_page_pdf, uploaded_seven_page_pdf], + "thumbnail_files": [thumbnail_file], + } + + # Prepare the form files + form_files = { + "pdf_files": [uploaded_two_page_pdf, uploaded_seven_page_pdf], + "thumbnail_files": [thumbnail_file], + } + + # Create the request object with form data and files + request = self.factory.post("/create/", data=form_data) + request.user = self.user + + # TODO mock the call to the Spaces S3 service inside the view + + # Call the create_resource view function + response = create_resource(request) + + # Assert the response status code + self.assertEqual( + response.status_code, + 302, + ) # Assuming a successful form submission redirects (status code 302) + + # Add more assertions as needed diff --git a/alphabetlearning/resources/tests/testdata/seven_page.pdf b/alphabetlearning/resources/tests/testdata/seven_page.pdf Binary files differnew file mode 100644 index 0000000..991a26d --- /dev/null +++ b/alphabetlearning/resources/tests/testdata/seven_page.pdf diff --git a/alphabetlearning/resources/tests/testdata/test_small_file.pdf b/alphabetlearning/resources/tests/testdata/test_small_file.pdf Binary files differnew file mode 100644 index 0000000..9a990c8 --- /dev/null +++ b/alphabetlearning/resources/tests/testdata/test_small_file.pdf diff --git a/alphabetlearning/resources/tests/testdata/two_page.pdf b/alphabetlearning/resources/tests/testdata/two_page.pdf Binary files differnew file mode 100644 index 0000000..9c74944 --- /dev/null +++ b/alphabetlearning/resources/tests/testdata/two_page.pdf |