biosample.tests.test_submit   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 466
Duplicated Lines 24.68 %

Importance

Changes 0
Metric Value
wmc 34
eloc 226
dl 115
loc 466
rs 9.68
c 0
b 0
f 0

32 Methods

Rating   Name   Duplication   Size   Complexity  
A ExpiredTokenViewTest.generate_token() 0 9 1
A ErrorSubmitViewtest.test_ownership() 11 11 1
A ExpiredTokenViewTest.test_expired_token() 0 9 1
A NoSubmitViewTest.test_submission_waiting() 5 5 1
A NoSubmitViewTest.__common_stuff() 23 23 1
A NoSubmitViewTest.test_submission_error() 5 5 1
A CreateTokenSubmitViewTest.setUpClass() 0 7 1
A CreateTokenSubmitViewTest.tearDownClass() 0 4 1
A NoTokenSubmitViewTest.generate_token() 0 10 2
A ErrorSubmitViewtest.setUp() 20 20 1
A ErrorTokenSubmitViewTest.setUp() 0 31 1
A SubmitMixin.setUp() 0 31 1
A SuccessfulSubmitViewTest.test_redirect() 0 5 1
A ErrorTokenSubmitViewTest.test_issue_with_biosample() 0 9 1
A InvalidSubmitViewTest.setUp() 0 7 1
A SuccessfulSubmitViewTest.generate_token() 0 6 1
A ErrorSubmitViewtest.test_does_not_exists() 11 11 1
A SubmitViewTest.test_form_inputs() 0 9 1
A TestMixin.setUp() 0 3 1
A NoSubmitViewTest.setUp() 16 16 1
A SuccessfulSubmitViewTest.test_valid_token() 0 8 1
A SubmitViewTest.setUp() 0 7 1
A NoSubmitViewTest.test_submission_completed() 5 5 1
A SubmitViewTest.test_url_resolves_view() 0 3 1
A SubmitMixin.setUpClass() 0 9 1
A CreateTokenSubmitViewTest.setUp() 0 36 1
A InvalidSubmitViewTest.test_status_code() 0 4 1
A SuccessfulSubmitViewTest.test_submit_status() 0 14 1
A SubmitMixin.tearDownClass() 0 8 2
A NoTokenSubmitViewTest.test_no_token() 0 9 1
A NoSubmitViewTest.test_submission_submitted() 5 5 1
A SubmitMixin.generate_token() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Tue Oct  9 16:05:54 2018
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import redis
10
11
from pyUSIrest.exceptions import USIConnectionError
12
13
from unittest.mock import Mock, patch
14
15
from django.test import Client, TestCase
16
from django.urls import resolve, reverse
17
from django.conf import settings
18
from django.utils import timezone
19
20
from uid.models import Submission
21
from common.constants import (
22
    WAITING, ERROR, READY, SUBMITTED, COMPLETED)
23
from common.tests import (
24
        FormMixinTestCase, MessageMixinTestCase, InvalidFormMixinTestCase)
25
26
from ..forms import SubmitForm
27
from ..views import SubmitView, TOKEN_DURATION_THRESHOLD
28
29
from .session_enabled_test_case import SessionEnabledTestCase
30
from .common import generate_token, TOKEN_DURATION
31
32
33
class TestMixin(object):
34
    """Base class for validation tests"""
35
36
    fixtures = [
37
        "uid/user",
38
        "uid/dictcountry",
39
        "uid/dictrole",
40
        "uid/organization",
41
        "uid/submission",
42
        "biosample/account",
43
        "biosample/managedteam",
44
    ]
45
46
    def setUp(self):
47
        self.client = Client()
48
        self.client.login(username='test', password='test')
49
50
51
class SubmitViewTest(TestMixin, FormMixinTestCase, TestCase):
52
    form_class = SubmitForm
53
54
    def setUp(self):
55
        # call base methods
56
        super(SubmitViewTest, self).setUp()
57
58
        # get the url for dashboard
