Ayub-Khan / django-view-permissions

@@ -1,3 +1,39 @@
Loading
1 1
"""
2 2
Test Module for django-view-permissions.
3 3
"""
4 +
from unittest.mock import PropertyMock, patch
5 +
6 +
from django.contrib.auth.models import User
7 +
from django.test.testcases import TestCase
8 +
from django.urls import reverse
9 +
10 +
from django_view_permissions.tests.test_app.permissions import AllowAccess, RejectAccess
11 +
12 +
13 +
class BaseTestClass(TestCase):
14 +
    """
15 +
    View Permission Middleware Tests
16 +
    """
17 +
18 +
    def setUp(self):
19 +
        super(BaseTestClass, self).setUp()
20 +
        self.user = User.objects.create_user(username='test')
21 +
        self.client.force_login(self.user)
22 +
23 +
    def call_view_and_assert_response(self, view, request_method, status_code):
24 +
        """
25 +
        Calls the View, checks the response.
26 +
        """
27 +
        if request_method == 'GET':
28 +
            response = self.client.get(reverse(view))
29 +
        else:
30 +
            response = self.client.post(reverse(view))
31 +
32 +
        self.assertEqual(response.status_code, status_code)
33 +
        if status_code == 200:
34 +
            self.assertEqual(response.content.decode('utf-8'), 'ok!')
35 +
36 +
    def tearDown(self):
37 +
        super(BaseTestClass, self).tearDown()
38 +
        self.client.logout()
39 +
        self.user.delete()

@@ -0,0 +1,88 @@
Loading
1 +
"""
2 +
Tests the functionality of Attribute based permissions.
3 +
"""
4 +
from unittest.mock import PropertyMock, patch
5 +
6 +
from ddt import data, ddt, unpack
7 +
8 +
from django_view_permissions.tests import BaseTestClass
9 +
10 +
11 +
@ddt
12 +
class AttrBasedPermissionsTests(BaseTestClass):
13 +
    """
14 +
    Tests the functionality of Attribute Based Permissions.
15 +
    """
16 +
    @unpack
17 +
    @data(
18 +
        # ........................................................
19 +
        (
20 +
            [('attr', 'is_staff', True)],
21 +
            'GET',
22 +
            200
23 +
        ),
24 +
        (
25 +
            [('attr', 'is_staff', False)],
26 +
            'GET',
27 +
            404
28 +
        ),
29 +
        (
30 +
            [('attr', 'is_staff', True)],
31 +
            'POST',
32 +
            200
33 +
        ),
34 +
        (
35 +
            [('attr', 'is_staff', False)],
36 +
            'POST',
37 +
            404
38 +
        ),
39 +
        # ........................................................
40 +
        (
41 +
            [('attr', 'is_staff', True, ('GET'))],
42 +
            'GET',
43 +
            200
44 +
        ),
45 +
        (
46 +
            [('attr', 'is_staff', False, ('GET'))],
47 +
            'GET',
48 +
            404
49 +
        ),
50 +
        (
51 +
            [('attr', 'is_staff', True, ('GET'))],
52 +
            'POST',
53 +
            404
54 +
        ),
55 +
        (
56 +
            [('attr', 'is_staff', False, ('GET'))],
57 +
            'POST',
58 +
            404
59 +
        ),
60 +
        # ........................................................
61 +
        (
62 +
            [('attr', 'is_staff', True, ())],
63 +
            'GET',
64 +
            404
65 +
        ),
66 +
        (
67 +
            [('attr', 'is_staff', True, ('GET', 'POST'))],
68 +
            'GET',
69 +
            200
70 +
        ),
71 +
        (
72 +
            [('attr', 'is_staff', False, ('GET', 'POST'))],
73 +
            'POST',
74 +
            404
75 +
        ),
76 +
    )
77 +
    def test_attribute_based_permissions(self, permissions, request_method, return_value):
78 +
        """
79 +
        Tests the functionality of user attr based permissions.
80 +
        """
