package main import ( "errors" "net" "net/http" "testing" "time" ) func TestShutdownServerForceClosesAfterGracefulTimeout(t *testing.T) { handlerStarted := make(chan struct{}) releaseHandler := make(chan struct{}) server := &http.Server{ Handler: http.HandlerFunc(func(http.ResponseWriter, *http.Request) { close(handlerStarted) <-releaseHandler }), ReadHeaderTimeout: time.Second, } listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen() error = %v", err) } serverErrors := make(chan error, 1) go func() { serverErrors <- server.Serve(listener) }() requestFinished := make(chan struct{}) go func() { defer close(requestFinished) client := http.Client{Timeout: time.Second} response, err := client.Get("http://" + listener.Addr().String()) if err == nil { _ = response.Body.Close() } }() select { case <-handlerStarted: case <-time.After(time.Second): t.Fatal("handler did not start") } err = shutdownServer(server, serverErrors, 10*time.Millisecond) if err == nil { t.Fatal("shutdownServer() error = nil") } close(releaseHandler) select { case <-requestFinished: case <-time.After(time.Second): t.Fatal("request did not finish after force close") } connection, dialErr := net.DialTimeout( "tcp", listener.Addr().String(), 100*time.Millisecond, ) if dialErr == nil { _ = connection.Close() t.Fatal("listener still accepted connections after force close") } } func TestShutdownServerAcceptsNormalServerClose(t *testing.T) { serverErrors := make(chan error, 1) serverErrors <- http.ErrServerClosed server := &http.Server{} if err := shutdownServer(server, serverErrors, time.Second); err != nil && !errors.Is(err, http.ErrServerClosed) { t.Fatalf("shutdownServer() error = %v", err) } }