FetchMixin.count_by_status()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nop 2
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
from pytest import raises
10
from collections import Counter
11
from unittest.mock import patch, Mock
12
from datetime import timedelta
13
from pyUSIrest.exceptions import USIConnectionError
14
15
from celery.exceptions import Retry
16
17
from django.test import TestCase
18
from django.core import mail
19
from django.db.models import F
20
from django.utils import timezone
21
22
from common.constants import (
23
    LOADED, ERROR, READY, NEED_REVISION, SUBMITTED, COMPLETED, STATUSES)
24
from common.tests import WebSocketMixin
25
from uid.models import Submission, Animal, Sample
26
from validation.models import ValidationResult, ValidationSummary
27
28
from ..tasks.retrieval import (
29
    FetchStatusTask, FetchStatusHelper, RetrievalCompleteTask)
30
from ..models import ManagedTeam, Submission as USISubmission
31
32
33
class FetchMixin():
34
    """Mixin for fetching status"""
35
36
    fixtures = [
37
        'biosample/account',
38
        'biosample/managedteam',
39
        'biosample/submission',
40
        'biosample/submissiondata',
41
        'biosample/validationresult',
42
        'biosample/validationsummary',
43
        'uid/animal',
44
        'uid/dictbreed',
45
        'uid/dictcountry',
46
        'uid/dictrole',
47
        'uid/dictsex',
48
        'uid/dictspecie',
49
        'uid/dictstage',
50
        'uid/dictuberon',
51
        'uid/organization',
52
        'uid/publication',
53
        'uid/sample',
54
        'uid/submission',
55
        'uid/user'
56
    ]
57
58
    @classmethod
59
    def setUpClass(cls):
60
        # calling my base class setup
61
        super().setUpClass()
62
63
        unmanaged = ManagedTeam.objects.get(pk=2)
64
        unmanaged.delete()
65
66
        # starting mocked objects
67
        cls.mock_root_patcher = patch('pyUSIrest.usi.Root')
68
        cls.mock_root = cls.mock_root_patcher.start()
69
70
        cls.mock_auth_patcher = patch('pyUSIrest.auth.Auth')
71
        cls.mock_auth = cls.mock_auth_patcher.start()
72
73
    @classmethod
74
    def tearDownClass(cls):
75
        cls.mock_root_patcher.stop()
76
        cls.mock_auth_patcher.stop()
77
78
        # calling base method
79
        super().tearDownClass()
80
81
    def setUp(self):
82
        # calling my base setup
83
        super().setUp()
84
85
        # get a submission object
86
        self.submission_obj = Submission.objects.get(pk=1)
87
88
        # set a status which I can fetch_status
89
        self.submission_obj.status = SUBMITTED
90
        self.submission_obj.message = "Waiting for biosample validation"
91
        self.submission_obj.save()
92
93
        # set status for objects, like submittask does.
94
        self.animal_qs = Animal.objects.all()
95
        self.animal_qs.update(status=SUBMITTED)
96
97
        self.sample_qs = Sample.objects.all()
98
        self.sample_qs.update(status=SUBMITTED)
99
100
        # count number of names in UID for such submission (exclude
101
        # unknown animals)
102
        self.n_to_submit = self.animal_qs.count() + self.sample_qs.count()
103
104
        # track submission ID
105
        self.submission_obj_id = self.submission_obj.id
106
107
        # start root object
108
        self.my_root = self.mock_root.return_value
109
110
    def count_by_status(self, status):
111
        """Return the number of sample and animal by status"""
112
113
        return (
114
            Animal.objects.filter(status=status).count() +
115
            Sample.objects.filter(status=status).count()
116
        )
117
118
119
class FetchStatusHelperMixin(FetchMixin):
120
    """Test class for FetchStatusHelper"""
121
122
    def setUp(self):
123
        # calling my base setup
124
        super().setUp()
125
126
        # define a biosample submission object
127
        self.my_submission = Mock()
128
        self.my_submission.name = "test-fetch"
129
130
        # passing submission to Mocked Root
131
        self.my_root.get_submission_by_name.return_value = self.my_submission
132
133
        # get a biosample.model.Submission and update object
134
        self.usi_submission = USISubmission.objects.get(pk=1)
