package usecase import ( "context" "errors" "io" "net/http" "strings" "testing" "gitea.maximumdirect.net/eric/promptkit/internal/domain" "gitea.maximumdirect.net/eric/promptkit/internal/llm" ) func TestReachabilityProbeTreatsEveryHTTPResponseAsReachable(t *testing.T) { for _, status := range []int{ http.StatusNoContent, http.StatusUnauthorized, http.StatusNotFound, http.StatusMethodNotAllowed, } { t.Run(http.StatusText(status), func(t *testing.T) { calls := 0 body := &reachabilityProbeBody{} client := reachabilityClient(t, func(request *http.Request) (*http.Response, error) { calls++ if request.Method != http.MethodGet { t.Errorf("method = %q, want GET", request.Method) } return &http.Response{StatusCode: status, Header: make(http.Header), Body: body}, nil }) result, err := (reachabilityProbe{client: client}).run(context.Background(), "https://example.invalid/health", 0) if err != nil { t.Fatal(err) } if calls != 1 || !body.closed { t.Fatalf("calls=%d body closed=%v", calls, body.closed) } if !result.supported || result.reachable == nil || !*result.reachable || !result.evidence.ResponseReceived { t.Fatalf("response evidence = %+v", result) } if result.evidence.HTTPStatus == nil || *result.evidence.HTTPStatus != status || result.failure != domain.ExecutionFailureNone { t.Fatalf("status/failure = %v / %v", result.evidence.HTTPStatus, result.failure) } }) } } func TestReachabilityProbeRemovesURLCredentials(t *testing.T) { var observed *http.Request client := reachabilityClient(t, func(request *http.Request) (*http.Response, error) { observed = request return &http.Response{StatusCode: http.StatusNoContent, Header: make(http.Header), Body: io.NopCloser(strings.NewReader(""))}, nil }) endpoint := "https://operator:secret@example.invalid/health?check=1" result, err := (reachabilityProbe{client: client}).run(context.Background(), endpoint, 0) if err != nil { t.Fatal(err) } if observed == nil || observed.URL.User != nil || observed.Header.Get("Authorization") != "" { t.Fatalf("probe request retained URL credentials: %+v", observed) } if result.initialEndpoint != "https://example.invalid/health?check=1" || result.evidence.CredentialsSupplied { t.Fatalf("credential-free evidence = %+v", result) } } func TestReachabilityProbeReportsTransportFailureWithoutResponse(t *testing.T) { client := reachabilityClient(t, func(*http.Request) (*http.Response, error) { return nil, errors.New("opaque network failure") }) result, err := (reachabilityProbe{client: client}).run(context.Background(), "https://example.invalid/health", 0) if err != nil { t.Fatal(err) } if result.reachable == nil || *result.reachable || result.evidence.ResponseReceived || result.evidence.HTTPStatus != nil { t.Fatalf("no-response evidence = %+v", result) } if !result.evidence.DispatchInvoked || !result.evidence.RequestObserved || result.failure != domain.ExecutionFailureTransport { t.Fatalf("transport failure evidence = %+v", result) } } func TestReachabilityProbeUsesTargetTimeout(t *testing.T) { client := reachabilityClient(t, func(request *http.Request) (*http.Response, error) { <-request.Context().Done() return nil, request.Context().Err() }) result, err := (reachabilityProbe{client: client}).run(context.Background(), "https://example.invalid/health", 1) if err != nil { t.Fatal(err) } if result.reachable == nil || *result.reachable || result.failure != domain.ExecutionFailureDeadline { t.Fatalf("timeout evidence = %+v", result) } } func TestReachabilityProbeIsUnsupportedWithoutHTTPClient(t *testing.T) { result, err := (reachabilityProbe{}).run(context.Background(), "https://example.invalid/health", 0) if err != nil { t.Fatal(err) } if result.supported || result.reason != domain.SmokeTestReasonHTTPDiagnosticsUnavailable || result.reachable != nil || result.evidence.DispatchInvoked { t.Fatalf("unsupported outcome = %+v", result) } } func reachabilityClient(t *testing.T, roundTrip func(*http.Request) (*http.Response, error)) *llm.OpenAICompatibleClient { t.Helper() client, err := llm.NewOpenAICompatibleClient(llm.OpenAICompatibleConfig{ HTTPClient: &http.Client{Transport: reachabilityProbeTransport(roundTrip)}, }) if err != nil { t.Fatal(err) } return client } type reachabilityProbeTransport func(*http.Request) (*http.Response, error) func (t reachabilityProbeTransport) RoundTrip(request *http.Request) (*http.Response, error) { return t(request) } type reachabilityProbeBody struct{ closed bool } func (*reachabilityProbeBody) Read([]byte) (int, error) { return 0, io.EOF } func (b *reachabilityProbeBody) Close() error { b.closed = true return nil }