mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-21 05:57:53 +00:00
test: testify table-driven coverage for low-coverage branches
Lifts all 14 functions the operator flagged as <75% (measured at ed2119c)
to >=75%, using table-driven tests (require for fatals, assert for checks):
- limits.go: failPolicyGet (50.0% -> 100.0%)
- provider_gemini.go: httpClient (0.0% -> 100.0%)
- redis_store.go: get (71.4% -> 78.6%)
- resp.go: dialTimeoutFor, respDeadlineExceededErr.{Error,Timeout,Temporary},
ensureConnLocked, getBatch (66.7-30.0% -> 91.3-100.0%)
- routes_media.go: resolveMediaRequest (50.0% -> 100.0%)
- routes_unified.go: unifiedCostMicros (66.7% -> 100.0%)
- translate_anthropic.go: isTruthy, toFloat64 (50.0/33.3% -> 100.0%)
- translate_gemini.go: geminiToolConfigFromOpenAI (66.7% -> 100.0%)
resp_test.go adds a hand-rolled fakeConn (net.Conn with injectable
Write/SetDeadline errors) to reach two respClient error branches a real
TCP connection cannot be coaxed into deterministically.
Total coverage: 90.7% -> 92.4% (no regression; report has the full
per-file table). Zero production-code changes. Existing tests untouched:
every diff is a pure addition of new test functions and their imports.
Gates: go test -count=1 (pass), -race (pass, 5x incl. an isolated
baseline-vs-branch comparison after one flaky run implicated pre-existing
registry_test.go timing tests this task never touched), gofmt/vet (clean),
golangci-lint incl. gosec and fieldalignment (0 issues), make yaegi-check
(OK), make integration (pass, untouched-green).
This commit is contained in:
@@ -13,6 +13,9 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// newMultipartTranscriptionRequest builds a POST /v1/audio/transcriptions
|
||||
@@ -1035,3 +1038,56 @@ func TestAnthropicMediaEndpoints_Return501_NeverCallUpstream(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ---- resolveMediaRequest: the shared resolve/limit failure branches ----
|
||||
//
|
||||
// Every other media-route test above drives resolveMediaRequest's success
|
||||
// path only; these two cover its two failure returns (routes_media.go) —
|
||||
// a model no configured provider knows, and a limit violation — using
|
||||
// images.generations as the representative caller, since all three media
|
||||
// routes share the same resolveMediaRequest call.
|
||||
|
||||
// TestHandleImagesGenerations_UnknownModel_404 covers resolveMediaRequest's
|
||||
// registry.resolve error branch: a model id no configured provider knows at
|
||||
// all.
|
||||
func TestHandleImagesGenerations_UnknownModel_404(t *testing.T) {
|
||||
gw := newMediaTestGateway(t, newMediaTestConfig("http://127.0.0.1:1", "img-test"))
|
||||
|
||||
body := map[string]any{"model": "no-such-model", "prompt": "a cat"}
|
||||
req := newUnifiedRequest(t, http.MethodPost, imagesGenerationsPath, "sk-alice", body)
|
||||
rec := httptest.NewRecorder()
|
||||
gw.ServeHTTP(rec, req)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, rec.Code, "body=%s", rec.Body.String())
|
||||
}
|
||||
|
||||
// TestHandleImagesGenerations_LimitExceeded_429WithRetryAfter covers
|
||||
// resolveMediaRequest's checkAndCount violation branch: a second request
|
||||
// past a one-per-minute limit is refused before the adapter is ever called.
|
||||
func TestHandleImagesGenerations_LimitExceeded_429WithRetryAfter(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(`{"created":1734000000,"data":[{"b64_json":"xyz"}]}`))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
cfg := newMediaTestConfig(srv.URL, "img-test")
|
||||
cfg.Users = &UsersConfig{Inline: []*UserConfig{
|
||||
{Name: "alice", Group: "default", APIKey: "sk-alice", Limits: &LimitsConfig{RequestsPerMinute: 1}},
|
||||
}}
|
||||
gw := newMediaTestGateway(t, cfg)
|
||||
|
||||
body := map[string]any{"model": "img-test", "prompt": "a cat"}
|
||||
req1 := newUnifiedRequest(t, http.MethodPost, imagesGenerationsPath, "sk-alice", body)
|
||||
rec1 := httptest.NewRecorder()
|
||||
gw.ServeHTTP(rec1, req1)
|
||||
require.Equal(t, http.StatusOK, rec1.Code, "first request body=%s", rec1.Body.String())
|
||||
|
||||
req2 := newUnifiedRequest(t, http.MethodPost, imagesGenerationsPath, "sk-alice", body)
|
||||
rec2 := httptest.NewRecorder()
|
||||
gw.ServeHTTP(rec2, req2)
|
||||
|
||||
assert.Equal(t, http.StatusTooManyRequests, rec2.Code, "body=%s", rec2.Body.String())
|
||||
assert.NotEmpty(t, rec2.Header().Get("Retry-After"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user