135
        self.usi_submission.usi_submission_name = self.my_submission.name
136
        self.usi_submission.status = SUBMITTED
137
        self.usi_submission.save()
138
139
        # get an auth obj
140
        self.my_auth = self.mock_auth()
141
142
        # ok setup the object
143
        self.status_helper = FetchStatusHelper(
144
            self.usi_submission, self.my_auth)
145
146
        # track names
147
        self.animal = Animal.objects.get(pk=1)
148
        self.sample = Sample.objects.get(pk=1)
149
150
    def common_tests(self):
151
        """Assert stuff for each test"""
152
153
        # call stuff
154
        self.status_helper.check_submission_status()
155
156
        # UID submission status remain the same
157
        self.submission_obj.refresh_from_db()
158
        self.assertEqual(self.submission_obj.status, SUBMITTED)
159
160
        self.assertTrue(self.mock_root.called)
161
        self.assertTrue(self.my_root.get_submission_by_name.called)
162
163
164
class FetchIgnoreTestCase(FetchStatusHelperMixin, TestCase):
165
    """a submission that could be ignored"""
166
167
    def setUp(self):
168
        # calling my base setup
169
        super().setUp()
170
171
        # an unmanaged status
172
        self.my_submission.status = 'Unmanaged'
173
174
    def common_tests(self, status):
175
        """Override default common tests. Status is the status the
176
        submission is supposed to remain"""
177
178
        # assert root and get_submission by name called
179
        super().common_tests()
180
181
        # USI submission status did't changed
182
        self.usi_submission.refresh_from_db()
183
        self.assertEqual(self.usi_submission.status, status)
184
185
        # check animal/sample status didn't changed
186
        n_to_submit = self.count_by_status(SUBMITTED)
187
        self.assertEqual(n_to_submit, self.n_to_submit)
188
189
    def test_fetch_unmanaged_submission_status(self):
190
        """Test fetch status for an unmanaged submission"""
191
192
        # assert my common tests
193
        self.common_tests(status=SUBMITTED)
194
195
    def test_fetch_not_submitted(self):
196
        """Ignore a submission with a status different from SUBMITTED"""
197
198
        self.usi_submission.status = COMPLETED
199
        self.usi_submission.save()
200
201
        self.common_tests(status=COMPLETED)
202
203
204
class FetchCompletedTestCase(FetchStatusHelperMixin, TestCase):
205
    """a completed submission with two samples"""
206
207
    def setUp(self):
208
        # calling my base setup
209
        super().setUp()
210
211
        # a completed submission with two samples
212
        self.my_submission.status = 'Completed'
213
214
    def test_fetch_status(self):
215
        """Test fetch status for a complete submission"""
216
217
        # Add samples
218
        my_sample1 = Mock()
219
        my_sample1.name = "test-animal"
220
        my_sample1.alias = "IMAGEA000000001"
221
        my_sample1.accession = "SAMEA0000001"
222
        my_sample2 = Mock()
223
        my_sample2.name = "test-sample"
224
        my_sample2.alias = "IMAGES000000001"
225
        my_sample2.accession = "SAMEA0000002"
226
        self.my_submission.get_samples.return_value = [my_sample1, my_sample2]
227
228
        # assert root and get_submission by name called
229
        self.common_tests()
230
231
        # USI submission status changed
232
        self.usi_submission.refresh_from_db()
233
        self.assertEqual(self.usi_submission.status, COMPLETED)
234
235
        # check name status changed
236
        n_completed = self.count_by_status(COMPLETED)
237
        self.assertEqual(n_completed, 2)
238
239
        # fetch two name objects
240
        self.animal.refresh_from_db()
241
        self.assertEqual(self.animal.biosample_id, "SAMEA0000001")
242
243
        self.sample.refresh_from_db()
244
        self.assertEqual(self.sample.biosample_id, "SAMEA0000002")
245
246
    def test_fetch_status_no_accession(self):
247
        """Test fetch status for a submission which doens't send accession
248
        no updates in such case"""
249
250
        # Add samples
251
        my_sample1 = Mock()
252
        my_sample1.name = "test-animal"
253
        my_sample1.alias = "IMAGEA000000001"
