Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for file uploads #192

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 91 additions & 5 deletions styleguide_example/files/tests/flows/test_direct_upload.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,95 @@
from django.test import TestCase
from django.test import TestCase, override_settings
from django.urls import reverse
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile

from rest_framework.test import APIClient

from unittest import mock

from styleguide_example.files.models import File

from styleguide_example.users.services import user_create

from styleguide_example.files.enums import FileUploadStorage


class DirectUploadApiTests(TestCase):
"""
We want to test the following:
def setUp(self):
self.client = APIClient()

self.jwt_login_url = reverse("api:authentication:jwt:login")
self.direct_upload_start_url = reverse("api:files:upload:direct:start")
self.direct_upload_finish_url = reverse("api:files:upload:direct:finish")
self.direct_upload_local_url = lambda file: reverse(
"api:files:upload:direct:local",
kwargs={"file_id": str(file.id)}
)

@override_settings(FILE_UPLOAD_STORAGE=FileUploadStorage.S3, FILE_MAX_SIZE=10)
def test_direct_upload(self):
"""
1. Get presigned_post_url from the direct_upload_start endpoint
1.1. to mock generate the presigned post

Assert the presigned data
Assert that the file object is created

2. Call the finish endpoint and assert that the file is marked as uploaded

"""
credentials = {
"email": "[email protected]",
"password": "123456"
}
user_create(**credentials)

response = self.client.post(self.jwt_login_url, credentials)

self.assertEqual(200, response.status_code)

token = response.data["token"]
auth_headers = {
"HTTP_AUTHORIZATION": f"{settings.JWT_AUTH['JWT_AUTH_HEADER_PREFIX']} {token}"
}

file_1 = SimpleUploadedFile(
name="file_small.txt",
content=(settings.FILE_MAX_SIZE - 5) * "a".encode(),
content_type="text/plain"
)

file_data = {
"file_name": file_1.name,
"file_type": file_1.content_type
}

presigned_url = "test_presigned_url"

presigned_data = {
"url": presigned_url,
}

with self.subTest("1. Get presigned_post_url from the direct_upload_start endpoint"):

self.assertEqual(0, File.objects.count())

with mock.patch(
"styleguide_example.files.services.s3_generate_presigned_post"
) as s3_generate_presigned_post_mock:
s3_generate_presigned_post_mock.return_value = {**presigned_data}

response = self.client.post(self.direct_upload_start_url, file_data, **auth_headers)
file_id = response.data["id"]

self.assertEqual(200, response.status_code)
self.assertEqual(presigned_url, response.data["url"])
self.assertTrue(s3_generate_presigned_post_mock.called)
self.assertEqual(1, File.objects.count())
self.assertIsNone(File.objects.last().upload_finished_at)

with self.subTest("2. Call the finish endpoint and assert that the file is marked as uploaded"):
response = self.client.post(self.direct_upload_finish_url, {"file_id": file_id})

1. A start-upload-finish cycle, where we patch the presign generation with local upload storage.
"""
self.assertEqual(200, response.status_code)
self.assertIsNotNone(File.objects.last().upload_finished_at)
196 changes: 194 additions & 2 deletions styleguide_example/files/tests/flows/test_standard_upload.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,97 @@
from django.test import TestCase
import shutil
from django.conf import settings
from django.test import TestCase, Client, override_settings
from django.urls import reverse
from django.core.files.uploadedfile import SimpleUploadedFile

from rest_framework.test import APIClient

from styleguide_example.files.models import File

from styleguide_example.users.models import BaseUser
LinaSSavova marked this conversation as resolved.
Show resolved Hide resolved
from styleguide_example.users.services import user_create


class StandardUploadApiTests(TestCase):
"""
We want to test the following general cases:

1. Upload a file, below the size limit, assert models gets created accordingly.
1. Upload a file, above the size limit (patch settings), assert API error, nothing gets created.
2. Upload a file, above the size limit (patch settings), assert API error, nothing gets created.
3. Upload a file, equal to the size limit, assert models gets created accordingly.
"""
def setUp(self):
self.client = APIClient()

self.jwt_login_url = reverse("api:authentication:jwt:login")
self.standard_upload_url = reverse("api:files:upload:standard")

@override_settings(FILE_MAX_SIZE=10)
def test_standard_upload(self):

self.assertEqual(0, File.objects.count())
self.assertEqual(0, BaseUser.objects.count())

# Create a user
credentials = {
"email": "[email protected]",
"password": "123456"
}
user_create(**credentials)

self.assertEqual(1, BaseUser.objects.count())
LinaSSavova marked this conversation as resolved.
Show resolved Hide resolved

# Log in and get the authorization data needed
response = self.client.post(self.jwt_login_url, credentials)

self.assertEqual(200, response.status_code)
slavov-v marked this conversation as resolved.
Show resolved Hide resolved

token = response.data["token"]
auth_headers = {
"HTTP_AUTHORIZATION": f"{settings.JWT_AUTH['JWT_AUTH_HEADER_PREFIX']} {token}"
}

