tcms.testruns.tests.test_views   F
last analyzed

Complexity

Total Complexity 73

Size/Duplication

Total Lines 827
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 73
eloc 595
dl 0
loc 827
rs 2.56
c 0
b 0
f 0

60 Methods

Rating   Name   Duplication   Size   Complexity  
A TestGetRun.setUpTestData() 0 15 2
A TestCreateNewRun.test_show_create_new_run_page() 0 17 2
A TestGetRun.test_get_a_run() 0 19 2
A TestGetRun.test_get_run_without_permissions_to_add_or_remove_tags() 0 13 1
A TestCreateNewRun.test_refuse_if_missing_plan_pk() 0 6 1
A TestGetRun.test_404_if_non_existing_pk() 0 4 1
A TestCreateNewRun.test_refuse_if_missing_cases_pks() 0 6 1
A TestCreateNewRun.setUpTestData() 0 8 1
A TestAddRemoveRunCC.test_refuse_if_user_not_exist() 0 10 1
A TestStartCloneRunFromRunPage.test_clone_a_run() 0 35 1
A TestAddRemoveRunCC.test_should_not_be_able_use_cc_when_user_has_no_pemissions() 0 6 1
A TestAddRemoveRunCC.test_remove_cc() 0 7 1
A TestStartCloneRunFromRunPage.setUpTestData() 0 6 1
A TestStartCloneRunFromRunPage.test_refuse_without_selecting_case_runs() 0 9 1
A CloneRunBaseTest.assert_one_run_clone_page() 0 16 2
A TestSearchRuns.setUpTestData() 0 5 1
A TestSearchRuns.test_search_page_is_shown() 0 3 1
A TestSearchRuns.test_search_page_is_shown_with_get_parameter_used() 0 6 1
A TestAddRemoveRunCC.setUpTestData() 0 15 1
A TestCreateNewRun.test_create_a_new_run_without_permissions_should_fail() 0 22 1
A TestStartCloneRunFromRunPage.test_open_clone_page_by_selecting_case_runs() 0 9 1
A TestAddRemoveRunCC.assert_cc() 0 9 2
A TestAddRemoveRunCC.test_add_cc() 0 8 1
A TestAddRemoveRunCC.test_404_if_run_not_exist() 0 5 1
A TestStartCloneRunFromRunPage.test_clone_a_run_without_permissions() 0 32 1
B TestCreateNewRun.test_create_a_new_run() 0 44 2
A TestAddRemoveRunCC.test_refuse_to_remove_if_missing_user() 0 9 1
A TestAddRemoveRunCC.test_refuse_if_missing_action() 0 5 1
A TestAddRemoveRunCC.test_refuse_to_add_if_missing_user() 0 9 1
A TestStartCloneRunFromRunPage.assert_cloned_run() 0 7 2
A TestEditRun.test_edit_run() 0 17 1
A TestRunCasesMenu.test_remove_cases_from_run_without_permission() 0 4 1
A TestExecutionComments.test_get_add_comment_with_permission() 0 4 1
A TestRunStatusMenu.test_get_status_options_with_permission() 0 7 2
A TestRunCasesMenu.test_update_caserun_text_without_permission() 0 4 1
A TestRunCasesMenu.test_remove_cases_from_run_with_permission() 0 4 1
A TestUpdateCaseRunText.test_get_update_caserun_text_with_permissions() 0 4 1
A TestChangeTestRunStatus.test_should_fail_when_try_to_change_status_without_permissions() 0 5 1
B TestAddCasesToRun.test_show_add_cases_to_run() 0 55 4
A TestRunStatusMenu.setUpTestData() 0 10 2
A TestRunCasesMenu.test_add_cases_to_run_with_permission() 0 4 1
A TestRunCasesMenu.setUpTestData() 0 38 1
A TestUpdateCaseRunText.setUpTestData() 0 14 1
A TestRunCasesMenu.test_update_caserun_text_with_permission() 0 4 1
A TestChangeTestRunStatus.setUpTestData() 0 4 1
A TestChangeTestRunStatus.test_change_status_to_running() 0 10 1
A TestAddCasesToRun.setUpTestData() 0 12 1
A TestUpdateCaseRunText.test_get_update_caserun_text_without_permissions() 0 4 1
A TestExecutionComments.setUpTestData() 0 8 1
A TestChangeTestRunStatus.test_should_throw_404_on_non_existing_testrun() 0 4 1
A TestExecutionComments.test_get_add_comment_without_permission() 0 4 1
A TestUpdateCaseRunText.test_update_selected_case_runs_without_permissions() 0 36 1
A TestChangeTestRunStatus.test_change_status_to_finished() 0 9 1
A TestRunCasesMenu.test_change_assignee_without_permission() 0 4 1
A TestEditRun.setUpTestData() 0 11 1
A TestRunCasesMenu.test_add_cases_to_run_without_permission() 0 4 1
A TestEditRun.test_404_if_edit_non_existing_run() 0 5 1
A TestRunStatusMenu.test_get_status_options_without_permission() 0 7 2
A TestUpdateCaseRunText.test_update_selected_case_runs_with_permissions() 0 29 1
A TestRunCasesMenu.test_change_assignee_with_permission() 0 4 1

