Skip to content

🧪 Add tests for get_provider_route - #41

Closed
b3nw wants to merge 14 commits into
devfrom
test-get-provider-route-17306181585139002901
Closed

b3nw wants to merge 14 commits into
devfrom
test-get-provider-route-17306181585139002901

Conversation

@b3nw

@b3nw b3nw commented Apr 25, 2026

Copy link
Copy Markdown
Owner

🎯 What: The testing gap addressed for get_provider_route which was missing tests.
📊 Coverage: Scenarios covered: providers with trailing slash, without trailing slash, empty route, missing route key, and unknown provider.
Result: The improvement in test coverage allows for confident refactoring of get_provider_route and litellm providers code.


PR created automatically by Jules for task 17306181585139002901 started by @b3nw

b3nw and others added 10 commits April 24, 2026 19:40
…ardization, and utilities

Core infrastructure improvements:
- Smart 'latest' model alias resolution with cost-based tiebreaking
- Standardized error responses with proper HTTP status codes and error.code field
- ProxyExhaustionError for structured credential exhaustion reporting
- TerminalRequestError for non-rotatable errors (404, model not found)
- Per-provider retry count override via MAX_RETRIES_{PROVIDER} env var
- Retry 429 rate_limit errors with backoff instead of rotating
- Cached token pricing in streaming cost calculation
- Split quota stats into current_period and global/lifetime views
- Log rotation for proxy.log and proxy_debug.log (RotatingFileHandler)
- Include latest virtual models in /v1/models endpoint
- Resolve singleton cache pollution for dynamic providers
- Fork-specific README and .gitignore updates
…ased model filtering, and enhanced X-Initiator heuristic
Test suite designed to catch breakage from branch re-organization without
sending queries to real LLM providers. Covers all critical integration
points that previously broke silently during deployment.

Coverage:
- Anthropic↔OpenAI format translation & streaming
- Error classification (determines retry/rotation behavior)
- Request sanitization (prevents 400s from invalid params)
- Provider-specific request transforms
- Model alias & latest registry parsing
- Usage tracking (windows, quota groups, custom caps)
- Credential discovery, deduplication, env:// URI
- Provider plugin registration & singleton pattern
- Proxy endpoint routing & auth

All tests use synthetic credentials and mocked HTTP.
Runs in ~2.3s. Zero API cost.
…flow

Replaces the old manifest-driven multi-branch replay system with a
simpler linear commit stack. Changes are made via fixup!/autosquash.
Upstream syncs are a single git rebase.

Includes:
- AGENTS.md: entry point for all AI coding agents
- .agent/rules/claude.md: Claude-specific SSH/deployment notes
- .agent/rules/llm-proxy.md: container layout and deployment pipeline
- .agent/skills/upstream-sync/SKILL.md: sync workflow reference
Custom provider for Google Vertex AI Express Mode API keys that uses
x-goog-api-key header authentication against the Vertex AI
OpenAI-compatible endpoint. Supports non-streaming and streaming
chat completions with automatic model discovery.

Models are prefixed as vertex/ (e.g. vertex/gemini-3.1-flash-lite-preview).
Env vars: VERTEX_PROJECT, VERTEX_LOCATION, VERTEX_API_KEY_N
Added tests for get_provider_route in litellm_providers.py covering different trailing slash configurations and edge cases.
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new test suite for the get_provider_route function in tests/rotator_library/test_litellm_providers.py, covering scenarios such as trailing slashes, empty routes, and missing keys. The reviewer suggested refactoring these tests using pytest.mark.parametrize to eliminate repetitive code and improve maintainability.

Comment on lines +21 to +39
@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_with_trailing_slash():
assert get_provider_route("provider_with_slash") == "myroute"

@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_without_trailing_slash():
assert get_provider_route("provider_without_slash") == "myroute"

@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_empty():
assert get_provider_route("provider_empty_route") is None

@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_missing_key():
assert get_provider_route("provider_no_route") is None

@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_unknown_provider():
assert get_provider_route("unknown_provider") is None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The test suite for get_provider_route can be significantly simplified and made more maintainable by using pytest.mark.parametrize. This avoids repeating the @patch decorator and the function structure for each test case, making it easier to add new scenarios in the future.