254
        my_sample1.accession = None
255
        my_sample2 = Mock()
256
        my_sample2.name = "test-sample"
257
        my_sample2.alias = "IMAGES000000001"
258
        my_sample2.accession = None
259
        self.my_submission.get_samples.return_value = [my_sample1, my_sample2]
260
261
        # assert root and get_submission by name called
262
        self.common_tests()
263
264
        # USI submission status didn't change
265
        self.usi_submission.refresh_from_db()
266
        self.assertEqual(self.usi_submission.status, SUBMITTED)
267
268
        # check name status didn't changed
269
        n_to_submit = self.count_by_status(SUBMITTED)
270
        self.assertEqual(n_to_submit, self.n_to_submit)
271
272
273
class FetchWithErrorsTestCase(FetchStatusHelperMixin, TestCase):
274
    """Test a submission with errors for biosample"""
275
276
    def setUp(self):
277
        # calling my base setup
278
        super().setUp()
279
280
        # a draft submission with errors
281
        self.my_submission.status = 'Draft'
282
        self.my_submission.has_errors.return_value = Counter(
283
            {True: 1, False: 1})
284
        self.my_submission.get_status.return_value = Counter({'Complete': 2})
285
286
        # Add samples. Suppose that first failed, second is ok
287
        my_validation_result1 = Mock()
288
        my_validation_result1.errorMessages = {
289
            'Ena': [
290
                'a sample message',
291
            ]
292
        }
293
294
        my_sample1 = Mock()
295
        my_sample1.name = "test-animal"
296
        my_sample1.alias = "IMAGEA000000001"
297
        my_sample1.has_errors.return_value = True
298
        my_sample1.get_validation_result.return_value = my_validation_result1
299
300
        # sample2 is ok
301
        my_validation_result2 = Mock()
302
        my_validation_result2.errorMessages = None
303
304
        my_sample2 = Mock()
305
        my_sample2.name = "test-sample"
306
        my_sample2.alias = "IMAGES000000001"
307
        my_sample2.has_errors.return_value = False
308
        my_sample2.get_validation_result.return_value = my_validation_result2
309
310
        # simulate that IMAGEA000000001 has errors
311
        self.my_submission.get_samples.return_value = [my_sample1, my_sample2]
312
313
        # track other objects
314
        self.my_sample1 = my_sample1
315
        self.my_sample2 = my_sample2
316
317
    def common_tests(self):
318
        # assert root and get_submission by name called
319
        super().common_tests()
320
321
        # assert custom mock attributes called
322
        self.assertTrue(self.my_sample1.has_errors.called)
323
        self.assertTrue(self.my_sample1.get_validation_result.called)
324
325
        # if sample has no errors, no all methods will be called
326
        self.assertTrue(self.my_sample2.has_errors.called)
327
        self.assertFalse(self.my_sample2.get_validation_result.called)
328
329
    def test_fetch_status(self):
330
        # assert mock methods called
331
        self.common_tests()
332
333
        # USI submission changed
334
        self.usi_submission.refresh_from_db()
335
        self.assertEqual(self.usi_submission.status, NEED_REVISION)
336
337
        # check name status changed only for animal (not sample)
338
        self.animal.refresh_from_db()
339
        self.assertEqual(self.animal.status, NEED_REVISION)
340
341
        self.sample.refresh_from_db()
342
        self.assertEqual(self.sample.status, SUBMITTED)
343
344
    def test_validationresult(self):
345
        # assert root and get_submission by name called
346
        super().common_tests()
347
348
        # reload object from database
349
        self.animal.validationresult.refresh_from_db()
350
        self.sample.validationresult.refresh_from_db()
351
352
        # ok check error messages
353
        self.assertEqual(self.animal.validationresult.status, "Error")
354
        self.assertEqual(self.sample.validationresult.status, "Pass")
355
356
        # a check on error messages
357
        messages = ["Ena: ['a sample message']"]
358
        self.assertListEqual(self.animal.validationresult.messages, messages)
359
360
        messages = []
361
        self.assertListEqual(self.sample.validationresult.messages, messages)
362
363
    def test_validationsummary(self):
364
        # assert root and get_submission by name called
365
        super().common_tests()