81 +
        with patch(
82 +
                'django_view_permissions.tests.test_app.views.TestView.permissions',
83 +
                new_callable=PropertyMock,
84 +
                return_value=permissions
85 +
            ):
86 +
            self.user.is_staff = True
87 +
            self.user.save()
88 +
            self.call_view_and_assert_response('test-view', request_method, return_value)

@@ -0,0 +1,88 @@
Loading
1 +
"""
2 +
Tests the functionality of Class based permissions.
3 +
"""
4 +
from unittest.mock import PropertyMock, patch
5 +
6 +
from ddt import data, ddt, unpack
7 +
8 +
from django_view_permissions.tests import BaseTestClass
9 +
from django_view_permissions.tests.test_app.permissions import AllowAccess, RejectAccess
10 +
11 +
12 +
@ddt
13 +
class ClassBasedPermissionsTests(BaseTestClass):
14 +
    """
15 +
    Tests the functionality of Class Based Permissions.
16 +
    """
17 +
    @unpack
18 +
    @data(
19 +
        # ........................................................
20 +
        (
21 +
            [('class', AllowAccess)],
22 +
            'GET',
23 +
            200
24 +
        ),
25 +
        (
26 +
            [('class', RejectAccess)],
27 +
            'GET',
28 +
            404
29 +
        ),
30 +
        (
31 +
            [('class', AllowAccess)],
32 +
            'POST',
33 +
            200
34 +
        ),
35 +
        (
36 +
            [('class', RejectAccess)],
37 +
            'POST',
38 +
            404
39 +
        ),
40 +
        # ........................................................
41 +
        (
42 +
            [('class', AllowAccess, ('GET'))],
43 +
            'GET',
44 +
            200
45 +
        ),
46 +
        (
47 +
            [('class', RejectAccess, ('GET'))],
48 +
            'GET',
49 +
            404
50 +
        ),
51 +
        (
52 +
            [('class', AllowAccess, ('GET'))],
53 +
            'POST',
54 +
            404
55 +
        ),
56 +
        (
57 +
            [('class', RejectAccess, ('GET'))],
58 +
            'POST',
59 +
            404
60 +
        ),
61 +
        # ........................................................
62 +
        (
63 +
            [('class', AllowAccess, ())],
64 +
            'GET',
65 +
            404
66 +
        ),
67 +
        (
68 +
            [('class', AllowAccess, ('GET', 'POST'))],
69 +
            'GET',
70 +
            200
71 +
        ),
72 +
        (
73 +
            [('class', RejectAccess, ('GET', 'POST'))],
74 +
            'POST',
75 +
            404
76 +
        ),
77 +
    )
78 +
    def test_class_based_permissions(self, permissions, request_method, return_value):
79 +
        """
80 +
        Tests the class based permissions functionality.
81 +
        """
82 +
83 +
        with patch(
84 +
                'django_view_permissions.tests.test_app.views.TestView.permissions',
85 +
                new_callable=PropertyMock,
86 +
                return_value=permissions
87 +
            ):
88 +
            self.call_view_and_assert_response('test-view', request_method, return_value)

@@ -9,7 +9,13 @@
Loading
9 9
    # pylint: disable=no-self-use, unused-argument
10 10
    def get(self, request):
11 11
        """
12 -
        Test Get Method
12 +
        Test GET Method
13 +
        """
14 +
        return HttpResponse("ok!")
15 +
16 +
    def post(self, request):
17 +
        """
18 +
        Test POST Method
13 19
        """
14 20
        return HttpResponse("ok!")
15 21

@@ -0,0 +1,27 @@
Loading
1 +
"""
2 +
Tests the functionality of middleware.
3 +
"""
4 +
from ddt import data, ddt
5 +
6 +
from django_view_permissions.tests import BaseTestClass
7 +
8 +
9 +
@ddt
10 +
class GeneralTests(BaseTestClass):
11 +
    """
12 +
    Genral Test cases of Permissions
13 +
    """
14 +
    @data('GET', 'POST')