How to fix   Complexity   

Complexity

Complex classes like tcms.testruns.tests.test_views often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
# pylint: disable=invalid-name, too-many-ancestors
3
4
import html
5
from http import HTTPStatus
6
7
from django.utils import formats
8
from django.urls import reverse
9
from django.conf import settings
10
from django.contrib.auth.models import Permission
11
from django.utils.translation import ugettext_lazy as _
12
13
from tcms.testruns.models import TestExecutionStatus
14
from tcms.testruns.models import TestRun
15
from tcms.utils.permissions import initiate_user_with_default_setups
16
17
from tcms.tests import BaseCaseRun
18
from tcms.tests import BasePlanCase
19
from tcms.tests import remove_perm_from_user
20
from tcms.tests import user_should_have_perm
21
from tcms.tests.factories import BuildFactory
22
from tcms.tests.factories import TagFactory
23
from tcms.tests.factories import TestCaseFactory
24
from tcms.tests.factories import UserFactory
25
26
27
class TestGetRun(BaseCaseRun):
28
    """Test get view method"""
29
30
    @classmethod
31
    def setUpTestData(cls):
32
        super().setUpTestData()
33
        initiate_user_with_default_setups(cls.tester)
34
35
        for _i in range(3):
36
            cls.test_run.add_tag(TagFactory())
37
38
        cls.unauthorized = UserFactory()
39
        cls.unauthorized.set_password('password')
40
        cls.unauthorized.save()
41
42
        cls.unauthorized.user_permissions.add(*Permission.objects.all())
43
        remove_perm_from_user(cls.unauthorized, 'testruns.add_testruntag')
44
        remove_perm_from_user(cls.unauthorized, 'testruns.delete_testruntag')
45
46
    def test_404_if_non_existing_pk(self):
47
        url = reverse('testruns-get', args=[99999999])
48
        response = self.client.get(url)
49
        self.assertEqual(HTTPStatus.NOT_FOUND, response.status_code)
50
51
    def test_get_a_run(self):
52
        url = reverse('testruns-get', args=[self.test_run.pk])
53
        response = self.client.get(url)
54
55
        self.assertEqual(HTTPStatus.OK, response.status_code)
56
        self.assertContains(response, 'Add Tag')
57
        self.assertContains(response, 'js-remove-tag')
58
59
        for i, case_run in enumerate(
60
                (self.execution_1, self.execution_2, self.execution_3), 1):
61
            self.assertContains(
62
                response,
63
                '<a href="#caserun_{0}">#{0}</a>'.format(case_run.pk),
64
                html=True)
65
            self.assertContains(
66
                response,
67
                '<a id="link_{0}" href="#caserun_{1}" title="Expand test case">'
68
                '{2}</a>'.format(i, case_run.pk, case_run.case.summary),
69
                html=True)
70
71
    def test_get_run_without_permissions_to_add_or_remove_tags(self):
72
        self.client.logout()
73
74
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
75
            username=self.unauthorized.username,
76
            password='password')
77
78
        url = reverse('testruns-get', args=[self.test_run.pk])
79
        response = self.client.get(url)
80
81
        self.assertEqual(HTTPStatus.OK, response.status_code)
82
        self.assertNotContains(response, 'Add Tag')
83
        self.assertNotContains(response, 'js-remove-tag')
84
85
86
class TestCreateNewRun(BasePlanCase):
87
    """Test creating new run"""
88
89
    @classmethod
90
    def setUpTestData(cls):
91
        super(TestCreateNewRun, cls).setUpTestData()
92
93
        cls.permission = 'testruns.add_testrun'
94
        user_should_have_perm(cls.tester, cls.permission)
95
        cls.url = reverse('testruns-new')
96
        cls.build_fast = BuildFactory(name='fast', product=cls.product)
97
98
    def test_refuse_if_missing_plan_pk(self):
99
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
100
            username=self.tester.username,
101
            password='password')
102
        response = self.client.post(self.url, {})
103
        self.assertRedirects(response, reverse('plans-search'))
104
105
    def test_refuse_if_missing_cases_pks(self):
106
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
107
            username=self.tester.username,
108
            password='password')
109
        response = self.client.post(self.url, {'from_plan': self.plan.pk}, follow=True)
110
        self.assertContains(response, _('Creating a TestRun requires at least one TestCase'))
