Skip to content

Move the regression and large-index tests into the pytest suite - #541

Merged
BenLangmead merged 2 commits into
masterfrom
port-regressions
Oct 24, 2026
Merged

BenLangmead merged 2 commits into
masterfrom
port-regressions

Conversation

@BenLangmead

@BenLangmead BenLangmead commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #535 and #540: retires the old Python unittest scripts in scripts/test in favour of the pytest suite. Two commits:

1. Move the issue regression tests into the pytest suite. test_regressions.py ports the tests from regressions.py, which had not run in CI and failed at startup whenever the checkout path contained "bowtie2" more than once.

  • Issues 288 (--un with --no-unal), 279 (--un-conc/--al-conc with --no-unal) and 313 (dots in output directory names) keep their original checks and now also compare output files byte for byte, so a change in which reads are written is caught, not only how many.
  • The check that a positional index without -x is rejected is kept. The --version check is dropped because test_output.py::test_version covers it.
  • regressions.py and dataface.py (used only by it) are removed.

2. Replace the large-index script with an opt-in pytest module. test_large_genome.py checks alignment against a prebuilt .bt2l index whose joined reference exceeds 2^32 bases, which the small --large-index tests cannot reach. It is skipped unless BOWTIE2_LARGE_INDEX names such an index, so CI is unaffected.

  • Reads and 300 bp pairs are cut from the index's own reference by streaming bowtie2-inspect one sequence at a time: about 150 at evenly spaced joined offsets beyond 2^32, one straddling that offset, and a few controls from the first sequence.
  • Unpaired reads must align perfectly and pairs concordantly; uniquely aligned reads and pairs must land where they were cut (pairs with the expected TLEN), and at least a quarter must be unique.
  • BOWTIE2_LARGE_INDEX_OFFSET lowers the target offset so the test logic can be exercised on a small .bt2l index.
  • large_idx.py, btdata.py, bt2face.py and big_data/ are removed. The old script downloaded hg19 and rn4 over UCSC FTP, built the index itself, checked only exit codes, and had the same startup path bug.

Testing

  • Full suite on macOS (Apple Silicon, Python 3.12): 614 passed, 4 skipped (the two large-genome tests skip without BOWTIE2_LARGE_INDEX).
  • test_large_genome.py against a small .bt2l E. coli index split into three sequences with N runs placed around the target offset, at several values of BOWTIE2_LARGE_INDEX_OFFSET; offsets checked by hand.
  • test_large_genome.py on the JHU Rockfish cluster against a GRCh38 + CAST/EiJ T2T mouse .bt2l index (6.05 Gbp): 2 passed in about 4 minutes with 16 threads, 8.3 GB peak RSS.

Found along the way (not changed here)

Aligning unpaired reads (-U) and pairs (-1/-2) in a single run at -p > 1 either drops the pairs from the output or hangs on master. The large-genome test aligns them in separate runs to avoid it.

Created by Ben with help from Claude Opus 5.5

scripts/test/test_regressions.py ports the tests from regressions.py, which had not run in CI and failed at startup whenever the checkout path contained "bowtie2" more than once. Issues 288 (--un with --no-unal), 279 (--un-conc and --al-conc with --no-unal) and 313 (dots in output directory names) keep their original checks and now also compare output files byte for byte, so a change in which reads are written is caught, not only a change in how many. The check that a positional index without -x is rejected is kept. The --version check is dropped because test_output.py::test_version already covers it.

regressions.py and dataface.py, which only regressions.py used, are removed. large_idx.py still uses bt2face.py and btdata.py, so those stay. The README now describes the pytest suite and where regression tests go.
scripts/test/test_large_genome.py checks alignment against a prebuilt .bt2l index whose joined reference exceeds 2^32 bases, which the small --large-index tests elsewhere in the suite cannot reach. It is skipped unless BOWTIE2_LARGE_INDEX names such an index. Reads and 300 bp pairs are cut from the index's own reference by streaming bowtie2-inspect one sequence at a time: 150 at evenly spaced offsets beyond 2^32 in the joined reference (which leaves out runs of N), one straddling that offset, and a few control reads from the first sequence. Even spacing keeps most reads in long sequences rather than in short, repetitive unplaced contigs. Every unpaired read must align perfectly and every pair concordantly. Uniquely aligned reads and pairs must land where they were cut, pairs with the expected TLEN, and at least a quarter must be unique. Pairs in repeats are not required to score perfectly, because bowtie2 can report a concordant placement there that is not the best one. BOWTIE2_LARGE_INDEX_OFFSET lowers the target offset so the test logic can be checked against a small .bt2l index.

Run against a GRCh38 plus CAST/EiJ T2T mouse index (6.05 Gbp), both tests pass in about four minutes with 16 threads and an 8.3 GB peak resident set.

large_idx.py, btdata.py, bt2face.py and big_data/ are removed. large_idx.py downloaded hg19 and rn4 over UCSC FTP, built the index itself, checked only exit codes, and failed at startup when the checkout path contained "bowtie2" more than once.

Unpaired and paired reads are aligned in separate runs, because mixing them in one run at -p > 1 loses the pairs or hangs on master.
@BenLangmead
BenLangmead merged commit 976e221 into master Oct 24, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant