Completed
Push — master ( eecf08...313cfe )
by Paolo
15s queued 12s
created

CheckUIDTest.test_missing_country()   A

Complexity

Conditions 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Thu Sep 20 16:01:04 2018
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
# --- import
10
from unittest.mock import patch
11
12
from django.conf import settings
13
from django.core.management import call_command
14
from django.test import TestCase
15
16
from common.constants import ERROR
17
from common.tests import WebSocketMixin
18
from language.models import SpecieSynonym
19
from image_app.models import (
20
    Submission, DictBreed, Name, Animal, Sample, DictSex,
21
    DictCountry, DictSpecie)
22
from image_app.tests import DataSourceMixinTestCase
23
24
from ..helpers import (
25
    upload_cryoweb, check_species, CryoWebImportError, cryoweb_import,
26
    check_UID, check_countries)
27
from ..models import db_has_data, truncate_database, BreedsSpecies
28
29
30
class BaseMixin():
31
    # import this file and populate database once
32
    fixtures = [
33
        'cryoweb/dictbreed',
34
        'image_app/dictcountry',
35
        'image_app/dictrole',
36
        'image_app/dictsex',
37
        'image_app/organization',
38
        'image_app/submission',
39
        'image_app/user',
40
        'language/dictspecie',
41
        'language/speciesynonym'
42
    ]
43
44
    # By default, fixtures are only loaded into the default database. If you
45
    # are using multiple databases and set multi_db=True, fixtures will be
46
    # loaded into all databases. However, this will raise problems when
47
    # managing extended user models
48
    multi_db = False
49
50
    def setUp(self):
51
        # calling my base class setup
52
        super().setUp()
53
54
        # track submission
55
        self.submission = Submission.objects.get(pk=1)
56
57
58
class CryoWebMixin(object):
59
    """Custom methods to upload cryoweb data into database for testing"""
60
61
    @classmethod
62
    def setUpClass(cls):
63
        # calling my base class setup
64
        super().setUpClass()
65
66
        # this fixture have to be loaded in a secondary (test) database,
67
        # I can't upload it using names and fixture section, so it will
68
        # be added manually using loaddata
69
        call_command(
70
            'loaddata',
71
            'cryoweb/cryoweb.json',
72
            app='cryoweb',
73
            database='cryoweb',
74
            verbosity=0)
75
76
    @classmethod
77
    def tearDownClass(cls):
78
        # truncate cryoweb database after loading
79
        if db_has_data():
80
            truncate_database()
81
82
        # calling my base class teardown class
83
        super().tearDownClass()
84
85
86
class ImportMixin(WebSocketMixin, CryoWebMixin):
87
    """Mixing to test cryoweb_import method"""
88
89
    def test_cryoweb_import(self):
90
        """A method to test if data were imported from cryoweb or not"""
91
92
        self.assertTrue(cryoweb_import(self.submission))
93
94
        # check breed upload
95
        queryset = DictBreed.objects.all()
96
97
        breeds = [(dictbreed.supplied_breed, dictbreed.country.label)
98
                  for dictbreed in queryset]
99
100
        self.assertEqual(len(queryset), 4)
101
        self.assertListEqual(
102
            breeds, [
103
                ('Bunte Bentheimer', 'United Kingdom'),
104
                ('Ostfriesisches Milchschaf', 'Italy'),
105
                ('Aberdeen Angus', 'Germany'),
106
                ('Ostfriesisches Milchschaf', 'Germany')],
107
            msg="Check breeds loaded")
108
109
        # check name upload (5 animal, 1 sample)
110
        queryset = Name.objects.filter(submission=self.submission)
111
        self.assertEqual(len(queryset), 6, msg='check name load')
112
113
        # check animal name
114
        queryset = Animal.objects.all()
115
        self.assertEqual(len(queryset), 3, msg="check animal load")
116
117
        queryset = Sample.objects.all()
118
        self.assertEqual(len(queryset), 1, msg="check sample load")
119
120
        # check async message called
121
        message = 'Loaded'
