Completed
Pull Request — devel (#90)
by Paolo
06:31
created

SubmitRemovalTestCase.setUp()   A

Complexity

Conditions 1

Size

Total Lines 24
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 24
rs 9.85
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
        # assert exactly one sample associated with this submission
161
        self.assertEqual(submission.submission_data.count(), 1)
162
        self.assertEqual(sample, submission.submission_data.get())
163
164
        # This was supposed to have a problem in this tests
165
        sample = OrphanSample.objects.get(pk=2)
166
        self.assertEqual(sample.status, ERROR)
167
168
169
class FetchRemovalTestCase(CommandsMixin, BioSamplesMixin, TestCase):
170
    fixtures = [
171
        'biosample/managedteam',
172
        'biosample/orphansample',
173
        'biosample/orphansubmission',
174
        'uid/dictspecie',
175
    ]
176
177
    def setUp(self):
178
        # calling my base class setup
179
        super().setUp()
180
181
        # starting mocked objects
182
        self.mock_root_patcher = patch('pyUSIrest.usi.Root')
183
        self.mock_root = self.mock_root_patcher.start()
184
185
        # start root object
186
        self.my_root = self.mock_root.return_value
187
188
        # mocking a new submission
189
        self.submission = self.my_root.get_submission_by_name.return_value
190
        self.submission.name = "7dbb563e-c162-4df2-a48f-bbf5de8d1e35"
191
        self.submission.status = "Draft"
192
193
        # track a orphan submission
194
        self.orphan_submission_obj = OrphanSubmission.objects.get(pk=1)
195
        self.orphan_submission_obj.status = SUBMITTED
196
        self.orphan_submission_obj.save()
197
198
        # track submission in samples
199
        OrphanSample.objects.update(
200
            submission=self.orphan_submission_obj, status=SUBMITTED)
201
202
    def tearDown(self):
203
        self.mock_root_patcher.stop()
204
205
        super().tearDown()
206
207
    def common_tests(self, status=SUBMITTED, args=[]):
208
        """Assert stuff for each test"""
209
210
        # calling commands
211
        call_command('fetch_orphan_biosamples', *args)
212
213
        # UID submission status remain the same
214
        self.orphan_submission_obj.refresh_from_db()
215
        self.assertEqual(self.orphan_submission_obj.status, status)
216
217
        self.assertTrue(self.mock_auth.called)
218
        self.assertTrue(self.mock_root.called)
219
        self.assertTrue(self.my_root.get_submission_by_name.called)
220
221
    def test_fetch_orphan_biosamples_pending(self):
222
        """test fetch_orphan_biosamples command"""
223
224
        # update submission status
225
        self.submission.status = 'Draft'
226
        self.submission.has_errors.return_value = Counter({False: 2})
227
        self.submission.get_status.return_value = Counter({'Pending': 2})
228
229
        # asserting things
230
        self.common_tests()
231
232
        # testing a not finalized biosample condition
233
        self.assertFalse(self.submission.finalize.called)
234
235
    def test_fetch_orphan_biosamples_complete(self):
236
        """test fetch_orphan_biosamples command"""
237
238
        # update submission status
239
        self.submission.status = 'Draft'
240
        self.submission.has_errors.return_value = Counter({False: 2})
241
        self.submission.get_status.return_value = Counter({'Complete': 2})
242
243
        # asserting things
244
        self.common_tests(args=['--finalize'])
245
246
        # testing a not finalized biosample condition
247
        self.assertTrue(self.submission.finalize.called)
248
249
    def test_fetch_orphan_biosamples_complete_ignore(self):
250
        """test fetch_orphan_biosamples command"""
251
252
        # update submission status
253
        self.submission.status = 'Draft'
254
        self.submission.has_errors.return_value = Counter({False: 2})
255
        self.submission.get_status.return_value = Counter({'Complete': 2})
256
257
        # asserting things
258
        self.common_tests()
259
260
        # testing a not finalized biosample condition
261
        self.assertFalse(self.submission.finalize.called)
262
263
    def test_fetch_orphan_biosamples_errors(self):
264
        """test fetch_orphan_biosamples command with issues in USI"""
265
266
        # a draft submission with errors
267
        self.submission.status = 'Draft'
268
        self.submission.has_errors.return_value = Counter(
269
            {True: 1, False: 1})
270
        self.submission.get_status.return_value = Counter({'Complete': 2})
271
272
        # Add samples. Suppose that first failed, second is ok
273
        my_validation_result1 = Mock()
274
        my_validation_result1.errorMessages = {
275
            'Ena': [
276
                'a sample message',
277
            ]
278
        }
279
280
        my_sample1 = Mock()
281
        my_sample1.accession = "SAMEA6376980"
282
        my_sample1.alias = "IMAGEA000005611"
283
        my_sample1.name = "test-animal"
284
        my_sample1.has_errors.return_value = True
285
        my_sample1.get_validation_result.return_value = my_validation_result1
286
287
        # sample2 is ok
288
        my_validation_result2 = Mock()
289
        my_validation_result2.errorMessages = None
290
291
        my_sample2 = Mock()
292
        my_sample2.accession = "SAMEA6376982"
293
        my_sample2.alias = "IMAGES000006757"
294
        my_sample2.name = "test-sample"
295
        my_sample2.has_errors.return_value = False
296
        my_sample2.get_validation_result.return_value = my_validation_result2
297
298
        # simulate that IMAGEA000000001 has errors
299
        self.submission.get_samples.return_value = [my_sample1, my_sample2]
300
301
        # track other objects
302
        self.my_sample1 = my_sample1
303
        self.my_sample2 = my_sample2
304
305
        # asserting things
306
        self.common_tests(args=['--finalize'], status=NEED_REVISION)
307
308
        # testing a not finalized biosample condition
309
        self.assertFalse(self.submission.finalize.called)
310
311
        # assert custom mock attributes called
312
        self.assertTrue(self.my_sample1.has_errors.called)
313
        self.assertTrue(self.my_sample1.get_validation_result.called)
314
315
        # if sample has no errors, no all methods will be called
316
        self.assertTrue(self.my_sample2.has_errors.called)
317
        self.assertFalse(self.my_sample2.get_validation_result.called)
318
319
        # assert sample status in db.
320
        sample = OrphanSample.objects.get(pk=1)
321
        self.assertEqual(sample.status, SUBMITTED)
322
323
        # Same logic of FetchStatusHelper
324
        sample = OrphanSample.objects.get(pk=2)
325
        self.assertEqual(sample.status, NEED_REVISION)
326
327
    def test_fetch_orphan_complete(self):
328
        """Test fetch status for a complete submission"""
329
330
        # a completed submission with two samples
331
        self.submission.status = 'Completed'
332
333
        # Add samples
334
        my_sample1 = Mock()
335
        my_sample1.accession = "SAMEA6376980"
336
        my_sample1.alias = "IMAGEA000005611"
337
        my_sample1.name = "test-animal"
338
        my_sample2 = Mock()
339
        my_sample2.accession = "SAMEA6376982"
340
        my_sample2.alias = "IMAGES000006757"
341
        my_sample2.name = "test-sample"
342
        self.submission.get_samples.return_value = [my_sample1, my_sample2]
343
344
        # assert auth, root and get_submission by name called
345
        self.common_tests(status=COMPLETED)
346
347
        # assert sample status in db.
348
        count = OrphanSample.objects.filter(status=COMPLETED).count()
349
        self.assertEqual(count, 2)
350
351
        # assert that flag are changed
352
        count = OrphanSample.objects.filter(removed=True).count()
353
        self.assertEqual(count, 2)
354
355
    def test_fetch_status_no_accession(self):
356
        """Test fetch status for a submission which doens't send accession
357
        no updates in such case"""
358
359
        # a completed submission with two samples
360
        self.submission.status = 'Completed'
361
362
        # Add samples
363
        my_sample1 = Mock()
364
        my_sample1.name = "test-animal"
365
        my_sample1.alias = "IMAGEA000005611"
366
        my_sample1.accession = None
367
        my_sample2 = Mock()
368
        my_sample2.name = "test-sample"
369
        my_sample2.alias = "IMAGES000006757"
370
        my_sample2.accession = None
371
        self.submission.get_samples.return_value = [my_sample1, my_sample2]
372
373
        # assert auth, root and get_submission by name called
374
        self.common_tests()
375
376
        # assert sample status in db. Same logich of FetchStatusHelper
377
        count = OrphanSample.objects.filter(status=SUBMITTED).count()
378
        self.assertEqual(count, 2)
379
380
        # assert that flag are changed
381
        count = OrphanSample.objects.filter(removed=False).count()
382
        self.assertEqual(count, 2)
383