Skip to content
12 changes: 11 additions & 1 deletion tests/e2e/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,20 @@ One sharp edge: a replayed response reuses the recorded provider response id, an

Another sharp edge, same root: record and replay derive every per-test token deterministically (the model name included, so a replay regenerates the exact requests the record run sent), which means an edge-wired deployment left in the database by an interrupted earlier run carries the same model name as the fresh one the current run registers. The proxy then holds two deployments under one model group and load-balances across both, and because the leftover's `api_base` points at the earlier run's edge process, which is gone, the calls that land on it fail with a connection error that reads like a transport bug rather than the stale row it is. Give each record or replay run a fresh database, or let a run finish so its own teardown deletes what it registered, and never reuse one long-lived proxy across back-to-back record/replay sessions. CI hands every job its own empty database and its own proxy, so it never sees this

Replay answers any provider call that drifted from the recording with an HTTP 599 whose body names the computed and closest recorded keys, so the test fails loudly instead of silently going live, and a bundle older than seven days fails at collection time naming its age; either way the fix is to re-record. Only tests that register edge-wired deployments participate: everything else hits its provider live in every mode, so record exactly the suite you replay. If the proxy runs in a container, set `E2E_PROVIDER_EDGE_ADVERTISE_HOST` (e.g. `host.docker.internal`) so the api_base the proxy stores can reach the edge on the pytest host, and `E2E_PROVIDER_EDGE_BIND_HOST=0.0.0.0` so the edge accepts it. The suites wired to the edge today are `quota_management/spend_tracking/test_provider_edge_spend_e2e.py`, `llm_translation/test_chat_completions_contract_e2e.py`, the OpenAI registrations in `llm_translation/test_embeddings_endpoint_e2e.py`, the Anthropic tests in `llm_translation/test_messages_e2e.py`, streamed and not, and the OpenAI batch deployment behind `batches/`. A streamed response replays as the chunk sequence the provider sent rather than one buffered body. See `AGENTS.md` in this directory for the bundle format, the edge design, and the current limits (Bedrock). The scheduled CI record/replay lane is described above
Replay answers any provider call that drifted from the recording with an HTTP 599 whose body names the computed and closest recorded keys, so the test fails loudly instead of silently going live, and a bundle older than seven days fails at collection time naming its age; either way the fix is to re-record. Only tests that register edge-wired deployments participate: everything else hits its provider live in every mode, so record exactly the suite you replay. If the proxy runs in a container, set `E2E_PROVIDER_EDGE_ADVERTISE_HOST` (e.g. `host.docker.internal`) so the api_base the proxy stores can reach the edge on the pytest host, and `E2E_PROVIDER_EDGE_BIND_HOST=0.0.0.0` so the edge accepts it. The suites wired to the edge today are `quota_management/spend_tracking/test_provider_edge_spend_e2e.py`, `llm_translation/test_chat_completions_contract_e2e.py`, the OpenAI registrations in `llm_translation/test_embeddings_endpoint_e2e.py`, the Anthropic tests in `llm_translation/test_messages_e2e.py`, streamed and not, the OpenAI and Anthropic cells of `llm_translation/test_endpoint_matrix_e2e.py`, and the OpenAI batch deployment behind `batches/`. A streamed response replays as the chunk sequence the provider sent rather than one buffered body. See `AGENTS.md` in this directory for the bundle format, the edge design, and the current limits (Bedrock). The scheduled CI record/replay lane is described above

Tests marked `@pytest.mark.e2e` hard-fail when no proxy answers `/health/liveliness`, so a run that goes red with `No live proxy` at setup means the proxy isn't up; they never skip for a missing proxy, so an absent proxy can't be mistaken for a pass

### The endpoint matrix

