Switch to unified view

a b/qiita_db/test/test_analysis.py
1
from unittest import TestCase, main
2
from os import remove
3
from os.path import exists, join, basename
4
from shutil import move
5
6
from biom import load_table
7
from pandas.testing import assert_frame_equal
8
from functools import partial
9
10
from qiita_core.util import qiita_test_checker
11
from qiita_core.testing import wait_for_processing_job
12
from qiita_core.qiita_settings import qiita_config
13
import qiita_db as qdb
14
from json import dumps
15
16
# -----------------------------------------------------------------------------
17
# Copyright (c) 2014--, The Qiita Development Team.
18
#
19
# Distributed under the terms of the BSD 3-clause License.
20
#
21
# The full license is in the file LICENSE, distributed with this software.
22
# -----------------------------------------------------------------------------
23
24
25
class TestAnalysisIter(TestCase):
26
    def test_iter(self):
27
        obs = list(qdb.analysis.Analysis.iter())
28
        exp = [
29
            qdb.analysis.Analysis(1), qdb.analysis.Analysis(2),
30
            qdb.analysis.Analysis(3), qdb.analysis.Analysis(4),
31
            qdb.analysis.Analysis(5), qdb.analysis.Analysis(6)]
32
        self.assertCountEqual(obs, exp)
33
34
35
@qiita_test_checker()
36
class TestAnalysis(TestCase):
37
    def setUp(self):
38
        self.analysis = qdb.analysis.Analysis(1)
39
        self.portal = qiita_config.portal
40
        _, self.fp = qdb.util.get_mountpoint("analysis")[0]
41
42
        self.get_fp = partial(join, self.fp)
43
        self.biom_fp = self.get_fp("1_analysis_dt-18S_r-1_c-3.biom")
44
        self._old_portal = qiita_config.portal
45
        self.table_fp = None
46
47
        # fullpaths for testing
48
        self.duplicated_samples_not_merged = self.get_fp(
49
            "not_merged_samples.txt")
50
        self.map_exp_fp = self.get_fp("1_analysis_mapping_exp.txt")
51
52
        from glob import glob
53
        conf_files = glob(join(qiita_config.plugin_dir, "BIOM*.conf"))
54
        for i, fp in enumerate(conf_files):
55
            qdb.software.Software.from_file(fp, update=True)
56
57
    def tearDown(self):
58
        self.analysis.artifacts[0].visibility = 'private'
59
60
        qiita_config.portal = self.portal
61
        with open(self.biom_fp, 'w') as f:
62
            f.write("")
63
64
        fp = self.get_fp('testfile.txt')
65
        if exists(fp):
66
            remove(fp)
67
68
        if self.table_fp:
69
            mp = qdb.util.get_mountpoint("processed_data")[0][1]
70
            if exists(self.table_fp):
71
                move(self.table_fp,
72
                     join(mp, "2_study_1001_closed_reference_otu_table.biom"))
73
74
        qiita_config.portal = self._old_portal
75
76
    def _wait_for_jobs(self, analysis):
77
        for j in analysis.jobs:
78
            wait_for_processing_job(j.id)
79
            if j.status == 'error':
80
                print(j.log.msg)
81
82
    def _create_analyses_with_samples(self, user='demo@microbio.me',
83
                                      merge=False):
84
        """Aux function to create an analysis with samples
85
86
        Parameters
87
        ----------
88
        user : qiita_db.user.User, optional
89
            The user email to attach to the analysis. Default: demo@microbio.me
90
        merge : bool, optional
91
            Merge duplicated ids or not
92
93
        Returns
94
        -------
95
        qiita_db.analysis.Analysis
96
97
        Notes
98
        -----
99
        Replicates the samples contained in Analysis(1) at the moment of
100
        creation of this function (September 15, 2016)
101
        """
102
        user = qdb.user.User(user)
103
        dflt_analysis = user.default_analysis
104
105
        dflt_analysis.add_samples(
106
            {4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
107
                 '1.SKM9.640192', '1.SKM4.640180']})