111
112
    def test_show_create_new_run_page(self):
113
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
114
            username=self.tester.username,
115
            password='password')
116
117
        response = self.client.post(self.url, {
118
            'from_plan': self.plan.pk,
119
            'case': [self.case_1.pk, self.case_2.pk, self.case_3.pk]
120
        })
121
122
        # Assert listed cases
123
        for _i, case in enumerate((self.case_1, self.case_2, self.case_3), 1):
124
            case_url = reverse('testcases-get', args=[case.pk])
125
            self.assertContains(
126
                response,
127
                '<a href="%s">TC-%d: %s</a>' % (case_url, case.pk, case.summary),
128
                html=True)
129
130
    def test_create_a_new_run(self):
131
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
132
            username=self.tester.username,
133
            password='password')
134
135
        clone_data = {
136
            'summary': self.plan.name,
137
            'from_plan': self.plan.pk,
138
            'build': self.build_fast.pk,
139
            'manager': self.tester.email,
140
            'default_tester': self.tester.email,
141
            'notes': 'Clone new run',
142
            'case': [self.case_1.pk, self.case_2.pk],
143
            'POSTING_TO_CREATE': 'YES',
144
        }
145
146
        url = reverse('testruns-new')
147
        response = self.client.post(url, clone_data)
148
149
        new_run = TestRun.objects.last()
150
151
        self.assertRedirects(
152
            response,
153
            reverse('testruns-get', args=[new_run.pk]))
154
155
        self.assertEqual(self.plan.name, new_run.summary)
156
        self.assertEqual(self.plan, new_run.plan)
157
        self.assertEqual(self.version, new_run.product_version)
158
        self.assertEqual(None, new_run.stop_date)
159
        self.assertEqual('Clone new run', new_run.notes)
160
        self.assertEqual(self.build_fast, new_run.build)
161
        self.assertEqual(self.tester, new_run.manager)
162
        self.assertEqual(self.tester, new_run.default_tester)
163
164
        for case, case_run in zip((self.case_1, self.case_2),
165
                                  new_run.case_run.order_by('case')):
166
            self.assertEqual(case, case_run.case)
167
            self.assertEqual(None, case_run.tested_by)
168
            self.assertEqual(self.tester, case_run.assignee)
169
            self.assertEqual(TestExecutionStatus.objects.get(name='IDLE'),
170
                             case_run.status)
171
            self.assertEqual(case.history.latest().history_id, case_run.case_text_version)
172
            self.assertEqual(new_run.build, case_run.build)
173
            self.assertEqual(None, case_run.close_date)
174
175
    def test_create_a_new_run_without_permissions_should_fail(self):
176
        remove_perm_from_user(self.tester, 'testruns.add_testrun')
177
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
178
            username=self.tester.username,
179
            password='password')
180
181
        clone_data = {
182
            'summary': self.plan.name,
183
            'from_plan': self.plan.pk,
184
            'build': self.build_fast.pk,
185
            'manager': self.tester.email,
186
            'default_tester': self.tester.email,
187
            'notes': 'Clone new run',
188
            'case': [self.case_1.pk, self.case_2.pk],
189
            'POSTING_TO_CREATE': 'YES',
190
        }
191
192
        url = reverse('testruns-new')
193
194
        self.assertRedirects(
195
            self.client.post(url, clone_data),
196
            reverse('tcms-login') + '?next=' + url)
197
198
199
class CloneRunBaseTest(BaseCaseRun):
200
201
    def assert_one_run_clone_page(self, response):
202
        """Verify clone page for cloning one test run"""
203
204
        self.assertContains(
205
            response,
206
            '<input id="id_summary" class="form-control" name="summary" '
207
            'type="text" value="%s%s" required>' % (_('Clone of '), self.test_run.summary),
208
            html=True)
209
210
        for case_run in (self.execution_1, self.execution_2):
211
            case_url = reverse('testcases-get', args=[case_run.case.pk])
212
213
            self.assertContains(
214
                response,
215
                '<a href="%s">TC-%d: %s</a>' % (case_url, case_run.case.pk, case_run.case.summary),
216
                html=True)
217
218
219
class TestStartCloneRunFromRunPage(CloneRunBaseTest):
220
    """Test case for cloning run from a run page"""
221
222
    @classmethod
223
    def setUpTestData(cls):
224
        super(TestStartCloneRunFromRunPage, cls).setUpTestData()
225
226
        cls.permission = 'testruns.add_testrun'
227
        user_should_have_perm(cls.tester, cls.permission)
228
229
    def test_refuse_without_selecting_case_runs(self):
230
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
231
            username=self.tester.username,
232
            password='password')
233
        url = reverse('testruns-clone', args=[self.test_run.pk])
234
235
        response = self.client.post(url, {}, follow=True)
236
237
        self.assertContains(response, _('At least one TestCase is required'))
238
239
    def test_open_clone_page_by_selecting_case_runs(self):
240
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
241
            username=self.tester.username,
242
            password='password')
243
        url = reverse('testruns-clone', args=[self.test_run.pk])
244
245
        response = self.client.post(url, {'case_run': [self.execution_1.pk, self.execution_2.pk]})
246
247
        self.assert_one_run_clone_page(response)
248
249
    def test_clone_a_run(self):
250
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
251
            username=self.tester.username,
252
            password='password')
253
254
        new_summary = 'Clone {} - {}'.format(self.test_run.pk, self.test_run.summary)
255
256
        clone_data = {
257
            'summary': new_summary,
258
            'from_plan': self.plan.pk,
259
            'product_id': self.test_run.plan.product_id,
260
            'do': 'clone_run',
261
            'orig_run_id': self.test_run.pk,
262
            'POSTING_TO_CREATE': 'YES',
263
            'product': self.test_run.plan.product_id,
264
            'product_version': self.test_run.product_version.pk,
265
            'build': self.test_run.build.pk,
266
            'errata_id': '',
267
            'manager': self.test_run.manager.email,
268
            'default_tester': self.test_run.default_tester.email,
269
            'notes': '',
270
            'case': [self.execution_1.case.pk, self.execution_2.case.pk],
271
            'case_run_id': [self.execution_1.pk, self.execution_2.pk],
272
        }
273
274
        url = reverse('testruns-new')
275
        response = self.client.post(url, clone_data)
276
277
        cloned_run = TestRun.objects.get(summary=new_summary)
278
279
        self.assertRedirects(
280
            response,
281
            reverse('testruns-get', args=[cloned_run.pk]))
282
283
        self.assert_cloned_run(cloned_run)
284
285
    def test_clone_a_run_without_permissions(self):
286
        remove_perm_from_user(self.tester, 'testruns.add_testrun')
287
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
288
            username=self.tester.username,
289
            password='password')
290
291
        new_summary = 'Clone {} - {}'.format(self.test_run.pk, self.test_run.summary)
292
293
        clone_data = {
294
            'summary': new_summary,
295
            'from_plan': self.plan.pk,
296
            'product_id': self.test_run.plan.product_id,
297
            'do': 'clone_run',
298
            'orig_run_id': self.test_run.pk,
299
            'POSTING_TO_CREATE': 'YES',
300
            'product': self.test_run.plan.product_id,
301
            'product_version': self.test_run.product_version.pk,
302
            'build': self.test_run.build.pk,
303
            'errata_id': '',
304
            'manager': self.test_run.manager.email,
305
            'default_tester': self.test_run.default_tester.email,
306
            'notes': '',
307
            'case': [self.execution_1.case.pk, self.execution_2.case.pk],
308
            'case_run_id': [self.execution_1.pk, self.execution_2.pk],
309
        }
310
311
        url = reverse('testruns-new')
312
        response = self.client.post(url, clone_data)
313
314
        self.assertRedirects(
315
            response,
316
            reverse('tcms-login') + '?next=' + url)
317
318
    def assert_cloned_run(self, cloned_run):
319
        # Assert clone settings result
320
        for origin_case_run, cloned_case_run in zip((self.execution_1, self.execution_2),
321
                                                    cloned_run.case_run.order_by('pk')):
322
            self.assertEqual(TestExecutionStatus.objects.get(name='IDLE'),
323
                             cloned_case_run.status)
324
            self.assertEqual(origin_case_run.assignee, cloned_case_run.assignee)
325
326
327
class TestSearchRuns(BaseCaseRun):
328
329
    @classmethod
330
    def setUpTestData(cls):
331
        super(TestSearchRuns, cls).setUpTestData()
332
333
        cls.search_runs_url = reverse('testruns-search')
334
335
    def test_search_page_is_shown(self):
336
        response = self.client.get(self.search_runs_url)
337
        self.assertContains(response, '<input id="id_summary" type="text"')
338
339
    def test_search_page_is_shown_with_get_parameter_used(self):
340
        response = self.client.get(self.search_runs_url, {'product': self.product.pk})
341
        self.assertContains(response,
342
                            '<option value="%d" selected>%s</option>' % (self.product.pk,
343
                                                                         self.product.name),
344
                            html=True)
345
346
347
class TestAddRemoveRunCC(BaseCaseRun):
348
    """Test view tcms.testruns.views.cc"""
349
350
    @classmethod
351
    def setUpTestData(cls):
352
        super(TestAddRemoveRunCC, cls).setUpTestData()
353
354
        cls.cc_url = reverse('testruns-cc', args=[cls.test_run.pk])
355
356
        cls.cc_user_1 = UserFactory(username='cc-user-1',
357
                                    email='[email protected]')