59
        self.url = reverse('biosample:submit')
60
        self.response = self.client.get(self.url)
61
62
    def test_url_resolves_view(self):
63
        view = resolve('/biosample/submit/')
64
        self.assertIsInstance(view.func.view_class(), SubmitView)
65
66
    def test_form_inputs(self):
67
        '''
68
        The view two inputs: csrf, submission_id"
69
        '''
70
71
        # total input is n of form fields + (CSRF)
72
        self.assertContains(self.response, '<input', 4)
73
        self.assertContains(self.response, '<input type="hidden"', 3)
74
        self.assertContains(self.response, 'type="password"', 1)
75
76
77
# --- testing view
78
79
80
class SubmitMixin(TestMixin, MessageMixinTestCase, SessionEnabledTestCase):
81
    @classmethod
82
    def setUpClass(cls):
83
        # calling my base class setup
84
        super().setUpClass()
85
86
        cls.redis = redis.StrictRedis(
87
            host=settings.REDIS_HOST,
88
            port=settings.REDIS_PORT,
89
            db=settings.REDIS_DB)
90
91
    @classmethod
92
    def tearDownClass(cls):
93
        key = "token:submission:1:test"
94
95
        if cls.redis.exists(key):
96
            cls.redis.delete(key)
97
98
        super().tearDownClass()
99
100
    @patch('biosample.views.SplitSubmissionTask.delay')
101
    def setUp(self, my_submit):
102
        # call base methods
103
        super(SubmitMixin, self).setUp()
104
105
        # get a submission object
106
        submission = Submission.objects.get(pk=1)
107
108
        # set a status which I can submit
109
        submission.status = READY
110
        submission.save()
111
112
        # track submission ID
113
        self.submission_id = submission.id
114
115
        # track owner
116
        self.owner = submission.owner
117
118
        # generate a valid token
119
        self.generate_token()
120
121
        # get the url for dashboard (make request)
122
        self.url = reverse('biosample:submit')
123
        self.response = self.client.post(
124
            self.url, {
125
                'submission_id': self.submission_id
126
            }
127
        )
128
129
        # track my patched function
130
        self.my_submit = my_submit
131
132
    def generate_token(self):
133
        """Placeholder for token generation"""
134
135
        self.fail("Please define this method")
136
137
138
class SuccessfulSubmitViewTest(SubmitMixin):
139
    def generate_token(self):
140
        """generate a valid token"""
141
        session = self.get_session()
142
        session['token'] = generate_token()
143
        session.save()
144
        self.set_session_cookies(session)
145
146
    def test_redirect(self):
147
        """test redirection after submission occurs"""
148
149
        url = reverse('submissions:detail', kwargs={'pk': self.submission_id})
150
        self.assertRedirects(self.response, url)
151
152
    def test_submit_status(self):
153
        """check submission to biosample started and submission.state"""
154
155
        # check validation started
156
        self.assertTrue(self.my_submit.called)
157
158
        # get submission object
159
        submission = Submission.objects.get(pk=self.submission_id)
160
161
        # check submission.state changed
162
        self.assertEqual(submission.status, WAITING)
163
        self.assertEqual(
164
            submission.message,
165
            "Waiting for biosample submission")
166
167
    def test_valid_token(self):
168
        """check that a valid token is writtein in redis"""
169
170
        key = "token:submission:{submission_id}:{username}".format(
171
            submission_id=self.submission_id,
172
            username=self.owner.username)
173
174
        self.assertIsNotNone(self.redis.get(key))
175
176
177
# --- issues with token
178
179
180
class NoTokenSubmitViewTest(SubmitMixin):
181
    """Do a submission without a token"""
182
183
    def generate_token(self):
184
        """remove token from session if present """
185
186
        # get session and remove token
187
        session = self.get_session()
188
189
        if 'token' in session:
190
            del(session['token'])
191
            session.save()
192
            self.set_session_cookies(session)
