Repository navigation
Run the Python suite in parallel and stop vitest's double work - #980
Merged
Merged
Conversation
Every test run shared ./config: the developer's real codex.toml, secret keys and, above all, the file-based Django caches that cachalot fills. A -p plugin now points CODEX_CONFIG_DIR at a per-process directory under the run's tmp root before pytest-django imports the settings, so serial runs, parallel worktrees and (next) xdist workers never share a cache. An explicit CODEX_CONFIG_DIR still wins in a serial run. With that isolation the SerializeMixin file lock on BaseTestImporter only serialized importer classes across processes, so it goes. --durations=25 --durations-min=1.0 makes slow tests visible in every run's output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The delete-backstop and custom-cover cleanup tests patched threading.Event.wait for every Event in the process. Thread.start() waits on an Event too, and the first multiprocessing.Queue put in a process starts the queue's feeder thread, so a stray wait() call landed on the mock whenever that test was the first in its process to put on LIBRARIAN_QUEUE. TestSecondLookBeforeDeleting then failed its assert_called_once_with(5), alone or on a fresh xdist worker, and the janitor test's assert_called() could pass without the second look ever waiting. Both now patch wait on the abort event the importer or janitor is built with, which is the wait the code under test calls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--numprocesses=auto --dist=loadscope spreads test classes across every core and keeps each class on one worker, so setUpTestData runs once per class. Each worker gets its own in-memory test database and, from the previous commit's plugin, its own config dir and file caches. --no-loadscope-reorder keeps pytest-django's TestCase-before- TransactionTestCase order on every worker. loadscope's default sorts scopes by size, which put BookmarkDedupeMigrationTests mid-run; its flush then stripped the migration-seeded rows (ComicboxTaggingDefaults, AgeRatingMetron) and left the comic sequence at 14 for the TestCases that followed on that worker: 13 failures. Locally on 12 cores: 239 s serial -> 75 s; -n 4 (the CI runner's vCPUs) 87 s. Same 1668 passed, 1 xfailed and the same coverage TOTAL as the serial run. -n0 runs serially. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vite-plugin-checker ran a full eslint_d pass inside every vitest run. The Lint job already lints the frontend, so the checker now loads only outside the test environment. reader-nav-button's only assertion on its initial markup was toMatchSnapshot() against a gitignored file that --update rewrote on every run, so it could never fail. It now asserts the link's tag, href, title, disabled state and classes. --update leaves test and test:ci; test:update regenerates snapshots on purpose. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements phases 1–2 of
.claude/plans/ci-test-speed.md. CI's critical path is the single-core Test Python job (7:20 of a 9:41 run). This PR runs that suite on every core without checking less: no new skips, xfails, deselects or ignores, and the same coverage.Changes
-p tests.pytest_config_dirplugin pointsCODEX_CONFIG_DIRat a per-process tmp dir before pytest-django imports settings. Until now every run shared./config, including the developer's realcodex.tomland the file caches cachalot fills; under xdist that sharing produced hundreds ofUNIQUE constraint failed: django_content_typeerrors. An explicitCODEX_CONFIG_DIRstill wins in a serial run. With isolation in place, theSerializeMixinfile lock on importer tests is no longer needed and is removed.--durations=25 --durations-min=1.0makes slow tests visible.threading.Event.waitfor every event in the process.Thread.start()waits on an Event too, and the first queueputin a process starts a feeder thread, soTestSecondLookBeforeDeletingfailed whenever it ran first in a process, including serially and alone. Both now mockwaitonly on the abort event the code under test uses.--numprocesses=auto --dist=loadscope --no-loadscope-reorder. Without--no-loadscope-reorder, loadscope sorts scopes by size. That broke pytest-django's TestCase-before-TransactionTestCase order: a TTC flush wiped migration-seeded rows for the TestCases after it on the same worker (13 failures).-n0runs serially.reader-nav-button's snapshot assertion could never fail (a gitignored file rewritten by--updateon every run). It is replaced with explicit assertions,--updateis removed fromtest/test:ci, and atest:updatescript is added.Verification (local, 12-core arm64)
-n 4(CI runner's vCPUs)./configwas not touched by any run.__snapshots__are written.make lintandmake tyare clean, apart from two existing basedpyrightreportUnreachablewarnings incodex/views/browser/annotate/cover.pythat this PR does not touch.Not in this PR
package.jsonscripts and.gitignorelines as unions, so codex can't drop the template's rooteslint_d --cache .(the frontend gets linted twice) or the root__snapshots__ignore.LOGLEVEL=DEBUGstays. On the parallel suite it costs about 4–5% (74 s vs 71 s).--pool=threadsfor vitest waits on this PR's CI timing, per the plan.🤖 Generated with Claude Code