358
        cls.cc_user_2 = UserFactory(username='cc-user-2',
359
                                    email='[email protected]')
360
        cls.cc_user_3 = UserFactory(username='cc-user-3',
361
                                    email='[email protected]')
362
363
        cls.test_run.add_cc(cls.cc_user_2)
364
        cls.test_run.add_cc(cls.cc_user_3)
365
366
    def test_404_if_run_not_exist(self):
367
        user_should_have_perm(self.tester, 'testruns.change_testrun')
368
        cc_url = reverse('testruns-cc', args=[999999])
369
        response = self.client.get(cc_url)
370
        self.assert404(response)
371
372
    def assert_cc(self, response, expected_cc):
373
        self.assertEqual(len(expected_cc), self.test_run.cc.count())  # pylint: disable=no-member
374
375
        for cc in expected_cc:
376
            href = reverse('tcms-profile', args=[cc.username])
377
            self.assertContains(
378
                response,
379
                '<a href="%s">%s</a>' % (href, cc.username),
380
                html=True)
381
382
    def test_refuse_if_missing_action(self):
383
        user_should_have_perm(self.tester, 'testruns.change_testrun')
384
        response = self.client.get(self.cc_url,
385
                                   {'user': self.cc_user_1.username})
386
        self.assert_cc(response, [self.cc_user_2, self.cc_user_3])
387
388
    def test_add_cc(self):
389
        user_should_have_perm(self.tester, 'testruns.change_testrun')
390
        response = self.client.get(
391
            self.cc_url,
392
            {'do': 'add', 'user': self.cc_user_1.username})
393
394
        self.assert_cc(response,
395
                       [self.cc_user_2, self.cc_user_3, self.cc_user_1])
396
397
    def test_remove_cc(self):
398
        user_should_have_perm(self.tester, 'testruns.change_testrun')
399
        response = self.client.get(
400
            self.cc_url,
401
            {'do': 'remove', 'user': self.cc_user_2.username})
402
403
        self.assert_cc(response, [self.cc_user_3])
404
405
    def test_refuse_to_remove_if_missing_user(self):
406
        user_should_have_perm(self.tester, 'testruns.change_testrun')
407
        response = self.client.get(self.cc_url, {'do': 'remove'})
408
409
        response_text = html.unescape(str(response.content, encoding=settings.DEFAULT_CHARSET))
410
        self.assertIn(str(_('The user you typed does not exist in database')),
411
                      response_text)
412
413
        self.assert_cc(response, [self.cc_user_2, self.cc_user_3])
414
415
    def test_refuse_to_add_if_missing_user(self):
416
        user_should_have_perm(self.tester, 'testruns.change_testrun')
417
        response = self.client.get(self.cc_url, {'do': 'add'})
418
419
        response_text = html.unescape(str(response.content, encoding=settings.DEFAULT_CHARSET))
420
        self.assertIn(str(_('The user you typed does not exist in database')),
421
                      response_text)
422
423
        self.assert_cc(response, [self.cc_user_2, self.cc_user_3])
424
425
    def test_refuse_if_user_not_exist(self):
426
        user_should_have_perm(self.tester, 'testruns.change_testrun')
427
        response = self.client.get(self.cc_url,
428
                                   {'do': 'add', 'user': 'not exist'})
429
430
        response_text = html.unescape(str(response.content, encoding=settings.DEFAULT_CHARSET))
431
        self.assertIn(str(_('The user you typed does not exist in database')),
432
                      response_text)
433
434
        self.assert_cc(response, [self.cc_user_2, self.cc_user_3])
435
436
    def test_should_not_be_able_use_cc_when_user_has_no_pemissions(self):
437
        remove_perm_from_user(self.tester, 'testruns.change_testrun')
438
439
        self.assertRedirects(
440
            self.client.get(self.cc_url),
441
            reverse('tcms-login') + '?next=%s' % self.cc_url
442
        )
443
444
445
class TestUpdateCaseRunText(BaseCaseRun):
446
    """Test update_case_run_text view method"""
447
448
    @classmethod
449
    def setUpTestData(cls):
450
        super().setUpTestData()
451
452
        cls.testruns_url = reverse('testruns-get', args=[cls.test_run.pk])
453
        cls.update_url = reverse('testruns-update_case_run_text',
454
                                 args=[cls.test_run.pk])
455
456
        # To increase case text version
457
        cls.execution_1.case.text = "Scenario Version 1"
458
        cls.execution_1.case.save()
459
460
        cls.execution_1.case.text = "Scenario Version 2"
461
        cls.execution_1.case.save()
462
463
    def test_get_update_caserun_text_with_permissions(self):
464
        user_should_have_perm(self.tester, 'testruns.change_testexecution')
