Passed
Pull Request — master (#30)
by
unknown
03:59
created

ValidateSubmissionTest.test_validate_submission_wrong_json()   B

Complexity

Conditions 2

Size

Total Lines 62
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 39
dl 0
loc 62
rs 8.9439
c 0
b 0
f 0
cc 2
nop 5

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 Fri Oct  5 11:39:21 2018
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import json
10
11
from collections import Counter
12
from unittest.mock import patch, Mock
13
from billiard.einfo import ExceptionInfo
14
from celery.exceptions import Retry
15
from pytest import raises
16
from image_validation.ValidationResult import (
17
    ValidationResultColumn, ValidationResultRecord)
18
19
from django.core import mail
20
from django.test import TestCase
21
22
from common.constants import LOADED, ERROR, READY, NEED_REVISION, COMPLETED
23
from common.tests import PersonMixinTestCase
24
from image_app.models import Submission, Person, Name, Animal, Sample
25
26
from ..tasks import ValidateTask, ValidationError
27
from ..helpers import OntologyCacheError, RulesetError
28
29
30
# https://github.com/testing-cabal/mock/issues/139#issuecomment-122128815
31
class PickableMock(Mock):
32
    """Provide a __reduce__ method to allow pickling mock objects"""
33
34
    def __reduce__(self):
35
        return (Mock, ())
36
37
38
class ValidateSubmissionMixin(PersonMixinTestCase):
39
    """A mixin to define common stuff for testing data validation"""
40
41
    # an attribute for PersonMixinTestCase
42
    person = Person
43
44
    fixtures = [
45
        'image_app/animal',
46
        'image_app/dictbreed',
47
        'image_app/dictcountry',
48
        'image_app/dictrole',
49
        'image_app/dictsex',
50
        'image_app/dictspecie',
51
        'image_app/dictstage',
52
        'image_app/dictuberon',
53
        'image_app/name',
54
        'image_app/ontology',
55
        'image_app/organization',
56
        'image_app/publication',
57
        'image_app/sample',
58
        'image_app/submission',
59
        'image_app/user',
60
        "validation/validationresult",
61
        'validation/validationsummary'
62
    ]
63
64
    def setUp(self):
65
        # calling base methods
66
        super().setUp()
67
68
        # get a submission object
69
        self.submission = Submission.objects.get(pk=1)
70
71
        # set a status which I can validate
72
        self.submission.status = LOADED
73
        self.submission.save()
74
75
        # track submission ID
76
        self.submission_id = self.submission.id
77
78
        # track names
79
        self.name_qs = Name.objects.exclude(name__contains="unknown")
80
81
        # track animal and samples
82
        self.animal_qs = Animal.objects.filter(
83
            name__submission=self.submission)
84
        self.sample_qs = Sample.objects.filter(
85
            name__submission=self.submission)
86
87
        # track animal and samples count
88
        self.n_animals = self.animal_qs.count()
89
        self.n_samples = self.sample_qs.count()
90
91
        # setting tasks
92
        self.my_task = ValidateTask()
93
94
        # setting channels methods
95
        self.asyncio_mock_patcher = patch(
96
            'asyncio.get_event_loop')
97
        self.asyncio_mock = self.asyncio_mock_patcher.start()
98
99
        # mocking asyncio return value
100
        self.run_until = self.asyncio_mock.return_value
101
        self.run_until.run_until_complete = Mock()
102
103
        # another patch
104
        self.send_msg_ws_patcher = patch(
105
            'validation.tasks.send_message_to_websocket')
106
        self.send_msg_ws = self.send_msg_ws_patcher.start()
107
108
    def check_async_called(
109
            self, message, notification_message, validation_message=None,
110
            pk=1):
111
112
        """Check django channels async messages called"""
113
114
        # defining default validation message.
115
        if not validation_message:
116
            animal_qs = Animal.objects.filter(
117
                name__submission=self.submission)
118
            sample_qs = Sample.objects.filter(
119
                name__submission=self.submission)
120
121
            validation_message = {
122
                'animals': self.n_animals,
123
                'samples': self.n_samples,
124
                'animal_unkn': animal_qs.filter(
125
                    name__validationresult__isnull=True).count(),
126
                'sample_unkn': sample_qs.filter(
127
                    name__validationresult__isnull=True).count(),
128
                'animal_issues': 0,
129
                'sample_issues': 0
130
            }
131
132
        self.assertEqual(self.asyncio_mock.call_count, 1)
133
        self.assertEqual(self.run_until.run_until_complete.call_count, 1)
134
        self.assertEqual(self.send_msg_ws.call_count, 1)
135
        self.send_msg_ws.assert_called_with(
136
            {'message': message,
137
             'notification_message': notification_message,
138
             'validation_message': validation_message}, pk)
139
140
    def check_async_not_called(self):
141
        """Check django channels async messages not called"""
142
143
        self.assertEqual(self.asyncio_mock.call_count, 0)
144
        self.assertEqual(self.run_until.run_until_complete.call_count, 0)
145
        self.assertEqual(self.send_msg_ws.call_count, 0)
146
147
    def tearDown(self):
148
        # stopping mock objects
149
        self.asyncio_mock_patcher.stop()
150
        self.send_msg_ws_patcher.stop()
151
152
        # calling base methods
153
        super().tearDown()
154
155
156
class ValidateSubmissionTest(ValidateSubmissionMixin, TestCase):
157
158
    def test_on_failure(self):
159
        """Testing on failure methods"""
160
161
        exc = Exception("Test")
162
        task_id = "test_task_id"
163
        args = [self.submission_id]
164
        kwargs = {}
165
        einfo = ExceptionInfo
166
167
        # call on_failure method
168
        self.my_task.on_failure(exc, task_id, args, kwargs, einfo)
169
170
        # check submission status and message
171
        submission = Submission.objects.get(pk=self.submission_id)
172
173
        # check submission.state changed
174
        self.assertEqual(submission.status, ERROR)
175
        self.assertEqual(
176
            submission.message,
177
            "Unknown error in validation - Test")
178
179
        # test email sent
180
        self.assertGreater(len(mail.outbox), 1)
181
182
        # read email
183
        email = mail.outbox[0]
184
185
        self.assertEqual(
186
            "Error in IMAGE Validation: Unknown error in validation - Test",
187
            email.subject)
188
189
        self.check_async_called(
190
            'Error',
191
            'Unknown error in validation - Test')
192
193
    @patch("validation.tasks.MetaDataValidation.read_in_ruleset")
194
    @patch("validation.helpers.validation.check_ruleset",
195
           return_value=[])
196
    @patch("validation.tasks.MetaDataValidation.check_usi_structure")
197
    @patch("validation.tasks.MetaDataValidation.validate")
198
    @patch("validation.tasks.ValidateTask.retry")
199
    def test_validate_retry(
200
            self, my_retry, my_validate, my_check, my_ruleset, my_read):
201
        """Test validation with retry"""
202
203
        # setting check_usi_structure result
204
        my_check.return_value = []
205
206
        # Set a side effect on the patched methods
207
        # so that they raise the errors we want.
208
        my_retry.side_effect = Retry()
209
        my_validate.side_effect = Exception()
210
211
        with raises(Retry):
212
            self.my_task.run(submission_id=self.submission_id)
213
214
        self.assertTrue(my_validate.called)
215
        self.assertTrue(my_retry.called)
216
        self.assertTrue(my_check.called)
217
        self.assertTrue(my_ruleset.called)
218
        self.assertTrue(my_read.called)
219
220
        # asserting django channels not called
221
        self.check_async_not_called()
222
223
    @patch("validation.tasks.MetaDataValidation.read_in_ruleset")
224
    @patch("validation.helpers.validation.check_ruleset",
225
           return_value=[])
226
    @patch("validation.tasks.MetaDataValidation.check_usi_structure")
227
    @patch("validation.tasks.MetaDataValidation.validate")
228
    @patch("validation.tasks.ValidateTask.retry")
229
    def test_issues_with_api(
230
            self, my_retry, my_validate, my_check, my_ruleset, my_read):
231
        """Test errors with validation API"""
232
233
        # Set a side effect on the patched methods
234
        # so that they raise the errors we want.
235
        my_retry.side_effect = Retry()
236
        my_check.return_value = []
237
        my_validate.side_effect = json.decoder.JSONDecodeError(
238
            msg="test", doc="test", pos=1)
239
240
        # call task. No retries with issues at EBI
241
        res = self.my_task.run(submission_id=self.submission_id)
242
243
        # assert a success with validation taks
244
        self.assertEqual(res, "success")
245
246
        # check submission status and message
247
        self.submission.refresh_from_db()
248
249
        # this is the message I want
250
        message = "Errors in EBI API endpoints. Please try again later"
251
252
        # check submission.status changed to NEED_REVISION
253
        self.assertEqual(self.submission.status, LOADED)
254
        self.assertIn(
255
            message,
256
            self.submission.message)
257
258
        # test email sent
259
        self.assertEqual(len(mail.outbox), 1)
260
261
        # read email
262
        email = mail.outbox[0]
263
264
        self.assertEqual(
265
            "Error in IMAGE Validation: %s" % message,
266
            email.subject)
267
268
        self.assertTrue(my_validate.called)
269
        self.assertFalse(my_retry.called)
270
        self.assertTrue(my_check.called)
271
        self.assertTrue(my_ruleset.called)
272
        self.assertTrue(my_read.called)
273
274
        self.check_async_called(
275
            'Loaded',
276
            'Errors in EBI API endpoints. Please try again later'
277
        )
278
279
    @patch("validation.helpers.validation.read_in_ruleset",
280
           side_effect=OntologyCacheError("test exception"))
281
    @patch("validation.tasks.ValidateTask.retry")
282
    def test_issues_with_ontologychache(
283
            self, my_retry, my_validate):
284
        """Test errors with validation API when loading OntologyCache
285
        objects"""
286
287
        # call task. No retries with issues at EBI
288
        res = self.my_task.run(submission_id=self.submission_id)
289
290
        # assert a success with validation taks
291
        self.assertEqual(res, "success")
292
293
        # check submission status and message
294
        self.submission.refresh_from_db()
295
296
        # this is the message I want
297
        message = "Errors in EBI API endpoints. Please try again later"
298
299
        # check submission.status changed to LOADED
300
        self.assertEqual(self.submission.status, LOADED)
301
        self.assertIn(
302
            message,
303
            self.submission.message)
304
305
        # test email sent
306
        self.assertEqual(len(mail.outbox), 1)
307
308
        # read email
309
        email = mail.outbox[0]
310
311
        self.assertEqual(
312
            "Error in IMAGE Validation: %s" % message,
313
            email.subject)
314
315
        self.assertTrue(my_validate.called)
316
        self.assertFalse(my_retry.called)
317
318
        self.check_async_called(
319
            'Loaded',
320
            'Errors in EBI API endpoints. Please try again later')
321
322
    @patch("validation.helpers.validation.read_in_ruleset",
323
           side_effect=RulesetError(["test exception"]))
324
    @patch("validation.tasks.ValidateTask.retry")
325
    def test_issues_with_ruleset(
326
            self, my_retry, my_validate):
327
        """Test errors with ruleset"""
328
329
        # call task. No retries with issues at EBI
330
        res = self.my_task.run(submission_id=self.submission_id)
331
332
        # assert a success with validation taks
333
        self.assertEqual(res, "success")
334
335
        # check submission status and message
336
        self.submission.refresh_from_db()
337
338
        # this is the message I want
339
        message = (
340
            "Error in IMAGE-metadata ruleset. Please inform InjectTool team")
341
342
        # check submission.status changed to ERROR
343
        self.assertEqual(self.submission.status, ERROR)
344
        self.assertIn(
345
            message,
346
            self.submission.message)
347
348
        # test email sent
349
        self.assertGreater(len(mail.outbox), 1)
350
351
        # read email
352
        email = mail.outbox[0]
353
354
        self.assertEqual(
355
            "Error in IMAGE Validation: %s" % message,
356
            email.subject)
357
358
        self.assertTrue(my_validate.called)
359
        self.assertFalse(my_retry.called)
360
361
        self.check_async_called(
362
            'Error',
363
            'Error in IMAGE-metadata ruleset. Please inform InjectTool team')
364
365
    @patch("validation.tasks.MetaDataValidation.read_in_ruleset")
366
    @patch("validation.helpers.validation.check_ruleset",
367
           return_value=[])
368
    @patch("validation.tasks.MetaDataValidation.check_usi_structure")
369
    @patch("validation.tasks.MetaDataValidation.validate")
370
    def test_validate_submission(
371
            self, my_validate, my_check, my_ruleset, my_read):
372
373
        # setting check_usi_structure result
374
        my_check.return_value = []
375
376
        # setting a return value for check_with_ruleset
377
        validation_result = Mock()
378
        validation_result.get_overall_status.return_value = "Pass"
379
        validation_result.get_messages.return_value = ["A message"]
380
        result_set = Mock()
381
        result_set.get_comparable_str.return_value = "A message"
382
        validation_result.result_set = [result_set]
383
        my_validate.return_value = validation_result
384
385
        # NOTE that I'm calling the function directly, without delay
386
        # (AsyncResult). I've patched the time consuming task
387
        res = self.my_task.run(submission_id=self.submission_id)
388
389
        # assert a success with validation taks
390
        self.assertEqual(res, "success")
391
392
        # check submission status and message
393
        self.submission.refresh_from_db()
394
395
        # check submission.state changed
396
        self.assertEqual(self.submission.status, READY)
397
        self.assertEqual(
398
            self.submission.message,
399
            "Submission validated with success")
400
401
        # check Names (they are all ok)
402
        for name in self.name_qs:
403
            self.assertEqual(name.status, READY)
404
405
            # test for model message (usi_results)
406
            self.assertEqual(
407
                name.validationresult.messages, ["A message"])
408
            self.assertEqual(name.validationresult.status, "Pass")
409
410
        # assert validation functions called
411
        self.assertTrue(my_check.called)
412
        self.assertTrue(my_ruleset.called)
413
        self.assertTrue(my_validate.called)
414
        self.assertTrue(my_read.called)
415
416
        # no unknown and sample with issues
417
        validation_message = {
418
            'animals': self.n_animals,
419
            'samples': self.n_samples,
420
            'animal_unkn': 0, 'sample_unkn': 0,
421
            'animal_issues': 0, 'sample_issues': 0}
422
423
        self.check_async_called(
424
            'Ready',
425
            'Submission validated with success',
426
            validation_message=validation_message
427
        )
428
429
    @patch("validation.tasks.MetaDataValidation.read_in_ruleset")
430
    @patch("validation.helpers.validation.check_ruleset",
431
           return_value=[])
432
    @patch("validation.tasks.MetaDataValidation.check_usi_structure")
433
    @patch("validation.tasks.MetaDataValidation.validate")
434
    def test_validate_submission_wrong_json(
435
            self, my_validate, my_check, my_ruleset, my_read):
436
437
        # assign a fake response for check_usi_structure
438
        usi_result = [
439
            ('Wrong JSON structure: no title field for record with '
440
             'alias as animal_1'),
441
            ('Wrong JSON structure: the values for attribute Person '
442
             'role needs to be in an array for record animal_1')
443
        ]
444
        my_check.return_value = usi_result
445
446
        # setting a return value for check_with_ruleset
447
        rule_result = Mock()
448
        rule_result.get_overall_status.return_value = "Pass"
449
        my_validate.return_value = rule_result
450
451
        # call task
452
        res = self.my_task.run(submission_id=self.submission_id)
453
454
        # assert a success with validation taks
455
        self.assertEqual(res, "success")
456
457
        # check submission status and message
458
        self.submission.refresh_from_db()
459
460
        # check submission.state changed
461
        self.assertEqual(self.submission.status, NEED_REVISION)
462
        self.assertIn(
463
            "Wrong JSON structure",
464
            self.submission.message)
465
466
        # check Names (they require revisions)
467
        for name in self.name_qs:
468
            self.assertEqual(name.status, NEED_REVISION)
469
470
            # test for model message (usi_results)
471
            self.assertEqual(
472
                name.validationresult.messages, usi_result)
473
            self.assertEqual(
474
                    name.validationresult.status, "Wrong JSON structure")
475
476
        # if JSON is not valid, I don't check for ruleset
477
        self.assertTrue(my_check.called)
478
        self.assertTrue(my_ruleset.called)
479
        self.assertFalse(my_validate.called)
480
        self.assertTrue(my_read.called)
481
482
        # all sample and animals have issues
483
        self.check_async_called(
484
            'Need Revision',
485
            'Validation got errors: Wrong JSON structure',
486
            {'animals': self.n_animals, 'samples': self.n_samples,
487
             'animal_unkn': 0, 'sample_unkn': 0,
488
             'animal_issues': self.n_animals,
489
             'sample_issues': self.n_samples},
490
            1)
491
492
    @patch("validation.tasks.MetaDataValidation.read_in_ruleset")
493
    @patch("validation.helpers.validation.check_ruleset",
494
           return_value=[])
495
    @patch("validation.tasks.MetaDataValidation.check_usi_structure")
496
    @patch("validation.tasks.MetaDataValidation.validate")
497
    def test_unsupported_status(
498
            self, my_validate, my_check, my_ruleset, my_read):
499
        """This test will ensure that image_validation ValidationResultRecord
500
        still support the same statuses"""
501
502
        # setting check_usi_structure result
503
        my_check.return_value = []
504
505
        # setting a return value for check_with_ruleset
506
        rule_result = PickableMock()
507
        rule_result.get_overall_status.return_value = "A fake status"
508
        rule_result.get_messages.return_value = ["A fake message", ]
509
510
        result_set = Mock()
511
        result_set.get_comparable_str.return_value = "A fake message"
512
        rule_result.result_set = [result_set]
513
514
        my_validate.return_value = rule_result
515
516
        # call task
517
        self.assertRaisesRegex(
518
            ValidationError,
519
            "Error in statuses for submission",
520
            self.my_task.run,
521
            submission_id=self.submission_id)
522
523
        # check submission status and message
524
        self.submission.refresh_from_db()
525
526
        # check submission.state changed
527
        self.assertEqual(self.submission.status, ERROR)
528
        self.assertIn(
529
            "Error in statuses for submission",
530
            self.submission.message)
531
532
        # if JSON is not valid, I don't check for ruleset
533
        self.assertTrue(my_check.called)
534
        self.assertTrue(my_ruleset.called)
535
        self.assertTrue(my_validate.called)
536
        self.assertTrue(my_read.called)
537
538
        self.check_async_called(
539
            message='Error',
540
            notification_message=(
541
                "Validation got errors: Error in statuses "
542
                "for submission Cryoweb (United Kingdom, "
543
                "test): animals - ['A fake status', "
544
                "'Error', 'Issues', 'JSON', 'Known', 'Pass', 'Warning'], "
545
                "samples - ['A fake status', 'Error', "
546
                "'Issues', 'JSON', 'Known', 'Pass', 'Warning']"),
547
            validation_message={
548
                'animals': self.n_animals, 'samples': self.n_samples,
549
                'animal_unkn': 0, 'sample_unkn': 0,
550
                'animal_issues': self.n_animals,
551
                'sample_issues': self.n_samples},
552
            pk=1)
553
554
    @patch("validation.tasks.MetaDataValidation.read_in_ruleset")
555
    @patch("validation.helpers.validation.check_ruleset",
556
           return_value=[])
557
    @patch("validation.tasks.MetaDataValidation.check_usi_structure")
558
    @patch("validation.tasks.MetaDataValidation.validate")
559
    def test_validate_submission_warnings(
560
            self, my_validate, my_check, my_ruleset, my_read):
561
        """A submission with warnings is a READY submission"""
562
563
        # setting check_usi_structure result
564
        my_check.return_value = []
565
566
        # setting a return value for check_with_ruleset
567
        result1 = ValidationResultRecord("animal_1")
568
        result1.add_validation_result_column(
569
            ValidationResultColumn(
570
                "warning",
571
                "warn message",
572
                "animal_1",
573
                "warn column")
574
        )
575
576
        result2 = ValidationResultRecord("animal_2")
577
        result2.add_validation_result_column(
578
            ValidationResultColumn(
579
                "pass",
580
                "a message",
581
                "animal_2",
582
                "")
583
        )
584
585
        result3 = ValidationResultRecord("animal_3")
586
        result3.add_validation_result_column(
587
            ValidationResultColumn(
588
                "pass",
589
                "a message",
590
                "animal_3",
591
                "")
592
        )
593
594
        result4 = ValidationResultRecord("sample_1")
595
        result4.add_validation_result_column(
596
            ValidationResultColumn(
597
                "pass",
598
                "a message",
599
                "sample_1",
600
                "")
601
        )
602
603
        # add results to result set
604
        responses = [result1, result2, result3, result4]
605
        my_validate.side_effect = responses
606
607
        # call task
608
        res = self.my_task.run(submission_id=self.submission_id)
609
610
        # assert a success with validation taks
611
        self.assertEqual(res, "success")
612
613
        # check submission status and message
614
        self.submission.refresh_from_db()
615
616
        # check submission.state changed
617
        self.assertEqual(self.submission.status, READY)
618
        self.assertIn(
619
            "Submission validated with some warnings",
620
            self.submission.message)
621
622
        # check Names (they are all ok)
623
        for i, name in enumerate(self.name_qs):
624
            # get the appropriate ValidationResultRecord
625
            result = responses[i]
626
627
            # all objects are ready for submissions
628
            self.assertEqual(name.status, READY)
629
630
            self.assertEqual(
631
                name.validationresult.messages,
632
                result.get_messages())
633
634
            self.assertEqual(
635
                name.validationresult.status,
636
                result.get_overall_status())
637
638
        # test for my methods called
639
        self.assertTrue(my_check.called)
640
        self.assertTrue(my_ruleset.called)
641
        self.assertTrue(my_validate.called)
642
        self.assertTrue(my_read.called)
643
644
        self.check_async_called(
645
            message='Ready',
646
            notification_message='Submission validated with some warnings',
647
            validation_message={
648
                'animals': self.n_animals, 'samples': self.n_samples,
649
                'animal_unkn': 0, 'sample_unkn': 0,
650
                'animal_issues': 1, 'sample_issues': 0},
651
            pk=1)
652
653
    @patch("validation.tasks.MetaDataValidation.read_in_ruleset")
654
    @patch("validation.helpers.validation.check_ruleset",
655
           return_value=[])
656
    @patch("validation.tasks.MetaDataValidation.check_usi_structure")
657
    @patch("validation.tasks.MetaDataValidation.validate")
658
    def test_validate_submission_errors(
659
            self, my_validate, my_check, my_ruleset, my_read):
660
        """A submission with errors is a NEED_REVISION submission"""
661
662
        # setting check_usi_structure result
663
        my_check.return_value = []
664
665
        # setting a return value for check_with_ruleset
666
        result1 = ValidationResultRecord("animal_1")
667
        result1.add_validation_result_column(
668
            ValidationResultColumn(
669
                "warning",
670
                "warn message",
671
                "animal_1",
672
                "warn column")
673
        )
674
675
        result2 = ValidationResultRecord("animal_2")
676
        result2.add_validation_result_column(
677
            ValidationResultColumn(
678
                "pass",
679
                "a message",
680
                "animal_2",
681
                "")
682
        )
683
684
        result3 = ValidationResultRecord("animal_3")
685
        result3.add_validation_result_column(
686
            ValidationResultColumn(
687
                "pass",
688
                "a message",
689
                "animal_3",
690
                "")
691
        )
692
693
        result4 = ValidationResultRecord("sample_1")
694
        result4.add_validation_result_column(
695
            ValidationResultColumn(
696
                "error",
697
                "error message",
698
                "sample_1",
699
                "error column")
700
        )
701
702
        # add results to result set
703
        responses = [result1, result2, result3, result4]
704
        my_validate.side_effect = responses
705
706
        # call task
707
        res = self.my_task.run(submission_id=self.submission_id)
708
709
        # assert a success with validation taks
710
        self.assertEqual(res, "success")
711
712
        # check submission status and message
713
        self.submission.refresh_from_db()
714
715
        # check submission.state changed
716
        self.assertEqual(self.submission.status, NEED_REVISION)
717
        self.assertIn(
718
            "Error in metadata",
719
            self.submission.message)
720
721
        # check Names (they are all ok, except 1 - sample)
722
        for i, name in enumerate(self.name_qs):
723
            # get the appropriate ValidationResultRecord
724
            result = responses[i]
725
726
            if hasattr(name, "animal"):
727
                self.assertEqual(name.status, READY)
728
729
            else:
730
                # sample has errors
731
                self.assertEqual(name.status, NEED_REVISION)
732
733
            self.assertEqual(
734
                name.validationresult.messages,
735
                result.get_messages())
736
737
            self.assertEqual(
738
                name.validationresult.status,
739
                result.get_overall_status())
740
741
        # test for my methods called
742
        self.assertTrue(my_check.called)
743
        self.assertTrue(my_ruleset.called)
744
        self.assertTrue(my_validate.called)
745
        self.assertTrue(my_read.called)
746
747
        self.check_async_called(
748
            message='Need Revision',
749
            notification_message=(
750
                'Validation got errors: Error in '
751
                'metadata. Need revisions before submit'),
752
            validation_message={
753
                'animals': self.n_animals, 'samples': self.n_samples,
754
                'animal_unkn': 0, 'sample_unkn': 0,
755
                'animal_issues': 1, 'sample_issues': 1},
756
            pk=1)
757
758
759
class ValidateSubmissionStatusTest(ValidateSubmissionMixin, TestCase):
760
    """Check database statuses after calling validation"""
761
762
    def setUp(self):
763
        # calling base setup
764
        super().setUp()
765
766
        # track an animal for testing
767
        self.animal = Animal.objects.get(pk=1)
768
        self.animal_name = self.animal.name
769
770
    def check_status(self, status, messages, name_status):
771
        """Test if I can update status for a model that pass validation"""
772
773
        result = PickableMock()
774
        result.get_overall_status.return_value = status
775
        result.get_messages.return_value = messages
776
        result_set = Mock()
777
        result_set.get_comparable_str.return_value = "A message"
778
        result.result_set = [result_set]
779
780
        submission_statuses = Counter(
781
            {'Pass': 0,
782
             'Warning': 0,
783
             'Error': 0,
784
             'JSON': 0})
785
786
        # calling update statuses
787
        self.my_task.update_statuses(submission_statuses, self.animal, result)
788
789
        # Test for animal status
790
        self.animal_name.refresh_from_db()
791
        self.assertEqual(self.animal_name.status, name_status)
792
793
        # get validation result object
794
        validationresult = self.animal_name.validationresult
795
        self.assertEqual(validationresult.status, status)
796
        self.assertEqual(validationresult.messages, messages)
797
798
        # test submission status
799
        self.assertEqual(submission_statuses[status], 1)
800
801
    def test_update_status_pass(self):
802
        status = 'Pass'
803
        messages = ['Passed all tests']
804
        name_status = READY
805
806
        self.check_status(status, messages, name_status)
807
808
    def test_update_status_warning(self):
809
        status = 'Warning'
810
        messages = ['issued a warning']
811
        name_status = READY
812
813
        self.check_status(status, messages, name_status)
814
815
    def test_update_status_error(self):
816
        status = 'Error'
817
        messages = ['issued an error']
818
        name_status = NEED_REVISION
819
820
        self.check_status(status, messages, name_status)
821
822
823
class ValidateUpdatedSubmissionStatusTest(ValidateSubmissionMixin, TestCase):
824
    """Check database statuses after calling validation for an updated
825
    submission (a submission completed and submitted to biosample in which
826
    I want to modify a thing)"""
827
828
    def setUp(self):
829
        # call base method
830
        super().setUp()
831
832
        # take all names and set them to completed, as after a successful
833
        # submission:
834
        self.name_qs.update(status=COMPLETED)
835
836
        # take the animal name I want to update
837
        self.animal_name = Name.objects.get(pk=3)
838
839
        # update submission status. Simulate a completed submission in which
840
        # I want to update something
841
        self.submission.status = NEED_REVISION
842
        self.submission.save()
843
844
        # update name objects. In this case, animal was modified
845
        self.animal_name.status = NEED_REVISION
846
        self.animal_name.save()
847
848
    def update_status(self, status, messages, name_status):
849
        """Test if I can update status for a model that pass validation"""
850
851
        # modelling validation same result for every object
852
        result = PickableMock()
853
        result.get_overall_status.return_value = status
854
        result.get_messages.return_value = messages
855
856
        result_set = Mock()
857
        result_set.get_comparable_str.return_value = "A message"
858
        result.result_set = [result_set]
859
860
        submission_statuses = Counter(
861
            {'Pass': 0,
862
             'Warning': 0,
863
             'Error': 0,
864
             'JSON': 0})
865
866
        # calling update statuses on name objects
867
        for name in self.name_qs:
868
            if hasattr(name, "animal"):
869
                self.my_task.update_statuses(
870
                    submission_statuses,
871
                    name.animal,
872
                    result)
873
            else:
874
                self.my_task.update_statuses(
875
                    submission_statuses,
876
                    name.sample,
877
                    result)
878
879
        # refreshing data from db
880
        self.animal_name.refresh_from_db()
881
882
    def test_update_status_pass(self):
883
        status = 'Pass'
884
        messages = ['Passed all tests']
885
        name_status = READY
886
887
        self.update_status(status, messages, name_status)
888
889
        # asserting status change for animal
890
        self.assertEqual(self.animal_name.status, name_status)
891
892
        # validationresult is tested outside this class
893
894
        # other statuses are unchanged
895
        for name in self.name_qs.exclude(pk=self.animal_name.pk):
896
            self.assertEqual(name.status, COMPLETED)
897
898
    def test_update_status_warning(self):
899
        status = 'Warning'
900
        messages = ['issued a warning']
901
        name_status = READY
902
903
        self.update_status(status, messages, name_status)
904
905
        # asserting status change for animal
906
        self.assertEqual(self.animal_name.status, name_status)
907
908
        # other statuses are unchanged
909
        for name in self.name_qs.exclude(pk=self.animal_name.pk):
910
            self.assertEqual(name.status, COMPLETED)
911
912
    def test_update_status_error(self):
913
        status = 'Error'
914
        messages = ['issued an error']
915
        name_status = NEED_REVISION
916
917
        self.update_status(status, messages, name_status)
918
919
        # all statuses are changed (and need revisions)
920
        for name in self.name_qs:
921
            self.assertEqual(name.status, NEED_REVISION)
922