108
109
        new = qdb.analysis.Analysis.create(
110
            user, "newAnalysis", "A New Analysis", from_default=True,
111
            merge_duplicated_sample_ids=merge)
112
113
        self._wait_for_jobs(new)
114
115
        return new
116
117
    def test_lock_samples(self):
118
        dflt = qdb.user.User('demo@microbio.me').default_analysis
119
        # The default analysis can have samples added/removed
120
        dflt._lock_samples()
121
122
        QE = qdb.exceptions
123
        with self.assertRaises(QE.QiitaDBOperationNotPermittedError):
124
            qdb.analysis.Analysis(1)._lock_samples()
125
126
    def test_get_by_status(self):
127
        qiita_config.portal = 'QIITA'
128
        self.assertEqual(
129
            qdb.analysis.Analysis.get_by_status('public'), set([]))
130
        qiita_config.portal = 'EMP'
131
        self.assertEqual(
132
            qdb.analysis.Analysis.get_by_status('public'), set([]))
133
134
        qiita_config.portal = 'QIITA'
135
        self.analysis.artifacts[0].visibility = 'public'
136
137
        self.assertEqual(qdb.analysis.Analysis.get_by_status('public'),
138
                         {self.analysis})
139
        qiita_config.portal = 'EMP'
140
        self.assertEqual(
141
            qdb.analysis.Analysis.get_by_status('public'), set([]))
142
143
    def test_can_be_publicized(self):
144
        analysis = qdb.analysis.Analysis(1)
145
        self.assertEqual(analysis.can_be_publicized, (False, [4, 5, 6]))
146
        a4 = qdb.artifact.Artifact(4)
147
148
        a4.visibility = 'public'
149
        self.assertEqual(analysis.can_be_publicized, (True, []))
150
151
        a4.visibility = 'private'
152
        self.assertEqual(analysis.can_be_publicized, (False, [4, 5, 6]))
153
154
    def test_add_artifact(self):
155
        obs = self._create_analyses_with_samples()
156
        exp = qdb.artifact.Artifact(4)
157
        obs.add_artifact(exp)
158
        self.assertIn(exp, obs.artifacts)
159
160
    def test_has_access_public(self):
161
        analysis = self._create_analyses_with_samples("admin@foo.bar")
162
        analysis.artifacts[0].visibility = 'public'
163
164
        qiita_config.portal = 'QIITA'
165
        self.assertTrue(
166
            analysis.has_access(qdb.user.User("demo@microbio.me")))
167
        qiita_config.portal = 'EMP'
168
        self.assertFalse(
169
            analysis.has_access(qdb.user.User("demo@microbio.me")))
170
171
    def test_has_access_shared(self):
172
        self.assertTrue(
173
            self.analysis.has_access(qdb.user.User("shared@foo.bar")))
174
175
    def test_has_access_private(self):
176
        self.assertTrue(
177
            self.analysis.has_access(qdb.user.User("test@foo.bar")))
178
179
    def test_has_access_admin(self):
180
        qiita_config.portal = 'QIITA'
181
        self.assertTrue(
182
            self.analysis.has_access(qdb.user.User("admin@foo.bar")))
183
        qiita_config.portal = 'EMP'
184
        with self.assertRaises(qdb.exceptions.QiitaDBError):
185
            qdb.analysis.Analysis(1).has_access(qdb.user.User("admin@foo.bar"))
186
187
    def test_has_access_no_access(self):
188
        self.assertFalse(
189
            self.analysis.has_access(qdb.user.User("demo@microbio.me")))
190
191
    def test_can_edit(self):
192
        a = qdb.analysis.Analysis(1)
193
        self.assertTrue(a.can_edit(qdb.user.User('test@foo.bar')))
194
        self.assertTrue(a.can_edit(qdb.user.User('shared@foo.bar')))
195
        self.assertTrue(a.can_edit(qdb.user.User('admin@foo.bar')))
196
        self.assertFalse(a.can_edit(qdb.user.User('demo@microbio.me')))
197
198
    def test_create_nonqiita_portal(self):
