From fa7f35dda59a391e79425152dee4bdd3089c272f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksi=20Ha=CC=88kli?= Date: Sun, 10 Feb 2019 19:08:51 +0200 Subject: [PATCH] Add tests for the new components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use mocks and test new backends, handlers and middleware on an API call level, aiming for a 100% coverage on behaviour. Also add tests for old decorators which are not covered after moving the default authentication checks from them to the authentication backends, middleware and signal handlers. Fixes #323 Signed-off-by: Aleksi Häkli --- axes/tests/test_backends.py | 21 +++++++++++++++ axes/tests/test_decorators.py | 40 +++++++++++++++++++++++++++ axes/tests/test_handlers.py | 51 +++++++++++++++++++++++++++++++++++ axes/tests/test_middleware.py | 28 +++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 axes/tests/test_backends.py create mode 100644 axes/tests/test_decorators.py create mode 100644 axes/tests/test_handlers.py create mode 100644 axes/tests/test_middleware.py diff --git a/axes/tests/test_backends.py b/axes/tests/test_backends.py new file mode 100644 index 0000000..22eec0f --- /dev/null +++ b/axes/tests/test_backends.py @@ -0,0 +1,21 @@ +from unittest.mock import patch, MagicMock + +from django.test import TestCase + +from axes.backends import AxesBackend +from axes.exceptions import AxesBackendRequestParameterRequired, AxesBackendPermissionDenied + + +class BackendTestCase(TestCase): + def test_authenticate_raises_on_missing_request(self): + request = None + + with self.assertRaises(AxesBackendRequestParameterRequired): + AxesBackend().authenticate(request) + + @patch('axes.backends.is_already_locked', return_value=True) + def test_authenticate_raises_on_locked_request(self, _): + request = MagicMock() + + with self.assertRaises(AxesBackendPermissionDenied): + AxesBackend().authenticate(request) diff --git a/axes/tests/test_decorators.py b/axes/tests/test_decorators.py new file mode 100644 index 0000000..82c5f29 --- /dev/null +++ b/axes/tests/test_decorators.py @@ -0,0 +1,40 @@ +from unittest.mock import MagicMock, patch + +from django.http import HttpResponse +from django.test import TestCase + +from axes.decorators import axes_dispatch, axes_form_invalid + + +class DecoratorTestCase(TestCase): + SUCCESS_RESPONSE = HttpResponse(status=200, content='Dispatched') + LOCKOUT_RESPONSE = HttpResponse(status=403, content='Locked out') + + def setUp(self): + self.request = MagicMock() + self.cls = MagicMock(return_value=self.request) + self.func = MagicMock(return_value=self.SUCCESS_RESPONSE) + + @patch('axes.decorators.is_already_locked', return_value=True) + @patch('axes.decorators.get_lockout_response', return_value=LOCKOUT_RESPONSE) + def test_axes_dispatch_locks_out(self, _, __): + response = axes_dispatch(self.func)(self.request) + self.assertEqual(response.content, self.LOCKOUT_RESPONSE.content) + + @patch('axes.decorators.is_already_locked', return_value=False) + @patch('axes.decorators.get_lockout_response', return_value=LOCKOUT_RESPONSE) + def test_axes_dispatch_dispatches(self, _, __): + response = axes_dispatch(self.func)(self.request) + self.assertEqual(response.content, self.SUCCESS_RESPONSE.content) + + @patch('axes.decorators.is_already_locked', return_value=True) + @patch('axes.decorators.get_lockout_response', return_value=LOCKOUT_RESPONSE) + def test_axes_form_invalid_locks_out(self, _, __): + response = axes_form_invalid(self.func)(self.cls) + self.assertEqual(response.content, self.LOCKOUT_RESPONSE.content) + + @patch('axes.decorators.is_already_locked', return_value=False) + @patch('axes.decorators.get_lockout_response', return_value=LOCKOUT_RESPONSE) + def test_axes_form_invalid_dispatches(self, _, __): + response = axes_form_invalid(self.func)(self.cls) + self.assertEqual(response.content, self.SUCCESS_RESPONSE.content) diff --git a/axes/tests/test_handlers.py b/axes/tests/test_handlers.py new file mode 100644 index 0000000..838c78a --- /dev/null +++ b/axes/tests/test_handlers.py @@ -0,0 +1,51 @@ +from unittest.mock import MagicMock, patch + +from django.test import TestCase + +from axes.handlers import AxesHandler +from axes.signals import ProxyHandler + + +class ProxyHandlerTestCase(TestCase): + def setUp(self): + self.sender = MagicMock() + self.credentials = MagicMock() + self.request = MagicMock() + self.user = MagicMock() + self.instance = MagicMock() + + @patch('axes.signals.ProxyHandler.implementation', None) + def test_initialize(self): + self.assertIsNone(ProxyHandler.implementation) + ProxyHandler.initialize() + self.assertIsInstance(ProxyHandler.implementation, AxesHandler) + + @patch('axes.signals.ProxyHandler.implementation') + def test_user_login_failed(self, handler): + self.assertFalse(handler.user_login_failed.called) + ProxyHandler().user_login_failed(self.sender, self.credentials, self.request) + self.assertTrue(handler.user_login_failed.called) + + @patch('axes.signals.ProxyHandler.implementation') + def test_user_logged_in(self, handler): + self.assertFalse(handler.user_logged_in.called) + ProxyHandler().user_logged_in(self.sender, self.request, self.user) + self.assertTrue(handler.user_logged_in.called) + + @patch('axes.signals.ProxyHandler.implementation') + def test_user_logged_out(self, handler): + self.assertFalse(handler.user_logged_out.called) + ProxyHandler().user_logged_out(self.sender, self.request, self.user) + self.assertTrue(handler.user_logged_out.called) + + @patch('axes.signals.ProxyHandler.implementation') + def test_post_save_access_attempt(self, handler): + self.assertFalse(handler.post_save_access_attempt.called) + ProxyHandler().post_save_access_attempt(self.instance) + self.assertTrue(handler.post_save_access_attempt.called) + + @patch('axes.signals.ProxyHandler.implementation') + def test_post_delete_access_attempt(self, handler): + self.assertFalse(handler.post_delete_access_attempt.called) + ProxyHandler().post_delete_access_attempt(self.instance) + self.assertTrue(handler.post_delete_access_attempt.called) diff --git a/axes/tests/test_middleware.py b/axes/tests/test_middleware.py new file mode 100644 index 0000000..cf47d3b --- /dev/null +++ b/axes/tests/test_middleware.py @@ -0,0 +1,28 @@ +from unittest.mock import patch, MagicMock + +from django.http import HttpResponse +from django.test import TestCase + +from axes.exceptions import AxesSignalPermissionDenied +from axes.middleware import AxesMiddleware + + +class MiddlewareTestCase(TestCase): + SUCCESS_RESPONSE = HttpResponse(status=200, content='Dispatched') + LOCKOUT_RESPONSE = HttpResponse(status=403, content='Locked out') + + def setUp(self): + self.request = MagicMock() + self.get_response = MagicMock() + + @patch('axes.middleware.get_lockout_response', return_value=LOCKOUT_RESPONSE) + def test_process_exception_axes(self, _): + exception = AxesSignalPermissionDenied() + response = AxesMiddleware(self.get_response).process_exception(self.request, exception) + self.assertEqual(response, self.LOCKOUT_RESPONSE) + + @patch('axes.middleware.get_lockout_response', return_value=LOCKOUT_RESPONSE) + def test_process_exception_other(self, _): + exception = Exception() + response = AxesMiddleware(self.get_response).process_exception(self.request, exception) + self.assertEqual(response, None)