# Create a small sized file
file_1 = SimpleUploadedFile(
name="file_small.txt",
content=(settings.FILE_MAX_SIZE - 5) * "a".encode(),
content_type="text/plain"
)

with self.subTest("1. Upload a file, below the size limit, assert models gets created accordingly"):
response = self.client.post(self.standard_upload_url, {"file": file_1}, **auth_headers)

self.assertEqual(201, response.status_code)
self.assertEqual(1, File.objects.count())

# Create a file above the size limit
file_2 = SimpleUploadedFile(
name="file_big.txt",
content=(settings.FILE_MAX_SIZE + 1) * "a".encode(),
content_type="text/plain"
)

with self.subTest("2. Upload a file, above the size limit, assert API error, nothing gets created"):
response = self.client.post(self.standard_upload_url, {"file": file_2}, **auth_headers)

self.assertEqual(400, response.status_code)
self.assertEqual(1, File.objects.count())

# Create a file equal to the size limit
file_3 = SimpleUploadedFile(
name="file_equal.txt",
content=settings.FILE_MAX_SIZE * "a".encode(),
content_type="text/plain"
)

with self.subTest("3. Upload a file, equal to the size limit, assert models gets created accordingly"):
response = self.client.post(self.standard_upload_url, {"file": file_3}, **auth_headers)

self.assertEqual(201, response.status_code)
self.assertEqual(2, File.objects.count())

def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT, ignore_errors=True)


class StandardUploadAdminTests(TestCase):
Expand All @@ -24,3 +108,111 @@ class StandardUploadAdminTests(TestCase):
1. Create a new file via the Django admin, assert error, nothing gets created.
2. Update an existing fila via the Django admin, assert error, nothing gets created.
"""
def setUp(self):
self.client = Client()

self.admin_upload_file_url = reverse("admin:files_file_add")
self.admin_files_list_url = reverse("admin:files_file_changelist")
self.admin_update_file_url = lambda file: reverse(
"admin:files_file_change",
kwargs={"object_id": str(file.id)}
)

@override_settings(FILE_MAX_SIZE=10)
def test_standard_admin_upload_and_update(self):

self.assertEqual(0, File.objects.count())

# Create a superuser
credentials = {
"email": "[email protected]",
"password": "123456",
"is_admin": True,
"is_superuser": True
}
user = BaseUser.objects.create(**credentials)

self.assertEqual(1, BaseUser.objects.count())

file_1 = SimpleUploadedFile(
name="first_file.txt",
content=(settings.FILE_MAX_SIZE - 5) * "a".encode(),
content_type="text/plain"
)

data_file_1 = {
"file": file_1,
"uploaded_by": user.id
}

# Log in with the superuser account
self.client.force_login(user)

with self.subTest("1. Create a new file via the Django admin, assert everything gets created"):
response = self.client.post(self.admin_upload_file_url, data_file_1)
successfully_uploaded_file = File.objects.last()

self.assertEqual(302, response.status_code)
self.assertEqual(1, File.objects.count())
self.assertEqual(file_1.name, successfully_uploaded_file.original_file_name)

file_2 = SimpleUploadedFile(
name="second_file.txt",
content=(settings.FILE_MAX_SIZE - 1) * "a".encode(),
content_type="text/plain"
)

data_file_2 = {
"file": file_2,
"uploaded_by": user.id
}

with self.subTest("2. Update an existing file via the Django admin, assert everything gets updated"):
response = self.client.post(self.admin_update_file_url(successfully_uploaded_file), data_file_2)

self.assertEqual(302, response.status_code)
self.assertEqual(1, File.objects.count())
self.assertEqual(file_2.name, File.objects.last().original_file_name)

file_3 = SimpleUploadedFile(
name="oversized_file.txt",
content=(settings.FILE_MAX_SIZE + 1) * "a".encode(),
content_type="text/plain"
)

data_oversized_file = {
"file": file_3,
"uploaded_by": user.id
}

with self.subTest("3. Create a new oversized file via the Django admin, assert error, nothing gets created"):
response = self.client.post(self.admin_upload_file_url, data_oversized_file, follow=True)

self.assertContains(response, "File is too large")
self.assertEqual(1, File.objects.count())
self.assertEqual(file_2.name, File.objects.last().original_file_name)

file_4 = SimpleUploadedFile(
name="new_oversized_file.txt",
content=(settings.FILE_MAX_SIZE + 1) * "a".encode(),
content_type="text/plain"
)

data_new_oversized_file = {
"file": file_4,
"uploaded_by": user.id
}

with self.subTest(
"4. Update an existing file with an oversized one via the Django admin, assert error, nothing gets created"
):
response = self.client.post(
self.admin_update_file_url(File.objects.last()), data_new_oversized_file, follow=True
)

self.assertContains(response, "File is too large")
self.assertEqual(1, File.objects.count())
self.assertEqual(file_2.name, File.objects.last().original_file_name)

def tearDown(self):
shutil.rmtree(settings.MEDIA_ROOT, ignore_errors=True)