File: test_views.py

package info (click to toggle)
python-django-rules 3.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 320 kB
  • sloc: python: 1,613; makefile: 5; sh: 3
file content (215 lines) | stat: -rw-r--r-- 9,323 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
from __future__ import absolute_import

from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.http import Http404, HttpRequest
from django.test import RequestFactory, TestCase
from django.urls import reverse
from django.utils.encoding import force_str
from django.views.generic import CreateView, View

from testapp.models import Book

import rules  # noqa
from rules.contrib.views import AutoPermissionRequiredMixin, objectgetter

from . import TestData


class FBVDecoratorTests(TestData, TestCase):
    def test_objectgetter(self):
        request = HttpRequest()
        book = Book.objects.get(pk=1)

        self.assertEqual(book, objectgetter(Book)(request, pk=1))
        self.assertEqual(book, objectgetter(Book, attr_name="id")(request, id=1))
        self.assertEqual(book, objectgetter(Book, field_name="id")(request, pk=1))

        with self.assertRaises(ImproperlyConfigured):
            # Raise if no `pk` argument is provided to the view
            self.assertEqual(book, objectgetter(Book)(request, foo=1))

        with self.assertRaises(ImproperlyConfigured):
            # Raise if given invalid model lookup field
            self.assertEqual(book, objectgetter(Book, field_name="foo")(request, pk=1))

        with self.assertRaises(Http404):
            # Raise 404 if no model instance found
            self.assertEqual(book, objectgetter(Book)(request, pk=100000))

    def test_permission_required(self):
        # Adrian can change his book
        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        response = self.client.get(reverse("change_book", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Martin can change Adrian's book
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("change_book", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Adrian can delete his book
        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        response = self.client.get(reverse("delete_book", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Martin can *not* create a book
        # Up to Django v2.1, the response was a redirect to login
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("cbv.create_book"))
        self.assertIn(response.status_code, [302, 403])

        # Martin can *not* delete Adrian's book and is redirected to login
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("delete_book", args=(1,)))
        self.assertEqual(response.status_code, 302)

        # Martin can *not* delete Adrian's book and an PermissionDenied is raised
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("view_that_raises", args=(1,)))
        self.assertEqual(response.status_code, 403)

        # Test views that require a list of permissions

        # Adrian has both permissions
        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        response = self.client.get(reverse("view_with_permission_list", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Martin does not have delete permission
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("view_with_permission_list", args=(1,)))
        self.assertEqual(response.status_code, 302)

        # Test views that accept a static object as argument
        # fn is passed to has_perm as-is

        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        response = self.client.get(reverse("view_with_object", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("view_with_object", args=(1,)))
        self.assertEqual(response.status_code, 302)


class CBVMixinTests(TestData, TestCase):
    def test_get_object_error(self):
        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        with self.assertRaises(AttributeError):
            self.client.get(reverse("cbv.change_book_error", args=(1,)))

    def test_permission_required_mixin(self):
        # Adrian can change his book
        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        response = self.client.get(reverse("cbv.change_book", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Martin can change Adrian's book
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("cbv.change_book", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Adrian can delete his book
        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        response = self.client.get(reverse("cbv.delete_book", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Martin can *not* delete Adrian's book
        # Up to Django v2.1, the response was a redirect to login
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("cbv.delete_book", args=(1,)))
        self.assertIn(response.status_code, [302, 403])

        # Martin can *not* delete Adrian's book and an PermissionDenied is raised
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("cbv.view_that_raises", args=(1,)))
        self.assertEqual(response.status_code, 403)

        # Test views that require a list of permissions

        # Adrian has both permissions
        self.assertTrue(self.client.login(username="adrian", password="secr3t"))
        response = self.client.get(reverse("cbv.view_with_permission_list", args=(1,)))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(force_str(response.content).strip(), "OK")

        # Martin does not have delete permission
        # Up to Django v2.1, the response was a redirect to login
        self.assertTrue(self.client.login(username="martin", password="secr3t"))
        response = self.client.get(reverse("cbv.view_with_permission_list", args=(1,)))
        self.assertIn(response.status_code, [302, 403])


class AutoPermissionRequiredMixinTests(TestCase):
    def setUp(self):
        from testapp.models import TestModel

        self.model = TestModel
        self.req = RequestFactory().get("/")
        self.req.user = AnonymousUser()

    def test_predefined_view_type(self):
        class TestView(AutoPermissionRequiredMixin, CreateView):
            model = self.model
            fields = ()

        self.assertEqual(TestView.as_view()(self.req).status_code, 200)

    def test_custom_view_type(self):
        class CustomViewMixin:
            pass

        class TestView(AutoPermissionRequiredMixin, CustomViewMixin, CreateView):
            model = self.model
            fields = ()
            permission_type_map = [
                (CustomViewMixin, "unknown_perm")
            ] + AutoPermissionRequiredMixin.permission_type_map
            raise_exception = True

        with self.assertRaises(PermissionDenied):
            TestView.as_view()(self.req)

    def test_unknown_view_type(self):
        class TestView(AutoPermissionRequiredMixin, View):
            pass

        with self.assertRaises(ImproperlyConfigured):
            TestView.as_view()(self.req)

    def test_overwrite_perm_type(self):
        class TestView(AutoPermissionRequiredMixin, CreateView):
            model = self.model
            fields = ()
            permission_type = "unknown"
            raise_exception = True

        with self.assertRaises(PermissionDenied):
            TestView.as_view()(self.req)

    def test_disable_perm_checking(self):
        class TestView(AutoPermissionRequiredMixin, CreateView):
            model = self.model
            fields = ()
            permission_type = None

        self.assertEqual(TestView.as_view()(self.req).status_code, 200)

    def test_permission_required_passthrough(self):
        class TestView(AutoPermissionRequiredMixin, CreateView):
            model = self.model
            fields = ()
            permission_required = "testapp.unknown_perm"
            raise_exception = True

        with self.assertRaises(PermissionDenied):
            TestView.as_view()(self.req)