package service import ( "io" "net/http" "strings" "testing" "browser.local/platform/domain" ) func TestHTTPAIProviderClientReturnsBoundedStructuredRecommendation(t *testing.T) { transport := roundTripFunc(func(r *http.Request) (*http.Response, error) { if r.URL.Path != "/v1/chat/completions" { t.Fatalf("unexpected provider path %q", r.URL.Path) } if r.Header.Get("Authorization") != "" { t.Fatal("local provider must not receive an authorization header") } body, _ := io.ReadAll(r.Body) if strings.Contains(string(body), "apiKeyRef") { t.Fatal("provider request leaked secret reference metadata") } return &http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}, Body: io.NopCloser(strings.NewReader(`{"choices":[{"message":{"role":"assistant","content":"{\"recommendation\":\"Review PVP policy\",\"suggestedConfig\":\"pvp=false\\n\"}"}}],"usage":{"prompt_tokens":12,"completion_tokens":8}}`))}, nil }) client := HTTPAIProviderClient{HTTPClient: &http.Client{Transport: transport}} result, err := client.Invoke(domain.AIProvider{ID: "local", Kind: domain.AIProviderKindOllama, BaseURL: "http://127.0.0.1:18000/v1", RelayMode: domain.AIRelayModeLocal, TimeoutMS: 1000, DefaultModel: "test-model"}, domain.AIInvocationRequest{RequestID: "http-ai-1", Purpose: "config.suggest", Prompt: "disable pvp", CurrentConfig: "pvp=true\n"}) if err != nil { t.Fatalf("invoke provider: %v", err) } if result.Recommendation != "Review PVP policy" || result.SuggestedConfig != "pvp=false\n" || result.Usage.Mocked { t.Fatalf("unexpected provider result %+v", result) } } func TestHTTPAIProviderClientRedactsTransportFailure(t *testing.T) { client := HTTPAIProviderClient{HTTPClient: &http.Client{Transport: failingRoundTripper{}}} _, err := client.Invoke(domain.AIProvider{ID: "local", Kind: domain.AIProviderKindOllama, BaseURL: "http://127.0.0.1:18000/v1", RelayMode: domain.AIRelayModeLocal, TimeoutMS: 1000, DefaultModel: "test-model"}, domain.AIInvocationRequest{RequestID: "http-ai-fail", Purpose: "logs.diagnose", Prompt: "inspect"}) if err == nil || err.Error() != "AI provider transport failed" { t.Fatalf("expected redacted transport failure, got %v", err) } } type failingRoundTripper struct{} func (failingRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, io.ErrUnexpectedEOF } type roundTripFunc func(*http.Request) (*http.Response, error) func (fn roundTripFunc) RoundTrip(request *http.Request) (*http.Response, error) { return fn(request) }