Suggested change
@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_with_trailing_slash():
assert get_provider_route("provider_with_slash") == "myroute"
@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_without_trailing_slash():
assert get_provider_route("provider_without_slash") == "myroute"
@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_empty():
assert get_provider_route("provider_empty_route") is None
@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_missing_key():
assert get_provider_route("provider_no_route") is None
@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
def test_get_provider_route_unknown_provider():
assert get_provider_route("unknown_provider") is None
@patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS)
@pytest.mark.parametrize(
"provider_key, expected_route",
[
("provider_with_slash", "myroute"),
("provider_without_slash", "myroute"),
("provider_empty_route", None),
("provider_no_route", None),
("unknown_provider", None),
],
)
def test_get_provider_route(provider_key, expected_route):
assert get_provider_route(provider_key) == expected_route

@b3nw

b3nw commented Apr 26, 2026

Copy link
Copy Markdown
Owner Author

[Gemini-CLI Review Skill] @jules Reviewing this PR against the checklist and Gemini Code Assist feedback:

  1. [Gemini Code Assist] Parametrization: Please refactor the repetitive test functions into a single test using @pytest.mark.parametrize. This will cover trailing slashes, empty routes, and missing keys in a much more maintainable way.
  2. [Review Checklist] Mocking Robustness: The use of @patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS) is applied to every function. When you switch to parametrization, ensure the patch is applied correctly to the single test function.
  3. [Boundary/Edge] Malformed Config: Add a test case for when the route key exists but its value is not a string (e.g., None or an integer) to ensure the logic handles non-string values gracefully (or returns None).

@google-labs-jules

Copy link
Copy Markdown

[Gemini-CLI Review Skill] @jules Reviewing this PR against the checklist and Gemini Code Assist feedback:

  1. [Gemini Code Assist] Parametrization: Please refactor the repetitive test functions into a single test using @pytest.mark.parametrize. This will cover trailing slashes, empty routes, and missing keys in a much more maintainable way.
  2. [Review Checklist] Mocking Robustness: The use of @patch("rotator_library.litellm_providers.SCRAPED_PROVIDERS", MOCK_PROVIDERS) is applied to every function. When you switch to parametrization, ensure the patch is applied correctly to the single test function.
  3. [Boundary/Edge] Malformed Config: Add a test case for when the route key exists but its value is not a string (e.g., None or an integer) to ensure the logic handles non-string values gracefully (or returns None).

I have updated the test file to use @pytest.mark.parametrize for cleaner maintenance. I've also added test cases for non-string config routes and updated the original get_provider_route logic to handle those gracefully.

Refactored tests for get_provider_route to use parametrization, added test cases for non-string config routes, and updated the original logic to gracefully handle non-string routes.
@b3nw
b3nw marked this pull request as ready for review April 26, 2026 03:23
Refactored tests for get_provider_route to use parametrization, added test cases for non-string config routes, and updated the original logic to gracefully handle non-string routes.
@b3nw

b3nw commented Apr 26, 2026

Copy link
Copy Markdown
Owner Author

[Gemini-CLI Review Skill] @jules Great work on the get_provider_route tests. However, it looks like a package-lock.json was accidentally committed to this PR. Since this is a Python project and this PR focuses on backend tests, please remove package-lock.json to keep the diff clean.

@google-labs-jules

Copy link
Copy Markdown

[Gemini-CLI Review Skill] @jules Great work on the get_provider_route tests. However, it looks like a package-lock.json was accidentally committed to this PR. Since this is a Python project and this PR focuses on backend tests, please remove package-lock.json to keep the diff clean.

I have removed the package-lock.json file from the commit to keep the diff clean. I've re-pushed the changes.

Refactored tests for get_provider_route to use parametrization, added test cases for non-string config routes, and updated the original logic to gracefully handle non-string routes.
@b3nw

b3nw commented Apr 26, 2026

Copy link
Copy Markdown
Owner Author

[Gemini-CLI Review Skill] @jules One more thing for PR #41: please remove the changes to uv.lock. It should be handled separately from these test additions to keep the PR focused.

Refactored tests for get_provider_route to use parametrization, added test cases for non-string config routes, and updated the original logic to gracefully handle non-string routes.
@b3nw

b3nw commented Apr 26, 2026

Copy link
Copy Markdown
Owner Author

[Gemini-CLI Review Skill] Consolidated into the linear commit stack on dev.

@b3nw b3nw closed this Apr 26, 2026
@google-labs-jules

Copy link
Copy Markdown

[Gemini-CLI Review Skill] Consolidated into the linear commit stack on dev.

Acknowledged. This issue is resolved.

b3nw pushed a commit that referenced this pull request May 31, 2026
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