litellm/tests/test_litellm_rust/AGENTS.md
yujonglee 7d79ccb7cc
test(rust-bridge): select native routes per test without LITELLM_RUST (#46620)
* feat(rust-bridge): scope catalog rules with a contextvar

Co-Authored-By: Yujong Lee <yujong@berri.ai>

* test(rust-bridge): select native integration routes with scoped rules

Co-Authored-By: Yujong Lee <yujong@berri.ai>

* test(rust-bridge): run the Rust extension suite without LITELLM_RUST

Co-Authored-By: Yujong Lee <yujong@berri.ai>

* test(rust-bridge): use scoped catalog rules in dispatch tests

Co-Authored-By: Yujong Lee <yujong@berri.ai>

* refactor(rust-bridge): keep catalog rules a static global and override them once per test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 09:12:08 -07:00

3 KiB

Invariants

  • This directory tests the Rust path and nothing else. Treat the Python implementation of every route as already removed. Never call it on purpose, never run one request through both engines, and never compare Python and Rust outputs, headers, cache keys or logs
  • A test that would still pass with Python serving the call does not belong here. Every test asserts the call was served natively with support.routing.assert_served_natively
  • Select the Rust path with support.routing.native_route(...), which prepends RUST_REQUIRED rules to catalog.RULES and restores them on exit. Each route folder's conftest.py applies it to every test through an autouse fixture. A test outside a route folder wraps its whole body in one native_route(...) block, and a child interpreter script assigns catalog.RULES once at its top. Never select a backend by reading or setting LITELLM_RUST, calling litellm.rust(...) or rebinding catalog.RULES any other way. The rollout in litellm/rust_bridge/catalog.py is a product decision, and a test here must pass no matter what it says, including for a route marked PYTHON_ONLY
  • catalog.RULES is static at runtime and native_route(...) swaps a module global, so open it once per test and never per call. Two overlapping blocks, such as one per task inside an asyncio.gather, restore out of order and leave the wrong rules behind for later tests
  • A test whose subject is the rollout switch itself (env, litellm.rust(...), catalog rules) is a unit test of litellm/rust_bridge/configuration.py or catalog.py and lives in tests/unit/rust_bridge/
  • A test lives here only when it cannot be written in Rust. That means it needs the Python public API, Python-owned state such as litellm.cache and callbacks, or the process boundary (fork, threads, event loops). Anything checkable from the Rust side goes in the crate's own tests
  • The wire is the local recording server. No test here reaches a real provider
  • Never parametrize one test across routes. Each route folder owns its tests, its server fixture, its request data and its call
  • Call _native directly only for a case the public API cannot reach

Layout

Each route folder (ocr/, messages/, responses/, chat_completions/) uses the same file names, one concern per file

  • test_dispatch.py the call reaches the native route
  • test_requests.py Python inputs that reach the wire
  • test_failures.py errors raised to the caller and rejection before provider IO
  • test_settings.py globals, env, named credentials and their precedence
  • test_streaming.py stream relay, early close and stream-time logging
  • test_callbacks.py the logger hook contract
  • test_body_hooks.py handler body hooks such as interceptors and agentic loops
  • test_lifecycle.py cancellation, concurrency, context and nested calls
  • test_cache.py the configured cache seen from this route

Route data and the route's call live in <route>/data.py, and <route>/conftest.py owns the server fixture and the autouse native fixture. support/ holds only route-neutral helpers