`llm_translation/test_endpoint_matrix_e2e.py` runs one scenario per inference endpoint (`/chat/completions`, `/v1/completions`, `/v1/messages`, `/v1/responses`, `/embeddings`, `/v1/images/generations`, `/v1/images/edits`, `/v1/audio/speech`, `/v1/audio/transcriptions`, `/v1/moderations`, streamed and not where the endpoint streams) over every provider in `llm_translation/endpoint_matrix.py` that serves it, and over every way the proxy can hold that provider's secret: `os.environ/` references, literal values, and a stored `litellm_credential_name`. Each cell is one pytest parameter carrying its exact registry id, so a translation bug fixed on `/chat/completions` but not on `/v1/messages` shows up as one red cell next to green ones instead of a test gap. Adding a provider is one `Provider` entry in the catalog naming its route, credential environment variables, and backend model per endpoint; it needs no new test code. `E2E_MATRIX_PROVIDERS` and `E2E_MATRIX_AUTH_MODES` narrow a run to a comma-separated subset of catalog routes and auth modes, unknown names fail at collection, and a provider whose secret is missing from the runner fails its inline and stored-credential cells by variable name rather than skipping, while its `os.environ/` cells and every other provider still run

```bash
E2E_MATRIX_PROVIDERS=openai,anthropic E2E_MATRIX_AUTH_MODES=env_ref uv run pytest tests/e2e/llm_translation/test_endpoint_matrix_e2e.py
```

Providers with a generic edge mount (OpenAI and Anthropic today) are edge-wired and marked `replayable`, so their cells join the scheduled record/replay lane and run with zero provider egress on weekdays; the rest hit their provider live in every fixture mode. The two lanes prove different things: replay proves routing and response shape, since the edge keys fixtures on the request body and never on the provider auth header, so only the live and record lanes prove the proxy sent the deployment's own secret, and even there an `inline` or `stored_credential` cell whose value equals the runner's `os.environ/` value cannot tell the two resolutions apart. The module registers the deployments its selected cells need as one `register_models` batch in a module fixture, so a run pays the data-plane reload and propagation budget once rather than once per cell, which is what keeps a 60-cell replay in the tens of seconds

## What a complete test looks like