366
367
        # get the two validationsummary objects
368
        summary = self.submission_obj.validationsummary_set.filter(
369
            type='animal').first()
370
371
        # assert values
372
        summary.refresh_from_db()
373
        self.assertEqual(summary.pass_count, 2)
374
        self.assertEqual(summary.error_count, 1)
375
        self.assertEqual(summary.issues_count, 1)
376
377
        summary = self.submission_obj.validationsummary_set.filter(
378
            type='sample').first()
379
380
        # assert values
381
        summary.refresh_from_db()
382
        self.assertEqual(summary.pass_count, 1)
383
        self.assertEqual(summary.error_count, 0)
384
        self.assertEqual(summary.issues_count, 0)
385
386
387
class FetchDraftTestCase(FetchStatusHelperMixin, TestCase):
388
    """a draft submission without errors"""
389
390
    def common_tests(self):
391
        # assert root and get_submission by name called
392
        super().common_tests()
393
394
        # USI submission status didn't change
395
        self.usi_submission.refresh_from_db()
396
        self.assertEqual(self.usi_submission.status, SUBMITTED)
397
398
    def test_fetch_status(self):
399
        # a draft submission without errors
400
        self.my_submission.status = 'Draft'
401
        self.my_submission.has_errors.return_value = Counter({False: 2})
402
        self.my_submission.get_status.return_value = Counter({'Complete': 2})
403
404
        # assert mock methods called
405
        self.common_tests()
406
407
        # testing a finalized biosample condition
408
        self.assertTrue(self.my_submission.finalize.called)
409
410
    def test_fetch_status_pending(self):
411
        """Testing status with pending validation"""
412
413
        # a draft submission without errors
414
        self.my_submission.status = 'Draft'
415
        self.my_submission.has_errors.return_value = Counter({False: 2})
416
        self.my_submission.get_status.return_value = Counter({'Pending': 2})
417
418
        # assert mock methods called
419
        self.common_tests()
420
421
        # testing a not finalized biosample condition
422
        self.assertFalse(self.my_submission.finalize.called)
423
424
    def test_fetch_status_submitted(self):
425
        """Testing status during biosample submission"""
426
427
        # a draft submission without errors
428
        self.my_submission.status = 'Submitted'
429
        self.my_submission.has_errors.return_value = Counter({False: 2})
430
        self.my_submission.get_status.return_value = Counter({'Complete': 2})
431
432
        # assert mock methods called
433
        self.common_tests()
434
435
        # testing a not finalized biosample condition
436
        self.assertFalse(self.my_submission.finalize.called)
437
438
    def test_fetch_status_processing(self):
439
        """This is a status I see during validation"""
440
441
        # an example submission in processing stage. If everything is ok
442
        # it has no errors and is complete
443
        self.my_submission.status = 'Processing'
444
        self.my_submission.has_errors.return_value = Counter({False: 2})
445
        self.my_submission.get_status.return_value = Counter({'Complete': 2})
446
447
        # assert mock methods called
448
        self.common_tests()
449
450
        # testing a not finalized biosample condition
451
        self.assertFalse(self.my_submission.finalize.called)
452
453
454
class FetchLongStatusTestCase(FetchStatusHelperMixin, TestCase):
455
    """A submission wich remain in the same status for a long time"""
456
457
    def setUp(self):
458
        # calling my base setup
459
        super().setUp()
460
461
        # make "now" 2 months ago
462
        testtime = timezone.now() - timedelta(days=60)
463
464
        # https://devblog.kogan.com/blog/testing-auto-now-datetime-fields-in-django
465
        with patch('django.utils.timezone.now') as mock_now:
466
            mock_now.return_value = testtime
467
468
            # update submission updated time with an older date than now
469
            self.usi_submission.updated_at = testtime
470
            self.usi_submission.save()
471
472
    def common_tests(self):
473
        # assert root and get_submission by name called
474
        super().common_tests()
475
476
        # biosample.models.Submission status changed
477
        self.assertEqual(self.usi_submission.status, ERROR)
478
        self.assertIn(
479
            "Biosample submission '{}' remained with the same status".format(
480
                self.my_submission.name),
481
            self.usi_submission.message
482
        )
483
484
    def test_error_in_submitted_status(self):
