package app import ( "context" "errors" "io" "net" "net/http" "testing" "time" ) func TestServeExposesHealthz(t *testing.T) { server := NewServer("127.0.0.1:0", nil) listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen() error = %v", err) } ctx, cancel := context.WithCancel(context.Background()) defer cancel() errCh := make(chan error, 1) go func() { errCh <- server.Serve(ctx, listener) }() response := waitForHealthz(t, "http://"+listener.Addr().String()+"/healthz") defer response.Body.Close() body, err := io.ReadAll(response.Body) if err != nil { t.Fatalf("ReadAll() error = %v", err) } if string(body) != "ok" { t.Fatalf("healthz body = %q, want %q", string(body), "ok") } cancel() if err := <-errCh; err != nil { t.Fatalf("Serve() error = %v, want nil", err) } } func TestRunReturnsAfterContextCancellation(t *testing.T) { listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen() error = %v", err) } server := NewServer("127.0.0.1:0", func(string, string) (net.Listener, error) { return listener, nil }) ctx, cancel := context.WithCancel(context.Background()) errCh := make(chan error, 1) go func() { errCh <- server.Run(ctx) }() response := waitForHealthz(t, "http://"+listener.Addr().String()+"/healthz") response.Body.Close() cancel() select { case err := <-errCh: if err != nil { t.Fatalf("Run() error = %v, want nil", err) } case <-time.After(2 * time.Second): t.Fatal("Run() did not return after context cancellation") } } func TestRunReturnsListenError(t *testing.T) { wantErr := errors.New("listen failed") server := NewServer("127.0.0.1:0", func(string, string) (net.Listener, error) { return nil, wantErr }) err := server.Run(context.Background()) if !errors.Is(err, wantErr) { t.Fatalf("Run() error = %v, want %v", err, wantErr) } } func TestServeReturnsListenerError(t *testing.T) { server := NewServer("127.0.0.1:0", nil) listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen() error = %v", err) } if err := listener.Close(); err != nil { t.Fatalf("listener.Close() error = %v", err) } err = server.Serve(context.Background(), listener) if err == nil { t.Fatal("Serve() error = nil, want listener startup error") } } func waitForHealthz(t *testing.T, url string) *http.Response { t.Helper() client := &http.Client{Timeout: 100 * time.Millisecond} deadline := time.Now().Add(2 * time.Second) for time.Now().Before(deadline) { response, err := client.Get(url) if err == nil && response.StatusCode == http.StatusOK { return response } if response != nil { response.Body.Close() } time.Sleep(20 * time.Millisecond) } t.Fatalf("health endpoint %q was not reachable before deadline", url) return nil }