199
        qiita_config.portal = "EMP"
200
        obs = qdb.analysis.Analysis.create(
201
            qdb.user.User("admin@foo.bar"), "newAnalysis", "A New Analysis")
202
203
        # make sure portal is associated
204
        self.assertCountEqual(obs._portals, ["QIITA", "EMP"])
205
206
    def test_create_from_default(self):
207
        with qdb.sql_connection.TRN:
208
            sql = "SELECT NOW()"
209
            qdb.sql_connection.TRN.add(sql)
210
            time1 = qdb.sql_connection.TRN.execute_fetchlast()
211
212
        owner = qdb.user.User("test@foo.bar")
213
        obs = qdb.analysis.Analysis.create(
214
            owner, "newAnalysis", "A New Analysis", from_default=True)
215
216
        self.assertEqual(obs.owner, owner)
217
        self.assertEqual(obs.name, "newAnalysis")
218
        self.assertEqual(obs._portals, ["QIITA"])
219
        self.assertLess(time1, obs.timestamp)
220
        self.assertEqual(obs.description, "A New Analysis")
221
        self.assertCountEqual(obs.samples, [4])
222
        self.assertCountEqual(
223
            obs.samples[4], ['1.SKD8.640184', '1.SKB7.640196',
224
                             '1.SKM9.640192', '1.SKM4.640180'])
225
        self.assertEqual(obs.data_types, ['18S'])
226
        self.assertEqual(obs.shared_with, [])
227
        self.assertEqual(obs.mapping_file, None)
228
        self.assertEqual(obs.tgz, None)
229
        self.assertNotEqual(obs.jobs, [])
230
        self.assertEqual(obs.pmid, None)
231
232
    def test_exists(self):
233
        qiita_config.portal = 'QIITA'
234
        self.assertTrue(qdb.analysis.Analysis.exists(1))
235
        self.assertFalse(qdb.analysis.Analysis.exists(1000))
236
        qiita_config.portal = 'EMP'
237
        self.assertFalse(qdb.analysis.Analysis.exists(1))
238
        self.assertFalse(qdb.analysis.Analysis.exists(1000))
239
240
    def test_delete(self):
241
        # successful delete
242
        new = qdb.analysis.Analysis.create(
243
            qdb.user.User('demo@microbio.me'), "newAnalysis",
244
            "A New Analysis")
245
        self.assertTrue(qdb.analysis.Analysis.exists(new.id))
246
        qdb.analysis.Analysis.delete(new.id)
247
        self.assertFalse(qdb.analysis.Analysis.exists(new.id))
248
249
        # no possible to delete
250
        QE = qdb.exceptions
251
        with self.assertRaises(QE.QiitaDBUnknownIDError):
252
            qdb.analysis.Analysis.delete(new.id)
253
254
        # Analysis with artifacts
255
        with self.assertRaises(QE.QiitaDBOperationNotPermittedError):
256
            qdb.analysis.Analysis.delete(1)
257
258
    def test_retrieve_owner(self):
259
        self.assertEqual(self.analysis.owner, qdb.user.User("test@foo.bar"))
260
261
    def test_retrieve_name(self):
262
        self.assertEqual(self.analysis.name, "SomeAnalysis")
263
264
    def test_retrieve_description(self):
265
        self.assertEqual(self.analysis.description, "A test analysis")
266
267
    def test_set_description(self):
268
        self.analysis.description = "New description"
269
        self.assertEqual(self.analysis.description, "New description")
270
271
    def test_retrieve_samples(self):
272
        exp = {4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
273
                   '1.SKM9.640192', '1.SKM4.640180'],
274
               5: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
275
                   '1.SKM9.640192', '1.SKM4.640180'],
276
               6: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
277
                   '1.SKM9.640192', '1.SKM4.640180']}
278
        self.assertCountEqual(self.analysis.samples, exp)
279
280
    def test_retrieve_portal(self):
281
        self.assertEqual(self.analysis._portals, ["QIITA"])
282
283
    def test_retrieve_data_types(self):