485
        # a still running submission
486
        self.my_submission.status = 'Submitted'
487
488
        # assert mock methods called
489
        self.common_tests()
490
491
    def test_error_in_draft_status(self):
492
        # a still running submission
493
        self.my_submission.status = 'Draft'
494
495
        # assert mock methods called
496
        self.common_tests()
497
498
    def test_error_in_processing_status(self):
499
        # a still running submission
500
        self.my_submission.status = 'Processing'
501
502
        # assert mock methods called
503
        self.common_tests()
504
505
506
class FetchUnsupportedStatusTestCase(FetchMixin, TestCase):
507
    """A submission object with a status I can ignore. Task will exit
508
    immediatey"""
509
510
    def setUp(self):
511
        # calling my base setup
512
        super().setUp()
513
514
        # define my task
515
        self.my_task = FetchStatusTask()
516
517
        # change lock_id (useful when running test during cron)
518
        self.my_task.lock_id = "test-FetchStatusTask"
519
520
    def update_status(self, status):
521
        # change status
522
        self.submission_obj.status = status
523
        self.submission_obj.save()
524
525
    # override FetchMixing methods
526
    def common_tests(self, status):
527
        # update submission status
528
        self.update_status(status)
529
530
        # NOTE that I'm calling the function directly, without delay
531
        # (AsyncResult). I've patched the time consuming task
532
        res = self.my_task.run()
533
534
        # assert a success with data uploading
535
        self.assertEqual(res, "success")
536
537
        self.assertFalse(self.mock_auth.called)
538
        self.assertFalse(self.mock_root.called)
539
        self.assertFalse(self.my_root.get_submission_by_name.called)
540
541
        # assert status for submissions
542
        self.submission_obj.refresh_from_db()
543
        self.assertEqual(self.submission_obj.status, status)
544
545
    def test_loaded(self):
546
        """Test fecth_status with a loaded submission"""
547
548
        # assert task and mock methods called
549
        self.common_tests(LOADED)
550
551
    def test_need_revision(self):
552
        """Test fecth_status with a need_revision submission"""
553
554
        # assert task and mock methods called
555
        self.common_tests(NEED_REVISION)
556
557
    def test_ready(self):
558
        """Test fecth_status with a ready submission"""
559
560
        # assert task and mock methods called
561
        self.common_tests(READY)
562
563
    def test_completed(self):
564
        """Test fecth_status with a completed submission"""
565
566
        # assert task and mock methods called
567
        self.common_tests(COMPLETED)
568
569
570
class FetchStatusTaskTestCase(FetchMixin, TestCase):
571
    def setUp(self):
572
        # calling my base setup
573
        super().setUp()
574
575
        # set proper status to biosample.models.Submission
576
        USISubmission.objects.update(status=SUBMITTED)
577
578
        # starting mocked objects
579
        self.mock_helper_patcher = patch(
580
            'biosample.tasks.retrieval.FetchStatusHelper')
581
        self.mock_helper = self.mock_helper_patcher.start()
582
583
        self.mock_complete_patcher = patch(
584
            'biosample.tasks.retrieval.RetrievalCompleteTask')
585
        self.mock_complete = self.mock_complete_patcher.start()
586
587
        # define my task
588
        self.my_task = FetchStatusTask()
589
590
        # change lock_id (useful when running test during cron)
591
        self.my_task.lock_id = "test-FetchStatusTask"
592
593
    def tearDown(self):
594
        self.mock_helper_patcher.stop()
595
        self.mock_complete_patcher.stop()
596
597
        # calling base method
598
        super().tearDown()
599
600
    def test_fetch_status(self):
601
        """Test fetch status task"""
602
603
        # NOTE that I'm calling the function directly, without delay
604
        # (AsyncResult). I've patched the time consuming task
605
        res = self.my_task.run()
606
607
        # assert a success with data uploading
608
        self.assertEqual(res, "success")
609
610
        # assert my objects called
611
        self.assertTrue(self.mock_helper.called)
612
        self.assertTrue(self.mock_complete.called)
613
614
        # I'm calling Auth if I query BioSamples
615
        self.assertTrue(self.mock_auth.called)
616
617
        # root is a property of FetchStatusHelper, so it is not called