465
        response = self.client.get(self.testruns_url)
466
        self.assertContains(response, 'id="update_case_run_text"')
467
468
    def test_update_selected_case_runs_with_permissions(self):
469
        user_should_have_perm(self.tester, 'testruns.change_testexecution')
470
471
        self.assertNotEqual(self.execution_1.case.history.latest().history_id,
472
                            self.execution_1.case_text_version)
473
474
        expected_text = "%s: %s -> %s" % (
475
            self.execution_1.case.summary,
476
            self.execution_1.case_text_version,
477
            self.execution_1.case.history.latest().history_id
478
        )
479
480
        response = self.client.post(self.update_url,
481
                                    {'case_run': [self.execution_1.pk]},
482
                                    follow=True)
483
484
        self.assertContains(response, expected_text)
485
486
        self.execution_1.refresh_from_db()
487
488
        self.assertEqual(
489
            self.execution_1.case.get_text_with_version(
490
                self.execution_1.case_text_version
491
            ),
492
            "Scenario Version 2"
493
        )
494
        self.assertEqual(
495
            self.execution_1.case.history.latest().history_id,
496
            self.execution_1.case_text_version
497
        )
498
499
    def test_get_update_caserun_text_without_permissions(self):
500
        remove_perm_from_user(self.tester, 'testruns.change_testexecution')
501
        response = self.client.get(self.testruns_url)
502
        self.assertNotContains(response, 'id="update_case_run_text"')
503
504
    def test_update_selected_case_runs_without_permissions(self):
505
        self.execution_1.case.text = "Scenario Version 3"
506
        self.execution_1.case.save()
507
508
        remove_perm_from_user(self.tester, 'testruns.change_testexecution')
509
510
        self.client.login(  # nosec:B106:hardcoded_password_funcarg
511
            username=self.tester.username,
512
            password='password')
513
514
        self.assertNotEqual(
515
            self.execution_1.case.history.latest().history_id,
516
            self.execution_1.case_text_version
517
        )
518
519
        response = self.client.post(self.update_url,
520
                                    {'case_run': [self.execution_1.pk]},
521
                                    follow=True)
522
523
        self.assertRedirects(
524
            response,
525
            reverse('tcms-login') + '?next=' + self.update_url
526
        )
527
528
        self.execution_1.refresh_from_db()
529
530
        self.assertNotEqual(
531
            self.execution_1.case.get_text_with_version(
532
                self.execution_1.case_text_version
533
            ),
534
            "Scenario Version 3"
535
        )
536
537
        self.assertNotEqual(
538
            self.execution_1.case.history.latest().history_id,
539
            self.execution_1.case_text_version
540
        )
541
542
543
class TestEditRun(BaseCaseRun):
544
    """Test edit view method"""
545
546
    @classmethod
547
    def setUpTestData(cls):
548
        super(TestEditRun, cls).setUpTestData()
549
550
        user_should_have_perm(cls.tester, 'testruns.change_testrun')
551
        cls.edit_url = reverse('testruns-edit', args=[cls.test_run.pk])
552
553
        cls.new_build = BuildFactory(name='FastTest',
554
                                     product=cls.test_run.plan.product)
555
        cls.intern = UserFactory(username='intern',
556
                                 email='[email protected]')
557
558
    def test_404_if_edit_non_existing_run(self):
559
        url = reverse('testruns-edit', args=[9999])
560
        response = self.client.get(url)
561
562
        self.assert404(response)
563
564
    def test_edit_run(self):
565
566
        post_data = {
567
            'summary': 'New run summary',
568
            'build': self.new_build.pk,
569
            'manager': self.test_run.manager.email,
570
            'default_tester': self.intern.email,
571
            'notes': 'easytest',
572
        }
573
574
        response = self.client.post(self.edit_url, post_data)
575
576
        run = TestRun.objects.get(pk=self.test_run.pk)
577
        self.assertEqual('New run summary', run.summary)
578
        self.assertEqual(self.new_build, run.build)
579
580
        self.assertRedirects(response, reverse('testruns-get', args=[run.pk]))
581
582
583
class TestAddCasesToRun(BaseCaseRun):
584
    """Test AddCasesToRunView"""
585
586
    @classmethod
587
    def setUpTestData(cls):
588
        super(TestAddCasesToRun, cls).setUpTestData()
589
590
        cls.proposed_case = TestCaseFactory(
591
            author=cls.tester,
592
            default_tester=None,
593
            reviewer=cls.tester,
594
            case_status=cls.case_status_proposed,
595
            plan=[cls.plan])
596
597
        user_should_have_perm(cls.tester, 'testruns.add_testexecution')
598
599
    def test_show_add_cases_to_run(self):
600
        url = reverse('add-cases-to-run', args=[self.test_run.pk])
601
        response = self.client.get(url)
