Commit Graph
6 Commits
Author SHA1 Message Date
lukaszraczylo 8eb06a4b8b test(integration): enable discovery on the real-upstream provider
Discovery failures are non-fatal (explicit model keeps resolving
offline), and with discovery on, INTEGRATION_REAL=1 runs serve the
gateway's full live catalog from /v1/models instead of one pinned id.
2026-08-20 23:15:13 +01:00
lukaszraczylo 2090b31ae2 feat: operator-defined model aliases
Spec §5 (v0.2): Config.ModelAliases map[string]string, alias-first
resolution precedence ahead of provider-prefix splitting, alias-OR-target
authorization, lazy target resolution with a 404 naming both ids,
/v1/models listing, admin overview alias table (JSON + dashboard), and
construction-time validation (shape, prefix-shadow, explicit-model
collision, chain, empty target).

routes_unified.go/routes_media.go needed no resolution-call-site changes
- both already pass the client's raw requested id through to
registry.resolve, so aliases inherit the __alias echo and multipart
rewrite machinery for free. cache.go needed no changes either - cacheKey
already hashes requestedModel, so two aliases resolving to the same
target already produce distinct cache entries.

Adds registry_test.go validation table + precedence/authz/lazy-404/
listing coverage, a dedicated cache-key split test, chat/embeddings/
images/audio-transcriptions end-to-end tests, an extended admin overview
test, and an integration test covering the openai-type vs anthropic-type
echo asymmetry under real Traefik+Yaegi.
2026-08-20 20:56:01 +01:00
lukaszraczylo f49c51b341 fix(docs,integration): example env completeness, flaky reset, cache key assertion
Task 5 re-review fixes: 1 Important + 3 folded.

1. (Important) examples/kubernetes.yaml was construction-broken on
   copy-paste: the inline dashboard-admin user resolves env:LLMGW_ADMIN_KEY
   at construction time regardless of admin.enabled, but the Helm env
   snippet never listed it. Added it there, alongside a comment on the
   admin user explaining the env var is required either way. Fixed the
   two reversed above/below cross-references (kubernetes.yaml:90/:115)
   and reworded the misleading "self-contained" comment on the inline
   admin user. Verified with a throwaway round-trip test covering: no env
   vars set fails, every documented env var set succeeds (admin.enabled
   staying false as committed), and — the actual bug — every var set
   EXCEPT LLMGW_ADMIN_KEY still fails even with admin disabled.

2. README: Admin section's "(disabled still 404s)" now points at the
   same 404/passthroughUnknown wording the section already uses above it.
   Caching section's "block absent entirely is a construction error" now
   says "not enabled" — auth.go's actual check is !cfg.Cache.Enabled,
   which is identically true whether the block is omitted or present with
   enabled: false.

3. integration/mock/main.go: added POST /flaky/reset (handleFlakyReset),
   reachable through the "flaky" provider's own native passthrough route,
   resetting the atomic hit counter on demand. TestRetryFlakyRecovers now
   calls it at the start of the test, removing the make integration-keep
   re-run trap the old doc comment warned about instead of fixing.
   dynamic.yml.tmpl's stale "test 8" comment now reads "task 5".

4. integration_test.go: added redisKeys (docker compose exec redis-cli
   KEYS, mirroring flushRedis's own pattern) and a
   TestResponseCache assertion that redis holds at least one
   llmgw:cache:* key immediately after the miss request.

go test ./... -count=1, gofmt, vet, make yaegi-check all pass; make
integration exits 0 across two fresh full runs.
2026-08-20 20:30:08 +01:00
lukaszraczylo 25578fb282 test: v0.2 integration coverage
Extends the integration suite (task 5) to exercise retry, cache, images/audio, and admin under real Traefik+Yaegi:

- mock/main.go: a /flaky/v1/chat/completions endpoint failing the first
  request per process with 503 then succeeding (atomic counter, response
  carries mock_attempt for verification); /v1/images/generations returning
  a canned OpenAI images response; /v1/audio/speech returning binary bytes
  under audio/mpeg; gemini mode's :predict returning canned Imagen
  predictions.
- dynamic.yml.tmpl: retry{enabled:true,attempts:1}, cache{enabled:true,
  ttl:2m}, admin{enabled:true}; a flaky provider pointed at the new mock
  endpoint; an admin:true inline user; alice and admin both given a
  generous-but-real per-user limits block so their own request counters
  are trackable via the usage API.
- integration_test.go: TestRetryFlakyRecovers (client 200, exactly two
  upstream hits proven via mock_attempt), TestResponseCache (miss then
  hit, tokensPerDay unchanged across the hit via the admin usage API),
  TestImagesGenerations (openai native forward + gemini Imagen
  translation), TestAudioSpeech (binary round trip, Content-Type
  forwarded), TestAdminDashboard (unauthenticated shell, admin vs
  non-admin gate, usage reflecting this suite's own traffic).

make integration exits 0 (verified across multiple fresh runs).
2026-08-20 20:14:38 +01:00
lukaszraczylo a280ee8aee test(integration): non-colliding provider name for real-upstream smoke
The upstream gateway's model ids carry a uni/ prefix; a provider named
uni made the plugin strip it as a provider prefix. Renamed to real and
listed the full slash-bearing id, exercising bare-id resolution.
2026-08-20 16:05:35 +01:00
lukaszraczylo 730583d98e fix(integration): green gate with tracked streaming skip, gemini coverage, robust probe
Addresses coordinator review of the Task 15 integration suite: 1 critical
ruling, 5 important, 3 folded. make integration now exits 0.

- integration_test.go: TestStreamingIncrementalityProbe restructured —
  content assertion (5 deltas + [DONE], in order) always runs; the raw-TCP
  timing assertion (unchanged, >=3 gaps >=100ms) is gated behind
  INTEGRATION_STREAMING=1 with t.Skipf naming traefik/traefik#10269,
  verified to still genuinely fail when re-armed (not silently disabled).
- Makefile: integration-up/integration-wait moved from prerequisites into
  the integration recipe body as go test ./... -count=1
ok  	github.com/lukaszraczylo/traefik-llmgateway	6.065s sub-invocations with per-stage
  status capture, so integration-down always runs even when bring-up or
  the health wait fails; verified with a synthetic failure. Added
  .NOTPARALLEL (the integration targets are stateful).
- translate_gemini.go: fixed the same yaegi multi-value-assignment panic
  shape as the prior sse.go fix, on the live max_tokens path. Added a
  gemini chat completion assertion to integration_test.go (renamed
  TestUnifiedChatAllProviders) so this path now runs under real Yaegi.
- providers.go, translate_anthropic.go: documented the never-wrap
  contract on providerHTTPError/translateError (routes_unified.go asserts
  their concrete type directly; errors.As panics under yaegi on these).
- integration_test.go: TestCrossReplicaLimits now FLUSHALLs Redis first,
  for idempotence under integration-keep.
- mock/main.go: probe's header-terminator search now accumulates a
  rolling buffer across reads instead of only checking the latest one.
- Folded: hot-reload deadline 10s -> 20s; dynamic.yml's real-upstream
  baseUrl is now a template (dynamic.yml.tmpl) rendered via
  INTEGRATION_REAL_BASEURL (default https://llmgw.example.com), not a
  hardcoded-only hostname.

See task-15-report.md's addendum for full verification detail.
2026-08-20 13:46:45 +01:00