618
        self.assertFalse(self.mock_root.called)
619
620
    def test_fetch_status_all_completed(self):
621
        """Test fetch status task with completed biosample.models.Submission"""
622
623
        # simulate completed case (no more requests to biosample)
624
        USISubmission.objects.update(status=COMPLETED)
625
626
        # NOTE that I'm calling the function directly, without delay
627
        # (AsyncResult). I've patched the time consuming task
628
        res = self.my_task.run()
629
630
        # assert a success with data uploading
631
        self.assertEqual(res, "success")
632
633
        # assert no helper called for this submission
634
        self.assertFalse(self.mock_helper.called)
635
636
        # this is called if every submission is completed
637
        self.assertTrue(self.mock_complete.called)
638
639
        # I'm calling Auth if I query BioSamples
640
        self.assertTrue(self.mock_auth.called)
641
642
        # root is a property of FetchStatusHelper, so it is not called
643
        self.assertFalse(self.mock_root.called)
644
645
    # http://docs.celeryproject.org/en/latest/userguide/testing.html#tasks-and-unit-tests
646
    @patch("biosample.tasks.FetchStatusTask.retry")
647
    @patch("biosample.tasks.FetchStatusTask.fetch_queryset")
648
    def test_fetch_status_retry(self, my_fetch, my_retry):
649
        """Test fetch status with retry"""
650
651
        # Set a side effect on the patched methods
652
        # so that they raise the errors we want.
653
        my_retry.side_effect = Retry()
654
        my_fetch.side_effect = USIConnectionError()
655
656
        with raises(Retry):
657
            self.my_task.run()
658
659
        self.assertTrue(my_fetch.called)
660
        self.assertTrue(my_retry.called)
661
662
        # assert no helper called for this submission
663
        self.assertFalse(self.mock_helper.called)
664
        self.assertFalse(self.mock_complete.called)
665
666
    # Test a non blocking instance
667
    @patch("biosample.tasks.FetchStatusTask.fetch_queryset")
668
    @patch("redis.lock.Lock.acquire", return_value=False)
669
    def test_fetch_status_nb(self, my_lock, my_fetch):
670
        """Test FetchSTatus while a lock is present"""
671
672
        res = self.my_task.run()
673
674
        # assert database is locked
675
        self.assertEqual(res, "%s already running!" % (self.my_task.name))
676
        self.assertFalse(my_fetch.called)
677
678
        # assert no helper called for this submission
679
        self.assertFalse(self.mock_helper.called)
680
        self.assertFalse(self.mock_complete.called)
681
682
683
class RetrievalCompleteTaskTestCase(FetchMixin, WebSocketMixin, TestCase):
684
    """testing update status after a fetch status"""
685
686
    def setUp(self):
687
        # calling my base setup
688
        super().setUp()
689
690
        # set proper status to biosample.models.Submission
691
        USISubmission.objects.update(status=SUBMITTED)
692
693
        # define my task
694
        self.my_task = RetrievalCompleteTask()
695
696
    def updated_check(self, status, message, validation_message=None):
697
        """Common check for tests"""
698
699
        # set proper status to biosample.models.Submission
700
        USISubmission.objects.update(status=status, message=message)
701
702
        # calling task
703
        result = self.my_task.run(
704
            uid_submission_id=self.submission_obj_id)
705
706
        # assert a success with data uploading
707
        self.assertEqual(result, "success")
708
709
        # check status and messages
710
        self.submission_obj.refresh_from_db()
711
        self.assertEqual(self.submission_obj.status, status)
712
        self.assertEqual(self.submission_obj.message, message)
713
714
        # calling a WebSocketMixin method
715
        self.check_message(
716
            STATUSES.get_value_display(status),
717
            message,
718
            validation_message)
719
720
    def not_updated_check(self, status, message):
721
        """Test a submission not updated"""
722
723
        # set proper status to biosample.models.Submission
724
        USISubmission.objects.filter(pk=1).update(
725
            status=status, message=message)
726
727
        # calling task
728
        result = self.my_task.run(
729
            uid_submission_id=self.submission_obj_id)
730
731
        # assert a success with data uploading
732
        self.assertEqual(result, "success")
