HYBIM-790: fix Windows test-suite slowness#22
Merged
Conversation
…IM-790) The autouse set_validated_config fixture rebuilds GalileoPythonConfig on every test (deliberate per-test isolation). That build fires 3 already-mocked async validation requests (healthcheck/login/current_user) through galileo_core's async_run / EventLoopThreadPool. On Windows + CPython 3.11+ the underlying IOCP poll (GetQueuedCompletionStatus) blocks ~11x longer per call, making per-test setup ~1335 ms vs ~9 ms and the full Windows suite ~23 min. Wrap only the per-test config build in a _fast_config_validation() context manager that stubs ApiClient.make_request / ApiClient.request with canned, await-free payloads, so the async dispatch is trivial and the slow poll never happens. Per-test reset/teardown is unchanged; test bodies still exercise the real validation/connect code with their own mocks. Verified on Windows CI: 3.11 setup avg 1335 ms -> 9 ms (identical to 3.10), full-suite wall time 1388 s -> 66 s, 2015 passed / 5 skipped (no regressions). See .local/HYBIM-790-investigation.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the dotless single-label test host localtest with fake.test
(RFC 6761 reserved .test TLD). A dotless host triggers a ~2.7s Windows
getaddrinfo penalty if any code path ever resolves it; a dotted reserved
name avoids that entirely. The suite never actually resolves the host today
(respx intercepts above the socket layer), so this is a safe mechanical swap.
fake.test (not console.test) is used deliberately: galileo_core derives
api_url = console_url.replace('console', 'api'), so console.test would become
api.test (!= console_url) and break host-pinned respx mocks. fake.test contains
no special substring, keeping api_url == console_url.
Host-only swap across the main suite and the galileo-a2a / galileo-adk
packages; env-var prefixes are left untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fercor-cisco
force-pushed
the
fernando/HYBIM-790
branch
from
June 12, 2026 23:13
765e071 to
9771de1
Compare
Collaborator
Author
PR #22 Review — HYBIM-790: Windows test-suite slownessVerdict: Safe to merge. Every load-bearing claim in the investigation was independently verified against the galileo_core source rather than trusted. The change is safe under both concurrent (pytest-xdist) and sequential execution. What the PR doesTwo mechanical, independently-revertible commits touching only test scaffolding (no
Concurrency & sequencing safety — verified
Correctness of the stub — verified against galileo_core source
Residual safety check — verifiedGrepped Local verification (this branch, which has the
|
…helper galileo-adk's autouse set_validated_config fixture had the same per-construction async-validation cost on Windows + CPython 3.11+ as the main package: it rebuilds GalileoPythonConfig on every test, firing 3 already-mocked validation round-trips through galileo_core's async_run / EventLoopThreadPool. Extract the per-test config-build stub (previously inline in tests/conftest.py) into a repo-level test_support.config helper and reuse it from adk's fixture. - test_support/: new top-level, non-shipped helper package (outside src/ and outside any testpaths). Lives at the repo root rather than under tests/ so the sibling packages, which have their own top-level `tests` package, can import it without a package-name collision. - tests/conftest.py: import fast_config_validation from the shared module instead of defining it locally (behavior unchanged). - galileo-adk/tests/conftest.py: wrap the GalileoPythonConfig.get(...) build in fast_config_validation(); per-test reset/teardown unchanged. - galileo-adk/pyproject.toml: add ".." to pytest pythonpath so test_support resolves from the monorepo root. galileo-a2a is intentionally untouched: it never builds GalileoPythonConfig, so it has no such cost. Verified: root suite 2018 passed / 2 skipped; galileo-adk 252 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
adityamehra
approved these changes
Jun 13, 2026
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
Fixes HYBIM-790 — the test suite takes ~23–28 min on Windows × Python ≥ 3.11 vs ~3–6 min on 3.10 / Linux / macOS, for an identical test set on an identical OS image.
Root cause: the autouse
set_validated_configfixture rebuilds the singletonGalileoPythonConfigon every test (deliberate per-test isolation for pytest-xdist on 3.14+). That build fires 3 already-mocked async validation requests (healthcheck / login / current_user) through galileo_core'sasync_run/EventLoopThreadPool. On Windows + CPython 3.11+ the underlying IOCP poll (GetQueuedCompletionStatus) blocks ~11× longer per call (212 ms vs 19 ms) — a CPython 3.10→3.11 behavioral change in the WindowsProactorEventLoop. The requests are fully respx-mocked (no real socket/DNS), so the cost is purely the event-loop machinery, not the HTTP.This made per-test setup ~1335 ms (3.11) vs ~71 ms (3.10), and setup totals ≈ the whole pytest wall time.
Fix
Three logically-distinct, independently-revertible commits:
test: skip per-test async config validation on Windows-slow path— wrap only the per-test config build in a_fast_config_validation()context manager that stubsApiClient.make_request/ApiClient.requestwith canned, await-free payloads. With noawait, theasync_rundispatch is trivial (~0.2 ms) and the slow IOCP poll never happens. Per-test reset/teardown is unchanged; test bodies still drive the real validation/connect code with their own mocks. This is the same patching pattern already idiomatic across the suite (test_metric.py,test_config.py,test_configuration.py).test: use RFC 6761 fake.test host instead of dotless localtest— replace the dotless single-label hostlocaltestwithfake.test(RFC 6761 reserved.testTLD), avoiding the ~2.7 s Windows dotless-hostgetaddrinfopenalty if any path ever resolves it.fake.test(notconsole.test) keepsapi_url == console_url, since galileo_core derivesapi_url = console_url.replace("console","api"). Host-only swap; env-var prefixes untouched.test: apply fast config-validation fixture to galileo-adk via shared helper—galileo-adkhad the same autouseGalileoPythonConfig.get(...)pattern and the same latent cost. Extract the config-build stub into a repo-level, non-shippedtest_support.confighelper and reuse it from adk's fixture. The helper lives at the repo root (not undertests/) so the sibling packages — which each have their own top-leveltestspackage — can import it without a package-name collision;galileo-adkgets".."added to its pytestpythonpathto resolve it.galileo-a2ais left as-is: it never buildsGalileoPythonConfig, so it has no such cost.Verification
Measured on Windows CI (probe branch, GH Actions run
27447060566, both jobs green):setup avg(full suite)3.11 setup is now identical to 3.10 — the version gap is eliminated with zero regressions. Locally: full
tests/suite 2015 passed / 5 skipped, ruff/mypy clean,poetry checkclean.Notes
galileo-adkshared the same autouseGalileoPythonConfig.get(...)pattern and latent Windows cost — now fixed via the sharedtest_support.confighelper (252 adk tests pass, no regression).galileo-a2aturned out not to share the pattern (it never buildsGalileoPythonConfig), so it only received thefake.testhost rename and needs no fixture fix. Note: these sub-package suites are not in the current CI matrix, so this is a local-dev / future-CI saving rather than a current CI-time reduction.async_run; a production-side fix would help real Windows SDK users, not just CI.See
HYBIM-790-investigation.mdattached to https://splunk.atlassian.net/browse/HYBIM-790 for the full investigation.🤖 Generated with Claude Code