Repository navigation
test(suite): convert the thirteen uncollected validation drivers and settle all three ceilings (#14979) - #15166
Conversation
…settle all three ceilings (#14979)
✅ SSOT Configuration Compliance: Passing🎉 No new hardcoded values of either class — Known backlog in |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Blocked on #15055 — root cause, and why this PR is not the causeLabelling The failing check is
Evidence that it is load, not this branch:
The entire diff between those two commits is Third data point against the same constant: passed, then 547 ms, then 538.9 ms. Both failures within ~10% of budget — a threshold set near the runner's median rather than above its worst case. This machine is also the CI runner and routinely has several suites running at once, so a loaded runner is the normal condition, not an anomaly. Why this PR is the first to hit it on a pull request. Not fixed here, deliberately. Raising or removing the 500 ms constant is #15055's call, in a file outside this PR's scope, and doing it under a #14979 commit would be the "raise a ceiling to reach a fix" move this work has avoided throughout. An agent is on #15055 now with a bar that the reworked assertion must still fail on a genuine regression. Everything this PR owns is green. Step 8 — its own invocation — passed again at 10 passed / 24 skipped with every floor holding, and the coverage report step succeeded. The 12 Unblocks when #15055 merges. This PR then needs a base update — already verified as a clean merge, with the two co-modified ratchet files touching disjoint keys. |
Refs #14979 — eleven of the thirteen files converted. Two were deliberately left unconverted; see "What is still unmet".
Thinking Path
#14927 landed the guard and the first tranche. #14979 is the remainder: 90
test_*methods in 14 classes across 14 files, every one of which collects zero items because pytest refuses a class defining__init__. A prior pass converted one file and moved one of three ceilings; this settles the rest.The issue is emphatic that a bare rename is worse than nothing —
SessionTakeoverTestSuite→TestSessionTakeoverSuitestill collects zero while looking fixed — so each file was converted rather than renamed:__init__replaced bysetup_methodor a fixture, everyreturn True/return Falsereplaced by an assertion naming what failed, the live dependency declared throughrequire_live_endpointso an absent service skips with a reason instead of failing on a refused socket, and a marker applied so the unit gate excludes anything needing a running stack.main(), therun_all_*drivers and everyprint()went with them.The correction that shaped this PR. An earlier revision converted all thirteen and described three of them as "knowingly cosmetic", leaning on AC3's own escape clause. CI rejected that, and it was right to:
repo_tests/marker_suite_root_coverage_test.py(#13286) fails any module carrying a markerci.ymldeselects that lives under nomarker-tests.ymlroot, because such a test runs in no workflow at all. Marking an unrun file does not leave it where it was — it converts "a file that ran nowhere" into "a test that runs nowhere", which is strictly worse, because it now reads as coverage. Three files tripped it. Each got a decision on its merits rather than an exemption.Two further corrections, both against my own earlier claims. I had reported that
autobot-infrastructure/shared/testswas a dead CI root whose conftest could not import. That was wrong. Measured with the invocation the workflow actually uses:The ImportError only appears when that directory is named alone:
autobot-infrastructure/shared/config/is a directory of YAML with no__init__.py, so as the sole root it resolves as a namespace package namedconfigand shadowsautobot-backend/config, which is what exportsunified_config_manager. Adding a second root fixes resolution. So the two files under that tree are genuinely wired and running, not blocked, and #15161 has been corrected and retitled to the narrower defect that is actually there.What Changed
Eleven files converted. Each collects exactly the number of methods the issue attributed to it, with no
PytestCollectionWarning.autobot-backend/utils/hardware_metrics_test.pyTestHardwareMonitoringintegration,slowhardware_monitor/gpu_optimizersingletonsautobot-backend/comprehensive_system_validation_test.pyTestAutoBotSystemValidation+TestSystemValidationLocalEnvironmentintegrationon the live class onlyautobot-backend/knowledge/chat_knowledge_system_e2e_test.pyTestChatKnowledgeSystemintegrationautobot-backend/monitoring/monitoring_and_alerts_test.pyTestMonitoringAndAlertingintegrationautobot-backend/agents/multi_agent_workflow_validation_test.pyTestMultiAgentWorkflowintegrationautobot-backend/npu_integration_e2e_test.pyTestNPUWorkerintegrationautobot-backend/async_baseline_performance_test.pyTestAsyncBaselineperformanceautobot-backend/knowledge/knowledge_performance_test.pyTestKnowledgePerformanceperformanceautobot-infrastructure/shared/tests/integration/test_distributed_system_integration.pyTestDistributedSystemdistributedautobot-infrastructure/shared/tests/performance/test_performance_optimization.pyTestPerformanceOptimizationperformanceautobot-frontend/tests/frontend_comprehensive_corrected_test.pyTestFrontendSurfaceintegrationOne tree wired in.
autobot-frontend/testsis now a root onmarker-tests.yml's third invocation. That directory holds exactly one tracked Python module — noconftest.py, no__init__.py— so it adds no collection surface of its own. It cannot ride the frontend workflow: that suite is npm/vitest and its path filter never fires on a.pyfile, so a Python invocation had to name it. It joined the existing third invocation rather than opening a fourth because a fourth would have needed--min-passed frontend=0, andmarker_suite_root_coverage_test.pyreads anyname=0floor as the claim "this tree carries no marker-selected test" — which is false here. Sharing the existing floors states the truth: the bucket collects more than it passes, andinfra=10still holds because skips do not reduce passes.Selection is proven by a real CI run, not by inspection. Because this PR edits
marker-tests.ymlitself, that workflow'spull_requestpaths filter matches and it ran on this branch — run 33151328667, conclusion success:The
infrainvocation went from 12 collected to 34 — the 22 added are this PR'sfrontend_comprehensive_corrected_test.py(10),test_distributed_system_integration.py(6) andtest_performance_optimization.py(5), plus one from population drift. Matching per-file counts from the same root list locally: frontend 10, distributed 6, performance 5.Two things that table settles, which no amount of local checking could:
require_live_endpointexists to give.--min-passed infra=10still holds — but with exactly zero margin. All 21 tests this PR added to that bucket skipped, sopassedstayed at 10 against a floor of 10. That is the correct outcome (no live stack in CI), and it is stated plainly rather than left for someone to discover: the floor is satisfied, not comfortably.Both
aiohttpandwebsockets, which the frontend module imports, were already installed by that job (requirements-ci/networking.txt:3,requirements-ci/framework.txt:8) — confirmed before pushing, so the wiring could not introduce a collection error.One marker registration fixed.
autobot-infrastructure/shared/tests/pytest.iniregisteredintegration,slowanddistributedbut notperformance, so under--strict-markersthe converted performance module was a collection error for any invocation rooted in that directory. Root cause fixed, not worked around.Ten tests that were structurally incapable of failing
The
python-suiteshard log carried tenPytestReturnNotNoneWarnings fromautobot-backend/cache/cache_consolidation_p4_test.py, a file this PR did not otherwise touch. The warning was the least of it. Every one of its tentest_*functions had this shape:The bare
except ExceptioncatchesAssertionError. Every assertion in the file was therefore decorative: a failing assert was caught, printed, and converted intoreturn False— which pytest reports as a pass with a warning. Ten tests, none of which could fail, in the same suite as a PR about making tests real.Worse, one of them asserted a fact it did not check.
test_migrated_files_importclaimed six modules "import successfully"; its body waspassplus sixprint()calls saying so. Theimportstatements had been stripped at some earlier point, leaving a function that performed no import and made no assertion — a coverage claim for six modules, backed by nothing.Fixed rather than deferred:
PytestReturnNotNoneWarningprint()callsexcept ExceptionswallowsEvery original
assertand its message was preserved; thetry/exceptwrapper and thereturn True/return Falsewere removed so failures propagate.test_migrated_files_importnow drivesimportlib.import_moduleover a namedMIGRATED_MODULEStuple and asserts on each — the only place a check was added rather than unwrapped. Removing the swallows exposed no hidden failure: all ten pass against the currentadvanced_cache_manager, so the vacuousness was structural rather than concealing a live defect.What let it survive — and it was not simple neglect. I first reported that nothing hid this file. That was half right, and the other half is the more useful finding.
No exemption list contains it: checked against
python_file_size_known_large.py,python_file_size_ratchet_baseline.py,sys_modules_leak_baseline.txt,_KNOWN_OFFENDERS,.flake8,.banditand the workflows. The only other mention repo-wide is a stale mapping atscripts/migrate_tests.py:161pointing atautobot-user-backend/cache— a directory in no commit, the same phantom tree theshared/testsconftest puts onsys.path. Reported for filing, not fixed here; it is one of 39 tracked references to that removed tree.But the repository does have a fatal guard for exactly this defect —
repo_tests/tests_that_return_instead_of_asserting_test.py(#14920), an AST sweep with a per-tree down-only ratchet. It did not catch these ten, and the reason is structural:The exclusion assumes an
assertthat is present is anassertthat can fire. Underexcept Exceptionit cannot. Nine of the ten functions had asserts — inert ones — so the sweep passed over them. Measured against the base file, it attributed only 2 offending returns in the whole module, both intest_migrated_files_import, the single function with noassertat all:So the shape was worse than "advisory warning nobody acted on": it tripped
PytestReturnNotNoneWarningat runtime and read as defended to the AST guard. Filed as #15195, with a suggested rule — do not treat anassertas protective when it sits under a handler catchingException/BaseException/AssertionErrorwithout re-raising. Not fixed here.Consequently this PR also lowers that guard's budget,
autobot-backend73 → 71, in the same commit that removed the returns — the ratchet fails below its budget as well as above. Only 2 of the 10 move the number, for the reason above, and that is recorded at the constant so the arithmetic is not mistaken for a miscount.Six size-ceiling entries deleted, not lowered. The conversions replaced driver scaffolding with tests, pushing six previously-grandfathered files back under 600 lines. An entry naming a compliant file exempts nothing while looking authoritative, so each was deleted from both
scripts/python_file_size_known_large.pyandrepo_tests/python_file_size_ratchet_baseline.py:autobot-backend/monitoring/monitoring_and_alerts_test.pyautobot-frontend/tests/frontend_comprehensive_corrected_test.pyautobot-backend/knowledge/knowledge_performance_test.pyautobot-backend/comprehensive_system_validation_test.pyautobot-backend/utils/hardware_metrics_test.pyautobot-backend/async_baseline_performance_test.pyThat was caught by CI, not by me. I had checked that no changed file exceeded 600 and never checked the inverse, even though the same both-directions property is the whole point of the ceilings this PR moves.
Ceilings, before and after
(ceiling, floor)autobot-backend(59, 18000)(8, 18000)autobot-infrastructure(19, 250)(11, 250)shared/testsfiles converted (11 methods). The 11 left are the twoshared/scriptsfiles, deliberately unconverted.autobot-frontend(10, 10)Measured, not assumed:
_offenders_by_tree()on the final tree returns{'autobot-backend': 8, 'autobot-infrastructure': 11}.Verification
warn=0 err=0, from a per-file--collect-onlysweep.repo_tests/test_methods_in_uncollected_classes_test.pypasses with the three values above; the guard fails if any ceiling does not match.shared/testsalready covered; twoshared/scriptsfiles left unconverted rather than made cosmetic. See below.repo_tests/marker_suite_root_coverage_test.py+ ratchet +hook_suites_run_in_ci_test.py→ 25 passed. Every marker-carrying module this PR touches is under amarker-tests.ymlroot.check_python_file_size.py --audit-ceilings→ 4910 scanned, 502 grandfathered, all live and at size.env_registry.pyuntouchedgit diff origin/Dev_new_gui -- autobot_shared/env_registry.pyempty; still exactly 1743 lines. All 36AUTOBOT_*names the conversions introduced were reverted to plain module constants.black --line-length=120andisort --settings-path=.clean over every changed file underautobot-backend/andautobot_shared/.print()introducedcache_consolidation_p4_test.py.cache_consolidation_p4_test.py: 10 passed, 0PytestReturnNotNoneWarning(was 10 warnings, 10 tests that could not fail).Contrast mutation 1 — reintroduce the defect
Added an
__init__back toTestChatKnowledgeSystem; its 7 methods stop being collected and become offenders again:Contrast mutation 2 — empty the enumeration
_test_modules()forced to return[], proving a sweep that finds nothing goes red rather than reporting every tree clean:Both reverted and the tree re-verified before commit.
Read the skip counts correctly
Every converted file is marker-gated and probe-guarded, so in CI — where no stack runs — they skip. "7 skipped" is exactly the shape that reads as "7 passing". What landed is that 72 methods which previously collected zero items and asserted nothing are now collected, marker-selected, and assert the moment a stack is present. It is not 72 passing tests in CI.
Against the stack on the build host,
chat_knowledge_system_e2e_test.pyis 1 passed / 6 failed. Those six are not conversion damage — all six are the one backend defect filed as #15160. The tests are right and the product is broken.What is still unmet
Two files were deliberately NOT converted, and #14979 stays open for them:
autobot-infrastructure/shared/scripts/utilities/test_autobot_functionality.py(8 methods)autobot-infrastructure/shared/scripts/analysis/test_npu_worker.py(3 methods)They live under
shared/scripts, which no pytest invocation names. Converting them would have produced marked tests that run in no workflow — the #13286 failure above, and the outcome that reads as coverage while being none. Wiring that tree in means taking on ~35 unvetted ad-hoc scripts underanalysis/and double-running the 18hooks/tests the unit gate already covers: a separate decision with its own blast radius, whichmarker-tests.yml's own comment says to file rather than smuggle in. Tracked by #15178. They are pinned at 11 in the infrastructure ceiling, so they cannot grow.Nothing here is host evidence. Nothing on this branch is deployed. Tests executed against the build host ran against a different revision, so those results are reported as findings only, never as verification of this branch.
Defects found and filed rather than fixed here:
POST /api/knowledge_base/searchstops answering under concurrent load (~0.3s idle; no response at 25s, 30s, >70s).test_agent_task_completionhas driven it since it was written, inside a baretrythat logged a warning in a class collecting zero items. Removing the swallow caught it on the first pre-push run. Its budget is now 180s with the reason and the issue recorded at the constant, and theReadTimeoutis re-raised as a namedAssertionError.chat_knowledge.py:500declareschat_knowledge_manager = Noneand nothing assigns it; six routes 500 on every call while the health probe reads the same dead global and reportsidle.configshadows the backend's #15161 — corrected and retitled; the real defect is thatshared/testscannot be collected alone because a namespace-packageconfigshadows the backend's.env_registry.pycase that forced the env-var revert.Model Used
Claude Opus 5 (1M context).