Skip to content

test(proxy/client): isolate client tests from the developer's real CLI token - #30175

Open
mateo-berri wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_fix_client_test_cli_token_leak
Open

test(proxy/client): isolate client tests from the developer's real CLI token#30175
mateo-berri wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_fix_client_test_cli_token_leak

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Note on the make test-unit box: the command currently aborts on litellm_internal_staging itself, before this PR. #29686 added tests/test_litellm/models/test_models.py, which collides with the long-existing tests/test_litellm/proxy/client/test_models.py; neither directory has an __init__.py, so pytest assigns both the module name test_models and collection dies with "import file mismatch". That needs a separate fix (add __init__.py files or unique basenames). Running the suite on this branch without -x gives 21915 passed, 113 skipped, that one pre-existing collection error, and 18 failures that are parallel-run flakes: all 18 pass when run in isolation on both this branch and a clean checkout of litellm_internal_staging

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

CI (LiteLLM team)

  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Screenshots / Proof of Fix

Simulate a developer who ran lite login against the URL the test uses, without touching the real ~/.litellm/token.json:

mkdir -p /tmp/fakehome/.litellm
printf '{"key": "sk-fake-cli-key", "base_url": "http://localhost:4000"}' > /tmp/fakehome/.litellm/token.json

On litellm_internal_staging:

$ HOME=/tmp/fakehome python -m pytest tests/test_litellm/proxy/client/test_client.py -q
E       AssertionError: assert 'sk-fake-cli-key' is None
E        +  where 'sk-fake-cli-key' = <litellm.proxy.client.http_client.HTTPClient object at 0x12049d5b0>._api_key
FAILED tests/test_litellm/proxy/client/test_client.py::test_client_without_api_key
1 failed, 3 passed in 3.34s

On this branch:

$ HOME=/tmp/fakehome python -m pytest tests/test_litellm/proxy/client/ -q
269 passed in 53.02s

Type

✅ Test

Changes

Client falls back to get_litellm_gateway_api_key() when constructed without an api_key, which reads the token that lite login stores in ~/.litellm/token.json. test_client_without_api_key asserts the resolved key is None, so it fails on any developer machine where the stored token was issued for the same base URL the test uses. The test suite's outcome should not depend on whether the developer has logged into a local proxy

This adds a conftest.py for tests/test_litellm/proxy/client/ with an autouse fixture that stubs load_cli_token to return None, so every test in the directory is hermetic with respect to the developer's home directory. The same latent leak existed in test_models.py and test_model_groups.py, which also construct Client without a key and assert it is None; the directory-wide fixture covers those too. The CLI tests under cli/ are unaffected: auth.py has its own load_token, and the tests that patch cli_token_utils.load_cli_token do so per test, which composes fine with the autouse fixture

While auditing the file I found that test_client.py defined test_client_initialization and test_client_without_api_key twice each; Python silently shadows the earlier definitions, so pytest only ever ran the second of each. The duplicates are now merged into single tests, with the custom timeout assertion split out as test_client_custom_timeout

The CLI token fallback had no coverage at the Client level, so this also adds two tests: one asserting the client picks up a stored token issued for the target server, one asserting it ignores a token issued for a different server. Besides covering the fallback and its origin check, the first one pins load_cli_token as the live seam, so if client.py ever stops resolving the key through it, the test fails and flags that the conftest isolation needs updating

…I token

