Completed
Push — master ( 5644bc...b87258 )
by Paolo
17s queued 13s
created

SubmitTestCase.test_token_expired()   A

Complexity

Conditions 1

Size

Total Lines 58
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 58
rs 9.16
c 0
b 0
f 0
cc 1
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Tue Oct  9 14:51:13 2018
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import redis
10
11
from billiard.einfo import ExceptionInfo
12
from pytest import raises
13
from collections import Counter
14
from unittest.mock import patch, Mock, PropertyMock
15
from datetime import timedelta
16
17
from celery.exceptions import Retry
18
19
from django.test import TestCase
20
from django.conf import settings
21
from django.core import mail
22
from django.utils import timezone
23
24
from common.constants import (
25
    LOADED, ERROR, READY, NEED_REVISION, SUBMITTED, COMPLETED)
26
from common.tests import WebSocketMixin
27
from image_app.models import Submission, Name
28
29
from ..tasks import SubmitTask, FetchStatusTask
30
from ..models import ManagedTeam
31
32
from .common import SubmitMixin, generate_token
33
34
35
class RedisMixin():
36
    """A class to setup a test token in redis database"""
37
38
    # this will be the token key in redis database
39
    submission_key = "token:submission:1:test"
40
41
    @classmethod
42
    def setUpClass(cls):
43
        # calling my base class setup
44
        super().setUpClass()
45
46
        cls.redis = redis.StrictRedis(
47
            host=settings.REDIS_HOST,
48
            port=settings.REDIS_PORT,
49
            db=settings.REDIS_DB)
50
51
        # generate a token
52
        token = generate_token(domains=['subs.test-team-1'])
53
54
        # write token to database
55
        cls.redis.set(cls.submission_key, token, ex=3600)
56
57
    @classmethod
58
    def tearDownClass(cls):
59
        if cls.redis.exists(cls.submission_key):
60
            cls.redis.delete(cls.submission_key)
61
62
        super().tearDownClass()
63
64
65
class SubmitTestCase(SubmitMixin, RedisMixin, WebSocketMixin, TestCase):
66
67
    def setUp(self):
68
        # call Mixin method
69
        super().setUp()
70
71
        # setting tasks
72
        self.my_task = SubmitTask()
73
74
    def test_submit(self):
75
        """Test submitting into biosample"""
76
77
        # NOTE that I'm calling the function directly, without delay
78
        # (AsyncResult). I've patched the time consuming task
79
        res = self.my_task.run(submission_id=self.submission_id)
80
81
        # assert a success with data uploading
82
        self.assertEqual(res, "success")
83
84
        # check submission status and message
85
        self.submission_obj.refresh_from_db()
86
87
        # check submission.state changed
88
        self.assertEqual(self.submission_obj.status, SUBMITTED)
89
        self.assertEqual(
90
            self.submission_obj.message,
91
            "Waiting for biosample validation")
92
        self.assertEqual(
93
            self.submission_obj.biosample_submission_id,
94
            "new-submission")
95
96
        # check name status changed
97
        qs = Name.objects.filter(status=SUBMITTED)
98
        self.assertEqual(len(qs), self.n_to_submit)
99
100
        # assert called mock objects
101
        self.assertTrue(self.mock_root.called)
102
        self.assertTrue(self.my_root.get_team_by_name.called)
103
        self.assertTrue(self.my_team.create_submission.called)
104
        self.assertFalse(self.my_root.get_submission_by_name.called)
105
        self.assertEqual(
106
            self.new_submission.create_sample.call_count, self.n_to_submit)
107
        self.assertFalse(self.new_submission.propertymock.called)
108
109
        message = 'Submitted'
110
        notification_message = 'Waiting for biosample validation'
111
112
        # calling a WebSocketMixin method
113
        self.check_message(message, notification_message)
114
115
    # http://docs.celeryproject.org/en/latest/userguide/testing.html#tasks-and-unit-tests
116
    @patch("biosample.tasks.SubmitTask.retry")
117
    @patch("biosample.tasks.SubmitTask.submit_biosample")
118
    def test_submit_retry(self, my_submit, my_retry):
119
        """Test submissions with retry"""
120
121
        # Set a side effect on the patched methods
122
        # so that they raise the errors we want.
123
        my_retry.side_effect = Retry()
124
        my_submit.side_effect = Exception()
125
126
        with raises(Retry):
127
            self.my_task.run(submission_id=1)
128
129
        self.assertTrue(my_submit.called)
130
        self.assertTrue(my_retry.called)
131
132
    @patch("biosample.tasks.SubmitTask.retry")
133
    @patch("biosample.tasks.SubmitTask.submit_biosample")
134
    def test_issues_with_api(self, my_submit, my_retry):
