Mercurial > repos > dcouvin > resfinder4
comparison resfinder/tests/functional_tests.py @ 0:55051a9bc58d draft default tip
Uploaded
| author | dcouvin |
|---|---|
| date | Mon, 10 Jan 2022 20:06:07 +0000 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:55051a9bc58d |
|---|---|
| 1 #!/usr/bin/env python3 | |
| 2 import unittest | |
| 3 from subprocess import PIPE, run | |
| 4 import os | |
| 5 import shutil | |
| 6 import sys | |
| 7 import argparse | |
| 8 | |
| 9 | |
| 10 # This is not best practice but for testing, this is the best I could | |
| 11 # come up with | |
| 12 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) | |
| 13 | |
| 14 # TODO: Species specific aqquired genes only pheno results, not spec specific? | |
| 15 | |
| 16 test_names = ["test1", "test2", "test3", "test4"] | |
| 17 test_data = { | |
| 18 # Test published acquired resistance | |
| 19 test_names[0]: "data/test_isolate_01.fa", | |
| 20 test_names[1]: "data/test_isolate_01_1.fq data/test_isolate_01_2.fq", | |
| 21 # Test published point mut resistance | |
| 22 test_names[2]: "data/test_isolate_05.fa", | |
| 23 test_names[3]: "data/test_isolate_05_1.fq data/test_isolate_05_2.fq", | |
| 24 } | |
| 25 run_test_dir = "running_test" | |
| 26 working_dir = os.path.dirname(os.path.realpath(__file__)) | |
| 27 | |
| 28 | |
| 29 class ResFinderRunTest(unittest.TestCase): | |
| 30 | |
| 31 @classmethod | |
| 32 def setUpClass(cls): | |
| 33 # Delete "running_test" folder from previous tests if still exists | |
| 34 if os.path.isdir(run_test_dir): | |
| 35 try: | |
| 36 shutil.rmtree(run_test_dir) | |
| 37 # The following error has occured using VirtualBox under Windows 10 | |
| 38 # with ResFinder installed in a shared folder: | |
| 39 # OSError [Errno: 26] Text file busy: 'tmp' | |
| 40 except OSError: | |
| 41 procs = run(["rm", "-r", run_test_dir]) | |
| 42 | |
| 43 # Set absolute path for database folders and external programs | |
| 44 cls.db_path_res = os.path.abspath(args.db_path_res) | |
| 45 cls.blastPath = os.path.abspath(args.blast_path) | |
| 46 cls.kmaPath = os.path.abspath(args.kma_path) | |
| 47 cls.db_path_point = os.path.abspath(args.db_path_point) | |
| 48 cls.dir_res = os.path.join(os.path.dirname(__file__), '../', ) | |
| 49 cls.dir_res = os.path.abspath(cls.dir_res) | |
| 50 # Change working dir to test dir | |
| 51 os.chdir(working_dir) | |
| 52 # Does not allow running two tests in parallel | |
| 53 os.makedirs(run_test_dir, exist_ok=False) | |
| 54 | |
| 55 @classmethod | |
| 56 def tearDownClass(cls): | |
| 57 try: | |
| 58 shutil.rmtree(run_test_dir) | |
| 59 # The following error has occured using VirtualBox under Windows 10 | |
| 60 # with ResFinder installed in a shared folder: | |
| 61 # OSError [Errno: 26] Text file busy: 'tmp' | |
| 62 except OSError: | |
| 63 procs = run(["rm", "-r", run_test_dir]) | |
| 64 | |
| 65 def test_on_data_with_just_acquired_resgene_using_blast(self): | |
| 66 # Maria has an E. coli isolate, with unknown resistance. | |
| 67 # At first, she just wants to know which acquired resistance genes are | |
| 68 # found in the genome. | |
| 69 # She therefore runs resfinder cmd line. | |
| 70 | |
| 71 # First Maria checks out the documentation. | |
| 72 procs = run("python3 ../run_resfinder.py -h", shell=True, stdout=PIPE, | |
| 73 check=True) | |
| 74 output = procs.stdout.decode() | |
| 75 self.assertIn("--help", output) | |
| 76 | |
| 77 # Maria goes on to run ResFinder for acquired genes with her E. coli | |
| 78 # isolate. | |
| 79 # First she creates a few directories to store her output. | |
| 80 test1_dir = run_test_dir + "/" + test_names[0] | |
| 81 os.makedirs(test1_dir) | |
| 82 # Then she runs run_resfinder with her first isolate. | |
| 83 cmd_acquired = ("python3 " + self.dir_res + "/run_resfinder.py" | |
| 84 + " -ifa " + test_data[test_names[0]] | |
| 85 + " -o " + test1_dir | |
| 86 + " -s 'Escherichia coli'" | |
| 87 + " --min_cov 0.6" | |
| 88 + " -t 0.8" | |
| 89 + " --acquired" | |
| 90 + " --db_path_res " + self.db_path_res | |
| 91 + " --blastPath " + self.blastPath) | |
| 92 | |
| 93 procs = run(cmd_acquired, shell=True, stdout=PIPE, stderr=PIPE, | |
| 94 check=True) | |
| 95 | |
| 96 fsa_hit = test1_dir + "/ResFinder_Hit_in_genome_seq.fsa" | |
| 97 fsa_res = test1_dir + "/ResFinder_Resistance_gene_seq.fsa" | |
| 98 res_table = test1_dir + "/ResFinder_results_table.txt" | |
| 99 res_tab = test1_dir + "/ResFinder_results_tab.txt" | |
| 100 results = test1_dir + "/ResFinder_results.txt" | |
| 101 | |
| 102 with open(fsa_hit, "r") as fh: | |
| 103 check_result = fh.readline() | |
| 104 self.assertIn("blaB-2_1_AF189300", check_result) | |
| 105 | |
| 106 with open(fsa_res, "r") as fh: | |
| 107 check_result = fh.readline() | |
| 108 self.assertIn("blaB-2_AF189300", check_result) | |
| 109 | |
| 110 with open(res_table, "r") as fh: | |
| 111 for line in fh: | |
| 112 if(line.startswith("blaB-2")): | |
| 113 check_result = line | |
| 114 break | |
| 115 self.assertIn("blaB-2_1_AF189300", check_result) | |
| 116 | |
| 117 with open(res_tab, "r") as fh: | |
| 118 fh.readline() | |
| 119 check_result = fh.readline() | |
| 120 self.assertIn("blaB-2_1_AF189300", check_result) | |
| 121 | |
| 122 with open(results, "r") as fh: | |
| 123 fh.readline() | |
| 124 fh.readline() | |
| 125 fh.readline() | |
| 126 fh.readline() | |
| 127 fh.readline() | |
| 128 check_result = fh.readline() | |
| 129 self.assertIn("blaB-2_1_AF189300", check_result) | |
| 130 | |
| 131 def test_on_data_with_just_acquired_resgene_using_kma(self): | |
| 132 # Maria has another E. coli isolate, with unknown resistance. | |
| 133 # This time she does not have an assembly, but only raw data. | |
| 134 # She therefore runs resfinder cmd line using KMA. | |
| 135 | |
| 136 # First she creates a few directories to store her output. | |
| 137 test2_dir = run_test_dir + "/" + test_names[1] | |
| 138 os.makedirs(test2_dir, exist_ok=False) | |
| 139 | |
| 140 # Then she runs run_resfinder with her first isolate. | |
| 141 cmd_acquired = ("python3 " + self.dir_res + "/run_resfinder.py" | |
| 142 + " -ifq " + test_data[test_names[1]] | |
| 143 + " -o " + test2_dir | |
| 144 + " -s 'Escherichia coli'" | |
| 145 + " --min_cov 0.6" | |
| 146 + " -t 0.8" | |
| 147 + " --acquired" | |
| 148 + " --db_path_res " + self.db_path_res | |
| 149 + " --kmaPath " + self.kmaPath) | |
| 150 | |
| 151 procs = run(cmd_acquired, shell=True, stdout=PIPE, stderr=PIPE, | |
| 152 check=True) | |
| 153 | |
| 154 fsa_hit = test2_dir + "/ResFinder_Hit_in_genome_seq.fsa" | |
| 155 fsa_res = test2_dir + "/ResFinder_Resistance_gene_seq.fsa" | |
| 156 res_table = test2_dir + "/ResFinder_results_table.txt" | |
| 157 res_tab = test2_dir + "/ResFinder_results_tab.txt" | |
| 158 results = test2_dir + "/ResFinder_results.txt" | |
| 159 | |
| 160 with open(fsa_hit, "r") as fh: | |
| 161 check_result = fh.readline() | |
| 162 self.assertIn("blaB-2", check_result) | |
| 163 | |
| 164 with open(fsa_res, "r") as fh: | |
| 165 check_result = fh.readline() | |
| 166 self.assertIn("blaB-2_AF189300", check_result) | |
| 167 | |
| 168 with open(res_table, "r") as fh: | |
| 169 for line in fh: | |
| 170 if(line.startswith("blaB-2")): | |
| 171 check_result = line | |
| 172 break | |
| 173 self.assertIn("blaB-2", check_result) | |
| 174 | |
| 175 with open(res_tab, "r") as fh: | |
| 176 fh.readline() | |
| 177 check_result = fh.readline() | |
| 178 self.assertIn("blaB-2", check_result) | |
| 179 | |
| 180 with open(results, "r") as fh: | |
| 181 fh.readline() | |
| 182 fh.readline() | |
| 183 fh.readline() | |
| 184 fh.readline() | |
| 185 fh.readline() | |
| 186 check_result = fh.readline() | |
| 187 self.assertIn("blaB-2", check_result) | |
| 188 | |
| 189 def test_on_data_with_just_point_mut_using_blast(self): | |
| 190 # Maria also wants to check her assembled E. coli isolate for | |
| 191 # resistance caused by point mutations. | |
| 192 | |
| 193 # First she creates a few directories to store her output. | |
| 194 test3_dir = run_test_dir + "/" + test_names[2] | |
| 195 os.makedirs(test3_dir) | |
| 196 | |
| 197 # Then she runs run_resfinder with her first isolate. | |
| 198 cmd_point = ("python3 " + self.dir_res + "/run_resfinder.py" | |
| 199 + " -ifa " + test_data[test_names[2]] | |
| 200 + " -o " + test3_dir | |
| 201 + " -s 'Escherichia coli'" | |
| 202 + " --min_cov 0.6" | |
| 203 + " --threshold 0.8" | |
| 204 + " --point" | |
| 205 + " --db_path_point " + self.db_path_point | |
| 206 + " --db_path_res " + self.db_path_res | |
| 207 + " --blastPath " + self.blastPath) | |
| 208 | |
| 209 procs = run(cmd_point, shell=True, stdout=PIPE, stderr=PIPE, | |
| 210 check=True) | |
| 211 | |
| 212 # Expected output files | |
| 213 pf_pred = test3_dir + "/PointFinder_prediction.txt" | |
| 214 pf_res = test3_dir + "/PointFinder_results.txt" | |
| 215 pf_table = test3_dir + "/PointFinder_table.txt" | |
| 216 | |
| 217 with open(pf_res, "r") as fh: | |
| 218 fh.readline() | |
| 219 check_result = fh.readline() | |
| 220 self.assertIn("gyrA", check_result) | |
| 221 self.assertIn("p.S83A", check_result) | |
| 222 | |
| 223 point_mut_found = False | |
| 224 with open(pf_table, "r") as fh: | |
| 225 for line in fh: | |
| 226 if(line.startswith("gyrA p.S83A")): | |
| 227 check_result = line | |
| 228 point_mut_found = True | |
| 229 break | |
| 230 self.assertEqual(point_mut_found, True) | |
| 231 | |
| 232 def test_on_data_with_just_point_mut_using_kma(self): | |
| 233 # Maria has another E. coli isolate, with unknown resistance. | |
| 234 # This time she does not have an assembly, but only raw data. | |
| 235 # She therefore runs resfinder cmd line using KMA. | |
| 236 | |
| 237 # First she creates a few directories to store her output. | |
| 238 test4_dir = run_test_dir + "/" + test_names[3] | |
| 239 os.makedirs(test4_dir, exist_ok=False) | |
| 240 | |
| 241 # Then she runs run_resfinder with her first isolate. | |
| 242 cmd_acquired = ("python3 " + self.dir_res + "/run_resfinder.py" | |
| 243 + " -ifq " + test_data[test_names[3]] | |
| 244 + " -o " + test4_dir | |
| 245 + " -s 'Escherichia coli'" | |
| 246 + " --min_cov 0.6" | |
| 247 + " --threshold 0.8" | |
| 248 + " --point" | |
| 249 + " --db_path_point " + self.db_path_point | |
| 250 + " --db_path_res " + self.db_path_res | |
| 251 + " --kmaPath " + self.kmaPath) | |
| 252 | |
| 253 procs = run(cmd_acquired, shell=True, stdout=PIPE, stderr=PIPE, | |
| 254 check=True) | |
| 255 | |
| 256 # Expected output files | |
| 257 pf_pred = test4_dir + "/PointFinder_prediction.txt" | |
| 258 pf_res = test4_dir + "/PointFinder_results.txt" | |
| 259 pf_table = test4_dir + "/PointFinder_table.txt" | |
| 260 | |
| 261 with open(pf_res, "r") as fh: | |
| 262 fh.readline() | |
| 263 check_result = fh.readline() | |
| 264 self.assertIn("gyrA", check_result) | |
| 265 self.assertIn("p.S83A", check_result) | |
| 266 | |
| 267 point_mut_found = False | |
| 268 with open(pf_table, "r") as fh: | |
| 269 for line in fh: | |
| 270 if(line.startswith("gyrA p.S83A")): | |
| 271 check_result = line | |
| 272 point_mut_found = True | |
| 273 break | |
| 274 self.assertEqual(point_mut_found, True) | |
| 275 | |
| 276 | |
| 277 def parse_args(): | |
| 278 parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False) | |
| 279 group = parser.add_argument_group("Options") | |
| 280 group.add_argument('-res_help', "--resfinder_help", | |
| 281 action="help") | |
| 282 group.add_argument("-db_res", "--db_path_res", | |
| 283 help="Path to the databases for ResFinder", | |
| 284 default="./db_resfinder") | |
| 285 group.add_argument("-b", "--blastPath", | |
| 286 dest="blast_path", | |
| 287 help="Path to blastn", | |
| 288 default="./cge/blastn") | |
| 289 group.add_argument("-k", "--kmaPath", | |
| 290 dest="kma_path", | |
| 291 help="Path to KMA", | |
| 292 default="./cge/kma/kma") | |
| 293 group.add_argument("-db_point", "--db_path_point", | |
| 294 help="Path to the databases for PointFinder", | |
| 295 default="./db_pointfinder") | |
| 296 ns, args = parser.parse_known_args(namespace=unittest) | |
| 297 return ns, sys.argv[:1] + args | |
| 298 | |
| 299 if __name__ == "__main__": | |
| 300 args, argv = parse_args() # run this first | |
| 301 sys.argv[:] = argv # create cleans argv for main() | |
| 302 unittest.main() |