122
        notification_message = (
123
            'Cryoweb import completed for submission: 1')
124
        validation_message = {
125
            'animals': 3, 'samples': 1,
126
            'animal_unkn': 3, 'sample_unkn': 1,
127
            'animal_issues': 0, 'sample_issues': 0}
128
129
        self.check_message(message, notification_message, validation_message)
130
131
132
class CheckSpecie(CryoWebMixin, BaseMixin, TestCase):
133
    def test_check_species(self):
134
        """Testing species and synonyms"""
135
136
        united_kingdom = DictCountry.objects.get(label="United Kingdom")
137
138
        # test for species synonoms for cryoweb
139
        self.assertTrue(check_species(united_kingdom))
140
141
        # now delete a synonym
142
        synonym = SpecieSynonym.objects.get(
143
            language__label='United Kingdom',
144
            word='Cattle')
145
        synonym.delete()
146
147
        self.assertFalse(check_species(united_kingdom))
148
149
    def test_no_species(self):
150
        """Test no species in cryoweb database"""
151
152
        queryset = BreedsSpecies.objects.all()
153
        queryset.delete()
154
155
        self.assertRaisesRegex(
156
            CryoWebImportError,
157
            "You have no species",
158
            check_species, "United Kingdom")
159
160
161
class CheckCountry(CryoWebMixin, BaseMixin, TestCase):
162
    def test_check_country(self):
163
        """Test that all Cryoweb countries are defined in database"""
164
165
        countries_not_found = check_countries()
166
167
        self.assertEqual(countries_not_found, [])
168
169
        # remove a country from UID
170
        DictCountry.objects.filter(label="Germany").delete()
171
172
        countries_not_found = check_countries()
173
174
        self.assertEqual(countries_not_found, ['Germany'])
175
176
177
class CheckBreed(TestCase):
178
    # import this file and populate database once
179
    fixtures = [
180
        'image_app/dictbreed',
181
        'image_app/dictcountry',
182
        'image_app/dictrole',
183
        'image_app/dictsex',
184
        'image_app/dictspecie',
185
        'image_app/organization',
186
        'image_app/submission',
187
        'image_app/user',
188
    ]
189
190
    def test_add_breed(self):
191
        italy = DictCountry.objects.get(label="Italy")
192
        united_kingdom = DictCountry.objects.get(label="United Kingdom")
193
194
        sus = DictSpecie.objects.get(label="Sus scrofa")
195
196
        # inserting an already present breed get the object without creation
197
        breed, created = DictBreed.objects.get_or_create(
198
            supplied_breed="Bunte Bentheimer",
199
            specie=sus,
200
            country=united_kingdom)
201
202
        self.assertFalse(created)
203
204
        # inserting a breed in a different country add a record
205
        breed, created = DictBreed.objects.get_or_create(
206
            supplied_breed="Bunte Bentheimer",
207
            specie=sus,
208
            country=italy)
209
210
        self.assertTrue(created)
211
212
213
class CheckUIDTest(CryoWebMixin, BaseMixin, TestCase):
214
    def test_empty_dictsex(self):
215
        """Empty dictsex and check that I can't proceed"""
216
217
        queryset = DictSex.objects.all()
218
        queryset.delete()
219
220
        self.assertRaisesRegex(
221
            CryoWebImportError,
222
            "You have to upload DictSex data",
223
            check_UID, self.submission)
224
225
    def test_no_synonym(self):
226
        # now delete a synonym
227
        synonym = SpecieSynonym.objects.get(
228
            language__label='United Kingdom',
229
            word='Cattle')
230
        synonym.delete()
231
232
        self.assertRaisesRegex(
233
            CryoWebImportError,
234
            "Some species haven't a synonym!",
235
            check_UID, self.submission)
236
237
    def test_missing_country(self):
238
        # remove a country from UID
239
        DictCountry.objects.filter(label="Germany").delete()
240
241
        self.assertRaisesRegex(
242
            CryoWebImportError,
243
            "Not all countries are loaded into database:",
244
            check_UID, self.submission)