733
734
        # check status and messages
735
        self.submission_obj.refresh_from_db()
736
        self.assertEqual(self.submission_obj.status, SUBMITTED)
737
        self.assertEqual(
738
            self.submission_obj.message,
739
            "Waiting for biosample validation")
740
741
        # defined in websoketmixin
742
        self.check_message_not_called()
743
744
    def test_submitted(self):
745
        """Test submitted status"""
746
747
        status = SUBMITTED
748
        message = "Waiting for biosample validation"
749
750
        self.not_updated_check(
751
            status,
752
            message)
753
754
    def issues_with_usi(self):
755
        """Change database and set stuff to simulate issues with USI"""
756
757
        # before doing tests, update validationresult
758
        result = ValidationResult.objects.get(pk=1)
759
        result.status = "Error"
760
        result.messages = ["message1", "message2"]
761
        result.save()
762
763
        # also summary changes with the same conditions
764
        summary = ValidationSummary.objects.get(pk=1)
765
        summary.pass_count = F('pass_count') - 1
766
        summary.error_count = F('error_count') + 1
767
        summary.issues_count = F('issues_count') + 1
768
        summary.save()
769
770
        validation_message = {
771
            'animals': 3, 'samples': 1, 'animal_unkn': 0,
772
            'sample_unkn': 0, 'animal_issues': 1, 'sample_issues': 0}
773
774
        summary_message = [
775
            {'ids': [1],
776
             'count': 1,
777
             'message': 'message1',
778
             'offending_column': ''},
779
            {'ids': [1],
780
             'count': 1,
781
             'message': 'message2',
782
             'offending_column': ''}]
783
784
        # returning custom values
785
        return validation_message, summary_message
786
787
    def test_error(self):
788
        """test an error in a submission"""
789
790
        # prepare database for issues with USI
791
        validation_message, summary_message = self.issues_with_usi()
792
793
        status = ERROR
794
        message = "error messages"
795
796
        self.updated_check(
797
            status,
798
            message,
799
            validation_message)
800
801
        # test email sent
802
        self.assertEqual(len(mail.outbox), 1)
803
804
        # read email
805
        email = mail.outbox[0]
806
807
        self.assertEqual(
808
            "Error in biosample submission 1",
809
            email.subject)
810
811
        # ok get validationsummary object
812
        summary = ValidationSummary.objects.get(
813
            submission=self.submission_obj,
814
            type="animal")
815
816
        self.assertListEqual(summary.messages, summary_message)
817
818
    def test_need_revision(self):
819
        """test an issue in a submission"""
820
821
        # prepare database for issues with USI
822
        validation_message, summary_message = self.issues_with_usi()
823
824
        status = NEED_REVISION
825
        message = "error messages"
826
827
        self.updated_check(
828
            status,
829
            message,
830
            validation_message)
831
832
        # test email sent
833
        self.assertEqual(len(mail.outbox), 1)
834
835
        # read email
836
        email = mail.outbox[0]
837
838
        self.assertEqual(
839
            "Error in biosample submission 1",
840
            email.subject)
841
842
        # ok get validationsummary object
843
        summary = ValidationSummary.objects.get(
844
            submission=self.submission_obj,
845
            type="animal")
846
847
        self.assertListEqual(summary.messages, summary_message)
848
849
    def test_completed(self):
850
        """test a submission completed"""
851
852
        status = COMPLETED
853
        message = "completed messages"
854
855
        validation_message = {
856
            'animals': 3, 'samples': 1, 'animal_unkn': 0,
857
            'sample_unkn': 0, 'animal_issues': 0, 'sample_issues': 0}
858
859
        self.updated_check(
860
            status,
861
            message,
862
            validation_message)
863
864
    def test_partial_submitted(self):
865
        """Having submitted in statuses will not complete the submission"""
866
867
        status = ERROR
868
        message = "error messages"
869
870
        self.not_updated_check(
871
            status,
872
            message)
873
874
        status = NEED_REVISION
875
        message = "error messages"
876
877
        self.not_updated_check(
878
            status,
879
            message)
880
881
        status = COMPLETED
882
        message = "completed messages"
883
884
        self.not_updated_check(
885
            status,
886
            message)
887