--- a +++ b/qiita_pet/test/test_software.py @@ -0,0 +1,254 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2014--, The Qiita Development Team. +# +# Distributed under the terms of the BSD 3-clause License. +# +# The full license is in the file LICENSE, distributed with this software. +# ----------------------------------------------------------------------------- + +from unittest import main +from qiita_pet.test.tornado_test_base import TestHandlerBase + +from mock import Mock +from copy import deepcopy + +from qiita_db.sql_connection import TRN +from qiita_db.user import User +from qiita_db.software import DefaultWorkflow +from qiita_db.sql_connection import perform_as_transaction +from qiita_pet.handlers.base_handlers import BaseHandler +from qiita_pet.handlers.software import _retrive_workflows + + +class TestSoftware(TestHandlerBase): + def test_get(self): + response = self.get('/software/') + self.assertEqual(response.code, 200) + body = response.body.decode('ascii') + self.assertNotEqual(body, "") + # checking that this software is not displayed + self.assertNotIn('Target Gene', body) + + BaseHandler.get_current_user = Mock(return_value=User("admin@foo.bar")) + response = self.get('/software/') + self.assertEqual(response.code, 200) + body = response.body.decode('ascii') + self.assertNotEqual(body, "") + # checking that this software is displayed + self.assertIn('Target Gene', body) + + +class TestWorkflowsHandler(TestHandlerBase): + def test_get(self): + DefaultWorkflow(2).active = False + response = self.get('/workflows/') + self.assertEqual(response.code, 200) + body = response.body.decode('ascii') + self.assertNotEqual(body, "") + # checking that this software is not displayed + self.assertNotIn('FASTA upstream workflow', body) + + BaseHandler.get_current_user = Mock(return_value=User("admin@foo.bar")) + response = self.get('/workflows/') + self.assertEqual(response.code, 200) + body = response.body.decode('ascii') + self.assertNotEqual(body, "") + # checking that this software is displayed + self.assertIn('FASTA upstream workflow', body) + DefaultWorkflow(2).active = True + + def test_retrive_workflows(self): + # we should see all 3 workflows + DefaultWorkflow(2).active = False + exp = deepcopy(WORKFLOWS) + self.assertCountEqual(_retrive_workflows(False), exp) + + # validating that the params_name is not being used + self.assertNotIn( + 'Split libraries | Defaults with Golay 12 barcodes', + [x[2] for x in _retrive_workflows(False)[1]['nodes']]) + # now it should be there + with TRN: + # Hard-coded values; 19 -> barcode_type + sql = """UPDATE qiita.command_parameter + SET name_order = 0 + WHERE command_parameter_id = 19""" + TRN.add(sql) + TRN.execute() + self.assertIn( + 'Split libraries | Defaults with Golay 12 barcodes', + [x[2] for x in _retrive_workflows(False)[1]['nodes']]) + # and gone again + with TRN: + sql = """UPDATE qiita.command_parameter + SET name_order = NULL + WHERE command_parameter_id = 19""" + TRN.add(sql) + TRN.execute() + self.assertNotIn( + 'Split libraries | Defaults with Golay 12 barcodes', + [x[2] for x in _retrive_workflows(False)[1]['nodes']]) + + # we should not see the middle one + del exp[1] + self.assertCountEqual(_retrive_workflows(True), exp) + + # let's create a couple of more complex scenarios so we touch all code + # by adding multiple paths, that should connect and get separate + # -- adds a new path that should be kept separate all the way; this is + # to emulate what happens with different trimming (different + # default parameter) and deblur (same for each of the previous + # steps) + sql = """ + INSERT INTO qiita.default_workflow_node ( + default_workflow_id, default_parameter_set_id) + VALUES (1, 2), (1, 10); + INSERT INTO qiita.default_workflow_edge ( + parent_id, child_id) + VALUES (7, 8); + INSERT INTO qiita.default_workflow_edge_connections ( + default_workflow_edge_id, parent_output_id, child_input_id) + VALUES (4, 1, 3)""" + perform_as_transaction(sql) + # -- adds a new path that should be kept together and then separate; + # this is to simulate what happens with MTX/WGS processing, one + # single QC step (together) and 2 separete profilers + sql = """ + INSERT INTO qiita.default_parameter_set ( + command_id, parameter_set_name, parameter_set) + VALUES (3, '100%', + ('{"reference":1,"sortmerna_e_value":1,' + || '"sortmerna_max_pos":' + || '10000,"similarity":1.0,"sortmerna_coverage":1.00,' + || '"threads":1}')::json); + INSERT INTO qiita.default_workflow_node ( + default_workflow_id, default_parameter_set_id) + VALUES (2, 17); + INSERT INTO qiita.default_workflow_edge ( + parent_id, child_id) + VALUES (3, 9); + INSERT INTO qiita.default_workflow_edge_connections ( + default_workflow_edge_id, parent_output_id, child_input_id) + VALUES (5, 1, 3)""" + perform_as_transaction(sql) + + # adding new expected values + exp = deepcopy(WORKFLOWS) + obs = _retrive_workflows(False) + exp[0]['nodes'].extend([ + ['params_7', 1, 'Split libraries FASTQ', 'Defaults with reverse ' + 'complement mapping file barcodes', { + 'max_bad_run_length': '3', + 'min_per_read_length_fraction': '0.75', + 'sequence_max_n': '0', 'rev_comp_barcode': 'False', + 'rev_comp_mapping_barcodes': 'True', 'rev_comp': 'False', + 'phred_quality_threshold': '3', 'barcode_type': 'golay_12', + 'max_barcode_errors': '1.5', 'phred_offset': 'auto'}], + ['input_params_7_FASTQ | per_sample_FASTQ', 1, + 'FASTQ | per_sample_FASTQ'], + ['output_params_7_demultiplexed | Demultiplexed', 1, + 'demultiplexed | Demultiplexed'], + ['params_8', 3, 'Pick closed-reference OTUs', 'Defaults', { + 'reference': '1', 'sortmerna_e_value': '1', + 'sortmerna_max_pos': '10000', 'similarity': '0.97', + 'sortmerna_coverage': '0.97', 'threads': '1'}], + ['output_params_8_OTU table | BIOM', 3, 'OTU table | BIOM']]) + exp[0]['edges'].extend([ + ['input_params_7_FASTQ | per_sample_FASTQ', 'params_7'], + ['params_7', 'output_params_7_demultiplexed | Demultiplexed'], + ['output_params_7_demultiplexed | Demultiplexed', 'params_8'], + ['params_8', 'output_params_8_OTU table | BIOM']]) + exp[1]['nodes'].extend([ + ['params_9', 3, 'Pick closed-reference OTUs', '100%', { + 'reference': '1', 'sortmerna_e_value': '1', + 'sortmerna_max_pos': '10000', 'similarity': '1.0', + 'sortmerna_coverage': '1.0', 'threads': '1'}], + ['output_params_9_OTU table | BIOM', 3, 'OTU table | BIOM']]) + exp[1]['edges'].extend([ + ['output_params_3_demultiplexed | Demultiplexed', 'params_9'], + ['params_9', 'output_params_9_OTU table | BIOM'] + ]) + self.assertCountEqual(obs, exp) + + +WORKFLOWS = [ + {'name': 'FASTQ upstream workflow', 'id': 1, 'data_types': ['16S', '18S'], + 'description': 'This accepts html <a href="https://qiita.ucsd.edu">Qiita!' + '</a><br/><br/><b>BYE!</b>', + 'active': True, 'parameters_sample': {}, 'parameters_prep': {}, + 'nodes': [ + ['params_1', 1, 'Split libraries FASTQ', 'Defaults', { + 'max_bad_run_length': '3', 'min_per_read_length_fraction': '0.75', + 'sequence_max_n': '0', 'rev_comp_barcode': 'False', + 'rev_comp_mapping_barcodes': 'False', 'rev_comp': 'False', + 'phred_quality_threshold': '3', 'barcode_type': 'golay_12', + 'max_barcode_errors': '1.5', 'phred_offset': 'auto'}], + ['input_params_1_FASTQ', 1, + 'FASTQ'], + ['output_params_1_demultiplexed | Demultiplexed', 1, + 'demultiplexed | Demultiplexed'], + ['params_2', 3, 'Pick closed-reference OTUs', 'Defaults', { + 'reference': '1', 'sortmerna_e_value': '1', + 'sortmerna_max_pos': '10000', 'similarity': '0.97', + 'sortmerna_coverage': '0.97', 'threads': '1'}], + ['output_params_2_OTU table | BIOM', 3, 'OTU table | BIOM']], + 'edges': [ + ['input_params_1_FASTQ', 'params_1'], + ['params_1', 'output_params_1_demultiplexed | Demultiplexed'], + ['output_params_1_demultiplexed | Demultiplexed', 'params_2'], + ['params_2', 'output_params_2_OTU table | BIOM']]}, + {'name': 'FASTA upstream workflow', 'id': 2, 'data_types': ['18S'], + 'description': 'This is another description', + 'active': False, 'parameters_sample': {}, 'parameters_prep': {}, + 'nodes': [ + ['params_3', 2, 'Split libraries', 'Defaults with Golay 12 barcodes', { + 'min_seq_len': '200', 'max_seq_len': '1000', + 'trim_seq_length': 'False', 'min_qual_score': '25', + 'max_ambig': '6', 'max_homopolymer': '6', + 'max_primer_mismatch': '0', 'barcode_type': 'golay_12', + 'max_barcode_errors': '1.5', 'disable_bc_correction': 'False', + 'qual_score_window': '0', 'disable_primers': 'False', + 'reverse_primers': 'disable', 'reverse_primer_mismatches': '0', + 'truncate_ambi_bases': 'False'}], + ['input_params_3_** WARNING, NOT DEFINED **', 2, + '** WARNING, NOT DEFINED **'], + ['output_params_3_demultiplexed | Demultiplexed', 2, + 'demultiplexed | Demultiplexed'], + ['params_4', 3, 'Pick closed-reference OTUs', 'Defaults', { + 'reference': '1', 'sortmerna_e_value': '1', + 'sortmerna_max_pos': '10000', 'similarity': '0.97', + 'sortmerna_coverage': '0.97', 'threads': '1'}], + ['output_params_4_OTU table | BIOM', 3, 'OTU table | BIOM']], + 'edges': [ + ['input_params_3_** WARNING, NOT DEFINED **', 'params_3'], + ['params_3', 'output_params_3_demultiplexed | Demultiplexed'], + ['output_params_3_demultiplexed | Demultiplexed', 'params_4'], + ['params_4', 'output_params_4_OTU table | BIOM']]}, + {'name': 'Per sample FASTQ upstream workflow', 'id': 3, + 'data_types': ['ITS'], 'description': None, + 'active': True, 'parameters_sample': {}, 'parameters_prep': {}, + 'nodes': [ + ['params_5', 1, 'Split libraries FASTQ', 'per sample FASTQ defaults', { + 'max_bad_run_length': '3', 'min_per_read_length_fraction': '0.75', + 'sequence_max_n': '0', 'rev_comp_barcode': 'False', + 'rev_comp_mapping_barcodes': 'False', 'rev_comp': 'False', + 'phred_quality_threshold': '3', 'barcode_type': 'not-barcoded', + 'max_barcode_errors': '1.5', 'phred_offset': 'auto'}], + ['input_params_5_FASTQ', 1, + 'FASTQ'], + ['output_params_5_demultiplexed | Demultiplexed', 1, + 'demultiplexed | Demultiplexed'], + ['params_6', 3, 'Pick closed-reference OTUs', 'Defaults', { + 'reference': '1', 'sortmerna_e_value': '1', + 'sortmerna_max_pos': '10000', 'similarity': '0.97', + 'sortmerna_coverage': '0.97', 'threads': '1'}], + ['output_params_6_OTU table | BIOM', 3, 'OTU table | BIOM']], + 'edges': [ + ['input_params_5_FASTQ', 'params_5'], + ['params_5', 'output_params_5_demultiplexed | Demultiplexed'], + ['output_params_5_demultiplexed | Demultiplexed', 'params_6'], + ['params_6', 'output_params_6_OTU table | BIOM']]}] + + +if __name__ == "__main__": + main()