From 98e13cd67e919d6f70670557e9939f47635d2130 Mon Sep 17 00:00:00 2001 From: Ian Garcez Date: Sat, 4 Apr 2020 17:02:17 +0200 Subject: [PATCH 1/4] Add authentication unit tests --- authentication/tests.py | 165 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-) diff --git a/authentication/tests.py b/authentication/tests.py index 7ce503c..924dfa6 100644 --- a/authentication/tests.py +++ b/authentication/tests.py @@ -1,3 +1,166 @@ +from unittest.mock import patch, MagicMock, Mock + from django.test import TestCase +from django.views import View +from rest_framework import serializers + +from authentication.permissions import IsAffectedUser, IsHelperUser, IsOwnerOfRequest +from authentication.serializer import EmailAuthTokenSerializer +from crisis.models import Request + + +class MockUser: + def __init__( + self, + is_authenticated: bool = False, + ): + self.is_authenticated = is_authenticated + +class MockRequest: + pass + +class MockRelatedParticipant: + def __init__(self, type: str = ""): + self.type = type + + +failure_authenticate_mock = MagicMock(return_value=None) +success_authenticate_mock = MagicMock(return_value=MockUser()) + + +class EmailAuthTokenSerializerTest(TestCase): + def setUp(self) -> None: + self.model = EmailAuthTokenSerializer() + + @patch("authentication.serializer.authenticate", failure_authenticate_mock) + def test_failed_authentication_should_raise_validation_error(self): + with self.assertRaisesMessage(serializers.ValidationError, 'Unable to log in with provided credentials.'): + self.model.validate(attrs=dict(email="test@email.se", password="abc123")) + + def test_missing_credentials_should_throw_exception(self): + with self.assertRaisesMessage(serializers.ValidationError, 'Must include "email" and "password".'): + self.model.validate(attrs=dict()) + + @patch("authentication.serializer.authenticate", success_authenticate_mock) + def test_success_authentication_should_return_authenticate_result(self): + result = self.model.validate(attrs=dict(email="test@email.se", password="abc123")) + self.assertEquals(type(result['user']), type(MockUser())) + + +class IsAffectedUserTest(TestCase): + def setUp(self) -> None: + self.model = IsAffectedUser() + + def test_request_user_must_be_authenticated_and_affected(self): + mock_request = MockRequest() + mock_user = MockUser(is_authenticated=False) + mock_user.related_participant = MockRelatedParticipant(type="AF") + mock_request.user = mock_user + self.assertFalse(self.model.has_permission(mock_request, None)) + + mock_request = MockRequest() + mock_user = MockUser(is_authenticated=True) + mock_user.related_participant = MockRelatedParticipant(type="SomethingElse") + mock_request.user = mock_user + self.assertFalse(self.model.has_permission(mock_request, None)) + + mock_request = MockRequest() + mock_user = MockUser(is_authenticated=False) + mock_user.related_participant = MockRelatedParticipant(type="SomethingElse") + mock_request.user = mock_user + self.assertFalse(self.model.has_permission(mock_request, None)) + + mock_request = MockRequest() + mock_user = MockUser(is_authenticated=True) + mock_user.related_participant = MockRelatedParticipant(type="AF") + mock_request.user = mock_user + self.assertTrue(self.model.has_permission(mock_request, None)) + + +class IsHelperUserTest(TestCase): + def setUp(self) -> None: + self.model = IsHelperUser() + + def test_only_helper_can_assign_a_request(self): + # test that all allowed types have permission as long as authenticated + allowed_types = ["HL", "AU", "TP"] + for allowed_type in allowed_types: + mock_request = MockRequest() + mock_user = MockUser(is_authenticated=True) + mock_user.related_participant = MockRelatedParticipant(type=allowed_type) + mock_request.user = mock_user + self.assertTrue(self.model.has_permission(mock_request, None)) + + mock_request = MockRequest() + mock_user = MockUser(is_authenticated=False) + mock_user.related_participant = MockRelatedParticipant(type=allowed_type) + mock_request.user = mock_user + self.assertFalse(self.model.has_permission(mock_request, None)) + + # test that an authenticated user with an disallowed type does not have permission + mock_request = MockRequest() + mock_user = MockUser(is_authenticated=True) + mock_user.related_participant = MockRelatedParticipant(type="AF") + mock_request.user = mock_user + self.assertFalse(self.model.has_permission(mock_request, None)) + + +currentUser = MockUser() + +participantRequestMock = Mock() +participantRequestMock.owner = Mock() +participantRequestMock.owner.user = currentUser + +objectsMock = Mock() +objectsMock.get.return_value = participantRequestMock + +SuccessRequestMock = Mock(spec=Request) +SuccessRequestMock.objects = objectsMock + +FoundButWrongParticipantRequestMock = Mock() +FoundButWrongParticipantRequestMock.owner = Mock() +# here we return another mock user different from 'owner' +FoundButWrongParticipantRequestMock.user = MockUser() + +FoundButWrongObjectsMock = Mock() +FoundButWrongObjectsMock.get.return_value = FoundButWrongParticipantRequestMock + +FoundButWrongRequest = Mock(spec=Request) +FoundButWrongRequest.objects = FoundButWrongObjectsMock + +# cannot test this because of +# TypeError: catching classes that do not inherit from BaseException is not allowed +# not sure if it is a production issue +# DoesNotExistObjectsMock = Mock() +# DoesNotExistObjectsMock.get.side_effect = ObjectDoesNotExist() +# DoesNotExistRequest = Mock(spec=Request) +# DoesNotExistRequest.objects = DoesNotExistObjectsMock + +class IsOwnerOfRequestTest(TestCase): + def setUp(self) -> None: + self.model = IsOwnerOfRequest() + self.viewMock = Mock(spec=View) + self.viewMock.kwargs = Mock() + self.viewMock.kwargs.get.return_value = None + + @patch("authentication.permissions.Request", SuccessRequestMock) + def test_owners_should_have_permission(self): + request = MockRequest() + request.user = currentUser + + self.assertTrue(self.model.has_permission(request, self.viewMock)) + + @patch("authentication.permissions.Request", FoundButWrongRequest) + def test_non_owners_should_not_have_permission(self): + request = MockRequest() + request.user = currentUser + + self.assertFalse(self.model.has_permission(request, self.viewMock)) -# Create your tests here. + # @patch("authentication.permissions.Request", DoesNotExistRequest) + # def test_not_found_owner_should_not_have_permission(self): + # request = MockRequest() + # request.user = currentUser + # + # with self.assertRaises(Http404): + # self.assertFalse(self.model.has_permission(request, self.viewMock)) From cb1826241d34ea437b22c54760d4773be7dc0010 Mon Sep 17 00:00:00 2001 From: Ian Garcez Date: Sat, 4 Apr 2020 17:08:17 +0200 Subject: [PATCH 2/4] Adjust the commented exception test --- authentication/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentication/tests.py b/authentication/tests.py index 924dfa6..80f3b63 100644 --- a/authentication/tests.py +++ b/authentication/tests.py @@ -132,7 +132,7 @@ def test_only_helper_can_assign_a_request(self): # TypeError: catching classes that do not inherit from BaseException is not allowed # not sure if it is a production issue # DoesNotExistObjectsMock = Mock() -# DoesNotExistObjectsMock.get.side_effect = ObjectDoesNotExist() +# DoesNotExistObjectsMock.get.side_effect = Request.DoesNotExist() # DoesNotExistRequest = Mock(spec=Request) # DoesNotExistRequest.objects = DoesNotExistObjectsMock From 22421b4152f6e7574c6771d6d0e9a6e7973403ac Mon Sep 17 00:00:00 2001 From: Ian Garcez Date: Sat, 4 Apr 2020 17:25:56 +0200 Subject: [PATCH 3/4] Update the README.md file with test information --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7896d7f..0252def 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,11 @@ your machine, or use `pyenv` as described later in this documentation. (env-3.7.5) quarantined_backend/$ python manage.py runserver ``` or even better, run it from pyCharm using your debugger + +## Automated tests + +You can run the test suite by executing `(env-3.7.5) quarantined_backend/$ python manage.py test` or setting up the +django test configuration to PyCharm. ## FAQ From c0f8cacd55df9baa85337e062453fe25df0a40b4 Mon Sep 17 00:00:00 2001 From: Ian Garcez Date: Sat, 4 Apr 2020 17:34:53 +0200 Subject: [PATCH 4/4] clean up PEP8 warnings and remove badly implemented test --- authentication/tests.py | 51 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/authentication/tests.py b/authentication/tests.py index 80f3b63..1424ef6 100644 --- a/authentication/tests.py +++ b/authentication/tests.py @@ -16,9 +16,11 @@ def __init__( ): self.is_authenticated = is_authenticated + class MockRequest: pass + class MockRelatedParticipant: def __init__(self, type: str = ""): self.type = type @@ -107,34 +109,27 @@ def test_only_helper_can_assign_a_request(self): currentUser = MockUser() -participantRequestMock = Mock() -participantRequestMock.owner = Mock() -participantRequestMock.owner.user = currentUser +participant_request_mock = Mock() +participant_request_mock.owner = Mock() +participant_request_mock.owner.user = currentUser -objectsMock = Mock() -objectsMock.get.return_value = participantRequestMock +objects_mock = Mock() +objects_mock.get.return_value = participant_request_mock -SuccessRequestMock = Mock(spec=Request) -SuccessRequestMock.objects = objectsMock +success_request_mock = Mock(spec=Request) +success_request_mock.objects = objects_mock -FoundButWrongParticipantRequestMock = Mock() -FoundButWrongParticipantRequestMock.owner = Mock() +found_but_wrong_participant_request_mock = Mock() +found_but_wrong_participant_request_mock.owner = Mock() # here we return another mock user different from 'owner' -FoundButWrongParticipantRequestMock.user = MockUser() +found_but_wrong_participant_request_mock.user = MockUser() -FoundButWrongObjectsMock = Mock() -FoundButWrongObjectsMock.get.return_value = FoundButWrongParticipantRequestMock +found_but_wrong_objects_mock = Mock() +found_but_wrong_objects_mock.get.return_value = found_but_wrong_participant_request_mock -FoundButWrongRequest = Mock(spec=Request) -FoundButWrongRequest.objects = FoundButWrongObjectsMock +found_but_wrong_request = Mock(spec=Request) +found_but_wrong_request.objects = found_but_wrong_objects_mock -# cannot test this because of -# TypeError: catching classes that do not inherit from BaseException is not allowed -# not sure if it is a production issue -# DoesNotExistObjectsMock = Mock() -# DoesNotExistObjectsMock.get.side_effect = Request.DoesNotExist() -# DoesNotExistRequest = Mock(spec=Request) -# DoesNotExistRequest.objects = DoesNotExistObjectsMock class IsOwnerOfRequestTest(TestCase): def setUp(self) -> None: @@ -143,24 +138,14 @@ def setUp(self) -> None: self.viewMock.kwargs = Mock() self.viewMock.kwargs.get.return_value = None - @patch("authentication.permissions.Request", SuccessRequestMock) + @patch("authentication.permissions.Request", success_request_mock) def test_owners_should_have_permission(self): request = MockRequest() request.user = currentUser - self.assertTrue(self.model.has_permission(request, self.viewMock)) - @patch("authentication.permissions.Request", FoundButWrongRequest) + @patch("authentication.permissions.Request", found_but_wrong_request) def test_non_owners_should_not_have_permission(self): request = MockRequest() request.user = currentUser - self.assertFalse(self.model.has_permission(request, self.viewMock)) - - # @patch("authentication.permissions.Request", DoesNotExistRequest) - # def test_not_found_owner_should_not_have_permission(self): - # request = MockRequest() - # request.user = currentUser - # - # with self.assertRaises(Http404): - # self.assertFalse(self.model.has_permission(request, self.viewMock))