15 +
    def test_empty_view(self, request_method):
16 +
        """
17 +
        Check empty view without permissions attribute works normaly.
18 +
        """
19 +
        self.call_view_and_assert_response('empty-view', request_method, 200)
20 +
21 +
    @data('GET', 'POST')
22 +
    def test_empty_permissions_reject_all_requests(self, request_method):
23 +
        """
24 +
        Tests if view permissions attr is empty all requests
25 +
        are rejected.
26 +
        """
27 +
        self.call_view_and_assert_response('test-view', request_method, 404)

@@ -1,4 +1,8 @@
Loading
1 1
"""Checks view access for Permissions"""
2 +
METHODS = (
3 +
    'GET',
4 +
    'POST',
5 +
)
2 6
3 7
4 8
# pylint: disable=too-few-public-methods
@@ -14,29 +18,54 @@
Loading
14 18
        """
15 19
        Checks if any of the permission is true for request.
16 20
        """
17 -
        method_based = tuple(filter(
18 -
            lambda x: x[0] == 'method',
19 -
            self.permissions
20 -
        ))
21 -
        class_based = tuple(filter(
22 -
            lambda x: x[0] == 'class',
23 -
            self.permissions
24 -
        ))
25 -
        attr_based = tuple(filter(
26 -
            lambda x: x[0] == 'attr',
27 -
            self.permissions
28 -
        ))
21 +
        method_based = tuple(
22 +
            filter(
23 +
                lambda x: bool(x[1](self.request)),
24 +
                tuple(
25 +
                    filter(
26 +
                        lambda x: x[0] == 'method',
27 +
                        self.permissions
28 +
                    )
29 +
                )
30 +
            )
31 +
        )
29 32
30 -
        if any(
31 -
                p[1](self.request) for p in method_based
32 -
        ):
33 -
            return True
34 -
        if any(
35 -
                p[1](self.request)() for p in class_based
36 -
        ):
37 -
            return True
38 -
        if any(
39 -
                p[2] == getattr(self.request.user, p[1]) for p in attr_based
40 -
        ):
33 +
        class_based = tuple(
34 +
            filter(
35 +
                lambda x: bool(x[1](self.request)()),
36 +
                tuple(
37 +
                    filter(
38 +
                        lambda x: x[0] == 'class',
39 +
                        self.permissions
40 +
                    )
41 +
                )
42 +
            )
43 +
        )
44 +
        attr_based = tuple(
45 +
            filter(
46 +
                lambda x: x[2] == getattr(self.request.user, x[1]),
47 +
                tuple(
48 +
                    filter(
49 +
                        lambda x: x[0] == 'attr',
50 +
                        self.permissions
51 +
                    )
52 +
                )
53 +
            )
54 +
        )
55 +
56 +
        allowed_permissions = tuple(
57 +
            filter(
58 +
                lambda x: self.request.method in (x[3] if len(x) == 4 else METHODS),
59 +
                attr_based
60 +
            )
61 +
        ) + tuple(
62 +
            filter(
63 +
                lambda x: self.request.method in (x[2] if len(x) == 3 else METHODS),
64 +
                method_based + class_based
65 +
            )
66 +
        )
67 +
68 +
        if any(allowed_permissions):
41 69
            return True
70 +
42 71
        return False

@@ -0,0 +1,87 @@
Loading
1 +
"""
2 +
Tests the functionality of Method based permissions.
3 +
"""
4 +
from unittest.mock import PropertyMock, patch
5 +
6 +
from ddt import data, ddt, unpack
7 +
8 +
from django_view_permissions.tests import BaseTestClass
9 +
10 +
11 +
@ddt
12 +
class MethodBasedPermissionsTests(BaseTestClass):
13 +
    """
14 +
    Tests the functionality of Method Based Permissions.
15 +
    """
16 +
17 +
    @unpack
