Passed
Pull Request — devel (#90)
by Paolo
06:14
created

CommandsMixin.tearDownClass()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
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 Mon Jan 21 14:30:04 2019
5
6
@author: Paolo Cozzi <[email protected]>
7
"""
8
9
import io
10
import json
11
from collections import Counter
12
13
from pyUSIrest.auth import Auth
14
from pyUSIrest.usi import Sample
15
from pyUSIrest.exceptions import USIDataError
16
17
from unittest.mock import patch, PropertyMock, Mock
18
19
from django.core.management import call_command
20
from django.test import TestCase
21
22
from common.constants import SUBMITTED, NEED_REVISION, ERROR, COMPLETED
23
24
from ..models import ManagedTeam, OrphanSubmission, OrphanSample
25
26
from .common import BaseMixin, generate_token, BioSamplesMixin
27
28
29
class CommandsMixin():
30
    @classmethod
31
    def setUpClass(cls):
32
        # calling my base class setup
33
        super().setUpClass()
34
35
        # starting mocked objects
36
        cls.mock_auth_patcher = patch('biosample.helpers.get_manager_auth')
37
        cls.mock_auth = cls.mock_auth_patcher.start()
38
39
    @classmethod
40
    def tearDownClass(cls):
41
        cls.mock_auth_patcher.stop()
42
43
        # calling base method
44
        super().tearDownClass()
45
46
47
class CommandsTestCase(CommandsMixin, BaseMixin, TestCase):
48
    @patch('biosample.helpers.get_manager_auth')
49
    def test_fill_managed(self, my_auth):
50
        """test fill_managed command"""
51
52
        # remove a managed team
53
        managed = ManagedTeam.objects.get(pk=2)
54
        managed.delete()
55
56
        # patch get_manager_auth value
57
        my_auth.return_value = Auth(
58
            token=generate_token(
59
                domains=[
60
                    'subs.test-team-1',
61
                    'subs.test-team-2',
62
                    'subs.test-team-3']
63
            )
64
        )
65
66
        # calling commands
67
        call_command('fill_managed')
68
69
        # get all managedteams object
70
        self.assertEqual(ManagedTeam.objects.count(), 3)
71
        self.assertTrue(my_auth.called)
72
73
    def test_get_json_for_biosample(self):
74
75
        args = ["--submission", 1]
76
77
        # https://stackoverflow.com/questions/4219717/how-to-assert-output-with-nosetest-unittest-in-python
78
        with patch('sys.stdout', new_callable=io.StringIO) as handle:
79
            call_command('get_json_for_biosample', *args)
80
            handle.seek(0)
81
82
            data = json.load(handle)
83
            self.assertIsInstance(data, dict)
84
85
86
class SubmitRemovalTestCase(CommandsMixin, BioSamplesMixin, TestCase):
87
    fixtures = [
88
        'biosample/managedteam',
89
        'biosample/orphansample',
90
        'uid/dictspecie',
91
    ]
92
93
    def setUp(self):
94
        # calling my base class setup
95
        super().setUp()
96
97
        # starting mocked objects
98
        self.mock_root_patcher = patch('pyUSIrest.usi.Root')
99
        self.mock_root = self.mock_root_patcher.start()
100
101
        # start root object
102
        self.my_root = self.mock_root.return_value
103
104
        # mocking chain
105
        self.my_team = self.my_root.get_team_by_name.return_value
106
        self.my_team.name = "subs.test-team-1"
107
108
        # mocking a new submission
109
        self.new_submission = self.my_team.create_submission.return_value
110
        self.new_submission.name = "new-submission"
111
112
        # set status. Because of the way mock attributes are stored you can’t
113
        # directly attach a PropertyMock to a mock object. Instead you can
114
        # attach it to the mock type object:
115
        self.new_submission.propertymock = PropertyMock(return_value='Draft')
116
        type(self.new_submission).status = self.new_submission.propertymock
117
118
    def tearDown(self):
119
        self.mock_root_patcher.stop()
120
121
        super().tearDown()
122
123
    @patch('biosample.helpers.get_manager_auth')
124
    def test_patch_orphan_biosamples(self, my_auth):
125
        """test patch_orphan_biosamples command"""
126
127
        # patch get_manager_auth value
128
        my_auth.return_value = Auth(
129
            token=generate_token()
130
        )
131
132
        # mocking sample creation: two objects: one submitted, one not
133
        self.new_submission.create_sample.side_effect = [
134
            Sample(auth=generate_token()),
135
            USIDataError("test")
136
        ]
137
138
        # calling commands
139
        call_command('patch_orphan_biosamples')
140
141
        # assert a submission created
142
        self.assertTrue(my_auth.called)
143
        self.assertTrue(self.my_team.create_submission.called)
144
        self.assertTrue(self.new_submission.create_sample.called)
145
146
        # check for an object into database
147
        submissions = OrphanSubmission.objects.all()
148
        self.assertEqual(len(submissions), 1)
149
150
        # test submission attributes
151
        submission = submissions[0]
152
        self.assertEqual(submission.usi_submission_name, "new-submission")
153
        self.assertEqual(submission.samples_count, 1)
154
        self.assertEqual(submission.status, SUBMITTED)
155
156
        # assert sample status
157
        sample = OrphanSample.objects.get(pk=1)
158
        self.assertEqual(sample.status, SUBMITTED)
159
160
        # This was supposed to have a problem in this tests
161
        sample = OrphanSample.objects.get(pk=2)
162
        self.assertEqual(sample.status, ERROR)
163
164
165
class FetchRemovalTestCase(CommandsMixin, BioSamplesMixin, TestCase):
166
    fixtures = [
167
        'biosample/managedteam',
168
        'biosample/orphansample',
169
        'biosample/orphansubmission',
170
        'uid/dictspecie',
171
    ]
172
173
    def setUp(self):
174
        # calling my base class setup
175
        super().setUp()
176
177
        # starting mocked objects
178
        self.mock_root_patcher = patch('pyUSIrest.usi.Root')
179
        self.mock_root = self.mock_root_patcher.start()
180
181
        # start root object
182
        self.my_root = self.mock_root.return_value
183
184
        # mocking a new submission
185
        self.submission = self.my_root.get_submission_by_name.return_value
186
        self.submission.name = "7dbb563e-c162-4df2-a48f-bbf5de8d1e35"
187
        self.submission.status = "Draft"
188
189
        # track a orphan submission
190
        self.orphan_submission_obj = OrphanSubmission.objects.get(pk=1)
191
        self.orphan_submission_obj.status = SUBMITTED
192
        self.orphan_submission_obj.save()
193
194
        # track submission in samples
195
        OrphanSample.objects.update(
196
            submission=self.orphan_submission_obj, status=SUBMITTED)
197
198
    def tearDown(self):
199
        self.mock_root_patcher.stop()
200
201
        super().tearDown()
202
203
    def common_tests(self, status=SUBMITTED, args=[]):
204
        """Assert stuff for each test"""
205
206
        # calling commands
207
        call_command('fetch_orphan_biosamples', *args)
208
209
        # UID submission status remain the same
210
        self.orphan_submission_obj.refresh_from_db()
211
        self.assertEqual(self.orphan_submission_obj.status, status)
212
213
        self.assertTrue(self.mock_auth.called)
214
        self.assertTrue(self.mock_root.called)
215
        self.assertTrue(self.my_root.get_submission_by_name.called)
216
217
    def test_fetch_orphan_biosamples_pending(self):
218
        """test fetch_orphan_biosamples command"""
219
220
        # update submission status
221
        self.submission.status = 'Draft'
222
        self.submission.has_errors.return_value = Counter({False: 2})
223
        self.submission.get_status.return_value = Counter({'Pending': 2})
224
225
        # asserting things
226
        self.common_tests()
227
228
        # testing a not finalized biosample condition
229
        self.assertFalse(self.submission.finalize.called)
230
231
    def test_fetch_orphan_biosamples_complete(self):
232
        """test fetch_orphan_biosamples command"""
233
234
        # update submission status
235
        self.submission.status = 'Draft'
236
        self.submission.has_errors.return_value = Counter({False: 2})
237
        self.submission.get_status.return_value = Counter({'Complete': 2})
238
239
        # asserting things
240
        self.common_tests(args=['--finalize'])
241
242
        # testing a not finalized biosample condition
243
        self.assertTrue(self.submission.finalize.called)
244
245
    def test_fetch_orphan_biosamples_complete_ignore(self):
246
        """test fetch_orphan_biosamples command"""
247
248
        # update submission status
249
        self.submission.status = 'Draft'
250
        self.submission.has_errors.return_value = Counter({False: 2})
251
        self.submission.get_status.return_value = Counter({'Complete': 2})
252
253
        # asserting things
254
        self.common_tests()
255
256
        # testing a not finalized biosample condition
257
        self.assertFalse(self.submission.finalize.called)
258
259
    def test_fetch_orphan_biosamples_errors(self):
260
        """test fetch_orphan_biosamples command with issues in USI"""
261
262
        # a draft submission with errors
263
        self.submission.status = 'Draft'
264
        self.submission.has_errors.return_value = Counter(
265
            {True: 1, False: 1})
266
        self.submission.get_status.return_value = Counter({'Complete': 2})
267
268
        # Add samples. Suppose that first failed, second is ok
269
        my_validation_result1 = Mock()
270
        my_validation_result1.errorMessages = {
271
            'Ena': [
272
                'a sample message',
273
            ]
274
        }
275
276
        my_sample1 = Mock()
277
        my_sample1.accession = "SAMEA6376980"
278
        my_sample1.alias = "IMAGEA000005611"
279
        my_sample1.name = "test-animal"
280
        my_sample1.has_errors.return_value = True
281
        my_sample1.get_validation_result.return_value = my_validation_result1
282
283
        # sample2 is ok
284
        my_validation_result2 = Mock()
285
        my_validation_result2.errorMessages = None
286
287
        my_sample2 = Mock()
288
        my_sample2.accession = "SAMEA6376982"
289
        my_sample2.alias = "IMAGES000006757"
290
        my_sample2.name = "test-sample"
291
        my_sample2.has_errors.return_value = False
292
        my_sample2.get_validation_result.return_value = my_validation_result2
293
294
        # simulate that IMAGEA000000001 has errors
295
        self.submission.get_samples.return_value = [my_sample1, my_sample2]
296
297
        # track other objects
298
        self.my_sample1 = my_sample1
299
        self.my_sample2 = my_sample2
300
301
        # asserting things
302
        self.common_tests(args=['--finalize'], status=NEED_REVISION)
303
304
        # testing a not finalized biosample condition
305
        self.assertFalse(self.submission.finalize.called)
306
307
        # assert custom mock attributes called
308
        self.assertTrue(self.my_sample1.has_errors.called)
309
        self.assertTrue(self.my_sample1.get_validation_result.called)
310
311
        # if sample has no errors, no all methods will be called
312
        self.assertTrue(self.my_sample2.has_errors.called)
313
        self.assertFalse(self.my_sample2.get_validation_result.called)
314
315
        # assert sample status in db.
316
        sample = OrphanSample.objects.get(pk=1)
317
        self.assertEqual(sample.status, SUBMITTED)
318
319
        # Same logic of FetchStatusHelper
320
        sample = OrphanSample.objects.get(pk=2)
321
        self.assertEqual(sample.status, NEED_REVISION)
322
323
    def test_fetch_orphan_complete(self):
324
        """Test fetch status for a complete submission"""
325
326
        # a completed submission with two samples
327
        self.submission.status = 'Completed'
328
329
        # Add samples
330
        my_sample1 = Mock()
331
        my_sample1.accession = "SAMEA6376980"
332
        my_sample1.alias = "IMAGEA000005611"
333
        my_sample1.name = "test-animal"
334
        my_sample2 = Mock()
335
        my_sample2.accession = "SAMEA6376982"
336
        my_sample2.alias = "IMAGES000006757"
337
        my_sample2.name = "test-sample"
338
        self.submission.get_samples.return_value = [my_sample1, my_sample2]
339
340
        # assert auth, root and get_submission by name called
341
        self.common_tests(status=COMPLETED)
342
343
        # assert sample status in db.
344
        count = OrphanSample.objects.filter(status=COMPLETED).count()
345
        self.assertEqual(count, 2)
346
347
        # assert that flag are changed
348
        count = OrphanSample.objects.filter(removed=True).count()
349
        self.assertEqual(count, 2)
350
351
    def test_fetch_status_no_accession(self):
352
        """Test fetch status for a submission which doens't send accession
353
        no updates in such case"""
354
355
        # a completed submission with two samples
356
        self.submission.status = 'Completed'
357
358
        # Add samples
359
        my_sample1 = Mock()
360
        my_sample1.name = "test-animal"
361
        my_sample1.alias = "IMAGEA000005611"
362
        my_sample1.accession = None
363
        my_sample2 = Mock()
364
        my_sample2.name = "test-sample"
365
        my_sample2.alias = "IMAGES000006757"
366
        my_sample2.accession = None
367
        self.submission.get_samples.return_value = [my_sample1, my_sample2]
368
369
        # assert auth, root and get_submission by name called
370
        self.common_tests()
371
372
        # assert sample status in db. Same logich of FetchStatusHelper
373
        count = OrphanSample.objects.filter(status=SUBMITTED).count()
374
        self.assertEqual(count, 2)
375
376
        # assert that flag are changed
377
        count = OrphanSample.objects.filter(removed=False).count()
378
        self.assertEqual(count, 2)
379