Client falls back to the key stored by lite login when no api_key is
given, so test_client_without_api_key failed on any machine whose
~/.litellm/token.json was issued for the URL the test uses. An autouse
conftest fixture now stubs load_cli_token for the whole client test
directory; the same latent leak existed in test_models.py and
test_model_groups.py. Also dedupes test functions in test_client.py
that shadowed each other and adds coverage for the CLI token fallback
and its base_url origin check, which had no tests at the Client level
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds a directory-wide conftest.py autouse fixture that stubs load_cli_token to None, preventing any test in tests/test_litellm/proxy/client/ from reading the developer's real ~/.litellm/token.json and producing environment-dependent failures. The patch target (litellm.litellm_core_utils.cli_token_utils.load_cli_token) is the correct seam: get_litellm_gateway_api_key calls it as a module-global lookup, so replacing the attribute on the module object intercepts every call.

  • Removes two pairs of duplicate test definitions that Python was silently shadowing; the previously-dead comprehensive definitions now actually run.
  • Expands test_client_without_api_key to assert None on all sub-clients (models, chat, keys, http), and adds two new tests pinning the CLI token fallback path and its origin-check (test_client_falls_back_to_stored_cli_token, test_client_ignores_cli_token_issued_for_other_server).
  • No production code is changed; all modifications are confined to the test directory.

Confidence Score: 5/5

Safe to merge — only test files are changed, no production logic is touched.

The change is entirely test-side: it fixes non-hermetic tests, removes shadowed duplicates that were never running, and adds meaningful coverage for the CLI token fallback. The monkeypatch target is the correct seam (module-level attribute patched before the function that calls it resolves the name), the autouse fixture composes correctly with per-test overrides because both use the same function-scoped monkeypatch instance, and the new assertions are accurate reflections of the production code's behavior.

No files require special attention.

Important Files Changed

Filename Overview
tests/test_litellm/proxy/client/conftest.py New autouse fixture that patches load_cli_token to return None for every test in the directory, hermetically isolating tests from the developer's real ~/.litellm/token.json.
tests/test_litellm/proxy/client/test_client.py Removes silently-shadowed duplicate test definitions, expands test_client_without_api_key to cover all sub-clients, splits out test_client_custom_timeout, and adds two new tests covering the CLI token fallback and its origin-check.

Reviews (1): Last reviewed commit: "test(proxy/client): isolate client tests..." | Re-trigger Greptile

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes the tests/test_litellm/proxy/client/ suite hermetic with respect to the developer's local environment by adding a directory-wide conftest.py that stubs load_cli_token to None for every test, preventing reads of the real ~/.litellm/token.json.

  • A new conftest.py introduces an autouse fixture that monkeypatches litellm.litellm_core_utils.cli_token_utils.load_cli_token to return None, covering all tests in the directory including test_models.py and test_model_groups.py which were also silently affected.
  • Duplicate test_client_initialization and test_client_without_api_key definitions (where Python silently shadowed the first with the second) are collapsed into single, more comprehensive tests; the timeout-specific assertion is split into test_client_custom_timeout.
  • Two new tests are added to explicitly cover the CLI-token fallback path: one asserting the stored token is used when issued for the matching server, and one asserting it is ignored when issued for a different server, pinning load_cli_token as the live isolation seam.

Confidence Score: 5/5

Safe to merge — the change is confined to the test directory, adds no production code, and the isolation strategy correctly targets the module-level symbol that get_litellm_gateway_api_key calls.

The autouse fixture patches the right symbol (litellm.litellm_core_utils.cli_token_utils.load_cli_token), which is what get_litellm_gateway_api_key resolves at call time. The two new per-test overrides compose correctly with the fixture because both use the same function-scoped monkeypatch instance, with LIFO teardown restoring state cleanly. The duplicate-test collapse retains all assertions from the surviving definitions, and no prior assertion was weakened or removed.

No files require special attention.

Important Files Changed

Filename Overview
tests/test_litellm/proxy/client/conftest.py New autouse fixture that stubs load_cli_token to None for all tests in the directory, preventing accidental reads of the developer's real ~/.litellm/token.json.
tests/test_litellm/proxy/client/test_client.py Merges shadowed duplicate test functions, extracts test_client_custom_timeout, and adds two new tests covering the CLI-token fallback and its origin-check. No coverage regressions found.

Reviews (2): Last reviewed commit: "test(proxy/client): isolate client tests..." | Re-trigger Greptile

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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