284
        exp = ['18S', '16S']
285
        self.assertCountEqual(self.analysis.data_types, exp)
286
287
    def test_retrieve_shared_with(self):
288
        self.assertEqual(self.analysis.shared_with,
289
                         [qdb.user.User("shared@foo.bar")])
290
291
    def test_retrieve_jobs(self):
292
        self.assertEqual(self.analysis.jobs, [])
293
294
    def test_retrieve_pmid(self):
295
        self.assertEqual(self.analysis.pmid, "121112")
296
297
    def test_set_pmid(self):
298
        new = self._create_analyses_with_samples("admin@foo.bar")
299
        self.assertIsNone(new.pmid)
300
        new.pmid = "11211221212213"
301
        self.assertEqual(new.pmid, "11211221212213")
302
303
    def test_retrieve_mapping_file(self):
304
        exp = join(self.fp, "1_analysis_mapping.txt")
305
        obs = self.analysis.mapping_file
306
        self.assertIsNotNone(obs)
307
        self.assertEqual(
308
            qdb.util.get_filepath_information(obs)['fullpath'], exp)
309
        self.assertTrue(exists(exp))
310
311
    def test_metadata_categories(self):
312
        exp = {1: {
313
            'sample': {
314
                'env_package', 'water_content_soil', 'collection_timestamp',
315
                'anonymized_name', 'sample_type', 'env_biome', 'host_taxid',
316
                'ph', 'env_feature', 'temp', 'country', 'scientific_name',
317
                'assigned_from_geo', 'physical_specimen_location',
318
                'common_name', 'longitude', 'depth', 'season_environment',
319
                'description', 'tot_org_carb', 'tot_nitro', 'dna_extracted',
320
                'texture', 'samp_salinity', 'taxon_id', 'host_subject_id',
321
                'description_duplicate', 'latitude',
322
                'physical_specimen_remaining', 'altitude', 'elevation'},
323
            'prep': {
324
                'run_prefix', 'platform', 'study_center',
325
                'library_construction_protocol', 'emp_status',
326
                'target_subfragment', 'target_gene', 'center_project_name',
327
                'illumina_technology', 'experiment_title', 'instrument_model',
328
                'run_date', 'run_center', 'pcr_primers', 'sequencing_meth',
329
                'experiment_center', 'experiment_design_description',
330
                'barcode', 'samp_size', 'sample_center', 'primer',
331
                'center_name'}}}
332
        obs = self.analysis.metadata_categories
333
        self.assertDictEqual(obs, exp)
334
335
    def test_retrieve_tgz(self):
336
        # generating here as the tgz is only generated once the analysis runs
337
        # to completion (un)successfully
338
        analysis = self._create_analyses_with_samples("admin@foo.bar")
339
        fp = self.get_fp('test.tgz')
340
        with open(fp, 'w') as f:
341
            f.write('')
342
        analysis._add_file(fp, 'tgz')
343
        self.assertEqual(analysis.tgz, fp)
344
345
    def test_retrieve_tgz_none(self):
346
        self.assertIsNone(self.analysis.tgz)
347
348
    def test_summary_data(self):
349
        obs = self.analysis.summary_data()
350
        exp = {'studies': 1,
351
               'artifacts': 3,
352
               'samples': 5}
353
        self.assertEqual(obs, exp)
354
355
    def test_add_remove_samples(self):
356
        analysis = qdb.user.User('shared@foo.bar').default_analysis
357
        exp = {4: ['1.SKD8.640184', '1.SKB7.640196', '1.SKM9.640192',
358
                   '1.SKM4.640180', '1.SKB8.640193'],
359
               5: ['1.SKD8.640184', '1.SKB7.640196', '1.SKM9.640192',
360
                   '1.SKM4.640180', '1.SKB8.640193'],
361
               6: ['1.SKD8.640184', '1.SKB7.640196', '1.SKM9.640192',
362
                   '1.SKM4.640180', '1.SKB8.640193']}
363
        analysis.add_samples(exp)
364
        obs = analysis.samples
