Passed
Pull Request — master (#26)
by Paolo
01:48
created

MetaDataValidationTestCase.test_check_biosample_id_target()   A

Complexity

Conditions 1

Size

Total Lines 27
Code Lines 14

Duplication

Lines 27
Ratio 100 %

Importance

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