135
        """Test errors with submission API"""
136
137
        # Set a side effect on the patched methods
138
        # so that they raise the errors we want.
139
        my_retry.side_effect = Retry()
140
        my_submit.side_effect = ConnectionError()
141
142
        # call task. No retries with issues at EBI
143
        res = self.my_task.run(submission_id=1)
144
145
        # assert a success with validation taks
146
        self.assertEqual(res, "success")
147
148
        # check submission status and message
149
        self.submission_obj.refresh_from_db()
150
151
        # this is the message I want
152
        message = "Errors in EBI API endpoints. Please try again later"
153
154
        # check submission.status NOT changed
155
        self.assertEqual(self.submission_obj.status, READY)
156
        self.assertIn(
157
            message,
158
            self.submission_obj.message)
159
160
        # test email sent
161
        self.assertEqual(len(mail.outbox), 1)
162
163
        # read email
164
        email = mail.outbox[0]
165
166
        self.assertEqual(
167
            "Error in biosample submission 1",
168
            email.subject)
169
170
        self.assertTrue(my_submit.called)
171
        self.assertFalse(my_retry.called)
172
173
        message = 'Ready'
174
        notification_message = (
175
            'Errors in EBI API endpoints. '
176
            'Please try again later')
177
178
        # calling a WebSocketMixin method
179
        self.check_message(message, notification_message)
180
181
    def test_submit_recover(self):
182
        """Test submission recovering"""
183
184
        # update submission object
185
        self.submission_obj.biosample_submission_id = "test-submission"
186
        self.submission_obj.save()
187
188
        # set one name as uploaded
189
        name = Name.objects.get(name='ANIMAL:::ID:::132713')
190
        name.status = SUBMITTED
191
        name.save()
192
193
        # calling submit
194
        res = self.my_task.run(submission_id=self.submission_id)
195
196
        # assert a success with data uploading
197
        self.assertEqual(res, "success")
198
199
        # reload submission
200
        self.submission_obj.refresh_from_db()
201
202
        # check submission.state changed
203
        self.assertEqual(self.submission_obj.status, SUBMITTED)
204
        self.assertEqual(
205
            self.submission_obj.message,
206
            "Waiting for biosample validation")
207
208
        # check name status changed
209
        qs = Name.objects.filter(status=SUBMITTED)
210
        self.assertEqual(len(qs), self.n_to_submit)
211
212
        # assert called mock objects
213
        self.assertTrue(self.mock_root.called)
214
        self.assertFalse(self.my_root.get_team_by_name.called)
215
        self.assertFalse(self.my_team.create_submission.called)
216
        self.assertTrue(self.my_root.get_submission_by_name.called)
217
        # I'm testing submission recover with 1 sample already sent, so:
218
        self.assertEqual(
219
            self.my_submission.create_sample.call_count, self.n_to_submit-1)
220
        self.assertTrue(self.my_submission.propertymock.called)
221
222
        message = 'Submitted'
223
        notification_message = 'Waiting for biosample validation'
224
225
        # calling a WebSocketMixin method
226
        self.check_message(message, notification_message)
227
228
    def test_submit_no_recover(self):
229
        """Test submission recovering with a closed submission"""
230
231
        # update submission status
232
        self.my_submission.propertymock = PropertyMock(
233
            return_value='Completed')
234
        type(self.my_submission).status = self.my_submission.propertymock
235
236
        # update submission object
237
        self.submission_obj.biosample_submission_id = "test-submission"
238
        self.submission_obj.save()
239
240
        # calling submit
241
        res = self.my_task.run(submission_id=self.submission_id)
242
243
        # assert a success with data uploading
244
        self.assertEqual(res, "success")
245
246
        # reload submission
247
        self.submission_obj.refresh_from_db()
248
249
        # check submission.state changed
250
        self.assertEqual(
251
            self.submission_obj.biosample_submission_id,
252
            "new-submission")
253
        self.assertEqual(self.submission_obj.status, SUBMITTED)
254
        self.assertEqual(
255
            self.submission_obj.message,
256
            "Waiting for biosample validation")
257
258
        # check name status changed
259
        qs = Name.objects.filter(status=SUBMITTED)
260
        self.assertEqual(len(qs), self.n_to_submit)
261
262
        # assert called mock objects
263
        self.assertTrue(self.mock_root.called)
264
        self.assertTrue(self.my_root.get_team_by_name.called)
265
        self.assertTrue(self.my_root.get_submission_by_name.called)
266
        self.assertTrue(self.my_team.create_submission.called)
267
        self.assertFalse(self.my_submission.create_sample.called)
268
        self.assertEqual(
269
            self.new_submission.create_sample.call_count, self.n_to_submit)
270
        self.assertTrue(self.my_submission.propertymock.called)