193
194
    def test_no_token(self):
195
        """check no token redirects to form"""
196
197
        self.assertEqual(self.response.status_code, 200)
198
199
        self.check_messages(
200
            self.response,
201
            "error",
202
            "You haven't generated any token yet")
203
204
205
class ExpiredTokenViewTest(SubmitMixin):
206
    def generate_token(self):
207
        """generate an expired token"""
208
209
        session = self.get_session()
210
        now = int(timezone.now().timestamp())
211
        session['token'] = generate_token(
212
            now - (TOKEN_DURATION-TOKEN_DURATION_THRESHOLD))
213
        session.save()
214
        self.set_session_cookies(session)
215
216
    def test_expired_token(self):
217
        """check that an expired token redirects to form"""
218
219
        self.assertEqual(self.response.status_code, 200)
220
221
        self.check_messages(
222
            self.response,
223
            "error",
224
            "Your token is expired or near to expire")
225
226
227
class CreateTokenSubmitViewTest(SuccessfulSubmitViewTest):
228
    """Test that by providing submission id and password I can do a
229
    submission"""
230
231
    @classmethod
232
    def setUpClass(cls):
233
        # calling my base class setup
234
        super().setUpClass()
235
236
        cls.mock_get_patcher = patch('pyUSIrest.auth.requests.get')
237
        cls.mock_get = cls.mock_get_patcher.start()
238
239
    @classmethod
240
    def tearDownClass(cls):
241
        cls.mock_get_patcher.stop()
242
        super().tearDownClass()
243
244
    @patch('biosample.views.SplitSubmissionTask.delay')
245
    def setUp(self, my_submit):
246
        """Custom setUp"""
247
248
        self.client = Client()
249
        self.client.login(username='test', password='test')
250
251
        # get a submission object
252
        submission = Submission.objects.get(pk=1)
253
254
        # set a status which I can submit
255
        submission.status = READY
256
        submission.save()
257
258
        # track submission ID
259
        self.submission_id = submission.id
260
261
        # track owner
262
        self.owner = submission.owner
263
264
        # generate token
265
        self.mock_get.return_value = Mock()
266
        self.mock_get.return_value.text = generate_token()
267
        self.mock_get.return_value.status_code = 200
268
269
        self.data = {
270
            'password': 'image-password',
271
            'submission_id': self.submission_id
272
        }
273
274
        # get the url for dashboard (make request)
275
        self.url = reverse('biosample:submit')
276
        self.response = self.client.post(self.url, self.data)
277
278
        # track my patched function
279
        self.my_submit = my_submit
280
281
282
class ErrorTokenSubmitViewTest(SubmitMixin):
283
    @patch("pyUSIrest.auth.Auth", side_effect=USIConnectionError("test"))
284
    def setUp(self, my_auth):
285
        """Custom setUp"""
286
287
        self.client = Client()
288
        self.client.login(username='test', password='test')
289
290
        # get a submission object
291
        submission = Submission.objects.get(pk=1)
292
293
        # set a status which I can submit
294
        submission.status = READY
295
        submission.save()
296
297
        # track submission ID
298
        self.submission_id = submission.id
299
300
        # track owner
301
        self.owner = submission.owner
302
303
        self.data = {
304
            'password': 'image-password',
305
            'submission_id': self.submission_id
306
        }
307
308
        # get the url for dashboard (make request)
309
        self.url = reverse('biosample:submit')
310
        self.response = self.client.post(self.url, self.data)
311
312
        # track my patched function
313
        self.my_auth = my_auth
314
315
    def test_issue_with_biosample(self):
316
        """check that issues with biosample redirects to form"""
317
318
        self.assertEqual(self.response.status_code, 200)
319
320
        self.check_messages(
321
            self.response,
322
            "error",
323
            "Unable to generate token")
324
325
# --- check status before submission
326
327
328 View Code Duplication
class NoSubmitViewTest(TestMixin, MessageMixinTestCase, TestCase):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
329
    """No submission if status is not OK"""
