package probe import ( "context" "errors" "net/http" "net/http/httptest" "strings" "testing" "time" ) // mockHTTPClient records requests and returns configurable responses type mockHTTPClient struct { Resp *http.Response Err error } func (m *mockHTTPClient) Do(req *http.Request) (*http.Response, error) { // Simulate context cancellation: if the request context is done, return context error select { case <-req.Context().Done(): return nil, req.Context().Err() default: } return m.Resp, m.Err } func TestProbeExecutor_ExecuteProbe_Success(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte(`{"status":"ok"}`)) })) defer server.Close() executor := NewProbeExecutor(nil) // nil → uses real http.Client outcome, err := executor.ExecuteProbe(context.Background(), ProbeTarget{ AccountID: 1, Platform: "openai", Endpoint: server.URL, AuthHeader: "Bearer test-key", }) if err != nil { t.Fatalf("unexpected error: %v", err) } if outcome.StatusCode != http.StatusOK { t.Fatalf("expected 200, got: %d", outcome.StatusCode) } if outcome.LatencyMs < 0 { t.Fatalf("expected latency >= 0, got: %d", outcome.LatencyMs) } if outcome.RequestID == "" { t.Fatal("expected request_id to be set") } } func TestProbeExecutor_ExecuteProbe_ExplicitFailure(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusUnauthorized) })) defer server.Close() executor := NewProbeExecutor(nil) outcome, err := executor.ExecuteProbe(context.Background(), ProbeTarget{ AccountID: 2, Platform: "openai", Endpoint: server.URL, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if outcome.StatusCode != http.StatusUnauthorized { t.Fatalf("expected 401, got: %d", outcome.StatusCode) } } func TestProbeExecutor_ExecuteProbe_Inconclusive_429(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusTooManyRequests) })) defer server.Close() executor := NewProbeExecutor(nil) outcome, err := executor.ExecuteProbe(context.Background(), ProbeTarget{ AccountID: 3, Platform: "openai", Endpoint: server.URL, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if outcome.StatusCode != http.StatusTooManyRequests { t.Fatalf("expected 429, got: %d", outcome.StatusCode) } } func TestProbeExecutor_ExecuteProbe_TransportError(t *testing.T) { client := &mockHTTPClient{ Err: errors.New("connection refused"), } executor := NewProbeExecutor(client) outcome, err := executor.ExecuteProbe(context.Background(), ProbeTarget{ AccountID: 4, Platform: "openai", Endpoint: "http://localhost:9999", }) if err != nil { t.Fatalf("unexpected error: %v", err) } if outcome.TransportError == nil { t.Fatal("expected transport error to be set") } if outcome.StatusCode != 0 { t.Fatalf("expected status 0 on transport error, got: %d", outcome.StatusCode) } } func TestProbeExecutor_ExecuteProbe_InvalidTarget(t *testing.T) { executor := NewProbeExecutor(nil) _, err := executor.ExecuteProbe(context.Background(), ProbeTarget{ AccountID: 5, Platform: "openai", Endpoint: "", // empty endpoint }) if err == nil { t.Fatal("expected error for empty endpoint") } } func TestProbeExecutor_ExecuteProbe_ContextCanceled(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(5 * time.Second) // delay longer than context w.WriteHeader(http.StatusOK) })) defer server.Close() executor := NewProbeExecutor(nil) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond) defer cancel() outcome, err := executor.ExecuteProbe(ctx, ProbeTarget{ AccountID: 6, Platform: "openai", Endpoint: server.URL, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if outcome.TransportError == nil { t.Fatal("expected context deadline exceeded transport error") } } func TestProbeExecutor_ExecuteProbe_ResponseBodyTruncated(t *testing.T) { largeBody := strings.Repeat("x", 10*1024) // 10KB server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte(largeBody)) })) defer server.Close() executor := NewProbeExecutor(nil) outcome, err := executor.ExecuteProbe(context.Background(), ProbeTarget{ AccountID: 7, Platform: "openai", Endpoint: server.URL, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(outcome.ResponseBody) > 1024 { t.Fatalf("expected body truncated to <=1024, got: %d", len(outcome.ResponseBody)) } } func TestProbeExecutor_SetsUserAgentAndAcceptHeader(t *testing.T) { var receivedHeaders http.Header server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { receivedHeaders = r.Header.Clone() w.WriteHeader(http.StatusOK) })) defer server.Close() executor := NewProbeExecutor(nil) _, _ = executor.ExecuteProbe(context.Background(), ProbeTarget{ AccountID: 8, Platform: "openai", Endpoint: server.URL, AuthHeader: "Bearer my-key", }) if receivedHeaders == nil { t.Fatal("server handler was not called — check test setup") } if receivedHeaders.Get("User-Agent") == "" { t.Fatal("expected User-Agent header to be set") } if receivedHeaders.Get("Accept") != "application/json" { t.Fatalf("expected Accept: application/json, got: %s", receivedHeaders.Get("Accept")) } if receivedHeaders.Get("Authorization") != "Bearer my-key" { t.Fatalf("expected Authorization header to be set") } }