245
246
    def test_check_UID(self):
247
        """testing normal behaviour"""
248
249
        self.assertTrue(check_UID(self.submission))
250
251
252
class UploadCryoweb(
253
        WebSocketMixin, DataSourceMixinTestCase, BaseMixin, TestCase):
254
    """Test upload cryoweb dump into cryoweb database"""
255
256
    # need to clean database after testing import. Can't use CryowebMixin
257
    # since i need to test cryoweb import
258
    def tearDown(self):
259
        """Clean test database after modifications"""
260
261
        # truncate cryoweb database after loading
262
        if db_has_data():
263
            truncate_database()
264
265
        # calling my base class teardown class
266
        super().tearDown()
267
268
    def test_database_name(self):
269
        self.assertEqual(
270
            settings.DATABASES['cryoweb']['NAME'], 'test_cryoweb')
271
272
    def test_upload_cryoweb(self):
273
        """Testing uploading and importing data from cryoweb to UID"""
274
275
        self.assertTrue(upload_cryoweb(self.submission.id))
276
        self.assertTrue(db_has_data())
277
278
        # if I try again to upload cryoweb, I will get a False object and
279
        # submission message
280
        self.assertRaises(
281
            CryoWebImportError,
282
            upload_cryoweb,
283
            self.submission.id)
284
285
        # reload submission
286
        self.submission = Submission.objects.get(pk=1)
287
288
        self.assertEqual(
289
            self.submission.status,
290
            ERROR)
291
292
        self.assertIn(
293
            "Cryoweb has data",
294
            self.submission.message)
295
296
        # check async message called
297
        message = 'Error'
298
        notification_message = 'Error in importing data: Cryoweb has data'
299
300
        self.check_message(message, notification_message)
301
302
    # mock subprocess.run and raise Exception. Read it and update submission
303
    # message using helpers.upload_cryoweb
304
    def test_upload_cryoweb_errors(self):
305
        """Testing errors in uploading cryoweb data"""
306
307
        with patch('subprocess.run') as runMock:
308
            runMock.side_effect = Exception("Test upload failed")
309
            self.assertFalse(upload_cryoweb(self.submission.id))
310
311
            # reload submission
312
            self.submission = Submission.objects.get(pk=1)
313
314
            self.assertEqual(
315
                self.submission.status,
316
                ERROR)
317
318
            self.assertIn(
319
                "Test upload failed",
320
                self.submission.message)
321
322
            # check async message called
323
            message = 'Error'
324
            notification_message = ('Error in importing data: Test '
325
                                    'upload failed')
326
327
            self.check_message(message, notification_message)
328
329
330
class CryowebImport(ImportMixin, BaseMixin, TestCase):
331
    def test_database_name(self):
332
        self.assertEqual(
333
            settings.DATABASES['cryoweb']['NAME'], 'test_cryoweb')
334
335
    @patch("cryoweb.helpers.check_UID", side_effect=Exception("Test message"))
336
    def test_cryoweb_import_errors(self, my_check):
337
        """Testing importing with data into UID with errors"""
338
339
        self.assertFalse(cryoweb_import(self.submission))
340
        self.assertTrue(my_check.called)
341
342
        # reload submission
343
        self.submission = Submission.objects.get(pk=1)
344
345
        self.assertEqual(
346
            self.submission.status,
347
            ERROR)
348
349
        self.assertIn(
350
            "Test message",
351
            self.submission.message)
352
353
        # check async message called
354
        message = 'Error'
355
        notification_message = (
356
            'Error in importing data: Test message')
357
358
        self.check_message(message, notification_message)
359
360
361
class CryowebReload(ImportMixin, BaseMixin, TestCase):
362
    """Simulate a cryoweb reload case. Load data as in CryowebImport, then
363
    call test which reload the same data"""
364
365
    # override fixtures
366
    fixtures = [
367
        'cryoweb/auth',
368
        'cryoweb/dictbreed',
369
        'cryoweb/image_app',
370
        'language/dictspecie',
371
        'language/speciesynonym'
372
    ]
373