Commit graph

6418 commits

Author SHA1 Message Date
Krrish Dholakia
7f6f6bc7ba feat(policy_endpoints.py): expose new endpoint for testing policies and guardrails
enables compliance playground to work as expected
2026-02-17 21:54:04 -08:00
Krrish Dholakia
c5394e7c3e feat(policy_endpoints.py): new helper function for testing policies 2026-02-17 21:40:59 -08:00
Ishaan Jaffer
beaf556563 add tests for EU AI Act compliance checker 2026-02-17 20:26:28 -08:00
Ishaan Jaff
5946a933a0
Add compliance checker endpoints + UI panel (#21432)
* eu_ai_act_article5_prohibited_practices_fr

* add backend for checkers

* test checker

* checkEuAiActCompliance

* register compliance router in proxy_server.py

* add compliance check functions to networking.tsx

* fix useEffect dependency array in CompliancePanel

* ui fixes
2026-02-17 18:22:26 -08:00
Sameer Kankute
2517c069ca
Merge pull request #21387 from BerriAI/litellm_vllm_e2e_testing
move e2e to llm translation
2026-02-18 07:44:53 +05:30
Ishaan Jaffer
a6f467e896 fixes - showing content filter on failure 2026-02-17 17:57:52 -08:00
jquinter
93bbc27c53
Merge pull request #21434 from BerriAI/fix/langfuse-otel-sys-modules-leak
fix: restore sys.modules after stub injection in langfuse otel test
2026-02-17 22:32:12 -03:00
Ishaan Jaff
24fcc9da7c
fix: session grouping broken for dict rows from query_raw (#21435)
* fix: session grouping for dict rows from query_raw

* test: add unit test for session count enrichment with dict rows
2026-02-17 17:21:17 -08:00
Julio Quinteros Pro
32922449a3 fix: restore sys.modules after stub injection in langfuse otel test
test_extract_langfuse_metadata_with_header_enrichment replaced
sys.modules["litellm.integrations.langfuse.langfuse"] with a stub
module but never restored it. This caused subsequent tests using
patch("litellm.integrations.langfuse.langfuse._add_prompt_to_generation_params")
to patch the stub instead of the real module, while _log_langfuse_v2
executed from the real module's globals (unpatched), triggering
ModuleNotFoundError and assertion failures.

Fix: use monkeypatch.setitem() so pytest automatically restores the
original module after the test completes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 22:01:21 -03:00
jquinter
cca4a8699a
Merge pull request #20595 from jquinter/fix/test-parallelization-isolation
fix: improve test isolation for parallel execution
2026-02-17 21:46:31 -03:00
Julio Quinteros Pro
c3346962a9 fix: replace silent if-hasattr guards with unconditional assertions in MCP streaming tests
The `if hasattr(...)` guards in test_acompletion_with_mcp_adds_metadata_to_streaming
and test_acompletion_with_mcp_streaming_metadata_in_correct_chunks could silently skip
the provider_specific_fields assertions if chunks lacked choices/delta. Replace with
unconditional `assert hasattr(...)` so failures surface immediately.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 21:42:31 -03:00
Julio Quinteros Pro
e6abb865d3 fix: properly reload litellm in setup_and_teardown fixture
Use importlib.import_module + reload uniformly in both code paths
to ensure fresh module state regardless of whether litellm was
previously in sys.modules. This fixes the inconsistency where the
"not in sys.modules" branch didn't reload the module.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 21:29:13 -03:00
Julio Quinteros Pro
77f315eb11 fix: address Greptile review feedback for test isolation
- test_pillar_guardrails.py: Fix fixture to properly update module-level
  litellm reference using global keyword and assignment from reload
- test_anthropic_experimental_pass_through_messages_handler.py: Add missing
  assert keywords to kwargs comparison statements (lines 36, 60-62)
- test_proxy_server.py: Replace silent pytest.skip with explicit assertion
  to catch router initialization regressions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 21:28:23 -03:00
Julio Quinteros Pro
ab6d2eefb9 fix: improve test isolation for parallel execution
Fixes test failures that occur during parallel test execution (pytest -n 4)
due to module reloading issues with conftest.py reloading litellm.

Changes:
- Add module reload fixtures to ensure fresh references after conftest reloads
- Use patch.object and string-based patches instead of direct attribute assignment
- Use class name comparison instead of isinstance for reloaded modules
- Handle case where litellm is missing from sys.modules during parallel runs
- Move stream consumption inside patch contexts to avoid real API calls
- Mock litellm.acompletion instead of low-level HTTP handlers
- Add skipif decorator for enterprise-only test classes

Affected test files:
- test_container_integration.py
- test_responses_background_cost.py
- test_huggingface_embedding_handler.py
- test_vertex_ai_rerank_integration.py
- test_volcengine_responses_transformation.py
- test_pillar_guardrails.py
- test_litellm_pre_call_utils.py
- test_proxy_server.py
- test_converse_transformation.py
- test_chat_completions_handler.py
- test_aresponses_api_with_mcp.py
- test_anthropic_experimental_pass_through_messages_handler.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 21:28:23 -03:00
Julio Quinteros Pro
eff082993a Fix mock target for enterprise license check
Changed from non-existent JWTAuthManager._is_jwt_auth_available to
the correct proxy_server.premium_user, which is the established
pattern used elsewhere in the test suite.

This fixes the AttributeError that would occur at runtime.

Addresses Greptile feedback (score 1/5 -> should be 5/5 now).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 21:25:00 -03:00
Julio Quinteros Pro
3c61c7fbb1 fix(test): mock enterprise license check in JWT test
The test test_jwt_non_admin_team_route_access was failing with:
```
AssertionError: assert 'Only proxy admin can be used to generate' in
'Authentication Error, JWT Auth is an enterprise only feature...'
```

Root cause: The test was hitting the enterprise license validation before
reaching the proxy admin authorization check. In parallel execution with
--dist=loadscope, environment variables like LITELLM_LICENSE can vary
between workers or be unset, causing inconsistent test behavior.

Solution: Mock the JWTAuthManager._is_jwt_auth_available method to
return True, bypassing the license check. This allows the test to
reach the actual authorization logic being tested (proxy admin check).

This approach is more reliable than setting environment variables which
can cause pollution between parallel tests.

Fixes test failure exposed by PR #21277.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 21:25:00 -03:00
jquinter
62c7ebfd2c
Merge pull request #21431 from BerriAI/fix/isolate-litellm-transport-state
fix(tests): restore disable_aiohttp_transport and force_ipv4 in isolate_litellm_state
2026-02-17 21:22:41 -03:00
jquinter
faa16ef29f
Merge pull request #21428 from BerriAI/fix/vertex-gpt-oss-test-isolation
fix(tests): use class-level AsyncHTTPHandler mock in vertex GPT-OSS tests
2026-02-17 21:22:27 -03:00
jquinter
59171bd76d
Merge pull request #21423 from BerriAI/fix/token-counter-test-isolation
fix(token-counter): fix test isolation and encode() return type normalization
2026-02-17 21:22:05 -03:00
Julio Quinteros Pro
d7b0a8c559 fix(tests): restore disable_aiohttp_transport and force_ipv4 in isolate_litellm_state
Many tests across the llms group (sap, compactifai, vercel_ai_gateway, mistral,
zai, heroku) set litellm.disable_aiohttp_transport = True without restoring it.
When these tests run before test_ssl_context_transport or test_session_reuse_chain
in the same xdist worker, _create_async_transport() returns None (because aiohttp
is disabled AND force_ipv4 is False), causing both tests to fail with
'assert None is not None'.

Fix: extend isolate_litellm_state in conftest.py to also save and restore
disable_aiohttp_transport and force_ipv4, following the same pattern already
used for callbacks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 21:18:49 -03:00
Ishaan Jaff
3cc032bc0c
Add French language support for EU AI Act Article 5 guardrail (#21427)
* Add French language support for EU AI Act Article 5 template

- Create eu_ai_act_article5_fr.yaml with comprehensive French keywords
- Includes identifier words: concevoir, créer, développer, noter, classer, etc.
- Includes block words: crédit social, comportement social, émotion des employés, etc.
- Includes always-block keywords for explicit prohibited practices
- Includes exceptions for research, compliance, and legitimate use cases
- Catches circumvention attempts with phrase variations

* Add comprehensive tests for French EU AI Act guardrail

- Test 3 critical scenarios: blocked query, circumvention attempt, safe query
- Test edge cases: case-insensitive, mixed language, research exceptions
- All 7 tests passing
- Validates both blocking and allowing behavior

* Fix content filter to support conditional matching without inherit_from

- Enable conditional matching when identifier_words + additional_block_words are present
- Previously required inherit_from, but EU AI Act templates are self-contained
- Fixes Greptile feedback: conditional matching now works as documented

* Add pure conditional matching test for French guardrail

- Test identifier + block word combinations not in always_block_keywords
- Verifies conditional matching works independently
- Addresses Greptile feedback about test coverage gap

* Fix exception word bypass risk in French template

- Replace short words (film, jeu, juste) with context-specific phrases
- Prevents substring matching bypasses (e.g., enjeu matching jeu)
- Add tests for bypass prevention and legitimate game context
- Addresses Greptile security feedback

* Make conditional match assertion more robust

- Use getattr to safely access exception detail field
- Check if detail is dict before calling .get()
- Addresses Greptile feedback about brittle string assertion
2026-02-17 16:07:54 -08:00
Julio Quinteros Pro
ea0cfac995 fix(tests): add cache flush fixture for reliable HTTP client isolation
Add _reset_litellm_http_client_cache autouse fixture (matching
test_vertex_gemma_transformation.py) to flush in_memory_llm_clients_cache
before each test. Without this, a cached real AsyncHTTPHandler from an
earlier test could bypass the class-level mock and cause real HTTP calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 21:02:56 -03:00
Julio Quinteros Pro
f0fc44c244 fix(tests): use class-level AsyncHTTPHandler mock in vertex GPT-OSS tests
Replace instance-level patch.object(client, "post", side_effect=...) with
class-level patch of AsyncHTTPHandler and AsyncMock to reliably intercept
HTTP calls in CI where real Google credentials are available.

The old approach patched a specific instance's post method and passed
client=client to acompletion(). In CI, the mock wasn't intercepting actual
HTTP calls, causing 401 ACCESS_TOKEN_TYPE_UNSUPPORTED errors. The new
approach patches AsyncHTTPHandler at the class level so any instance
created internally by get_async_httpx_client() is also mocked.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:52:25 -03:00
Julio Quinteros Pro
a6df01caec fix: remove importlib.reload calls that cause cross-test class-reference staleness
Two test files were reloading modules in setup_method/fixtures, which
caused class-reference staleness for subsequent tests in the same worker:

1. test_huggingface_embedding_handler.py reloaded
   litellm.llms.custom_httpx.http_handler, creating a new HTTPHandler
   class. Subsequent tests (e.g. hosted_vllm embedding) created
   client = HTTPHandler() from the new class, but llm_http_handler.py
   still held the old class reference. isinstance(client, HTTPHandler)
   returned False, so a new unpatched client was used and
   client.post was never called.

2. test_vertex_ai_rerank_integration.py reloaded
   litellm.llms.vertex_ai.rerank.transformation in setup_method,
   creating a new VertexAIRerankConfig class. The transformation test
   file's module-level import still referenced the old class, so
   @patch('...VertexAIRerankConfig._ensure_access_token') patched the
   new class while self.config was an instance of the old class,
   leaving the mock unapplied and hitting real Google credentials.

Fix: remove the reload calls. The module-level class references are
stable across tests within a worker; the reloads were solving a problem
that doesn't exist and actively created cross-test contamination.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:31:10 -03:00
Julio Quinteros Pro
fd1237e9af fix(token-counter): fix test isolation and encode() return type normalization
Two independent fixes for test_token_counter.py failures in CI:

1. test_disable_hf_tokenizer_download leaked litellm.disable_hf_tokenizer_download=True
   because pytest.MonkeyPatch() was never undone. The setting persisted into the
   alphabetically-subsequent test_llama2/3_tokenizer_api_failure tests, causing
   _select_tokenizer_helper to short-circuit before calling from_pretrained.
   Fix: wrap the test body in try/finally and call monkeypatch.undo().

2. encode() returns a HuggingFace Encoding object when the HF tokenizer loads, but
   falls back to returning a plain List[int] (tiktoken) when the model hub is
   unreachable. test_encoding_and_decoding called .ids on the result, which raises
   AttributeError when the list-based fallback is active.
   Fix: normalize encode() to always return List[int] by extracting .ids when present,
   and remove the now-unnecessary .ids access in the test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 20:07:52 -03:00
jquinter
acbcfec313
Merge pull request #21422 from BerriAI/fix/lakera-keyerror-missing-api-key
fix(lakera-guardrail): avoid KeyError on missing LAKERA_API_KEY during initialization
2026-02-17 20:06:43 -03:00
jquinter
153af8b901
Merge pull request #21421 from BerriAI/fix/mock-prisma-in-backoff-tests
fix(tests): mock prisma.Prisma in backoff retry tests to avoid 'prisma generate'
2026-02-17 20:04:34 -03:00
jquinter
7b49be1ee1
Merge pull request #21416 from BerriAI/fix/token-counter-hf-fallback
fix(token-counter): normalize encode() return type and handle HF tokenizer fallback
2026-02-17 20:01:42 -03:00
jquinter
6d5f9b5baa
Merge pull request #21419 from BerriAI/fix/langfuse-test-supports-prompt-flakiness
fix(test): prevent flaky failure in test_log_langfuse_v2_handles_null_usage_values
2026-02-17 20:01:03 -03:00
jquinter
afbfbf3cae
Update tests/test_litellm/litellm_core_utils/test_token_counter.py
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-02-17 19:52:06 -03:00
Julio Quinteros Pro
f8f2a86ce1 fix(lakera-guardrail): use os.environ.get() to avoid KeyError on missing LAKERA_API_KEY
`os.environ["LAKERA_API_KEY"]` raises KeyError when the env var is absent,
causing test_active_callbacks to error during fixture setup. Switch to
`os.environ.get()` in both lakera_ai.py and lakera_ai_v2.py so initialization
succeeds without the key (actual API calls will fail separately if key is unset).

Also mock `premium_user=True` in the test fixture so the enterprise
`hide_secrets` guardrail can initialize, matching the test's expectations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 19:30:22 -03:00
Julio Quinteros Pro
defc76b32a fix(tests): mock prisma.Prisma in backoff retry tests to avoid 'prisma generate'
PrismaClient.__init__ does `from prisma import Prisma` inline, which raises
RuntimeError when the Prisma client hasn't been generated.  This caused two
tests to fail in CI with:

  Exception: Unable to find Prisma binaries. Please run 'prisma generate' first.

Add an autouse fixture that replaces sys.modules['prisma'] with a MagicMock
for the duration of each test, allowing PrismaClient to be instantiated and
client.db to be overridden with the existing mock objects.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 19:29:20 -03:00
Julio Quinteros Pro
16ca7f4f96 fix(token-counter): normalize encode() return type and handle HF tokenizer fallback
- encode() now always returns List[int] by extracting .ids from HuggingFace
  Encoding objects, making the return type consistent regardless of tokenizer backend
- test_encoding_and_decoding: remove .ids access since encode() now returns a list
- test_tokenizers: skip llama2 differentiation assertion when HuggingFace tokenizer
  is unavailable (CI without network access falls back to tiktoken)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 19:19:27 -03:00
Julio Quinteros Pro
703f02bf99 fix(test): prevent flaky failure in test_log_langfuse_v2_handles_null_usage_values
This test has failed repeatedly in CI with:
  'Expected _add_prompt_to_generation_params to have been called once. Called 0 times.'

Root cause: _add_prompt_to_generation_params is only called when _supports_prompt()
returns True. Under cross-test state contamination in CI (parallel workers),
langfuse_sdk_version can be in an unexpected state, causing _supports_prompt() to
return False and silently skip the call (exception swallowed by the outer try/except).

Fixes:
- Use reset_mock(side_effect=True) so setUp's trace side_effect is cleared and the
  explicit return_value assignment actually takes effect
- Patch _supports_prompt on the logger instance to always return True, making the
  _add_prompt_to_generation_params assertion independent of SDK version state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-17 19:18:12 -03:00
Julio Quinteros Pro
26f8e1ac0a fix(tests): resolve test isolation issue in http_handler tests
Fix isinstance() checks failing due to module reload in conftest.py.

The conftest.py fixture reloads the litellm module between test modules,
which causes class references imported at module-level to become stale.
When AsyncHTTPHandler is imported at the top of the file and then litellm
is reloaded by the fixture, the isinstance() check fails because the
returned instance is of the NEW AsyncHTTPHandler class while the test
is checking against the OLD class reference.

Solution: Import AsyncHTTPHandler locally within each test function that
uses isinstance() checks. This ensures we get the fresh class reference
after the module reload.

Fixed tests:
- test_session_reuse_integration
- test_get_async_httpx_client_with_shared_session
- test_get_async_httpx_client_without_shared_session

This resolves intermittent CI failures where parallel test execution
triggers the module reload behavior.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 19:01:02 -03:00
Julio Quinteros Pro
890cc08a3a fix: resolve merge conflict and Greptile feedback
- Remove pytest-retry config from pyproject.toml (fixes merge conflict with main)
- Fix asymmetric callback restoration in isolate_litellm_state fixture
  - Now properly saves and restores all callback lists
  - Prevents test pollution from callback state leakage
- Add cache flush after module reload in setup_and_teardown
  - Prevents stale client instances after importlib.reload
- Remove unused imports (curr_dir, Router)

This addresses:
1. Merge conflict in pyproject.toml (CONFLICTING status)
2. Greptile's feedback about asymmetric callback handling
3. Missing cache flush after module reload
4. Code cleanliness (unused variables)
2026-02-17 18:20:44 -03:00
Julio Quinteros Pro
480974e0f9 fix: complete asyncio.iscoroutinefunction deprecation fix across codebase
Replace all asyncio.iscoroutinefunction() calls with inspect.iscoroutinefunction()
to fix Python 3.16 deprecation warnings throughout the entire codebase.

Files updated:
- litellm/litellm_core_utils/logging_utils.py
- litellm/proxy/common_utils/performance_utils.py
- litellm/proxy/management_endpoints/key_management_endpoints.py (2 occurrences)
- litellm/proxy/management_endpoints/ui_sso.py
- litellm/litellm_core_utils/redact_messages.py
- litellm/integrations/custom_guardrail.py
- tests/proxy_unit_tests/test_response_polling_handler.py

This addresses Greptile's feedback about incomplete deprecation fixes.
All instances now use the standard library inspect.iscoroutinefunction()
which is the recommended approach and won't be deprecated.
2026-02-17 18:20:44 -03:00
Julio Quinteros Pro
e37befd5b4 fix: address Greptile feedback - remove duplicates and fix deprecations
- Remove duplicate @pytest.fixture decorator on setup_and_teardown
- Delete conftest_improved.py (duplicate file, pytest only loads conftest.py)
- Remove deprecated event_loop fixture override
- Add asyncio_default_fixture_loop_scope config in pyproject.toml (modern approach)

This fixes pytest-asyncio >=0.22 deprecation warnings while maintaining
session-scoped event loop behavior.
2026-02-17 18:20:43 -03:00
Julio Quinteros Pro
53d9cad8f5 fix(tests): restore autouse=True to setup_and_teardown fixture
Critical fix for Greptile feedback: The setup_and_teardown fixture was
missing the autouse=True parameter, causing the module reload logic to
never execute. This would result in test pollution as callbacks would
chain across modules.

Changes:
- Add autouse=True to setup_and_teardown fixture in conftest.py
- Add autouse=True to setup_and_teardown fixture in conftest_improved.py

Note: conftest_improved.py is intentionally kept as a reference
implementation showing the recommended improvements. It demonstrates
better patterns for test isolation that can be adopted later.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 18:20:23 -03:00
Julio Quinteros Pro
3b176a0970 fix(tests): remove asyncio.get_event_loop_policy deprecation warning
- Replace asyncio.get_event_loop_policy() with asyncio.new_event_loop()
- Use asyncio.set_event_loop() to set the event loop
- Fixes deprecation warning in Python 3.16
- Updated both conftest.py and conftest_improved.py

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-17 18:20:23 -03:00
Julio Quinteros Pro
f9ea565b3b fix(tests): improve test isolation in conftest.py
- Move cache flushing to function scope
  - Disable module reload in parallel mode
  - Remove manual event loop creation
2026-02-17 18:20:23 -03:00
Sameer Kankute
126cf36dc4 move e2e to llm translation 2026-02-17 22:33:13 +05:30
Sameer Kankute
809838042e
Merge pull request #21382 from BerriAI/litellm_vllm_e2e_testing
Add vllm e2e test for embedding
2026-02-17 22:32:42 +05:30
Sameer Kankute
811ffff0b8 move e2e to llm translation 2026-02-17 21:14:44 +05:30
Sameer Kankute
ec573ee2b0
Merge pull request #21375 from BerriAI/litellm_evals_api
[feat] Add support for Openai Evals API
2026-02-17 21:01:36 +05:30
Sameer Kankute
791cef6d99 fix test_chat_completion 2026-02-17 20:26:28 +05:30
Sameer Kankute
288f7b860c fix test_allow_access_by_email 2026-02-17 20:19:39 +05:30
Sameer Kankute
1ced47c612 fix tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server.py 2026-02-17 20:14:56 +05:30
Sameer Kankute
550bb621f7 fix llm tests 2026-02-17 20:13:23 +05:30
Sameer Kankute
fe20e66a1d Fix : test_exception_without_scanners 2026-02-17 20:12:02 +05:30