Repository navigation
fix(tests): refuse a silently shuffled local run, announce an opted-in one (#2891) - #3841
Merged
Merged
Conversation
…n one (#2891) pytest-randomly is kept out of tests/requirements-test.txt because pytest auto-discovers installed plugins, but nothing enforced it: once the plugin landed in a local venv every run was shuffled with no signal, and latent order dependencies were triaged as product regressions. - tests/testing_utils/randomly_guard.py (reached as testkit.randomly_guard): with the plugin active, a run that did not opt in fails fast with a UsageError naming both ways out; an opted-in run (--randomly-seed, -p randomly, TRINITY_RANDOM_ORDER=1, or PYTEST_ADDOPTS) prints a banner with the seed and how to reproduce or disable it. Opt-in is read from the invocation, because pytest-randomly resolves an implicit seed in its own pytest_configure. - Both conftests call it (tryfirst), since the unit/ island never loads the root conftest. - run-core.sh, run-full.sh, run-integration.sh and run-smoke.sh pass -p no:randomly. Every CI pytest call that installs the plugin already passes -p randomly --randomly-seed=N; the jobs that run without a seed do not install it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the tests/registry.json conflict by keeping both sides' entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
obasilakis
approved these changes
Oct 22, 2026
obasilakis
left a comment
Contributor
There was a problem hiding this comment.
Ran it in a scratch venv with pytest-randomly and xdist 3.6.1: a plain run refuses; -p randomly --randomly-seed=4242 passes with one banner; -n 2 passes (workers get the full args); -p no:randomly passes. The three unit files from the issue pass 97/97 together under 8 seeds.
Minor:
tests/testing_utils/randomly_guard.py:96—banner()docstring says call from atrylastpytest_configure; it is called frompytest_sessionstart.tests/testing_utils/randomly_guard.py:71— thePYTEST_ADDOPTScheck misses the one-token-prandomlyform the argv check handles.- The evidence for the three unit-tier deps is isolated runs; the failures came from a full unit run. A full
unit/run under one seed (or a green nightly) would close it.
# Conflicts: # tests/registry.json
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.
Summary
pytest-randomlyis kept out oftests/requirements-test.txton purpose, because pytest auto-discovers installed plugins. Nothing enforced that: once the plugin landed in a local virtualenv, every local run was shuffled with no signal, and latent order dependencies got triaged as product regressions.tests/testing_utils/randomly_guard.pyis imported astestkit.randomly_guard, through the trackedtestkit → testing_utilssymlink.UsageErrorthat names both ways out.--randomly-seed=N,-p randomly,TRINITY_RANDOM_ORDER=1, orPYTEST_ADDOPTS.pytest_configure.tryfirst, because the sealedunit/tests never load the root conftest.run-core.sh,run-full.sh,run-integration.shandrun-smoke.shpass-p no:randomly.The acceptance criteria, item by item
Banner or fail-fast: done, as above. Checked live in a venv with pytest-randomly 4.1.0:
-p randomly --randomly-seed=4242prints the banner;TRINITY_RANDOM_ORDER=1andPYTEST_ADDOPTSboth opt in.Scripts pin order: done for all four
run-*.shscripts.The three unit-tier order dependencies: no longer reproduce on
dev.test_1081_physical_meter,test_2638_subscription_switch_on_turnandtest_subscription_auto_switch_pingpongwere run together under eight seeds: 1, 2, 3, 12345, 67890, 99999, 4242 and 777 (97/97 each).test_1081is unchanged since the report, so this matches thesys.modulesbaseline restore in the unit conftest. I could not reproduce the reporter's own seed, so nothing is quarantined; if one comes back, the guard now tells you it was a shuffle.The four API-tier order dependencies: already fixed on
devby test: fix order-dependent and stale tests surfaced by the full suite run #3681 (2026-10-14).test_folders_default_values,test_info_no_configandtest_get_config_no_configuseisolated_agent.test_round_robin_distributionskips on a foreign-subscriptions precondition.Does CI's three-seed run hit these? Every CI job that installs pytest-randomly already passes
-p randomly --randomly-seed=N:backend-unit-test.yml: the head seed, the inline base and push-absolute runs;backend-unit-nightly.ymlanddev-nightly.yml: the unit matrix.The jobs that run pytest without a seed (
dev-nightly's live suite,integration-nightly,journey-smoke,schema-parity,backend-image-smoke) don't install the plugin, so the guard does nothing there and no workflow changes are needed. The nightly three-seed runs ondevand on open PRs are what exercise order independence. Those seeds do not hit the reported orderings today, and this run reproduced none of them either.Changes
tests/testing_utils/randomly_guard.py(new),tests/unit/test_2891_randomly_guard.py(new, 24 tests).tests/conftest.py,tests/unit/conftest.py: wire the guard intopytest_configureandpytest_sessionstart.tests/run-{core,full,integration,smoke}.sh:-p no:randomly.tests/registry.jsonentry.Behaviour change for local runs: in a venv with pytest-randomly installed, any pytest call that neither passes
-p no:randomlynor opts in now stops with an explanation, instead of silently shuffling. That's the point of the issue.Test Plan
cd tests && pytest -p no:randomly unit/test_2891_randomly_guard.py: 24 pass. They also pass under-p randomly --randomly-seed=…,TRINITY_RANDOM_ORDER=1andPYTEST_ADDOPTS; the refusal test now clears an inherited opt-in.Fixes #2891
🤖 Generated with Claude Code