package main import ( "context" "net/http" "net/http/httptest" "sync/atomic" "testing" "time" ) func TestRunSendsConcurrentRequestsAcrossTargets(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, _ *http.Request) { response.WriteHeader(http.StatusOK) _, _ = response.Write([]byte("ok")) })) defer server.Close() requestTargets, err := targets(server.URL, "/,/transactions") if err != nil { t.Fatal(err) } ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() result := run(ctx, server.Client(), requestTargets, 4) if result.Requests == 0 || result.Errors != 0 || result.Non2xx != 0 { t.Fatalf("unexpected load result: %+v", result) } if len(result.Latency) != int(result.Requests) { t.Fatalf("expected one latency per request, got %d for %d", len(result.Latency), result.Requests) } } func TestTargetsRejectsExternalAndRelativePaths(t *testing.T) { for _, paths := range []string{"relative", "https://example.com/"} { if _, err := targets("http://localhost:8080", paths); err == nil { t.Fatalf("expected %q to be rejected", paths) } } } func TestPercentileUsesNearestRank(t *testing.T) { values := []time.Duration{time.Millisecond, 4 * time.Millisecond, 2 * time.Millisecond, 3 * time.Millisecond} if got := percentile(values, 95); got != 4*time.Millisecond { t.Fatalf("unexpected p95: %s", got) } } func TestRunDrainsInflightRequestAfterDuration(t *testing.T) { var canceled atomic.Bool server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) { time.Sleep(20 * time.Millisecond) if request.Context().Err() != nil { canceled.Store(true) } response.WriteHeader(http.StatusOK) })) defer server.Close() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond) defer cancel() result := run(ctx, server.Client(), []string{server.URL}, 1) if result.Requests != 1 || result.Errors != 0 || canceled.Load() { t.Fatalf("in-flight request was not drained cleanly: %+v", result) } }