|
24 | 24 |
|
25 | 25 | import os |
26 | 26 | import shutil |
| 27 | +import signal |
27 | 28 | import subprocess |
28 | 29 | import sys |
29 | 30 | import tempfile |
@@ -171,14 +172,21 @@ def test_malformed_fastq(self): |
171 | 172 | class TestInvalidParameterErrors(unittest.TestCase): |
172 | 173 | """Test that invalid parameter errors return exit code 67.""" |
173 | 174 |
|
| 175 | + def setUp(self): |
| 176 | + self.temp_dir = tempfile.mkdtemp() |
| 177 | + |
| 178 | + def tearDown(self): |
| 179 | + shutil.rmtree(self.temp_dir, ignore_errors=True) |
| 180 | + |
174 | 181 | def test_kmercount_invalid_kmer(self): |
175 | 182 | """spades-kmercount with invalid k-mer should exit with error.""" |
176 | | - # Using an even k-mer value which is invalid |
| 183 | + # Using an even k-mer value which is invalid. |
| 184 | + # Run in temp_dir so kmer_splitter_*/kmer_counter_* dirs are created there and cleaned up. |
177 | 185 | cmd = [os.path.join(BIN_DIR, "spades-kmercount"), |
178 | 186 | "-k", "32", # Even k is invalid |
179 | | - "-o", "/tmp/test_out", |
| 187 | + "-o", os.path.join(self.temp_dir, "test_out"), |
180 | 188 | "/nonexistent/reads.fastq"] |
181 | | - exit_code, stdout, stderr = run_command(cmd) |
| 189 | + exit_code, stdout, stderr = run_command(cmd, cwd=self.temp_dir) |
182 | 190 | # Should fail with parameter error (67) or file not found (65) |
183 | 191 | self.assertNotEqual(exit_code, 0, |
184 | 192 | f"Expected error, but command succeeded\nstdout: {stdout}") |
@@ -325,8 +333,24 @@ def tearDown(self): |
325 | 333 | shutil.rmtree(self.tmp, ignore_errors=True) |
326 | 334 |
|
327 | 335 | def _run(self, args, timeout=60): |
| 336 | + """Run spades.py in its own process group so all children can be killed on timeout.""" |
328 | 337 | cmd = [sys.executable, SPADES_PY] + args |
329 | | - return run_command(cmd, timeout=timeout, cwd=self.tmp) |
| 338 | + try: |
| 339 | + proc = subprocess.Popen( |
| 340 | + cmd, |
| 341 | + stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
| 342 | + text=True, |
| 343 | + start_new_session=True # new process group → kill whole tree on timeout |
| 344 | + ) |
| 345 | + try: |
| 346 | + stdout, stderr = proc.communicate(timeout=timeout) |
| 347 | + return proc.returncode, stdout, stderr |
| 348 | + except subprocess.TimeoutExpired: |
| 349 | + os.killpg(os.getpgid(proc.pid), signal.SIGKILL) |
| 350 | + proc.wait() |
| 351 | + return -1, "", "Command timed out" |
| 352 | + except Exception as e: |
| 353 | + return -1, "", str(e) |
330 | 354 |
|
331 | 355 | def test_nonexistent_input_file_exit_code(self): |
332 | 356 | """spades.py with non-existent -1 file should exit with 65 (InputFileNotFound).""" |
|
0 commit comments