Skip to content

test: stop the suite from writing the developer's real version cache - #604

Merged
padak merged 2 commits into
mainfrom
fix/test-pollution-version-cache
Aug 18, 2026
Merged

test: stop the suite from writing the developer's real version cache#604
padak merged 2 commits into
mainfrom
fix/test-pollution-version-cache

Conversation

@padak

@padak padak commented Aug 18, 2026

Copy link
Copy Markdown
Member

The incident

Running make test broke kbagent auto-update for whoever ran it. Observed on a dev machine today:

$ kbagent project list
Updating kbagent v0.84.2 -> v1.0.0...
Auto-update failed; continuing with current version. Recover with: uv tool install --force --reinstall 'keboola-cli[server] @ git+https://github.com/keboola/cli@v1.0.0'

$ kbagent version
kbagent v0.84.2    up to date

There is no v1.0.0 release — no tag, no draft, nothing in pyproject.toml history. The number came out of the test suite.

Root cause

auto_update._get_cache_path() resolves through platformdirs, so it ignores --config-dir and always points at the machine's own version_cache.json. Two tests in TestMaybeAutoUpdate mock _read_cache but not _write_cache, and the class's autouse _no_real_mcp_calls fixture forces the per-stage skip helpers to False — which also bypasses the _is_dev_install() gate that would otherwise stop the orchestrator in a dev tree. So both reach the real writer:

test writes
test_version_comparison_none_no_update latest_version: "1.0.0" (the canonical fake latest)
test_fetch_failure_continues latest_version: <__version__> (the None fallback)

AUTO_UPDATE_CHECK_INTERVAL is 1 hour, so for the next hour every kbagent command served 1.0.0 from cache, printed an update banner, and failed the reinstall against a tag that does not exist.

kbagent version disagreed because it is excluded from the startup hook (_should_skip_all_top_level_subcommand_is_versioning) and VersionService calls _fetch_kbagent_latest_version() directly, with no cache — a live GitHub fetch, correctly reporting 0.84.2.

The fix

  • tests/conftest.py: autouse _redirect_version_cache fixture repoints the auto_update._get_cache_path module attribute at tmp_path. Fixing it in conftest rather than in the two tests also covers tests written later that forget to mock the write.
  • tests/test_auto_update.py: test_suite_never_resolves_to_the_real_user_cache fails if the fixture is removed. The file's top-level _get_cache_path import stays bound to the original function, so TestGetCachePath::test_returns_path_with_filename still exercises the real resolver.

No src/ change: _get_cache_path staying platformdirs-based is correct for the shipped CLI — the cache is per-machine, not per-project.

Verification

Written test-first (RED on the guard, GREEN after the fixture). Verified by positive evidence rather than a sentinel file, because a concurrent suite run on the same machine can write that file too — both writes now land inside tmp_path:

/tmp/kbpt2/test_version_comparison_none_n0/version_cache.json -> {"latest_version": "1.0.0", ...}
/tmp/kbpt2/test_fetch_failure_continues0/version_cache.json   -> {"latest_version": "0.84.2", ...}

Full suite: 5748 passed, 166 skipped. ruff check, ruff format --check and ty check clean.

Tests only — no version bump, no changelog entry.


Open in Devin Review

`auto_update._get_cache_path` resolves through platformdirs, so it ignores
--config-dir and always points at the machine's own
`~/.config/keboola-agent-cli/version_cache.json`. Two tests in
TestMaybeAutoUpdate mock `_read_cache` but not `_write_cache`, and the
class's autouse fixture disables the dev-install skip gate, so they reach
the real writer:

  test_version_comparison_none_no_update -> latest_version "1.0.0"
  test_fetch_failure_continues           -> latest_version <__version__>

Running `make test` therefore stamped the canonical fake latest version
1.0.0 into the developer's own cache. For the next hour
(AUTO_UPDATE_CHECK_INTERVAL) every kbagent command then believed 1.0.0 was
available, printed an update banner, and failed the reinstall against a
release tag that does not exist -- while `kbagent version`, which bypasses
the cache and refetches from GitHub, kept reporting "up to date".

Adds an autouse `_redirect_version_cache` fixture pointing the module
attribute at tmp_path, which also covers tests written later that forget to
mock the write, plus a guard test that fails if the fixture is removed. The
top-level import in test_auto_update.py stays bound to the original
resolver, so TestGetCachePath still exercises the real path logic.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Open in Devin Review

Comment thread tests/conftest.py Outdated
…n cache

Review follow-up: `update_runner.state_dir()` resolves through the same
`platformdirs.user_config_dir("keboola-agent-cli")` as the version cache and
backs the deferred-update marker / exit / log files, but only
`tests/test_update_runner.py` patched it, file-scoped.

Verified latent rather than live: a full suite run creates no files in the
real config directory, because the deferral tests mock
`request_deferred_update` and `should_defer()` is False off Windows. It is
the same class of bug though -- on Windows `should_defer()` defaults to True,
and `report_finished_deferred_update` runs ahead of every skip gate and
unlinks a genuine pending report as it reads it, so a developer's own update
outcome would disappear into a test run.

Extends the autouse fixture (renamed `_redirect_global_state_paths`) and its
guard test to cover both writers.
@padak
padak merged commit b13850b into main Aug 18, 2026
4 checks passed
@padak
padak deleted the fix/test-pollution-version-cache branch August 18, 2026 14:41
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