271
        self.assertFalse(self.new_submission.propertymock.called)
272
273
        message = 'Submitted'
274
        notification_message = 'Waiting for biosample validation'
275
276
        # calling a WebSocketMixin method
277
        self.check_message(message, notification_message)
278
279
    def test_submit_patch(self):
280
        """Test patching submission"""
281
282
        # creating mock samples
283
        my_samples = [
284
            Mock(**{'alias': 'IMAGEA000000001',
285
                    'title': 'a 4-year old pig organic fed'}),
286
            Mock(**{'alias': 'IMAGES000000001',
287
                    'title': 'semen collected when the animal turns to 4'}),
288
        ]
289
290
        # mocking set samples
291
        self.my_submission.get_samples.return_value = my_samples
292
293
        # update submission object
294
        self.submission_obj.biosample_submission_id = "test-submission"
295
        self.submission_obj.save()
296
297
        # calling submit
298
        res = self.my_task.run(submission_id=self.submission_id)
299
300
        # assert a success with data uploading
301
        self.assertEqual(res, "success")
302
303
        # reload submission
304
        self.submission_obj.refresh_from_db()
305
306
        # check submission.state changed
307
        self.assertEqual(self.submission_obj.status, SUBMITTED)
308
        self.assertEqual(
309
            self.submission_obj.message,
310
            "Waiting for biosample validation")
311
312
        # check name status changed
313
        qs = Name.objects.filter(status=SUBMITTED)
314
        self.assertEqual(len(qs), self.n_to_submit)
315
316
        # assert called mock objects
317
        self.assertTrue(self.mock_root.called)
318
        self.assertFalse(self.my_root.get_team_by_name.called)
319
        self.assertFalse(self.my_team.create_submission.called)
320
        self.assertTrue(self.my_root.get_submission_by_name.called)
321
        # I've patched 2 samples in this test, so:
322
        self.assertEqual(
323
            self.my_submission.create_sample.call_count, 2)
324
        self.assertTrue(self.my_submission.propertymock.called)
325
326
        # testing patch
327
        for sample in my_samples:
328
            self.assertTrue(sample.patch.called)
329
330
        message = 'Submitted'
331
        notification_message = 'Waiting for biosample validation'
332
333
        # calling a WebSocketMixin method
334
        self.check_message(message, notification_message)
