Passed
Pull Request — master (#44)
by Paolo
07:04
created

biosample.tests.test_tasks_retrieval   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 703
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 42
eloc 356
dl 0
loc 703
rs 9.0399
c 0
b 0
f 0

40 Methods

Rating   Name   Duplication   Size   Complexity  
A RetrievalCompleteTaskTestCase.updated_check() 0 22 1
A FetchStatusTaskTestCase.test_fetch_status_retry() 0 19 2
A RetrievalCompleteTaskTestCase.test_completed() 0 9 1
A FetchStatusTaskTestCase.test_fetch_status() 0 18 1
A RetrievalCompleteTaskTestCase.test_error() 0 19 1
A FetchStatusTaskTestCase.tearDown() 0 6 1
A FetchCompletedTestCase.test_fetch_status() 0 31 1
A FetchUnsupportedStatusTestCase.test_ready() 0 5 1
A FetchWithErrorsTestCase.setUp() 0 40 1
A FetchCompletedTestCase.test_fetch_status_no_accession() 0 25 1
A FetchLongStatusTestCase.setUp() 0 14 2
A FetchLongStatusTestCase.test_error_in_submitted_status() 0 6 1
A FetchDraftTestCase.test_fetch_status_pending() 0 13 1
A RetrievalCompleteTaskTestCase.setUp() 0 9 1
A FetchStatusHelperMixin.setUp() 0 23 1
A FetchDraftTestCase.common_tests() 0 7 1
A FetchStatusTaskTestCase.test_fetch_status_nb() 0 14 1
A RetrievalCompleteTaskTestCase.test_partial_submitted() 0 23 1
A FetchWithErrorsTestCase.common_tests() 0 11 1
A FetchWithErrorsTestCase.test_fetch_status() 0 14 1
A FetchUnsupportedStatusTestCase.update_status() 0 4 1
A RetrievalCompleteTaskTestCase.test_submitted() 0 9 1
A FetchStatusHelperMixin.common_tests() 0 13 1
A FetchUnsupportedStatusTestCase.test_loaded() 0 5 1
A FetchUnsupportedStatusTestCase.test_completed() 0 5 1
A RetrievalCompleteTaskTestCase.not_updated_check() 0 23 1
A FetchUnsupportedStatusTestCase.setUp() 0 9 1
A FetchUnsupportedStatusTestCase.test_need_revision() 0 5 1
A FetchDraftTestCase.test_fetch_status() 0 11 1
A FetchMixin.setUp() 0 26 1
A FetchLongStatusTestCase.test_error_in_draft_status() 0 6 1
A RetrievalCompleteTaskTestCase.test_need_revision() 0 19 1
A FetchCompletedTestCase.setUp() 0 6 1
A FetchMixin.tearDownClass() 0 7 1
A FetchUnsupportedStatusTestCase.common_tests() 0 18 1
A FetchMixin.setUpClass() 0 14 1
A FetchStatusTaskTestCase.test_fetch_status_all_completed() 0 23 1
A FetchLongStatusTestCase.common_tests() 0 10 1
A FetchStatusTaskTestCase.setUp() 0 21 1
A FetchDraftTestCase.test_fetch_status_submitted() 0 13 1

How to fix   Complexity   

Complexity

Complex classes like biosample.tests.test_tasks_retrieval 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
#!/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
14
from celery.exceptions import Retry
15
16
from django.test import TestCase
17
from django.core import mail
18
from django.utils import timezone
19
20
from common.constants import (
21
    LOADED, ERROR, READY, NEED_REVISION, SUBMITTED, COMPLETED, STATUSES)
22
from common.tests import WebSocketMixin
23
from image_app.models import Submission, Name
24
25
from ..tasks.retrieval import (
26
    FetchStatusTask, FetchStatusHelper, RetrievalCompleteTask)
27
from ..models import ManagedTeam, Submission as USISubmission
28
29
30
class FetchMixin():
31
    """Mixin for fetching status"""
32
33
    fixtures = [
34
        'biosample/account',
35
        'biosample/managedteam',
36
        'biosample/submission',
37
        'biosample/submissiondata',
38
        'image_app/animal',
39
        'image_app/dictbreed',
40
        'image_app/dictcountry',
41
        'image_app/dictrole',
42
        'image_app/dictsex',
43
        'image_app/dictspecie',
44
        'image_app/dictstage',
45
        'image_app/dictuberon',
46
        'image_app/name',
47
        'image_app/organization',
48
        'image_app/publication',
49
        'image_app/sample',
50
        'image_app/submission',
51
        'image_app/user'
52
    ]
53
54
    @classmethod
55
    def setUpClass(cls):
56
        # calling my base class setup
57
        super().setUpClass()
58
59
        unmanaged = ManagedTeam.objects.get(pk=2)
60
        unmanaged.delete()
61
62
        # starting mocked objects
63
        cls.mock_root_patcher = patch('pyUSIrest.client.Root')
64
        cls.mock_root = cls.mock_root_patcher.start()
65
66
        cls.mock_auth_patcher = patch('biosample.helpers.Auth')
67
        cls.mock_auth = cls.mock_auth_patcher.start()
68
69
    @classmethod
70
    def tearDownClass(cls):
71
        cls.mock_root_patcher.stop()
72
        cls.mock_auth_patcher.stop()
73
74
        # calling base method
75
        super().tearDownClass()
76
77
    def setUp(self):
78
        # calling my base setup
79
        super().setUp()
80
81
        # get a submission object
82
        self.submission_obj = Submission.objects.get(pk=1)
83
84
        # set a status which I can fetch_status
85
        self.submission_obj.status = SUBMITTED
86
        self.submission_obj.message = "Waiting for biosample validation"
87
        self.submission_obj.save()
88
89
        # set status for names, like submittask does. Only sample not unknown
90
        # are submitted
91
        self.name_qs = Name.objects.exclude(name__contains="unknown")
92
        self.name_qs.update(status=SUBMITTED)
93
94
        # count number of names in UID for such submission (exclude
95
        # unknown animals)
96
        self.n_to_submit = self.name_qs.count()
97
98
        # track submission ID
99
        self.submission_obj_id = self.submission_obj.id
100
101
        # start root object
102
        self.my_root = self.mock_root.return_value
103
104
105
class FetchStatusHelperMixin(FetchMixin):
106
    """Test class for FetchStatusHelper"""
107
108
    def setUp(self):
109
        # calling my base setup
110
        super().setUp()
111
112
        # define a biosample submission object
113
        self.my_submission = Mock()
114
        self.my_submission.name = "test-fetch"
115
116
        # passing submission to Mocked Root
117
        self.my_root.get_submission_by_name.return_value = self.my_submission
118
119
        # get a biosample.model.Submission and update object
120
        self.usi_submission = USISubmission.objects.get(pk=1)
121
        self.usi_submission.usi_submission_name = self.my_submission.name
122
        self.usi_submission.status = SUBMITTED
123
        self.usi_submission.save()
124
125
        # ok setup the object
126
        self.status_helper = FetchStatusHelper(self.usi_submission)
127
128
        # track names
129
        self.animal_name = Name.objects.get(pk=3)
130
        self.sample_name = Name.objects.get(pk=4)
131
132
    def common_tests(self):
133
        """Assert stuff for each test"""
134
135
        # call stuff
136
        self.status_helper.check_submission_status()
137
138
        # UID submission status remain the same
139
        self.submission_obj.refresh_from_db()
140
        self.assertEqual(self.submission_obj.status, SUBMITTED)
141
142
        self.assertTrue(self.mock_auth.called)
143
        self.assertTrue(self.mock_root.called)
144
        self.assertTrue(self.my_root.get_submission_by_name.called)
145
146
147
class FetchCompletedTestCase(FetchStatusHelperMixin, TestCase):
148
    """a completed submission with two samples"""
149
150
    def setUp(self):
151
        # calling my base setup
152
        super().setUp()
153
154
        # a completed submission with two samples
155
        self.my_submission.status = 'Completed'
156
157
    def test_fetch_status(self):
158
        """Test fetch status for a complete submission"""
159
160
        # Add samples
161
        my_sample1 = Mock()
162
        my_sample1.name = "test-animal"
163
        my_sample1.alias = "IMAGEA000000001"
164
        my_sample1.accession = "SAMEA0000001"
165
        my_sample2 = Mock()
166
        my_sample2.name = "test-sample"
167
        my_sample2.alias = "IMAGES000000001"
168
        my_sample2.accession = "SAMEA0000002"
169
        self.my_submission.get_samples.return_value = [my_sample1, my_sample2]
170
171
        # assert auth, root and get_submission by name called
172
        self.common_tests()
173
174
        # USI submission status changed
175
        self.usi_submission.refresh_from_db()
176
        self.assertEqual(self.usi_submission.status, COMPLETED)
177
178
        # check name status changed
179
        qs = Name.objects.filter(status=COMPLETED)
180
        self.assertEqual(len(qs), 2)
181
182
        # fetch two name objects
183
        self.animal_name.refresh_from_db()
184
        self.assertEqual(self.animal_name.biosample_id, "SAMEA0000001")
185
186
        self.sample_name.refresh_from_db()
187
        self.assertEqual(self.sample_name.biosample_id, "SAMEA0000002")
188
189
    def test_fetch_status_no_accession(self):
190
        """Test fetch status for a submission which doens't send accession
191
        no updates in such case"""
192
193
        # Add samples
194
        my_sample1 = Mock()
195
        my_sample1.name = "test-animal"
196
        my_sample1.alias = "IMAGEA000000001"
197
        my_sample1.accession = None
198
        my_sample2 = Mock()
199
        my_sample2.name = "test-sample"
200
        my_sample2.alias = "IMAGES000000001"
201
        my_sample2.accession = None
202
        self.my_submission.get_samples.return_value = [my_sample1, my_sample2]
203
204
        # assert auth, root and get_submission by name called
205
        self.common_tests()
206
207
        # USI submission status didn't change
208
        self.usi_submission.refresh_from_db()
209
        self.assertEqual(self.usi_submission.status, SUBMITTED)
210
211
        # check name status didn't changed
212
        qs = Name.objects.filter(status=SUBMITTED)
213
        self.assertEqual(len(qs), self.n_to_submit)
214
215
216
class FetchWithErrorsTestCase(FetchStatusHelperMixin, TestCase):
217
    """Test a submission with errors for biosample"""
218
219
    def setUp(self):
220
        # calling my base setup
221
        super().setUp()
222
223
        # a draft submission with errors
224
        self.my_submission.status = 'Draft'
225
        self.my_submission.has_errors.return_value = Counter(
226
            {True: 1, False: 1})
227
        self.my_submission.get_status.return_value = Counter({'Complete': 2})
228
229
        # Add samples. Suppose that first failed, second is ok
230
        my_validation_result1 = Mock()
231
        my_validation_result1.errorMessages = {
232
            'Ena': [
233
                'a sample message',
234
            ]
235
        }
236
237
        my_sample1 = Mock()
238
        my_sample1.name = "test-animal"
239
        my_sample1.alias = "IMAGEA000000001"
240
        my_sample1.has_errors.return_value = True
241
        my_sample1.get_validation_result.return_value = my_validation_result1
242
243
        # sample2 is ok
244
        my_validation_result2 = Mock()
245
        my_validation_result2.errorMessages = None
246
247
        my_sample2 = Mock()
248
        my_sample2.name = "test-sample"
249
        my_sample2.alias = "IMAGES000000001"
250
        my_sample2.has_errors.return_value = False
251
        my_sample2.get_validation_result.return_value = my_validation_result2
252
253
        # simulate that IMAGEA000000001 has errors
254
        self.my_submission.get_samples.return_value = [my_sample1, my_sample2]
255
256
        # track other objects
257
        self.my_sample1 = my_sample1
258
        self.my_sample2 = my_sample2
259
260
    def common_tests(self):
261
        # assert auth, root and get_submission by name called
262
        super().common_tests()
263
264
        # assert custom mock attributes called
265
        self.assertTrue(self.my_sample1.has_errors.called)
266
        self.assertTrue(self.my_sample1.get_validation_result.called)
267
268
        # if sample has no errors, no all methods will be called
269
        self.assertTrue(self.my_sample2.has_errors.called)
270
        self.assertFalse(self.my_sample2.get_validation_result.called)
271
272
    def test_fetch_status(self):
273
        # assert tmock methods called
274
        self.common_tests()
275
276
        # USI submission changed
277
        self.usi_submission.refresh_from_db()
278
        self.assertEqual(self.usi_submission.status, NEED_REVISION)
279
280
        # check name status changed only for animal (not sample)
281
        self.animal_name.refresh_from_db()
282
        self.assertEqual(self.animal_name.status, NEED_REVISION)
283
284
        self.sample_name.refresh_from_db()
285
        self.assertEqual(self.sample_name.status, SUBMITTED)
286
287
288
class FetchDraftTestCase(FetchStatusHelperMixin, TestCase):
289
    """a draft submission without errors"""
290
291
    def common_tests(self):
292
        # assert auth, root and get_submission by name called
293
        super().common_tests()
294
295
        # USI submission status didn't change
296
        self.usi_submission.refresh_from_db()
297
        self.assertEqual(self.usi_submission.status, SUBMITTED)
298
299
    def test_fetch_status(self):
300
        # a draft submission without errors
301
        self.my_submission.status = 'Draft'
302
        self.my_submission.has_errors.return_value = Counter({False: 2})
303
        self.my_submission.get_status.return_value = Counter({'Complete': 2})
304
305
        # assert mock methods called
306
        self.common_tests()
307
308
        # testing a finalized biosample condition
309
        self.assertTrue(self.my_submission.finalize.called)
310
311
    def test_fetch_status_pending(self):
312
        """Testing status with pending validation"""
313
314
        # a draft submission without errors
315
        self.my_submission.status = 'Draft'
316
        self.my_submission.has_errors.return_value = Counter({False: 2})
317
        self.my_submission.get_status.return_value = Counter({'Pending': 2})
318
319
        # assert mock methods called
320
        self.common_tests()
321
322
        # testing a not finalized biosample condition
323
        self.assertFalse(self.my_submission.finalize.called)
324
325
    def test_fetch_status_submitted(self):
326
        """Testing status during biosample submission"""
327
328
        # a draft submission without errors
329
        self.my_submission.status = 'Submitted'
330
        self.my_submission.has_errors.return_value = Counter({False: 2})
331
        self.my_submission.get_status.return_value = Counter({'Complete': 2})
332
333
        # assert mock methods called
334
        self.common_tests()
335
336
        # testing a not finalized biosample condition
337
        self.assertFalse(self.my_submission.finalize.called)
338
339
340
class FetchLongStatusTestCase(FetchStatusHelperMixin, TestCase):
341
    """A submission wich remain in the same status for a long time"""
342
343
    def setUp(self):
344
        # calling my base setup
345
        super().setUp()
346
347
        # make "now" 2 months ago
348
        testtime = timezone.now() - timedelta(days=60)
349
350
        # https://devblog.kogan.com/blog/testing-auto-now-datetime-fields-in-django
351
        with patch('django.utils.timezone.now') as mock_now:
352
            mock_now.return_value = testtime
353
354
            # update submission updated time with an older date than now
355
            self.usi_submission.updated_at = testtime
356
            self.usi_submission.save()
357
358
    def common_tests(self):
359
        # assert auth, root and get_submission by name called
360
        super().common_tests()
361
362
        # biosample.models.Submission status changed
363
        self.assertEqual(self.usi_submission.status, ERROR)
364
        self.assertIn(
365
            "Biosample submission '{}' remained with the same status".format(
366
                self.my_submission.name),
367
            self.usi_submission.message
368
        )
369
370
    def test_error_in_submitted_status(self):
371
        # a still running submission
372
        self.my_submission.status = 'Submitted'
373
374
        # assert mock methods called
375
        self.common_tests()
376
377
    def test_error_in_draft_status(self):
378
        # a still running submission
379
        self.my_submission.status = 'Draft'
380
381
        # assert mock methods called
382
        self.common_tests()
383
384
385
class FetchUnsupportedStatusTestCase(FetchMixin, TestCase):
386
    """A submission object with a status I can ignore. Task will exit
387
    immediatey"""
388
389
    def setUp(self):
390
        # calling my base setup
391
        super().setUp()
392
393
        # define my task
394
        self.my_task = FetchStatusTask()
395
396
        # change lock_id (useful when running test during cron)
397
        self.my_task.lock_id = "test-FetchStatusTask"
398
399
    def update_status(self, status):
400
        # change status
401
        self.submission_obj.status = status
402
        self.submission_obj.save()
403
404
    # override FetchMixing methods
405
    def common_tests(self, status):
406
        # update submission status
407
        self.update_status(status)
408
409
        # NOTE that I'm calling the function directly, without delay
410
        # (AsyncResult). I've patched the time consuming task
411
        res = self.my_task.run()
412
413
        # assert a success with data uploading
414
        self.assertEqual(res, "success")
415
416
        self.assertFalse(self.mock_auth.called)
417
        self.assertFalse(self.mock_root.called)
418
        self.assertFalse(self.my_root.get_submission_by_name.called)
419
420
        # assert status for submissions
421
        self.submission_obj.refresh_from_db()
422
        self.assertEqual(self.submission_obj.status, status)
423
424
    def test_loaded(self):
425
        """Test fecth_status with a loaded submission"""
426
427
        # assert task and mock methods called
428
        self.common_tests(LOADED)
429
430
    def test_need_revision(self):
431
        """Test fecth_status with a need_revision submission"""
432
433
        # assert task and mock methods called
434
        self.common_tests(NEED_REVISION)
435
436
    def test_ready(self):
437
        """Test fecth_status with a ready submission"""
438
439
        # assert task and mock methods called
440
        self.common_tests(READY)
441
442
    def test_completed(self):
443
        """Test fecth_status with a completed submission"""
444
445
        # assert task and mock methods called
446
        self.common_tests(COMPLETED)
447
448
449
class FetchStatusTaskTestCase(FetchMixin, TestCase):
450
    def setUp(self):
451
        # calling my base setup
452
        super().setUp()
453
454
        # set proper status to biosample.models.Submission
455
        USISubmission.objects.update(status=SUBMITTED)
456
457
        # starting mocked objects
458
        self.mock_helper_patcher = patch(
459
            'biosample.tasks.retrieval.FetchStatusHelper')
460
        self.mock_helper = self.mock_helper_patcher.start()
461
462
        self.mock_complete_patcher = patch(
463
            'biosample.tasks.retrieval.RetrievalCompleteTask')
464
        self.mock_complete = self.mock_complete_patcher.start()
465
466
        # define my task
467
        self.my_task = FetchStatusTask()
468
469
        # change lock_id (useful when running test during cron)
470
        self.my_task.lock_id = "test-FetchStatusTask"
471
472
    def tearDown(self):
473
        self.mock_helper_patcher.stop()
474
        self.mock_complete_patcher.stop()
475
476
        # calling base method
477
        super().tearDown()
478
479
    def test_fetch_status(self):
480
        """Test fetch status task"""
481
482
        # NOTE that I'm calling the function directly, without delay
483
        # (AsyncResult). I've patched the time consuming task
484
        res = self.my_task.run()
485
486
        # assert a success with data uploading
487
        self.assertEqual(res, "success")
488
489
        # assert my objects called
490
        self.assertTrue(self.mock_helper.called)
491
        self.assertTrue(self.mock_complete.called)
492
493
        # those objects are proper of FetchStatusHelper class, no one
494
        # call them in this task itself
495
        self.assertFalse(self.mock_auth.called)
496
        self.assertFalse(self.mock_root.called)
497
498
    def test_fetch_status_all_completed(self):
499
        """Test fetch status task with completed biosample.models.Submission"""
500
501
        # simulate completed case (no more requests to biosample)
502
        USISubmission.objects.update(status=COMPLETED)
503
504
        # NOTE that I'm calling the function directly, without delay
505
        # (AsyncResult). I've patched the time consuming task
506
        res = self.my_task.run()
507
508
        # assert a success with data uploading
509
        self.assertEqual(res, "success")
510
511
        # assert no helper called for this submission
512
        self.assertFalse(self.mock_helper.called)
513
514
        # this is called if every submission is completed
515
        self.assertTrue(self.mock_complete.called)
516
517
        # those objects are proper of FetchStatusHelper class, no one
518
        # call them in this task itself
519
        self.assertFalse(self.mock_auth.called)
520
        self.assertFalse(self.mock_root.called)
521
522
    # http://docs.celeryproject.org/en/latest/userguide/testing.html#tasks-and-unit-tests
523
    @patch("biosample.tasks.FetchStatusTask.retry")
524
    @patch("biosample.tasks.FetchStatusTask.fetch_queryset")
525
    def test_fetch_status_retry(self, my_fetch, my_retry):
526
        """Test fetch status with retry"""
527
528
        # Set a side effect on the patched methods
529
        # so that they raise the errors we want.
530
        my_retry.side_effect = Retry()
531
        my_fetch.side_effect = ConnectionError()
532
533
        with raises(Retry):
534
            self.my_task.run()
535
536
        self.assertTrue(my_fetch.called)
537
        self.assertTrue(my_retry.called)
538
539
        # assert no helper called for this submission
540
        self.assertFalse(self.mock_helper.called)
541
        self.assertFalse(self.mock_complete.called)
542
543
    # Test a non blocking instance
544
    @patch("biosample.tasks.FetchStatusTask.fetch_queryset")
545
    @patch("redis.lock.Lock.acquire", return_value=False)
546
    def test_fetch_status_nb(self, my_lock, my_fetch):
547
        """Test FetchSTatus while a lock is present"""
548
549
        res = self.my_task.run()
550
551
        # assert database is locked
552
        self.assertEqual(res, "%s already running!" % (self.my_task.name))
553
        self.assertFalse(my_fetch.called)
554
555
        # assert no helper called for this submission
556
        self.assertFalse(self.mock_helper.called)
557
        self.assertFalse(self.mock_complete.called)
558
559
560
class RetrievalCompleteTaskTestCase(FetchMixin, WebSocketMixin, TestCase):
561
    """testing update status after a fetch status"""
562
563
    def setUp(self):
564
        # calling my base setup
565
        super().setUp()
566
567
        # set proper status to biosample.models.Submission
568
        USISubmission.objects.update(status=SUBMITTED)
569
570
        # define my task
571
        self.my_task = RetrievalCompleteTask()
572
573
    def updated_check(self, status, message):
574
        """Common check for tests"""
575
576
        # set proper status to biosample.models.Submission
577
        USISubmission.objects.update(status=status, message=message)
578
579
        # calling task
580
        result = self.my_task.run(
581
            uid_submission_id=self.submission_obj_id)
582
583
        # assert a success with data uploading
584
        self.assertEqual(result, "success")
585
586
        # check status and messages
587
        self.submission_obj.refresh_from_db()
588
        self.assertEqual(self.submission_obj.status, status)
589
        self.assertEqual(self.submission_obj.message, message)
590
591
        # calling a WebSocketMixin method
592
        self.check_message(
593
            STATUSES.get_value_display(status),
594
            message)
595
596
    def not_updated_check(self, status, message):
597
        """Test a submission not updated"""
598
599
        # set proper status to biosample.models.Submission
600
        USISubmission.objects.filter(pk=1).update(
601
            status=status, message=message)
602
603
        # calling task
604
        result = self.my_task.run(
605
            uid_submission_id=self.submission_obj_id)
606
607
        # assert a success with data uploading
608
        self.assertEqual(result, "success")
609
610
        # check status and messages
611
        self.submission_obj.refresh_from_db()
612
        self.assertEqual(self.submission_obj.status, SUBMITTED)
613
        self.assertEqual(
614
            self.submission_obj.message,
615
            "Waiting for biosample validation")
616
617
        # defined in websoketmixin
618
        self.check_message_not_called()
619
620
    def test_submitted(self):
621
        """Test submitted status"""
622
623
        status = SUBMITTED
624
        message = "Waiting for biosample validation"
625
626
        self.not_updated_check(
627
            status,
628
            message)
629
630
    def test_error(self):
631
        """test an error in a submission"""
632
633
        status = ERROR
634
        message = "error messages"
635
636
        self.updated_check(
637
            status,
638
            message)
639
640
        # test email sent
641
        self.assertEqual(len(mail.outbox), 1)
642
643
        # read email
644
        email = mail.outbox[0]
645
646
        self.assertEqual(
647
            "Error in biosample submission 1",
648
            email.subject)
649
650
    def test_need_revision(self):
651
        """test an issue in a submission"""
652
653
        status = NEED_REVISION
654
        message = "error messages"
655
656
        self.updated_check(
657
            status,
658
            message)
659
660
        # test email sent
661
        self.assertEqual(len(mail.outbox), 1)
662
663
        # read email
664
        email = mail.outbox[0]
665
666
        self.assertEqual(
667
            "Error in biosample submission 1",
668
            email.subject)
669
670
    def test_completed(self):
671
        """test a submission completed"""
672
673
        status = COMPLETED
674
        message = "completed messages"
675
676
        self.updated_check(
677
            status,
678
            message)
679
680
    def test_partial_submitted(self):
681
        """Having submitted in statuses will not complete the submission"""
682
683
        status = ERROR
684
        message = "error messages"
685
686
        self.not_updated_check(
687
            status,
688
            message)
689
690
        status = NEED_REVISION
691
        message = "error messages"
692
693
        self.not_updated_check(
694
            status,
695
            message)
696
697
        status = COMPLETED
698
        message = "completed messages"
699
700
        self.not_updated_check(
701
            status,
702
            message)
703