A feature test is complete only when it walks the feature end to end, in this order
Expand Down
13 changes: 13 additions & 0 deletions tests/e2e/coverage_registry/llm_conversational.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,16 @@
- {id: llm.messages.together_ai.basic.stream.works, module: llm, tier: P1, subject_endpoint: messages, route: together_ai, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_together_ai_e2e.py", rationale: "Together over /v1/messages streaming"}
- {id: llm.messages.together_ai.tool_use.nonstream.works, module: llm, tier: P1, subject_endpoint: messages, route: together_ai, capability: tool_use, streaming: nonstream, assertions: [works], source: "llm_translation/test_together_ai_e2e.py", rationale: "Together tool calls over /v1/messages"}
- {id: llm.messages.together_ai.multi_turn.nonstream.works, module: llm, tier: P1, subject_endpoint: messages, route: together_ai, capability: multi_turn, streaming: nonstream, assertions: [works], source: "llm_translation/test_together_ai_e2e.py", rationale: "Together tool result round trip over /v1/messages"}
- {id: llm.chat_completions.together_ai.basic.nonstream.works, module: llm, tier: P0, subject_endpoint: chat_completions, route: together_ai, capability: basic, streaming: nonstream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Together chat, plain visible answer over /chat/completions; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.chat_completions.together_ai.basic.stream.works, module: llm, tier: P0, subject_endpoint: chat_completions, route: together_ai, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Together chat streaming; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.chat_completions.gemini.basic.stream.works, module: llm, tier: P0, subject_endpoint: chat_completions, route: gemini, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Gemini chat streaming; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.messages.openai.basic.nonstream.works, module: llm, tier: P0, subject_endpoint: messages, route: openai, capability: basic, streaming: nonstream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "OpenAI over /v1/messages translation; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.messages.openai.basic.stream.works, module: llm, tier: P0, subject_endpoint: messages, route: openai, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "OpenAI over /v1/messages streaming; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.messages.gemini.basic.nonstream.works, module: llm, tier: P0, subject_endpoint: messages, route: gemini, capability: basic, streaming: nonstream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Gemini over /v1/messages translation; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.messages.gemini.basic.stream.works, module: llm, tier: P0, subject_endpoint: messages, route: gemini, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Gemini over /v1/messages streaming; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.messages.together_ai.basic.nonstream.works, module: llm, tier: P0, subject_endpoint: messages, route: together_ai, capability: basic, streaming: nonstream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Together over /v1/messages translation; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.responses.anthropic.basic.stream.works, module: llm, tier: P0, subject_endpoint: responses, route: anthropic, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Responses streaming w/ Anthropic translation; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.responses.bedrock_converse.basic.stream.works, module: llm, tier: P0, subject_endpoint: responses, route: bedrock_converse, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Responses streaming w/ Bedrock Converse; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.responses.vertex.basic.stream.works, module: llm, tier: P0, subject_endpoint: responses, route: vertex, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Responses streaming w/ Vertex; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.responses.gemini.basic.nonstream.works, module: llm, tier: P0, subject_endpoint: responses, route: gemini, capability: basic, streaming: nonstream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Responses w/ Gemini translation; same request and assertion as every other endpoint/provider cell in the matrix"}
- {id: llm.responses.gemini.basic.stream.works, module: llm, tier: P0, subject_endpoint: responses, route: gemini, capability: basic, streaming: stream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Responses streaming w/ Gemini; same request and assertion as every other endpoint/provider cell in the matrix"}
1 change: 1 addition & 0 deletions tests/e2e/coverage_registry/llm_nonconversational.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,4 @@
- {id: llm.audio_transcriptions.nvidia_riva.basic.nonstream.works, module: llm, tier: P2, subject_endpoint: audio_transcriptions, route: openai, capability: basic, streaming: nonstream, assertions: [works], source: "nvidia_riva/audio_transcription/handler.py", rationale: "NVIDIA Riva (smoke)"}
- {id: llm.moderations.openai.basic.nonstream.works, module: llm, tier: P1, subject_endpoint: moderations, route: openai, capability: basic, streaming: nonstream, assertions: [works], source: "proxy_server.py", rationale: "OpenAI moderations (only provider)"}
- {id: llm.moderations.openai.input_validation.nonstream.works, module: llm, tier: P1, subject_endpoint: moderations, route: openai, capability: input_validation, streaming: nonstream, assertions: [works], source: "vendor strategy §9.8 / LIT-4778", rationale: "Moderations missing input rejected"}
- {id: llm.embeddings.gemini.basic.nonstream.works, module: llm, tier: P0, subject_endpoint: embeddings, route: gemini, capability: basic, streaming: nonstream, assertions: [works], source: "llm_translation/test_endpoint_matrix_e2e.py", rationale: "Gemini embeddings; same request and assertion as every other embeddings cell in the matrix"}
13 changes: 9 additions & 4 deletions tests/e2e/fixture_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,17 @@ class ReplayMiss(AssertionError):
_marker_ordinals: Final[dict[str, int]] = {}


def marker_owner() -> str:
owner = registration_owner()
return current_test_key() if owner == SESSION_TEST_KEY else owner


def deterministic_marker() -> str:
"""Stable stand-in for uuid-based unique markers in record and replay modes:
the Nth marker of a test is a pure function of the test's node id and N, so a
replay run regenerates exactly the model names, prompts, and tags the record
run sent and every recorded provider interaction still matches its key."""
test_key = current_test_key()
the Nth marker of a node is a pure function of its id and N, so a replay run
regenerates exactly the model names, prompts, and tags the record run sent and
every recorded provider interaction still matches its key."""
test_key = marker_owner()
ordinal = _marker_ordinals.get(test_key, 0)
_marker_ordinals[test_key] = ordinal + 1
return hashlib.sha1(f"{test_key}#{ordinal}".encode()).hexdigest()[:12]
Expand Down
Loading
Loading