365
        self.assertCountEqual(list(obs.keys()), exp.keys())
366
        for k in obs:
367
            self.assertCountEqual(obs[k], exp[k])
368
369
        analysis.remove_samples(artifacts=(qdb.artifact.Artifact(4), ),
370
                                samples=('1.SKB8.640193', ))
371
        exp = {4: ['1.SKD8.640184', '1.SKB7.640196', '1.SKM9.640192',
372
                   '1.SKM4.640180'],
373
               5: ['1.SKD8.640184', '1.SKB7.640196', '1.SKM9.640192',
374
                   '1.SKM4.640180', '1.SKB8.640193'],
375
               6: ['1.SKD8.640184', '1.SKB7.640196', '1.SKM9.640192',
376
                   '1.SKM4.640180', '1.SKB8.640193']}
377
        obs = analysis.samples
378
        self.assertCountEqual(list(obs.keys()), exp.keys())
379
        for k in obs:
380
            self.assertCountEqual(obs[k], exp[k])
381
382
        analysis.remove_samples(samples=('1.SKD8.640184', ))
383
        exp = {4: ['1.SKB7.640196', '1.SKM9.640192', '1.SKM4.640180'],
384
               5: ['1.SKB8.640193', '1.SKB7.640196', '1.SKM9.640192',
385
                   '1.SKM4.640180'],
386
               6: ['1.SKB8.640193', '1.SKB7.640196', '1.SKM9.640192',
387
                   '1.SKM4.640180']}
388
        self.assertCountEqual(analysis.samples, exp)
389
390
        analysis.remove_samples(
391
            artifacts=(qdb.artifact.Artifact(4), qdb.artifact.Artifact(5)))
392
        exp = {6: {'1.SKB7.640196', '1.SKB8.640193',
393
                   '1.SKM4.640180', '1.SKM9.640192'}}
394
        self.assertCountEqual(analysis.samples, exp)
395
396
    def test_share_unshare(self):
397
        analysis = self._create_analyses_with_samples()
398
        user = qdb.user.User("admin@foo.bar")
399
        self.assertEqual(analysis.shared_with, [])
400
        analysis.share(user)
401
        exp = [user]
402
        self.assertEqual(analysis.shared_with, exp)
403
        analysis.unshare(user)
404
        self.assertEqual(analysis.shared_with, [])
405
406
    def test_build_mapping_file(self):
407
        analysis = self._create_analyses_with_samples()
