Passed
Pull Request — master (#26)
by Paolo
02:00
created

SubmissionTestCase.test_sample_issue_organism_part()   A

Complexity

Conditions 1

Size

Total Lines 31
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 31
rs 9.65
c 0
b 0
f 0
cc 1
nop 1
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Tue Jan 22 14:28:16 2019
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import json
10
11
from image_validation.ValidationResult import ValidationResultRecord
12
from unittest.mock import patch, Mock
13
14
from django.test import TestCase
15
16
from image_app.models import Animal, Sample, Submission, Person, Name
17
18
from common.tests import PersonMixinTestCase
19
20
from ..helpers import (
21
    MetaDataValidation, ValidationSummary, OntologyCacheError, RulesetError)
22
23
from ..models import ValidationResult
24
25
26
class MetaDataValidationTestCase(TestCase):
27
    @patch("validation.helpers.validation.read_in_ruleset",
28
           side_effect=json.JSONDecodeError("meow", "woof", 42))
29
    def test_issues_with_ebi(self, my_issue):
30
        """
31
        Test temporary issues related with OLS EBI server during
32
        image_validation.use_ontology.OntologyCache loading"""
33
34
        # assert issues from validation.helpers.validation.read_in_ruleset
35
        self.assertRaisesMessage(
36
            OntologyCacheError,
37
            "Issue with 'https://www.ebi.ac.uk/ols/api/'",
38
            MetaDataValidation)
39
40
        # test mocked function called
41
        self.assertTrue(my_issue.called)
42
43
    @patch("validation.helpers.validation.check_ruleset",
44
           return_value=["Test for ruleset errors"])
45
    def test_issues_with_ruleset(self, my_issue):
46
        """
47
        Test errors regarding ruleset
48
        """
49
50
        # assert issues from validation.helpers.validation.read_in_ruleset
51
        self.assertRaisesMessage(
52
            RulesetError,
53
            "Test for ruleset errors",
54
            MetaDataValidation)
55
56
        # test mocked function called
57
        self.assertTrue(my_issue.called)
58
59 View Code Duplication
    @patch("requests.get")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
60
    @patch("validation.helpers.validation.read_in_ruleset")
61
    @patch("validation.helpers.validation.check_ruleset",
62
           return_value=[])
63
    def test_check_biosample_id_target(self, my_check, my_read, mock_get):
64
        """Test fecthing biosample ids from MetaDataValidation"""
65
66
        # paching response
67
        response = Mock()
68
        response.status_code = 200
69
        mock_get.return_value = response
70
71
        # create a fake ValidationResultRecord
72
        record_result = ValidationResultRecord(record_id="test")
73
74
        # get a metadata object
75
        metadata = MetaDataValidation()
76
77
        # check biosample object
78
        record_result = metadata.check_biosample_id_target(
79
            "FAKEA123456", "test", record_result)
80
81
        # test pass status and no messages
82
        self.assertEqual(record_result.get_overall_status(), 'Pass')
83
        self.assertEqual(record_result.get_messages(), [])
84
85
        # assert my methods called
86
        self.assertTrue(my_check.called)
87
        self.assertTrue(my_read.called)
88
        self.assertTrue(mock_get.called)
89
90 View Code Duplication
    @patch("requests.get")
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
91
    @patch("validation.helpers.validation.read_in_ruleset")
92
    @patch("validation.helpers.validation.check_ruleset",
93
           return_value=[])
94
    def test_check_biosample_id_issue(self, my_check, my_read, mock_get):
95
        """No valid biosample is found for this object"""
96
97
        # paching response
98
        response = Mock()
99
        response.status_code = 404
100
        mock_get.return_value = response
101
102
        # create a fake ValidationResultRecord
103
        record_result = ValidationResultRecord(record_id="test")
104
105
        # get a metadata object
106
        metadata = MetaDataValidation()
107
108
        # check biosample object
109
        record_result = metadata.check_biosample_id_target(
110
            "FAKEA123456", "test", record_result)
111
112
        # test Warning status and one message
113
        self.assertEqual(record_result.get_overall_status(), 'Warning')
114
        self.assertEqual(len(record_result.get_messages()), 1)
115
116
        # assert my methods called
117
        self.assertTrue(my_check.called)
118
        self.assertTrue(my_read.called)
119
        self.assertTrue(mock_get.called)
120
121
122
class SubmissionMixin(PersonMixinTestCase):
123
    # an attribute for PersonMixinTestCase
124
    person = Person
125
126
    fixtures = [
127
        'image_app/animal',
128
        'image_app/dictbreed',
129
        'image_app/dictcountry',
130
        'image_app/dictrole',
131
        'image_app/dictsex',
132
        'image_app/dictspecie',
133
        'image_app/dictstage',
134
        'image_app/dictuberon',
135
        'image_app/name',
136
        'image_app/ontology',
137
        'image_app/organization',
138
        'image_app/publication',
139
        'image_app/sample',
140
        'image_app/submission',
141
        'image_app/user'
142
    ]
143
144
    @classmethod
145
    def setUpClass(cls):
146
        # calling my base class setup
147
        super().setUpClass()
148
149
        # drop publication for semplicity
150
        name = Name.objects.get(pk=3)
151
        publication = name.publication
152
        publication.delete()
153
154
    def setUp(self):
155
        # calling my base class setup
156
        super().setUp()
157
158
        self.metadata = MetaDataValidation()
159
160
161
class SubmissionTestCase(SubmissionMixin, TestCase):
162
    """Deal real tests using image_validation library: this want to ensure
163
    that InjectTools can work with image_validation"""
164
165
    def setUp(self):
166
        # calling my base class setup
167
        super().setUp()
168
169
        # get an animal object
170
        self.animal = Animal.objects.get(pk=1)
171
        self.animal_record = self.animal.to_biosample()
172
173
        # get a sample object
174
        self.sample = Sample.objects.get(pk=1)
175
        self.sample_record = self.sample.to_biosample()
176
177
    def test_animal(self):
178
        """Testing an animal submission"""
179
180
        # at the time of writing this reference data raise one warning
181
        reference = ("Pass", "")
182
183
        # check for usi structure
184
        usi_result = self.metadata.check_usi_structure([self.animal_record])
185
        self.assertEqual(usi_result, [])
186
187
        # validate record
188
        result = self.metadata.validate(self.animal_record)
189
190
        # assert result type
191
        self.assertIsInstance(result, ValidationResultRecord)
192
        self.assertEqual(result.get_overall_status(), reference[0])
193
194
        def search(y):
195
            return reference[1] in y
196
197
        matches = [search(message) for message in result.get_messages()]
198
        self.assertNotIn(False, matches)
199
200
    def test_animal_relationship(self):
201
        """Testing an animal with a relationship"""
202
203
        # at the time of writing this reference data raise one warning
204
        reference = ("Pass", "")
205
206
        # get a to_biosample record
207
        animal = Animal.objects.get(pk=3)
208
        animal_record = animal.to_biosample()
209
210
        # check for usi structure
211
        usi_result = self.metadata.check_usi_structure([animal_record])
212
        self.assertEqual(usi_result, [])
213
214
        # validate record
215
        result = self.metadata.validate(animal_record)
216
217
        # assert result type
218
        self.assertIsInstance(result, ValidationResultRecord)
219
        self.assertEqual(result.get_overall_status(), reference[0])
220
221
        def search(y):
222
            return reference[1] in y
223
224
        matches = [search(message) for message in result.get_messages()]
225
        self.assertNotIn(False, matches)
226
227
    def test_sample(self):
228
        """Test a sample submission"""
229
230
        # at the time of writing this reference pass without problems
231
        reference = ("Pass", "")
232
233
        # check for usi structure
234
        usi_result = self.metadata.check_usi_structure([self.sample_record])
235
        self.assertEqual(usi_result, [])
236
237
        result = self.metadata.validate(self.sample_record)
238
239
        # assert result type
240
        self.assertIsInstance(result, ValidationResultRecord)
241
        self.assertEqual(result.get_overall_status(), reference[0])
242
243
        def search(y):
244
            return reference[1] == y
245
246
        matches = [search(message) for message in result.get_messages()]
247
        self.assertNotIn(False, matches)
248
249
    def test_sample_relationship_issue(self):
250
        """Testing an error with related alias. Not sure if it can happen or
251
        not"""
252
253
        # get record from sample
254
        record = self.sample_record
255
256
        # change alias in relationship in order to have no a related obj
257
        record["sampleRelationships"] = [{
258
            "alias": "IMAGEA999999999",
259
            "relationshipNature": "derived from"
260
        }]
261
262
        # create a fake ValidationResultRecord
263
        record_result = ValidationResultRecord(record_id=record['title'])
264
265
        # check relationship method
266
        related, result = self.metadata.check_relationship(
267
            record, record_result)
268
269
        # this is an error in results
270
        self.assertEqual(related, [])
271
        self.assertEqual(result.get_overall_status(), 'Error')
272
        self.assertIn(
273
            "Could not locate the referenced record",
274
            result.get_messages()[0])
275
276
    def test_sample_issue_organism_part(self):
277
        """Testing a problem in metadata: organism_part lacks of term"""
278
279
        # at the time of writing, this will have Errors
280
        reference = (
281
            "Error", (
282
                "Error: No url found for the field Organism part which has "
283
                "the type of ontology_id")
284
        )
285
286
        sample_record = self.sample.to_biosample()
287
288
        # set an attribute without ontology
289
        sample_record['attributes']['Organism part'] = [{'value': 'hair'}]
290
291
        # check for usi structure
292
        usi_result = self.metadata.check_usi_structure([sample_record])
293
        self.assertEqual(usi_result, [])
294
295
        # validate record. This will result in an error object
296
        result = self.metadata.validate(sample_record)
297
298
        # assert result type
299
        self.assertIsInstance(result, ValidationResultRecord)
300
        self.assertEqual(result.get_overall_status(), reference[0])
301
302
        def search(y):
303
            return reference[1] in y
304
305
        matches = [search(message) for message in result.get_messages()]
306
        self.assertNotIn(False, matches)
307
308
    def test_submission(self):
309
        """Testing usi_structure and duplicates in a submission"""
310
311
        # get all biosample data in a list
312
        data = [self.animal_record, self.sample_record]
313
314
        # test for usi structure
315
        usi_result = self.metadata.check_usi_structure(data)
316
317
        # no errors for check usi_structure
318
        self.assertIsInstance(usi_result, list)
319
        self.assertEqual(len(usi_result), 0)
320
321
        # test for duplicated data
322
        dup_result = self.metadata.check_duplicates(data)
323
324
        # no errors for check_duplicates
325
        self.assertIsInstance(dup_result, list)
326
        self.assertEqual(len(dup_result), 0)
327
328
    def test_wrong_json_structure(self):
329
        """Test that json structure is ok"""
330
331
        reference = [
332
            ('Wrong JSON structure: no title field for record with '
333
             'alias as IMAGEA000000001'),
334
        ]
335
336
        # delete some attributes from animal data
337
        del(self.animal_record['title'])
338
339
        # test for Json structure
340
        test = self.metadata.check_usi_structure([self.animal_record])
341
342
        self.assertEqual(reference, test)
343
344
345
class SampleUpdateTestCase(SubmissionMixin, TestCase):
346
    """Testing validation for a sample update"""
347
348
    def setUp(self):
349
        # calling my base class setup
350
        super().setUp()
351
352
        # get a samlple
353
        self.sample = Sample.objects.get(pk=1)
354
355
        # modify animal and sample
356
        self.animal_reference = "SAMEA4450079"
357
        self.sample.animal.name.biosample_id = self.animal_reference
358
        self.sample.animal.name.save()
359
360
        self.sample_reference = "SAMEA4450075"
361
        self.sample.name.biosample_id = self.sample_reference
362
        self.sample.name.save()
363
364
        self.record = self.sample.to_biosample()
365
366
    def test_sample_update(self):
367
        """Simulate a validation for an already submitted sample"""
368
369
        # at the time of writing this reference pass without problems
370
        reference = ("Pass", "")
371
372
        # check object
373
        result = self.metadata.validate(self.record)
374
375
        # assert result type
376
        self.assertIsInstance(result, ValidationResultRecord)
377
        self.assertEqual(result.get_overall_status(), reference[0])
378
379
        def search(y):
380
            return reference[1] == y
381
382
        matches = [search(message) for message in result.get_messages()]
383
        self.assertNotIn(False, matches)
384
385
386
class RulesTestCase(TestCase):
387
    """Assert that image rules are valid"""
388
389
    def setUp(self):
390
        self.metadata = MetaDataValidation()
391
392
    def test_check_ruleset(self):
393
        """Assert that rules are valid"""
394
395
        # get validation results
396
        ruleset_check = self.metadata.check_ruleset()
397
398
        # test image metadata rules
399
        self.assertIsInstance(ruleset_check, list)
400
        self.assertEqual(len(ruleset_check), 0)
401
402
403
class ValidationSummaryTestCase(TestCase):
404
    fixtures = [
405
        'image_app/animal',
406
        'image_app/dictbreed',
407
        'image_app/dictcountry',
408
        'image_app/dictrole',
409
        'image_app/dictsex',
410
        'image_app/dictspecie',
411
        'image_app/dictstage',
412
        'image_app/dictuberon',
413
        'image_app/name',
414
        'image_app/organization',
415
        'image_app/publication',
416
        'image_app/submission',
417
        'image_app/user',
418
        'image_app/sample',
419
        'validation/validationresult'
420
    ]
421
422
    def setUp(self):
423
        self.submission = Submission.objects.get(pk=1)
424
        self.validationsummary = ValidationSummary(self.submission)
425
426
        # set names
427
        self.animal_name = Name.objects.get(pk=3)
428
        self.sample_name = Name.objects.get(pk=4)
429
430
        # track validationresult object
431
        self.validationresult = ValidationResult.objects.get(pk=1)
432
433
    def test_initialization(self):
434
        """Test that ValidationSummary is correctly initialized"""
435
436
        self.assertEqual(self.validationsummary.n_animal_issues, 0)
437
        self.assertEqual(self.validationsummary.n_sample_issues, 0)
438
439
        self.assertEqual(self.validationsummary.n_animal_unknown, 2)
440
        self.assertEqual(self.validationsummary.n_sample_unknown, 1)
441
442
    def test_process_errors(self):
443
        report = self.validationsummary.process_errors()
444
        self.assertIsInstance(report, dict)
445
        self.assertEqual(report, {})
446
447
    def update_message(self, message):
448
        self.validationresult.status = "Error"
449
        self.validationresult.messages = [message]
450
        self.validationresult.save()
451
452
    def test_process_error_unmanaged(self):
453
        # modify validation results object
454
        message = "Unmanaged error"
455
        self.update_message(message)
456
457
        with self.assertLogs('validation.helpers', level="ERROR") as log:
458
            report = self.validationsummary.process_errors()
459
460
        self.assertEqual(len(report), 1)
461
462
        # log.output is a list of rows for each logger message
463
        self.assertEqual(len(log.output), 1)
464
        self.assertIn("Cannot parse: '%s'" % message, log.output[0])
465
466
    def test_patterns1(self):
467
        # define test strings for patterns
468
        message = (
469
            'Error: <link> of field Availability is message for Record test')
470
        self.update_message(message)
471
472
        with self.assertLogs('validation.helpers', level="DEBUG") as log:
473
            report = self.validationsummary.process_errors()
474
475
        self.assertEqual(len(report), 1)
476
        self.assertEqual(len(log.output), 2)
477
        self.assertIn(
478
            "DEBUG:validation.helpers:parse1: Got 'link','Availability' and "
479
            "'message'",
480
            log.output)
481
482
    def test_patterns2(self):
483
        # define test strings for patterns
484
        message = (
485
            'reason meow for the field myfield which blah, blah for Record '
486
            'test')
487
        self.update_message(message)
488
489
        with self.assertLogs('validation.helpers', level="DEBUG") as log:
490
            report = self.validationsummary.process_errors()
491
492
        self.assertEqual(len(report), 1)
493
        self.assertEqual(len(log.output), 2)
494
        self.assertIn(
495
            "DEBUG:validation.helpers:parse2: Got 'reason meow','myfield' "
496
            "and 'blah, blah'",
497
            log.output)
498
499
    def test_patterns3(self):
500
        # define test strings for patterns
501
        message = (
502
            'Provided value term does not match to the provided ontology '
503
            'for Record test')
504
        self.update_message(message)
505
506
        with self.assertLogs('validation.helpers', level="DEBUG") as log:
507
            report = self.validationsummary.process_errors()
508
509
        self.assertEqual(len(report), 1)
510
        self.assertEqual(len(log.output), 2)
511
        self.assertIn(
512
            "DEBUG:validation.helpers:parse3: Got 'term' and 'does not match "
513
            "to the provided ontology'",
514
            log.output)
515
516
    def test_update_message(self):
517
        # define an error message as for test_pattern1
518
        message = (
519
            'Error: <link> of field Availability is message for Record test')
520
        self.update_message(message)
521
522
        # get another validation result object and assign errors
523
        validationresult = ValidationResult()
524
        validationresult.status = "Error"
525
        validationresult.messages = [message]
526
        validationresult.name = self.sample_name
527
        validationresult.save()
528
529
        with self.assertLogs('validation.helpers', level="DEBUG") as log:
530
            report = self.validationsummary.process_errors()
531
532
        self.assertEqual(len(report), 1)
533
        self.assertEqual(len(log.output), 4)
534
        self.assertIn(
535
            "DEBUG:validation.helpers:parse1: Got 'link','Availability' and "
536
            "'message'",
537
            log.output)
538