Files
tapir/internal/adapters/llm/status_error_test.go

64 lines
1.9 KiB
Go

package llm
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"git.d-ma.be/mathias/tapir/internal/errkind"
)
// A non-200 from the gateway is an HTTP status error: its kind can be logged and stored
// without its body, which can echo the prompt (adversarial review F3).
func failingGateway(t *testing.T, status int, body string) *httptest.Server {
t.Helper()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(status)
_, _ = w.Write([]byte(body))
}))
t.Cleanup(srv.Close)
return srv
}
func TestClient_ANon200IsAnHTTPStatusErrorWhoseKindCarriesNoBody(t *testing.T) {
srv := failingGateway(t, http.StatusBadRequest, `{"error":"prompt was: Anders ansvarar för virket"}`)
_, err := New(srv.URL, "", "m", 5*time.Second).Complete(context.Background(), "s", "u")
if err == nil {
t.Fatal("expected an error")
}
if got := errkind.Of(err); got != "http_400" {
t.Errorf("errkind.Of = %q, want http_400", got)
}
var he *HTTPError
if !errors.As(err, &he) || he.Code != http.StatusBadRequest {
t.Errorf("error is not an *HTTPError with the status code: %v", err)
}
}
func TestClient_TheErrorTextIsUnchangedForCallersThatLogIt(t *testing.T) {
srv := failingGateway(t, http.StatusBadGateway, "upstream down")
_, err := New(srv.URL, "", "m", 5*time.Second).Complete(context.Background(), "s", "u")
if err == nil || err.Error() != "LLM returned 502: upstream down" {
t.Errorf("error text = %v: callers that log it already rely on this form", err)
}
}
func TestClient_AnEnormousErrorBodyIsBoundedInTheErrorText(t *testing.T) {
srv := failingGateway(t, http.StatusInternalServerError, strings.Repeat("x", 100_000))
_, err := New(srv.URL, "", "m", 5*time.Second).Complete(context.Background(), "s", "u")
if err == nil || len(err.Error()) > 1024 {
t.Errorf("error text is %d bytes: a gateway's whole body must not become an error message", len(err.Error()))
}
}