602
603
        self.assertNotContains(
604
            response,
605
            '<a href="{0}">{1}</a>'.format(
606
                reverse('testcases-get',
607
                        args=[self.proposed_case.pk]),
608
                self.proposed_case.pk),
609
            html=True
610
        )
611
612
        confirmed_cases = [self.case, self.case_1, self.case_2, self.case_3]
613
614
        # Check selected and unselected case id checkboxes
615
        # cls.case is not added to cls.test_run, so it should not be checked.
616
        self.assertContains(
617
            response,
618
            '<td align="left">'
619
            '<input type="checkbox" name="case" value="{0}">'
620
            '</td>'.format(self.case.pk),
621
            html=True)
622
623
        # other cases are added to cls.test_run, so must be checked.
624
        for case in confirmed_cases[1:]:
625
            self.assertContains(
626
                response,
627
                '<td align="left">'
628
                '<input type="checkbox" name="case" value="{0}" '
629
                'disabled="true" checked="true">'
630
                '</td>'.format(case.pk),
631
                html=True)
632
633
        # Check listed case properties
634
        # note: the response is ordered by 'case'
635
        for loop_counter, case in enumerate(confirmed_cases, 1):
636
            html_pieces = [
637
                '<a href="{0}">{1}</a>'.format(
638
                    reverse('testcases-get', args=[case.pk]),
639
                    case.pk),
640
641
                '<td class="js-case-summary" data-param="{0}">'
642
                '<a id="link_{0}" class="blind_title_link" '
643
                'href="javascript:void(0);">{1}</a></td>'.format(loop_counter,
644
                                                                 case.summary),
645
646
                '<td>{0}</td>'.format(case.author.username),
647
                '<td>{0}</td>'.format(
648
                    formats.date_format(case.create_date, 'DATETIME_FORMAT')),
649
                '<td>{0}</td>'.format(case.category.name),
650
                '<td>{0}</td>'.format(case.priority.value),
651
            ]
652
            for piece in html_pieces:
653
                self.assertContains(response, piece, html=True)
654
655
656
class TestRunCasesMenu(BaseCaseRun):
657
    @classmethod
658
    def setUpTestData(cls):
659
        super().setUpTestData()
660
661
        cls.url = reverse('testruns-get', args=[cls.test_run.pk])
662
663
        cls.add_cases_html = \
664
            '<a href="{0}" class="addBlue9">{1}</a>' \
665
            .format(
666
                reverse('add-cases-to-run', args=[cls.test_run.pk]),
667
                _('Add')
668
            )
669
670
        cls.remove_cases_html = \
671
            '<a href="#" title="{0}" data-param="{1}" \
672
            class="removeBlue9 js-del-case">{2}</a>' \
673
            .format(
674
                _('Remove selected cases form this test run'),
675
                cls.test_run.pk,
676
                _('Remove')
677
            )
678
679
        cls.update_case_run_text_html = \
680
            '<a href="#" title="{0}" \
681
            href="javascript:void(0)" data-param="{1}" \
682
            class="updateBlue9 js-update-case" id="update_case_run_text">{2}</a>' \
683
            .format(
684
                _('Update the IDLE case runs to newest case text'),
685
                reverse('testruns-update_case_run_text', args=[cls.test_run.pk]),
686
                _('Update')
687
            )
688
689
        cls.change_assignee_html = \
690
            '<a href="#" title="{0}" \
691
            class="assigneeBlue9 js-change-assignee">{1}</a>' \
692
            .format(
693
                _('Assign this case(s) to other people'),
694
                _('Assignee')
695
            )
696
697
    def test_add_cases_to_run_with_permission(self):
698
        user_should_have_perm(self.tester, 'testruns.add_testexecution')
699
        response = self.client.get(self.url)
700
        self.assertContains(response, self.add_cases_html, html=True)
701
702
    def test_remove_cases_from_run_with_permission(self):
703
        user_should_have_perm(self.tester, 'testruns.delete_testexecution')
704
        response = self.client.get(self.url)
705
        self.assertContains(response, self.remove_cases_html, html=True)
706
707
    def test_update_caserun_text_with_permission(self):
708
        user_should_have_perm(self.tester, 'testruns.change_testexecution')
709
        response = self.client.get(self.url)
710
        self.assertContains(response, self.update_case_run_text_html, html=True)
711
712
    def test_change_assignee_with_permission(self):
713
        user_should_have_perm(self.tester, 'testruns.change_testexecution')
714
        response = self.client.get(self.url)
715
        self.assertContains(response, self.change_assignee_html, html=True)
716
717
    def test_add_cases_to_run_without_permission(self):
718
        remove_perm_from_user(self.tester, 'testruns.add_testexecution')
719
        response = self.client.get(self.url)