330
331
    @patch('biosample.views.SplitSubmissionTask.delay')
332
    def setUp(self, my_submit):
333
        # call base methods
334
        super(NoSubmitViewTest, self).setUp()
335
336
        # get a submission object
337
        submission = Submission.objects.get(pk=1)
338
339
        # track submission ID
340
        self.submission_id = submission.id
341
342
        # set URL
343
        self.url = reverse('biosample:submit')
344
345
        # track my patched function
346
        self.my_submit = my_submit
347
348
    def __common_stuff(self, status):
349
        """Common function for statuses"""
350
351
        # get submission
352
        submission = Submission.objects.get(pk=self.submission_id)
353
354
        # update status and save
355
        submission.status = status
356
        submission.save()
357
358
        # call valiate views with cyrrent status WAITING
359
        response = self.client.post(
360
            self.url, {
361
                'submission_id': self.submission_id
362
            }
363
        )
364
365
        # assert redirect
366
        url = reverse('submissions:detail', kwargs={'pk': self.submission_id})
367
        self.assertRedirects(response, url)
368
369
        # get number of call (equal to first call)
370
        self.assertEqual(self.my_submit.call_count, 0)
371
372
    def test_submission_waiting(self):
373
        """check no submission with submission status WAITING"""
374
375
        # valutate status and no function called
376
        self.__common_stuff(WAITING)
377
378
    def test_submission_error(self):
379
        """check no submission with submission status ERROR"""
380
381
        # valutate status and no function called
382
        self.__common_stuff(ERROR)
383
384
    def test_submission_submitted(self):
385
        """check no submission with submission status SUBMITTED"""
386
387
        # valutate status and no function called
388
        self.__common_stuff(SUBMITTED)
389
390
    def test_submission_completed(self):
391
        """check no submission with submission status COMPLETED"""
392
393
        # valutate status and no function called
394
        self.__common_stuff(COMPLETED)
395
396
397
# errors with form
398
399
400
class InvalidSubmitViewTest(TestMixin, InvalidFormMixinTestCase, TestCase):
401
    def setUp(self):
402
        # call base methods
403
        super(InvalidSubmitViewTest, self).setUp()
404
405
        # get the url for dashboard
406
        self.url = reverse('biosample:submit')
407
        self.response = self.client.post(self.url, {})
408
409
    def test_status_code(self):
410
        """Invalid post data returns the form"""
411
412
        self.assertEqual(self.response.status_code, 200)
413
414
415
# --- submission owenership
416
417
418 View Code Duplication
class ErrorSubmitViewtest(TestMixin, TestCase):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
419
    """A class to test submission not belonging to the user or which doesn't
420
    exists"""
421
422
    @patch('biosample.views.SplitSubmissionTask.delay')
423
    def setUp(self, my_submit):
424
        self.client = Client()
425
        self.client.login(username='test2', password='test2')
426
427
        # get a submission object
428
        submission = Submission.objects.get(pk=1)
429
430
        # set a status which I can ready
431
        submission.status = READY
432
        submission.save()
433
434
        # track submission ID
435
        self.submission_id = submission.id
436
437
        # get the url for dashboard
438
        self.url = reverse('biosample:submit')
439
440
        # track my patched function
441
        self.my_submit = my_submit
442
443
    def test_ownership(self):
444
        """Test a non-owner having a 404 response"""
445
446
        response = self.client.post(
447
            self.url, {
448
                'submission_id': self.submission_id
449
            }
450
        )
451
452
        self.assertEqual(response.status_code, 404)
453
        self.assertFalse(self.my_submit.called)
454
455
    def test_does_not_exists(self):
456
        """Test a submission which doesn't exists"""
457
458
        response = self.client.post(
459
            self.url, {
460
                'submission_id': 99
461
            }
462
        )
463
464
        self.assertEqual(response.status_code, 404)
465
        self.assertFalse(self.my_submit.called)
466