18 +
    @data(
19 +
        # ........................................................
20 +
        (
21 +
            [('method', lambda request: True)],
22 +
            'GET',
23 +
            200
24 +
        ),
25 +
        (
26 +
            [('method', lambda request: False)],
27 +
            'GET',
28 +
            404
29 +
        ),
30 +
        (
31 +
            [('method', lambda request: True)],
32 +
            'POST',
33 +
            200
34 +
        ),
35 +
        (
36 +
            [('method', lambda request: False)],
37 +
            'POST',
38 +
            404
39 +
        ),
40 +
        # ........................................................
41 +
        (
42 +
            [('method', lambda request: True, ('GET'))],
43 +
            'GET',
44 +
            200
45 +
        ),
46 +
        (
47 +
            [('method', lambda request: False, ('GET'))],
48 +
            'GET',
49 +
            404
50 +
        ),
51 +
        (
52 +
            [('method', lambda request: True, ('GET'))],
53 +
            'POST',
54 +
            404
55 +
        ),
56 +
        (
57 +
            [('method', lambda request: False, ('GET'))],
58 +
            'POST',
59 +
            404
60 +
        ),
61 +
        # ........................................................
62 +
        (
63 +
            [('method', lambda request: True, ())],
64 +
            'GET',
65 +
            404
66 +
        ),
67 +
        (
68 +
            [('method', lambda request: True, ('GET', 'POST'))],
69 +
            'GET',
70 +
            200
71 +
        ),
72 +
        (
73 +
            [('method', lambda request: False, ('GET', 'POST'))],
74 +
            'POST',
75 +
            404
76 +
        ),
77 +
    )
78 +
    def test_method_based_permissions(self, permissions, request_method, return_value):
79 +
        """
80 +
        Tests the method based permissions functionality.
81 +
        """
82 +
        with patch(
83 +
                'django_view_permissions.tests.test_app.views.TestView.permissions',
84 +
                new_callable=PropertyMock,
85 +
                return_value=permissions
86 +
            ):
87 +
            self.call_view_and_assert_response('test-view', request_method, return_value)
Files Coverage
django_view_permissions 100.00%
Project Totals (11 files) 100.00%
68.12
TRAVIS_PYTHON_VERSION=3.7
TRAVIS_OS_NAME=linux
68.13
TRAVIS_PYTHON_VERSION=3.7
TRAVIS_OS_NAME=linux
68.11
TRAVIS_PYTHON_VERSION=3.7
TRAVIS_OS_NAME=linux
68.14
TRAVIS_PYTHON_VERSION=3.7
TRAVIS_OS_NAME=linux
68.16
TRAVIS_PYTHON_VERSION=3.8
TRAVIS_OS_NAME=linux
68.15
TRAVIS_PYTHON_VERSION=3.8
TRAVIS_OS_NAME=linux
68.19
TRAVIS_PYTHON_VERSION=3.8
TRAVIS_OS_NAME=linux
68.17
TRAVIS_PYTHON_VERSION=3.8
TRAVIS_OS_NAME=linux
68.18
TRAVIS_PYTHON_VERSION=3.8
TRAVIS_OS_NAME=linux
68.5
TRAVIS_PYTHON_VERSION=3.6
TRAVIS_OS_NAME=linux
68.3
TRAVIS_PYTHON_VERSION=3.5
TRAVIS_OS_NAME=linux
68.4
TRAVIS_PYTHON_VERSION=3.5
TRAVIS_OS_NAME=linux
68.2
TRAVIS_PYTHON_VERSION=3.5
TRAVIS_OS_NAME=linux
68.7
TRAVIS_PYTHON_VERSION=3.6
TRAVIS_OS_NAME=linux
68.1
TRAVIS_PYTHON_VERSION=3.5
TRAVIS_OS_NAME=linux
68.9
TRAVIS_PYTHON_VERSION=3.6
TRAVIS_OS_NAME=linux
68.8
TRAVIS_PYTHON_VERSION=3.6
TRAVIS_OS_NAME=linux
68.6
TRAVIS_PYTHON_VERSION=3.6
TRAVIS_OS_NAME=linux