Skip to content

test(ai-proxy): end-to-end coverage for ADR-0030 + drive-by dispatch fix#80

Merged
ndreno merged 1 commit intomainfrom
test/ai-proxy-routes-coverage
May 5, 2026
Merged

test(ai-proxy): end-to-end coverage for ADR-0030 + drive-by dispatch fix#80
ndreno merged 1 commit intomainfrom
test/ai-proxy-routes-coverage

Conversation

@ndreno
Copy link
Copy Markdown
Contributor

@ndreno ndreno commented May 5, 2026

Replacement for #77 (auto-closed on #79's merge). Same content; rebased onto main.

Original PR: #77

…e-by dispatch fix

Adds integration tests, fixture coverage, and a vacuum migration fixture
for the ADR-0030 implementation stack (PR-1 → PR-3). Surfaced and fixed
one bug along the way.

Drive-by fix
============

The path-based dispatch added in PR-1 (#73) was too strict: it returned
404 for any req.path != /v1/chat/completions, breaking every existing
test fixture and any operator-defined operation path. The dispatcher
shouldn't constrain the operator's choice of path when only one protocol
is on offer. Now defaults to chat_completion::handle for any path; PR-4
will narrowly add /v1/responses when there's a real second protocol to
differentiate. Removes the dead 404 arm from error_response().

The unit test from PR-1 that asserted the rejected behavior is replaced
with one that asserts the dispatcher accepts custom paths today.

Coverage added
==============

Integration tests (crates/barbacane-test/tests/ai_proxy.rs, +5 tests):
- test_ai_proxy_routes_first_match_wins — wiremock with three route
  prefixes proves claude-* / gpt-* / catch-all dispatch to the right
  upstream URL via the actual data plane pipeline.
- test_ai_proxy_400_when_body_omits_model — proves the model_required
  short-circuit fires end-to-end.
- test_ai_proxy_400_no_route_when_model_does_not_match — proves the
  no_route response shape ships through the data plane.
- test_ai_proxy_403_model_not_permitted_does_not_reach_upstream —
  wiremock with .expect(0) proves the upstream is never called when
  catalog policy denies; would catch a regression that leaks through
  to the provider.
- test_ai_proxy_403_does_not_fall_through_to_next_route — proves the
  no-fallthrough rule from ADR-0030 §3 holds in the real pipeline.

End-to-end tests (crates/barbacane-test/tests/ai_gateway.rs, +2 tests):
- cel_driven_target_deny_fires_403_not_silent_pass — the load-bearing
  ADR-0030 §3 subtlety in the actual pipeline. cel writes
  ai.target=anthropic-tier based on a header; the named target carries
  deny:["claude-opus-*"]; a request with claude-opus-4-6 hits 403,
  not silent pass. Mock has .expect(0) so the test proves the upstream
  is never called.
- cel_driven_target_deny_passes_when_model_does_not_match_deny —
  positive control for the same spec; proves a non-denied model still
  reaches upstream.

Compilation smoke (tests/fixtures/ai-proxy.yaml, +2 operations):
- /ai/routed/chat/completions with full routes table including allow,
  deny, and a catch-all.
- /ai/restricted/chat/completions with default_target + catalog deny
  on a named target.

Vacuum migration UX (docs/rulesets/tests/invalid-ai-proxy-leftover-
model.yaml + run-tests.sh):
- Regression fixture proving the auto-generated dispatch validator
  surfaces "Unknown config field 'model' for dispatcher 'ai-proxy'"
  with the full list of allowed fields when an operator forgets to
  delete `model:` after upgrading from ADR-0024. The lint message is
  the migration UX promised in PR-2's CHANGELOG.

Known gap (out of scope for this PR): nested-glob lint coverage for
routes[].pattern and allow/deny entries. The auto-generated validator
doesn't recurse into nested objects, so vacuum can't catch a regex-
syntax pattern at lint time today. Runtime catches it via globset
compile error from ensure_compiled_routes (covered by unit tests).
This is the generator-recursion improvement we discussed earlier — a
separate PR that benefits every plugin's nested schema, not a
migration-specific lint.

Test counts: plugin 793 → 801 (+8 — PR-1 unit test relaxed +1 test,
PR-3 +17 already in stack, this PR +8 from drive-by fix and new
helpers). Integration 275 → 282 (+7). 15/15 ruleset tests pass.
@ndreno ndreno merged commit 005156e into main May 5, 2026
8 checks passed
@ndreno ndreno deleted the test/ai-proxy-routes-coverage branch May 5, 2026 06:42
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