408
        samples = {4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196']}
409
410
        analysis._build_mapping_file(samples)
411
        obs = qdb.util.get_filepath_information(
412
            analysis.mapping_file)['fullpath']
413
414
        exp = self.get_fp("%s_analysis_mapping.txt" % analysis.id)
415
        self.assertEqual(obs, exp)
416
417
        obs = qdb.metadata_template.util.load_template_to_dataframe(
418
            obs, index='#SampleID')
419
        exp = qdb.metadata_template.util.load_template_to_dataframe(
420
            self.map_exp_fp, index='#SampleID')
421
422
        # assert_frame_equal assumes same order on the rows, thus sorting
423
        # frames by index
424
        obs.sort_index(inplace=True)
425
        exp.sort_index(inplace=True)
426
        # then sorting columns
427
        obs = obs.reindex(sorted(obs.columns), axis=1)
428
        exp = exp.reindex(sorted(exp.columns), axis=1)
429
430
        assert_frame_equal(obs, exp, check_like=True)
431
432
        # testing categories
433
        analysis._build_mapping_file(
434
            samples, categories=set(
435
                ['env_package', 'experiment_design_description']))
436
        obs = qdb.util.get_filepath_information(
437
            analysis.mapping_file)['fullpath']
438
        obs = qdb.metadata_template.util.load_template_to_dataframe(
439
            obs, index='#SampleID').columns
440
        exp = ['experiment_design_description', 'env_package',
441
               'qiita_artifact_id', 'qiita_prep_deprecated',
442
               'qiita_study_title', 'qiita_study_alias', 'qiita_owner',
443
               'qiita_principal_investigator']
444
        self.assertCountEqual(obs, exp)
445
446
    def test_build_mapping_file_duplicated_samples_no_merge(self):
447
        analysis = self._create_analyses_with_samples()
448
        samples = {4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'],
449
                   3: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196']}
450
        analysis._build_mapping_file(samples, True)
451
452
        mapping_fp = qdb.util.get_filepath_information(
453
            analysis.mapping_file)['fullpath']
454
        obs = qdb.metadata_template.util.load_template_to_dataframe(
455
            mapping_fp, index='#SampleID')
456
        exp = qdb.metadata_template.util.load_template_to_dataframe(
457
            self.duplicated_samples_not_merged, index='#SampleID')
458
459
        # assert_frame_equal assumes same order on the rows, thus sorting
460
        # frames by index
461
        obs.sort_index(inplace=True)
462
        exp.sort_index(inplace=True)
463
        # then sorting columns
464
        obs = obs.reindex(sorted(obs.columns), axis=1)
465
        exp = exp.reindex(sorted(exp.columns), axis=1)
466
467
        assert_frame_equal(obs, exp, check_like=True)
468
469
    def test_build_mapping_file_duplicated_samples_merge(self):
470
        analysis = self._create_analyses_with_samples()
471
        samples = {4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'],
472
                   3: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196']}
473
        analysis._build_mapping_file(samples)
474
        mapping_fp = qdb.util.get_filepath_information(
475
            analysis.mapping_file)['fullpath']
476
        obs = qdb.metadata_template.util.load_template_to_dataframe(
477
            mapping_fp, index='#SampleID')
478
        exp = qdb.metadata_template.util.load_template_to_dataframe(
479
            self.map_exp_fp, index='#SampleID')
480
481
        # assert_frame_equal assumes same order on the rows, thus sorting
482
        # frames by index
483
        obs.sort_index(inplace=True)
484
        exp.sort_index(inplace=True)
485
        # then sorting columns
486
        obs = obs.reindex(sorted(obs.columns), axis=1)
487
        exp = exp.reindex(sorted(exp.columns), axis=1)
488
489
        assert_frame_equal(obs, exp, check_like=True)
490
491
    def test_build_biom_tables(self):
492
        analysis = self._create_analyses_with_samples()
493
        grouped_samples = {
494
            '18S || algorithm': [
495
                (4, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'])]}
496
        obs_bioms = analysis._build_biom_tables(grouped_samples)
497
        biom_fp = self.get_fp(
498
            "%s_analysis_18S_algorithm.biom" % analysis.id)
499
        obs = [(a, basename(b)) for a, b, _ in obs_bioms]
500
        self.assertEqual(obs, [('18S', basename(biom_fp))])
501
502
        table = load_table(obs_bioms[0][1])
503
        obs = set(table.ids(axis='sample'))
504
        exp = {'1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'}
505
        self.assertEqual(obs, exp)
506
507
    def test_build_biom_tables_with_references(self):
508
        analysis = self._create_analyses_with_samples()
509
        analysis_id = analysis.id
510
        grouped_samples = {
511
            ('18S || Pick closed-reference OTUs (reference: 1) | '
512
             'Split libraries FASTQ'): [
513
                (4, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196']),
514
                (5, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'])],
515
            ('18S || Pick closed-reference OTUs (reference: 1) | '
516
             'Trim (lenght: 150)'): [
517
                (4, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196']),
518
                (5, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'])],
519
            ('16S || Pick closed-reference OTUs (reference: 2) | '
520
             'Trim (lenght: 100)'): [
521
                (4, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196']),
522
                (5, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'])]}
523
        obs_bioms = analysis._build_biom_tables(grouped_samples)
524
        obs = [(a, basename(b)) for a, b, _ in obs_bioms]
525
        exp = [
526
            ('16S', '%s_analysis_16S_PickclosedreferenceOTUsreference2'
527
             'Trimlenght100.biom' % analysis_id),
528
            ('18S', '%s_analysis_18S_PickclosedreferenceOTUsreference1'
529
             'SplitlibrariesFASTQ.biom' % analysis_id),
530
            ('18S', '%s_analysis_18S_PickclosedreferenceOTUsreference1'
531
             'Trimlenght150.biom' % analysis_id)]
532
        self.assertCountEqual(obs, exp)
533
534
        exp = {'1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'}
535
        for dt, fp, _ in obs_bioms:
536
            table = load_table(fp)
537
            obs = set(table.ids(axis='sample'))
538
            self.assertEqual(obs, exp)
539
540
    def test_build_biom_tables_duplicated_samples_not_merge(self):
541
        analysis = self._create_analyses_with_samples()
542
        grouped_samples = {
543
            '18S || algorithm': [
544
                (4, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196']),
545
                (5, ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196'])]}
546
        obs_bioms = analysis._build_biom_tables(grouped_samples, True)
547
        obs = [(a, basename(b)) for a, b, _ in obs_bioms]
548
        biom_fp = (
549
            "%s_analysis_18S_algorithm.biom" % analysis.id)
550
        self.assertEqual(obs, [('18S', biom_fp)])
551
552
        table = load_table(obs_bioms[0][1])
553
        obs = set(table.ids(axis='sample'))
554
        exp = {'4.1.SKD8.640184', '4.1.SKB7.640196', '4.1.SKB8.640193',
555
               '5.1.SKB8.640193', '5.1.SKB7.640196', '5.1.SKD8.640184'}
556
        self.assertCountEqual(obs, exp)
557
558
    def test_build_biom_tables_raise_error_due_to_sample_selection(self):
559
        grouped_samples = {
560
            '18S || algorithm': [
561
                (4, ['sample_name_1', 'sample_name_2', 'sample_name_3'])]}
562
        with self.assertRaises(RuntimeError):
563
            self.analysis._build_biom_tables(grouped_samples)
564
565
    def test_build_files(self):
566
        analysis = self._create_analyses_with_samples()
567
        biom_tables = analysis.build_files(True)
568
569
        # testing that the generated files have the same sample ids
570
        biom_fp = biom_tables[0][1]
571
        biom_ids = load_table(biom_fp).ids(axis='sample')
572
        mapping_fp = qdb.util.get_filepath_information(
573
            analysis.mapping_file)['fullpath']
574
        mf_ids = qdb.metadata_template.util.load_template_to_dataframe(
575
            mapping_fp, index='#SampleID').index
576
577
        self.assertCountEqual(biom_ids, mf_ids)
578
579
        # now that the samples have been prefixed
580
        exp = ['1.SKM9.640192', '1.SKM4.640180', '1.SKD8.640184',
581
               '1.SKB8.640193', '1.SKB7.640196']
582
        self.assertCountEqual(biom_ids, exp)
583
584
    def test_build_files_post_processing_cmd(self):
585
        tmp = qdb.artifact.Artifact(4).processing_parameters.command
586
        cmd_id = tmp.id
587
588
        # set a known artifact's additional processing command
589
        # to a known value. Then test for it.
590
        # qiita_db/test/support_files/worker.py will work w/py2.7 & 3.6 envs.
591
        results = {}
592
        results['script_env'] = 'source deactivate; source activate qiita;'
593
        results['script_path'] = 'qiita_db/test/support_files/worker.py'
594
        # no additional parameters are needed for worker.py
595
        # fp_biom and fp_archive will be generated by build_files()
596
        results['script_params'] = {}
597
598
        # convert to json representation and store in PostgreSQL
599
        results = dumps(results)
600
601
        sql = """UPDATE qiita.software_command
602
                 SET post_processing_cmd = %s
603
                 WHERE command_id = %s"""
604
        qdb.sql_connection.perform_as_transaction(sql, [results, cmd_id])
605
606
        # create a sample analysis and run build_files on it.
607
        analysis = self._create_analyses_with_samples()
608
        biom_files = analysis.build_files(False)
609
610
        # if build_files used additional processing commands, it will
611
        # return a couple of tuples, where the third element contains
612
        # output archive-artifact data.
613
        self.assertEqual(2, len(biom_files))
614
        aid = analysis.id
615
        exp = [('%d_analysis_18S_PickclosedreferenceOTUsSplitlibraries'
616
                'FASTQ.biom' % aid, None),
617
               ('%d_analysis_18S_PickclosedreferenceOTUsSplitlibraries'
618
                'FASTQ.biom' % aid, 'archive_%d.tre' % aid)]
619
        obs = [(basename(fp1),
620
                basename(fp2) if fp2 is not None else None)
621
               for _, fp1, fp2 in biom_files]
622
        self.assertEqual(obs, exp)
623
624
        # cleanup (assume command was NULL previously)
625
        sql = """UPDATE qiita.software_command
626
                 SET post_processing_cmd = NULL
627
                 WHERE command_id = %s"""
628
        qdb.sql_connection.perform_as_transaction(sql, [cmd_id])
629
630
    def test_build_files_merge_duplicated_sample_ids(self):
631
        user = qdb.user.User("demo@microbio.me")
632
        dflt_analysis = user.default_analysis
633
        dflt_analysis.add_samples(
634
            {4: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
635
                 '1.SKM9.640192', '1.SKM4.640180'],
636
             5: ['1.SKB8.640193', '1.SKB7.640196', '1.SKM9.640192',
637
                 '1.SKM4.640180', '1.SKD8.640184'],
638
             6: ['1.SKB8.640193', '1.SKD8.640184', '1.SKB7.640196',
639
                 '1.SKM9.640192', '1.SKM4.640180']})
640
        new = qdb.analysis.Analysis.create(
641
            user, "newAnalysis", "A New Analysis", from_default=True,
642
            merge_duplicated_sample_ids=True)
643
644
        self._wait_for_jobs(new)
645
646
        biom_tables = new.build_files(False)
647
648
        # testing that the generated files have the same sample ids
649
        biom_ids = []
650
        for _, fp, _ in biom_tables:
651
            biom_ids.extend(load_table(fp).ids(axis='sample'))
652
653
        mapping_fp = qdb.util.get_filepath_information(
654
            new.mapping_file)['fullpath']
655
        mf_ids = qdb.metadata_template.util.load_template_to_dataframe(
656
            mapping_fp, index='#SampleID').index
657
658
        self.assertCountEqual(biom_ids, mf_ids)
659
660
        # now that the samples have been prefixed
661
        exp = ['4.1.SKM9.640192', '4.1.SKM4.640180', '4.1.SKD8.640184',
662
               '4.1.SKB8.640193', '4.1.SKB7.640196',
663
               '5.1.SKM9.640192', '5.1.SKM4.640180', '5.1.SKD8.640184',
664
               '5.1.SKB8.640193', '5.1.SKB7.640196',
665
               '6.1.SKM9.640192', '6.1.SKM4.640180', '6.1.SKD8.640184',
666
               '6.1.SKB8.640193', '6.1.SKB7.640196']
667
        self.assertCountEqual(biom_ids, exp)
668
669
    def test_add_file(self):
670
        # Tested indirectly through build_files
671
        pass
672
673
    def test_is_public_make_public(self):
674
        analysis = self._create_analyses_with_samples()
675
        self.assertFalse(analysis.is_public)
676
677
        # testing errors
678
        with self.assertRaises(ValueError):
679
            analysis.make_public()
680
681
        # testing successfully making public
682
        # 4 is the only artifact being used in _create_analyses_with_samples
683
        qdb.artifact.Artifact(4).visibility = 'public'
684
        analysis.make_public()
685
686
        self.assertTrue(analysis.is_public)
687
688
    def test_slurm_reservation(self):
689
        analysis = qdb.analysis.Analysis(1)
690
        self.assertIsNone(analysis.slurm_reservation)
691
        text = 'thisisatest'
692
        analysis.slurm_reservation = text
693
        self.assertEqual(analysis._slurm_reservation(), [text])
694
        self.assertIsNone(analysis.slurm_reservation)
695
696
697
if __name__ == "__main__":
698
    main()