Coverage for CIResults/tests/test_views.py: 100%
233 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 09:20 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 09:20 +0000
1import json
2from unittest.mock import patch, MagicMock
3from rest_framework.test import APIRequestFactory
4from django.conf import settings
5from django.contrib.auth import get_user_model
6from django.contrib.auth.models import Permission
7from django.core.exceptions import ValidationError
8from django.test import TestCase
9from django.urls import reverse
10from django.utils import timezone
12from CIResults.models import Test, Machine, RunConfigTag, TestSuite, Build
13from CIResults.models import TextStatus, IssueFilter, Issue
14from CIResults.models import RunConfig, TestsuiteRun, TestResult, Component
15from CIResults.views import IssueFilterView, ResultsCompareView
17from datetime import timedelta
20# HACK: Massively speed up the login primitive. We don't care about security in tests
21settings.PASSWORD_HASHERS = ('django.contrib.auth.hashers.MD5PasswordHasher', )
24def create_user_and_log_in(client, admin=False, permissions=[]):
25 user = get_user_model().objects.create_user('user', 'user@provider.com', 'pwd',
26 first_name='First', last_name='Last',
27 is_superuser=admin)
28 perm_objs = []
29 for codename in permissions:
30 perm_objs.append(Permission.objects.get(codename=codename))
31 user.user_permissions.add(*perm_objs)
33 client.login(username='user', password='pwd')
34 return user
37class ViewMixin:
38 view_kwargs = {}
40 @property
41 def url(self):
42 return reverse(self.reverse_name, kwargs=self.view_kwargs)
44 def test_get__authorized(self):
45 if hasattr(self, 'permissions_needed'):
46 create_user_and_log_in(self.client, permissions=self.permissions_needed)
48 response = self.client.get(self.url)
49 self.assertEqual(response.status_code, 200)
51 def test_get__unauthorized_access(self):
52 if not hasattr(self, 'permissions_needed'):
53 self.skipTest("No need for authorization for the class") # pragma: no cover
55 create_user_and_log_in(self.client, permissions=[])
57 response = self.client.get(self.url)
58 self.assertEqual(response.status_code, 403)
61class UserFiltrableViewMixin(ViewMixin):
62 def test_invalid_query(self):
63 response = self.client.get(self.url + "?query=djzkhjkf")
64 self.assertEqual(response.status_code, 200)
65 self.assertContains(response, "Filtering error")
67 def test_valid_query(self):
68 response = self.client.get(self.url + "?query=" + self.query)
69 self.assertEqual(response.status_code, 200)
70 self.assertNotContains(response, "Filtering error")
73class IndexTests(ViewMixin, TestCase):
74 reverse_name = "CIResults-index"
77class IssueListTests(UserFiltrableViewMixin, TestCase):
78 reverse_name = "CIResults-issues-list"
79 query = "filter_description = 'desc'"
82class IssueAddTests(ViewMixin, TestCase):
83 reverse_name = "CIResults-issue"
84 permissions_needed = ['add_issue']
85 view_kwargs = {'action': 'create'}
88class IssueEditTests(ViewMixin, TestCase):
89 reverse_name = "CIResults-issue"
90 permissions_needed = ['change_issue']
92 def setUp(self):
93 issue = Issue.objects.create()
94 self.view_kwargs = {'action': 'edit', 'pk': issue.pk}
97class IssueMiscTests(TestCase):
98 post_actions = ["archive", "restore", "hide", "show"]
100 def setUp(self):
101 self.issue = Issue.objects.create()
103 def url(self, action):
104 return reverse("CIResults-issue", kwargs={'action': action, 'pk': self.issue.pk})
106 def test_post__unauthorized_access(self):
107 create_user_and_log_in(self.client, permissions=[])
108 for action in self.post_actions:
109 with self.subTest(action=action):
110 response = self.client.post(self.url(action), {})
111 self.assertEqual(response.status_code, 403)
113 def test_post__authorized_access(self):
114 for action in self.post_actions:
115 with self.subTest(action=action):
116 user = create_user_and_log_in(self.client, permissions=['{}_issue'.format(action)])
118 response = self.client.post(self.url(action), {})
119 self.assertEqual(response.status_code, 302)
120 self.assertEqual(response.url, reverse('CIResults-index'))
122 user.delete()
124 def test_get_on_post_action(self):
125 for action in self.post_actions:
126 with self.subTest(action=action):
127 self.assertRaises(ValidationError, self.client.get, self.url(action))
130class TestTests(ViewMixin, TestCase):
131 reverse_name = "CIResults-tests"
134class TestMassRenameTests(ViewMixin, TestCase):
135 reverse_name = "CIResults-tests-massrename"
136 permissions_needed = ['change_test']
139class TestRenameTests(ViewMixin, TestCase):
140 reverse_name = "CIResults-test-rename"
141 permissions_needed = ['change_test']
143 def setUp(self):
144 testsuite = TestSuite.objects.create(name='ts1', public=True)
145 t = Test.objects.create(name='test', testsuite=testsuite, public=True)
146 self.view_kwargs = {'pk': t.pk}
149class MachineTests(ViewMixin, TestCase):
150 reverse_name = "CIResults-machines"
153class TestResultListViewTests(UserFiltrableViewMixin, TestCase):
154 reverse_name = "CIResults-results"
155 query = "test_name = 'test'"
158class KnownFailureListViewTests(UserFiltrableViewMixin, TestCase):
159 reverse_name = "CIResults-knownfailures"
160 query = "test_name = 'test'"
163class ResultsCompareTests(ViewMixin, TestCase):
164 reverse_name = "CIResults-compare"
166 def test_urlify(self):
167 view = ResultsCompareView()
168 string = "Hello http://gitlab.freedesktop.org, https://x.org"
169 self.assertEqual(view.urlify(string),
170 "Hello <http://gitlab.freedesktop.org>, <https://x.org>")
172 def test_invalid_runconfig(self):
173 response = self.client.get(self.url + "?from=RUNCONFIG1&to=RUNCONFIG2")
174 self.assertEqual(response.status_code, 200)
176 @patch('CIResults.models.RunConfig.objects.filter')
177 def test_valid_runconfig(self, filter_mocked):
178 filter_mocked.return_value.first.return_value.compare.return_value.text = "Test"
179 response = self.client.get(self.url + "?from=RUNCONFIG1&to=RUNCONFIG2")
180 self.assertEqual(response.status_code, 200)
183class MassVettingMixin:
184 def test_get_request_should_fail(self):
185 create_user_and_log_in(self.client, permissions=[self.needed_permission])
186 response = self.client.get(self.url)
187 self.assertEqual(response.status_code, 405)
189 def test_normal_query__without_privileges(self):
190 create_user_and_log_in(self.client)
191 response = self.client.post(self.url, {})
192 self.assertEqual(response.status_code, 403)
194 def test_normal_query__with_privileges(self):
195 create_user_and_log_in(self.client, permissions=[self.needed_permission])
197 with patch('CIResults.models.{}.objects.filter'.format(self.klass),
198 return_value=[MagicMock(name='object 1'),
199 MagicMock(name='object 2'),
200 MagicMock(name='object 3')]) as filter_mocked:
201 response = self.client.post(self.url, {'1': 'on', '2': 'on', '3': 'on', 'gfdgdfg': 'invalid'})
202 self.assertEqual(response.status_code, 302)
204 # Check that all the machines were requested from the DB
205 filter_mocked.assert_called_once_with(pk__in=set([1, 2, 3]))
207 # Check that all machine returned were vetted
208 for obj in filter_mocked.return_value:
209 obj.vet.assert_called_once_with()
212class MachineMassVettingTests(MassVettingMixin, TestCase):
213 def setUp(self):
214 self.url = reverse('CIResults-machine-mass-vetting')
215 self.klass = "Machine"
216 self.needed_permission = 'vet_machine'
219class TestMassVettingTests(MassVettingMixin, TestCase):
220 def setUp(self):
221 self.url = reverse('CIResults-test-mass-vetting')
222 self.klass = "Test"
223 self.needed_permission = 'vet_test'
226class TextStatustMassVettingTests(MassVettingMixin, TestCase):
227 def setUp(self):
228 self.url = reverse('CIResults-textstatus-mass-vetting')
229 self.klass = "TextStatus"
230 self.needed_permission = 'vet_textstatus'
233class IssueDetailTests(ViewMixin, TestCase):
234 reverse_name = "CIResults-issue-detail"
236 def setUp(self):
237 issue = Issue.objects.create(filer='me@me.org', expected=True)
238 self.view_kwargs = {'pk': issue.pk}
241class IFADetailTests(ViewMixin, TestCase):
242 reverse_name = "CIResults-ifa-detail"
244 def setUp(self):
245 issue = Issue.objects.create(filer='me@me.org', expected=True)
246 f = IssueFilter.objects.create(description='filter')
248 user = get_user_model().objects.create_user('user')
249 issue.set_filters([f], user)
250 pk = f.issuefilterassociated_set.first().pk
251 self.view_kwargs = {'pk': pk}
254class IssueFilterViewTests(TestCase):
255 def setUp(self):
256 self.issueFilterView = IssueFilterView()
258 def test_parse_filter_from_params(self):
259 filter = self.issueFilterView.__parse_filter_from_params__(
260 {"description": "Description", "stdout_regex": "stdout regex"}
261 )
262 self.assertEqual(filter.description, "Description")
263 self.assertEqual(filter.stdout_regex, "stdout regex")
265 def test_convert_to_user_query(self):
266 arf = APIRequestFactory()
267 request = arf.post("/", {"stderr_regex": "stderr regex"}, format="json")
268 user_query = self.issueFilterView.__convert_to_user_query__(request)
269 self.assertEqual(json.loads(user_query.content)["userQuery"], "stderr ~= 'stderr regex'")
272class MachineDetailTests(ViewMixin, TestCase):
273 reverse_name = "CIResults-machine-detail"
275 def setUp(self):
276 machine = Machine.objects.create(name='Machine1', public=True)
277 self.view_kwargs = {'pk': machine.pk}
280class TestSuiteDetailTests(ViewMixin, TestCase):
281 reverse_name = "CIResults-testsuite-detail"
283 def setUp(self):
284 ts = TestSuite.objects.create(name='TestSuite', public=True)
285 self.view_kwargs = {'pk': ts.pk}
288class TestDetailTests(ViewMixin, TestCase):
289 reverse_name = "CIResults-test-detail"
291 def setUp(self):
292 ts = TestSuite.objects.create(name='TestSuite', public=True)
293 test = Test.objects.create(name='test1', testsuite=ts, public=True)
294 self.view_kwargs = {'pk': test.pk}
297class TextStatusDetailTests(ViewMixin, TestCase):
298 reverse_name = "CIResults-textstatus-detail"
300 def setUp(self):
301 ts = TestSuite.objects.create(name='TestSuite', public=True)
302 txt_stat = TextStatus.objects.create(name='status1', testsuite=ts)
303 self.view_kwargs = {'pk': txt_stat.pk}
306class TestResultDetailTests(ViewMixin, TestCase):
307 reverse_name = "CIResults-testresult-detail"
309 def setUp(self):
310 ts = TestSuite.objects.create(name='TestSuite', public=True)
311 machine = Machine.objects.create(name='Machine1', public=True)
312 runconfig = RunConfig.objects.create(name='runconfig', temporary=True)
313 ts_run = TestsuiteRun.objects.create(testsuite=ts, machine=machine, runconfig=runconfig,
314 run_id=0, start=timezone.now(), duration=timedelta(hours=3))
316 test = Test.objects.create(name='test1', testsuite=ts, public=True)
317 status = TextStatus.objects.create(name='status1', testsuite=ts)
318 tr = TestResult.objects.create(test=test, status=status, ts_run=ts_run,
319 start=timezone.now(), duration=timedelta(seconds=5))
320 self.view_kwargs = {'pk': tr.pk}
323class RunConfigDetailTests(ViewMixin, TestCase):
324 reverse_name = "CIResults-runcfg-detail"
326 def setUp(self):
327 cfg = RunConfig.objects.create(name='runconfig', temporary=True)
328 self.view_kwargs = {'pk': cfg.pk}
331class RunConfigTagDetailTests(ViewMixin, TestCase):
332 reverse_name = "CIResults-runcfgtag-detail"
334 def setUp(self):
335 cfg = RunConfigTag.objects.create(name='tag', public=True)
336 self.view_kwargs = {'pk': cfg.pk}
339class BuildDetailTests(ViewMixin, TestCase):
340 reverse_name = "CIResults-build-detail"
342 def setUp(self):
343 component = Component.objects.create(name='component', public=True)
344 build = Build.objects.create(name='build1', component=component)
345 self.view_kwargs = {'pk': build.pk}
348class ComponentDetailTests(ViewMixin, TestCase):
349 reverse_name = "CIResults-component-detail"
351 def setUp(self):
352 comp = Component.objects.create(name='runconfig', public=True)
353 self.view_kwargs = {'pk': comp.pk}