335
336 View Code Duplication
    def test_on_failure(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
337
        """Testing on failure methods"""
338
339
        exc = Exception("Test")
340
        task_id = "test_task_id"
341
        args = [self.submission_id]
342
        kwargs = {}
343
        einfo = ExceptionInfo
344
345
        # call on_failure method
346
        self.my_task.on_failure(exc, task_id, args, kwargs, einfo)
347
348
        # check submission status and message
349
        submission = Submission.objects.get(pk=self.submission_id)
350
351
        # check submission.state changed
352
        self.assertEqual(submission.status, ERROR)
353
        self.assertEqual(
354
            submission.message,
355
            "Error in biosample submission: Test")
356
357
        # test email sent
358
        self.assertEqual(len(mail.outbox), 1)
359
360
        # read email
361
        email = mail.outbox[0]
362
363
        self.assertEqual(
364
            "Error in biosample submission %s" % self.submission_id,
365
            email.subject)
366
367
        message = 'Error'
368
        notification_message = 'Error in biosample submission: Test'
369
370
        # calling a WebSocketMixin method
371
        self.check_message(message, notification_message)
372
373
    def test_token_expired(self):
374
        """Testing token expiring during a submission"""
375
376
        # simulating a token expiring during a submission
377
        self.new_submission.create_sample.side_effect = RuntimeError(
378
                "Your token is expired")
379
380
        # calling task
381
        res = self.my_task.run(submission_id=self.submission_id)
382
383
        # assert a success with data uploading
384
        self.assertEqual(res, "success")
385
386
        # check submission status and message
387
        self.submission_obj.refresh_from_db()
388
389
        # check submission.state return to ready (if it was valid before,
390
        # should be valid again, if rules are the same)
391
        self.assertEqual(self.submission_obj.status, READY)
392
        self.assertEqual(
393
            self.submission_obj.message,
394
            "Your token is expired: please submit again to resume submission")
395
        self.assertEqual(
396
            self.submission_obj.biosample_submission_id,
397
            "new-submission")
398
399
        # check name status unchanged (counts are equal to setUp name queryset)
400
        qs = Name.objects.filter(status=READY)
401
        self.assertEqual(len(qs), self.name_qs.count())
402
403
        # test email sent
404
        self.assertEqual(len(mail.outbox), 1)
405
406
        # read email
407
        email = mail.outbox[0]
408
409
        self.assertEqual(
410
            "Error in biosample submission 1",
411
            email.subject)
412
413
        # assert called mock objects
414
        self.assertTrue(self.mock_root.called)
415
        self.assertTrue(self.my_root.get_team_by_name.called)
416
        self.assertTrue(self.my_team.create_submission.called)
417
        self.assertFalse(self.my_root.get_submission_by_name.called)
418
419
        # is called once. With the first call, I got an exception and I
420
        # dont't do the second request
421
        self.assertEqual(self.new_submission.create_sample.call_count, 1)
422
        self.assertFalse(self.new_submission.propertymock.called)
423
424
        message = 'Ready'
425
        notification_message = (
426
            'Your token is expired: please submit '
427
            'again to resume submission')
428
429
        # calling a WebSocketMixin method
430
        self.check_message(message, notification_message)
431
432
433
class UpdateSubmissionTestCase(
434
        SubmitMixin, RedisMixin, WebSocketMixin, TestCase):
435
    """Test a submission for an already completed submission which
436
    receives one update, is valid and need to be updated in biosample"""
437
438
    def setUp(self):
439
        # call Mixin method
440
        super().setUp()
441
442
        # get all name objects and set status to completed
443
        self.name_qs.update(status=COMPLETED)
444
445
        # Now get first animal and set status to ready. Take also its sample
446
        # and assign a fake biosample id
447
        self.animal_name = Name.objects.get(pk=3)
448
        self.sample_name = Name.objects.get(pk=4)
449
450
        # update name objects. In this case, animal was modified
451
        self.animal_name.status = READY
452
        self.animal_name.save()
453
454
        # sample is supposed to be submitted with success
455
        self.sample_name.status = COMPLETED
456
        self.sample_name.biosample_id = "FAKES123456"
457
        self.sample_name.save()
458
459
        # setting tasks
460
        self.my_task = SubmitTask()
461
462
    def test_submit(self):
463
        """Test submitting into biosample"""
464
465
        res = self.my_task.run(submission_id=self.submission_id)
466
467
        # assert a success with data uploading
468
        self.assertEqual(res, "success")
469
470
        # check submission status and message
471
        self.submission_obj.refresh_from_db()
472
473
        # check submission.state changed
474
        self.assertEqual(self.submission_obj.status, SUBMITTED)
475
        self.assertEqual(
476
            self.submission_obj.message,
477
            "Waiting for biosample validation")
478
        self.assertEqual(
479
            self.submission_obj.biosample_submission_id,
480
            "new-submission")
481
482
        # check name status changed for animal
483
        self.animal_name.refresh_from_db()
484
        self.assertEqual(self.animal_name.status, SUBMITTED)
485
486
        # check that sample status is unchanged
487
        self.sample_name.refresh_from_db()
488
        self.assertEqual(self.sample_name.status, COMPLETED)
489
490
        # assert that all statuses (except one) remain unchanged
491
        qs = Name.objects.filter(status=COMPLETED)
492
        self.assertEqual(qs.count(), self.name_qs.count()-1)
493
494
        # assert called mock objects
495
        self.assertTrue(self.mock_root.called)
496
        self.assertTrue(self.my_root.get_team_by_name.called)
497
        self.assertTrue(self.my_team.create_submission.called)
498
        self.assertFalse(self.my_root.get_submission_by_name.called)
499
        self.assertEqual(self.new_submission.create_sample.call_count, 1)
500
        self.assertFalse(self.new_submission.propertymock.called)
501
502
        message = 'Submitted'
503
        notification_message = 'Waiting for biosample validation'
504
505
        # calling a WebSocketMixin method
506
        self.check_message(message, notification_message)
507
508
509
class FetchMixin():
510
    """Mixin for fetching status"""
511
512
    fixtures = [
513
        'biosample/account',
514
        'biosample/managedteam',
515
        'image_app/dictcountry',
516
        'image_app/dictrole',
517
        'image_app/organization',
518
        'image_app/submission',
519
        'image_app/user'
520
    ]
521
522
    @classmethod
523
    def setUpClass(cls):
524
        # calling my base class setup
525
        super().setUpClass()
526
527
        unmanaged = ManagedTeam.objects.get(pk=2)
528
        unmanaged.delete()
529
530
        # starting mocked objects
531
        cls.mock_root_patcher = patch('pyUSIrest.client.Root')
532
        cls.mock_root = cls.mock_root_patcher.start()
533
534
        cls.mock_auth_patcher = patch('biosample.helpers.Auth')
535
        cls.mock_auth = cls.mock_auth_patcher.start()
536
537
    @classmethod
538
    def tearDownClass(cls):
539
        cls.mock_root_patcher.stop()
540
        cls.mock_auth_patcher.stop()
541
542
        # calling base method
543
        super().tearDownClass()
544
545
    def setUp(self):
546
        # calling my base setup
547
        super().setUp()
548
549
        # get a submission object
550
        self.submission_obj = Submission.objects.get(pk=1)
551
552
        # set a status which I can fetch_status
553
        self.submission_obj.status = SUBMITTED
554
        self.submission_obj.biosample_submission_id = "test-fetch"
555
        self.submission_obj.save()
556
557
        # set status for names, like submittask does. Only sample not unknown
558
        # are submitted
559
        self.name_qs = Name.objects.exclude(name__contains="unknown")
560
        self.name_qs.update(status=SUBMITTED)
561
562
        # count number of names in UID for such submission (exclude
563
        # unknown animals)
564
        self.n_to_submit = self.name_qs.count()
565
566
        # track submission ID
567
        self.submission_obj_id = self.submission_obj.id
568
569
        # start root object
570
        self.my_root = self.mock_root.return_value
571
572
        # define my task
573
        self.my_task = FetchStatusTask()
574
575
        # change lock_id (useful when running test during cron)
576
        self.my_task.lock_id = "test-FetchStatusTask"
577
578
    def common_tests(self, my_submission):
579
        # passing submission to Mocked Root
580
        self.my_root.get_submission_by_name.return_value = my_submission
581
582
        # NOTE that I'm calling the function directly, without delay
583
        # (AsyncResult). I've patched the time consuming task
584
        res = self.my_task.run()
585
586
        # assert a success with data uploading
587
        self.assertEqual(res, "success")
588
589
        self.assertTrue(self.mock_auth.called)
590
        self.assertTrue(self.mock_root.called)
591
        self.assertTrue(self.my_root.get_submission_by_name.called)
592
593
594
class FetchCompletedTestCase(FetchMixin, WebSocketMixin, TestCase):
595
    """a completed submission with two samples"""
596
597
    fixtures = [
598
        'biosample/account',
599
        'biosample/managedteam',
600
        'image_app/animal',
601
        'image_app/dictbreed',
602
        'image_app/dictcountry',
603
        'image_app/dictrole',
604
        'image_app/dictsex',
605
        'image_app/dictspecie',
606
        'image_app/dictstage',
607
        'image_app/dictuberon',
608
        'image_app/name',
609
        'image_app/organization',
610
        'image_app/publication',
611
        'image_app/sample',
612
        'image_app/submission',
613
        'image_app/user'
614
    ]
615
616
    def test_fetch_status(self):
617
        # a completed submission with two samples
618
        my_submission = Mock()
619
        my_submission.name = "test-fetch"
620
        my_submission.status = 'Completed'
621
622
        # Add samples
623
        my_sample1 = Mock()
624
        my_sample1.name = "test-animal"
625
        my_sample1.alias = "IMAGEA000000001"
626
        my_sample1.accession = "SAMEA0000001"
627
        my_sample2 = Mock()
628
        my_sample2.name = "test-sample"
629
        my_sample2.alias = "IMAGES000000001"
630
        my_sample2.accession = "SAMEA0000002"
631
        my_submission.get_samples.return_value = [my_sample1, my_sample2]
632
633
        # assert task and mock methods called
634
        self.common_tests(my_submission)
635
636
        # assert status for submissions
637
        self.submission_obj.refresh_from_db()
638
        self.assertEqual(self.submission_obj.status, COMPLETED)
639
640
        # check name status changed
641
        qs = Name.objects.filter(status=COMPLETED)
642
        self.assertEqual(len(qs), 2)
643
644
        # fetch two name objects
645
        name = Name.objects.get(name='ANIMAL:::ID:::132713')
646
        self.assertEqual(name.biosample_id, "SAMEA0000001")
647
648
        name = Name.objects.get(name='Siems_0722_393449')
649
        self.assertEqual(name.biosample_id, "SAMEA0000002")
650
651
        message = 'Completed'
652
        notification_message = 'Successful submission into biosample'
653
654
        # calling a WebSocketMixin method
655
        self.check_message(message, notification_message)
656
657
    def test_fetch_status_no_accession(self):
658
        # a completed submission with two samples
659
        my_submission = Mock()
660
        my_submission.name = "test-fetch"
661
        my_submission.status = 'Submitted'
662
663
        # Add samples
664
        my_sample1 = Mock()
665
        my_sample1.name = "test-animal"
666
        my_sample1.alias = "IMAGEA000000001"
667
        my_sample1.accession = None
668
        my_sample2 = Mock()
669
        my_sample2.name = "test-sample"
670
        my_sample2.alias = "IMAGES000000001"
671
        my_sample2.accession = None
672
        my_submission.get_samples.return_value = [my_sample1, my_sample2]
673
674
        # assert task and mock methods called
675
        self.common_tests(my_submission)
676
677
        # assert status for submissions
678
        self.submission_obj.refresh_from_db()
679
        self.assertEqual(self.submission_obj.status, SUBMITTED)
680
681
        # check name status changed
682
        qs = Name.objects.filter(status=SUBMITTED)
683
        self.assertEqual(len(qs), self.n_to_submit)
684
685
    # http://docs.celeryproject.org/en/latest/userguide/testing.html#tasks-and-unit-tests
686
    @patch("biosample.tasks.FetchStatusTask.retry")
687
    @patch("biosample.tasks.FetchStatusTask.fetch_queryset")
688
    def test_fetch_status_retry(self, my_fetch, my_retry):
689
        """Test fetch status with retry"""
690
691
        # Set a side effect on the patched methods
692
        # so that they raise the errors we want.
693
        my_retry.side_effect = Retry()
694
        my_fetch.side_effect = ConnectionError()
695
696
        with raises(Retry):
697
            self.my_task.run()
698
699
        self.assertTrue(my_fetch.called)
700
        self.assertTrue(my_retry.called)
701
702
    # Test a non blocking instance
703
    @patch("biosample.tasks.FetchStatusTask.fetch_queryset")
704
    @patch("redis.lock.Lock.acquire", return_value=False)
705
    def test_fetch_status_nb(self, my_lock, my_fetch):
706
        """Test FetchSTatus while a lock is present"""
707
708
        res = self.my_task.run()
709
710
        # assert database is locked
711
        self.assertEqual(res, "%s already running!" % (self.my_task.name))
712
        self.assertFalse(my_fetch.called)
713
714
715
class FetchNotInDBTestCase(FetchMixin, TestCase):
716
    """A submission not in db"""
717
718
    def test_fetch_status(self):
719
        # mocking submissions. A submission not in db
720
        my_submission = Mock()
721
        my_submission.name = "not-present-in-db"
722
723
        # assert task and mock methods called
724
        self.common_tests(my_submission)
725
726
727
class FetchWithErrorsTestCase(FetchMixin, WebSocketMixin, TestCase):
728
    """Test a submission with errors for biosample"""
729
730
    fixtures = [
731
        'biosample/account',
732
        'biosample/managedteam',
733
        'image_app/animal',
734
        'image_app/dictbreed',
735
        'image_app/dictcountry',
736
        'image_app/dictrole',
737
        'image_app/dictsex',
738
        'image_app/dictspecie',
739
        'image_app/dictstage',
740
        'image_app/dictuberon',
741
        'image_app/name',
742
        'image_app/organization',
743
        'image_app/publication',
744
        'image_app/sample',
745
        'image_app/submission',
746
        'image_app/user'
747
    ]
748
749
    def setUp(self):
750
        # calling my base setup
751
        super().setUp()
752
753
        # a draft submission with errors
754
        my_submission = Mock()
755
        my_submission.name = "test-fetch"
756
        my_submission.status = 'Draft'
757
        my_submission.has_errors.return_value = Counter({True: 1, False: 1})
758
        my_submission.get_status.return_value = Counter({'Complete': 2})
759
760
        # Add samples. Suppose that first failed, second is ok
761
        my_validation_result1 = Mock()
762
        my_validation_result1.errorMessages = {
763
            'Ena': [
764
                'a sample message',
765
            ]
766
        }
767
768
        my_sample1 = Mock()
769
        my_sample1.name = "test-animal"
770
        my_sample1.alias = "IMAGEA000000001"
771
        my_sample1.has_errors.return_value = True
772
        my_sample1.get_validation_result.return_value = my_validation_result1
773
774
        # sample2 is ok
775
        my_validation_result2 = Mock()
776
        my_validation_result2.errorMessages = None
777
778
        my_sample2 = Mock()
779
        my_sample2.name = "test-sample"
780
        my_sample2.alias = "IMAGES000000001"
781
        my_sample2.has_errors.return_value = False
782
        my_sample2.get_validation_result.return_value = my_validation_result2
783
784
        # simulate that IMAGEA000000001 has errors
785
        my_submission.get_samples.return_value = [my_sample1, my_sample2]
786
787
        # track objects
788
        self.my_submission = my_submission
789
        self.my_validation_result1 = my_validation_result1
790
        self.my_validation_result2 = my_validation_result2
791
        self.my_sample1 = my_sample1
792
        self.my_sample2 = my_sample2
793
794
        # track names
795
        self.animal_name = Name.objects.get(pk=3)
796
        self.sample_name = Name.objects.get(pk=4)
797
798
    def common_tests(self):
799
        # assert task and mock methods called
800
        super().common_tests(self.my_submission)
801
802
        # assert custom mock attributes called
803
        self.assertTrue(self.my_sample1.has_errors.called)
804
        self.assertTrue(self.my_sample1.get_validation_result.called)
805
806
        # if sample has no errors, no all methods will be called
807
        self.assertTrue(self.my_sample2.has_errors.called)
808
        self.assertFalse(self.my_sample2.get_validation_result.called)
809
810
    def test_fetch_status(self):
811
        # assert task and mock methods called
812
        self.common_tests()
813
814
        # assert submission status
815
        self.submission_obj.refresh_from_db()
816
        self.assertEqual(self.submission_obj.status, NEED_REVISION)
817
818
        # check name status changed only for animal (not sample)
819
        self.animal_name.refresh_from_db()
820
        self.assertEqual(self.animal_name.status, NEED_REVISION)
821
822
        self.sample_name.refresh_from_db()
823
        self.assertEqual(self.sample_name.status, SUBMITTED)
824
825
        message = 'Need Revision'
826
        notification_message = 'Error in biosample submission'
827
828
        # calling a WebSocketMixin method
829
        self.check_message(message, notification_message)
830
831
    def test_email_sent(self):
832
        # assert task and mock methods called
833
        self.common_tests()
834
835
        # test email sent
836
        self.assertEqual(len(mail.outbox), 1)
837
838
        # read email
839
        email = mail.outbox[0]
840
841
        self.assertEqual(
842
            "Error in biosample submission %s" % self.submission_obj_id,
843
            email.subject)
844
845
        # check for error messages in object
846
        self.assertIn("a sample message", email.body)
847
848
        message = 'Need Revision'
849
        notification_message = 'Error in biosample submission'
850
851
        # calling a WebSocketMixin method
852
        self.check_message(message, notification_message)
853
854
855
class FetchDraftTestCase(FetchMixin, TestCase):
856
    """a draft submission without errors"""
857
858
    def test_fetch_status(self):
859
        # a draft submission without errors
860
        my_submission = Mock()
861
        my_submission.name = "test-fetch"
862
        my_submission.status = 'Draft'
863
        my_submission.has_errors.return_value = Counter({False: 1})
864
        my_submission.get_status.return_value = Counter({'Complete': 1})
865
866
        # assert task and mock methods called
867
        self.common_tests(my_submission)
868
869
        # assert status for submissions
870
        self.submission_obj.refresh_from_db()
871
        self.assertEqual(self.submission_obj.status, SUBMITTED)
872
873
        # testing a finalized biosample condition
874
        self.assertTrue(my_submission.finalize.called)
875
876
    def test_fetch_status_pending(self):
877
        """Testing status with pending validation"""
878
879
        # a draft submission without errors
880
        my_submission = Mock()
881
        my_submission.name = "test-fetch"
882
        my_submission.status = 'Draft'
883
        my_submission.has_errors.return_value = Counter({False: 1})
884
        my_submission.get_status.return_value = Counter({'Pending': 1})
885
886
        # assert task and mock methods called
887
        self.common_tests(my_submission)
888
889
        # assert status for submissions
890
        self.submission_obj.refresh_from_db()
891
        self.assertEqual(self.submission_obj.status, SUBMITTED)
892
893
        # testing a not finalized biosample condition
894
        self.assertFalse(my_submission.finalize.called)
895
896
    def test_fetch_status_submitted(self):
897
        """Testing status during biosample submission"""
898
899
        # a draft submission without errors
900
        my_submission = Mock()
901
        my_submission.name = "test-fetch"
902
        my_submission.status = 'Submitted'
903
        my_submission.has_errors.return_value = Counter({False: 1})
904
        my_submission.get_status.return_value = Counter({'Complete': 1})
905
906
        # assert task and mock methods called
907
        self.common_tests(my_submission)
908
909
        # assert status for submissions
910
        self.submission_obj.refresh_from_db()
911
        self.assertEqual(self.submission_obj.status, SUBMITTED)
912
913
        # testing a not finalized biosample condition
914
        self.assertFalse(my_submission.finalize.called)
915
916
917
class FetchLongTaskTestCase(FetchMixin, WebSocketMixin, TestCase):
918
    """A submission wich remain in the same status for a long time"""
919
920
    def setUp(self):
921
        # calling my base setup
922
        super().setUp()
923
924
        # make "now" 2 months ago
925
        testtime = timezone.now() - timedelta(days=60)
926
927
        # https://devblog.kogan.com/blog/testing-auto-now-datetime-fields-in-django
928
        with patch('django.utils.timezone.now') as mock_now:
929
            mock_now.return_value = testtime
930
931
            # update submission updated time with an older date than now
932
            self.submission_obj.updated_at = testtime
933
            self.submission_obj.save()
934
935 View Code Duplication
    def test_error_in_submitted_status(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
936
        # a still running submission
937
        self.my_submission = Mock()
938
        self.my_submission.name = "test-fetch"
939
        self.my_submission.status = 'Submitted'
940
941
        # assert task and mock methods called
942
        self.common_tests(self.my_submission)
943
944
        # test email sent
945
        self.assertEqual(len(mail.outbox), 1)
946
947
        # read email
948
        email = mail.outbox[0]
949
950
        self.assertEqual(
951
            "Error in biosample submission %s" % self.submission_obj_id,
952
            email.subject)
953
954
        # check submission.state changed
955
        self.submission_obj.refresh_from_db()
956
957
        self.assertEqual(self.submission_obj.status, ERROR)
958
        self.assertIn(
959
            "Biosample subission {} remained with the same status".format(
960
                    self.submission_obj),
961
            self.submission_obj.message
962
            )
963
964
        message = 'Error'
965
        notification_message = (
966
            'Biosample subission Cryoweb '
967
            '(United Kingdom, test) remained with the '
968
            'same status for more than 5 days. Please '
969
            'report it to InjectTool team')
970
971
        # calling a WebSocketMixin method
972
        self.check_message(message, notification_message)
973
974 View Code Duplication
    def test_error_in_draft_status(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
975
        # a still running submission
976
        self.my_submission = Mock()
977
        self.my_submission.name = "test-fetch"
978
        self.my_submission.status = 'Draft'
979
980
        # assert task and mock methods called
981
        self.common_tests(self.my_submission)
982
983
        # test email sent
984
        self.assertEqual(len(mail.outbox), 1)
985
986
        # read email
987
        email = mail.outbox[0]
988
989
        self.assertEqual(
990
            "Error in biosample submission %s" % self.submission_obj_id,
991
            email.subject)
992
993
        # check submission.state changed
994
        self.submission_obj.refresh_from_db()
995
996
        self.assertEqual(self.submission_obj.status, ERROR)
997
        self.assertIn(
998
            "Biosample subission {} remained with the same status".format(
999
                    self.submission_obj),
1000
            self.submission_obj.message
1001
            )
1002
1003
        message = 'Error'
1004
        notification_message = (
1005
            'Biosample subission Cryoweb '
1006
            '(United Kingdom, test) remained with the '
1007
            'same status for more than 5 days. Please '
1008
            'report it to InjectTool team')
1009
1010
        # calling a WebSocketMixin method
1011
        self.check_message(message, notification_message)
1012
1013
1014
class FetchUnsupportedStatusTestCase(FetchMixin, TestCase):
1015
    """A submission object with a status I can ignore"""
1016
1017
    def setUp(self):
1018
        # calling my base setup
1019
        super().setUp()
1020
1021
        # a still running submission
1022
        self.my_submission = Mock()
1023
        self.my_submission.name = "test-fetch"
1024
1025
        # passing submission to Mocked Root
1026
        self.my_root.get_submission_by_name.return_value = self.my_submission
1027
1028
    def update_status(self, status):
1029
        # change status
1030
        self.submission_obj.status = status
1031
        self.submission_obj.save()
1032
1033
    # override FetchMixing methods
1034
    def common_tests(self, status):
1035
        # update submission status
1036
        self.update_status(status)
1037
1038
        # NOTE that I'm calling the function directly, without delay
1039
        # (AsyncResult). I've patched the time consuming task
1040
        res = self.my_task.run()
1041
1042
        # assert a success with data uploading
1043
        self.assertEqual(res, "success")
1044
1045
        self.assertFalse(self.mock_auth.called)
1046
        self.assertFalse(self.mock_root.called)
1047
        self.assertFalse(self.my_root.get_submission_by_name.called)
1048
        self.assertFalse(self.my_submission.follow_url.called)
1049
1050
        # assert status for submissions
1051
        self.submission_obj.refresh_from_db()
1052
        self.assertEqual(self.submission_obj.status, status)
1053
1054
    def test_loaded(self):
1055
        """Test fecth_status with a loaded submission"""
1056
1057
        # assert task and mock methods called
1058
        self.common_tests(LOADED)
1059
1060
    def test_need_revision(self):
1061
        """Test fecth_status with a need_revision submission"""
1062
1063
        # assert task and mock methods called
1064
        self.common_tests(NEED_REVISION)
1065
1066
    def test_ready(self):
1067
        """Test fecth_status with a ready submission"""
1068
1069
        # assert task and mock methods called
1070
        self.common_tests(READY)
1071
1072
    def test_completed(self):
1073
        """Test fecth_status with a completed submission"""
1074
1075
        # assert task and mock methods called
1076
        self.common_tests(COMPLETED)
1077