720
        self.assertNotContains(response, self.add_cases_html, html=True)
721
722
    def test_remove_cases_from_run_without_permission(self):
723
        remove_perm_from_user(self.tester, 'testruns.delete_testexecution')
724
        response = self.client.get(self.url)
725
        self.assertNotContains(response, self.remove_cases_html, html=True)
726
727
    def test_update_caserun_text_without_permission(self):
728
        remove_perm_from_user(self.tester, 'testruns.change_testexecution')
729
        response = self.client.get(self.url)
730
        self.assertNotContains(response, self.update_case_run_text_html, html=True)
731
732
    def test_change_assignee_without_permission(self):
733
        remove_perm_from_user(self.tester, 'testruns.change_testexecution')
734
        response = self.client.get(self.url)
735
        self.assertNotContains(response, self.change_assignee_html, html=True)
736
737
738
class TestRunStatusMenu(BaseCaseRun):
739
    @classmethod
740
    def setUpTestData(cls):
741
        super().setUpTestData()
742
        cls.url = reverse('testruns-get', args=[cls.test_run.pk])
743
        cls.status_menu_html = []
744
745
        for tcrs in TestExecutionStatus.objects.all():
746
            cls.status_menu_html.append(
747
                '<a value="{0}" href="#" class="{1}Blue9">{2}</a>'
748
                .format(tcrs.pk, tcrs.name.lower(), tcrs.name)
749
            )
750
751
    def test_get_status_options_with_permission(self):
752
        user_should_have_perm(self.tester, 'testruns.change_testexecution')
753
        response = self.client.get(self.url)
754
        self.assertEqual(HTTPStatus.OK, response.status_code)
755
756
        for html_code in self.status_menu_html:
757
            self.assertContains(response, html_code, html=True)
758
759
    def test_get_status_options_without_permission(self):
760
        remove_perm_from_user(self.tester, 'testruns.change_testexecution')
761
        response = self.client.get(self.url)
762
        self.assertEqual(HTTPStatus.OK, response.status_code)
763
764
        for tcrs in TestExecutionStatus.objects.all():
765
            self.assertNotContains(response, self.status_menu_html, html=True)
766
767
768
class TestExecutionComments(BaseCaseRun):
769
    @classmethod
770
    def setUpTestData(cls):
771
        super().setUpTestData()
772
        cls.url = reverse('testruns-get', args=[cls.test_run.pk])
773
774
        cls.add_comment_html = \
775
            '<a href="#" class="addBlue9 js-show-commentdialog">{0}</a>' \
776
            .format(_('Add'))
777
778
    def test_get_add_comment_with_permission(self):
779
        user_should_have_perm(self.tester, 'django_comments.add_comment')
780
        response = self.client.get(self.url)
781
        self.assertContains(response, self.add_comment_html, html=True)
782
783
    def test_get_add_comment_without_permission(self):
784
        remove_perm_from_user(self.tester, 'django_comments.add_comment')
785
        response = self.client.get(self.url)
786
        self.assertNotContains(response, self.add_comment_html, html=True)
787
788
789
class TestChangeTestRunStatus(BaseCaseRun):
790
791
    @classmethod
792
    def setUpTestData(cls):
793
        super().setUpTestData()
794
        cls.url = reverse('testruns-change_status', args=[cls.test_run.pk])
795
796
    def test_change_status_to_finished(self):
797
        user_should_have_perm(self.tester, 'testruns.change_testrun')
798
        response = self.client.get(self.url, {'finished': 1})
799
        self.assertRedirects(
800
            response,
801
            reverse('testruns-get', args=[self.test_run.pk]))
802
803
        self.test_run.refresh_from_db()
804
        self.assertIsNotNone(self.test_run.stop_date)
805
806
    def test_change_status_to_running(self):
807
        user_should_have_perm(self.tester, 'testruns.change_testrun')
808
        response = self.client.get(self.url, {'finished': 0})
809
810
        self.assertRedirects(
811
            response,
812
            reverse('testruns-get', args=[self.test_run.pk]))
813
814
        self.test_run.refresh_from_db()
815
        self.assertIsNone(self.test_run.stop_date)
816
817
    def test_should_throw_404_on_non_existing_testrun(self):
818
        user_should_have_perm(self.tester, 'testruns.change_testrun')
819
        response = self.client.get(reverse('testruns-change_status', args=[99999]), {'finished': 0})
820
        self.assertEqual(HTTPStatus.NOT_FOUND, response.status_code)
821
822
    def test_should_fail_when_try_to_change_status_without_permissions(self):
823
        remove_perm_from_user(self.tester, 'testruns.change_testrun')
824
        self.assertRedirects(
825
            self.client.get(self.url, {'finished': 1}),
826
            reverse('tcms-login') + '?next=%s?finished=1' % self.url)
827