test(ai-proxy): end-to-end coverage for ADR-0030 + drive-by dispatch fix#80
Merged
test(ai-proxy): end-to-end coverage for ADR-0030 + drive-by dispatch fix#80
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replacement for #77 (auto-closed on #79's merge). Same content; rebased onto main.
Original PR: #77