test: pin the production receive limits, split the vacuous drain test, harden the lint-gate test (review of #55)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
+42
-13
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -32,9 +33,20 @@ func TestShutdownContext_IsCancelledBySIGTERMAndSIGINT(t *testing.T) {
|
||||
}
|
||||
|
||||
// serveHTTP must not return while a request is in flight or the worker is still recording
|
||||
// its job: ListenAndServe returns ErrServerClosed the moment Shutdown starts, so returning
|
||||
// from it let the process exit before either finished (#50).
|
||||
func TestServeHTTP_ReturnsOnlyAfterTheInFlightRequestAndTheWorkerHaveFinished(t *testing.T) {
|
||||
// its job: Serve returns http.ErrServerClosed as soon as Shutdown STARTS, and returning
|
||||
// from it let the process exit before either finished (#50). Each half is tested with the
|
||||
// other already satisfied, so neither can hold the call open on the other's behalf.
|
||||
|
||||
func pendingFor(t *testing.T, returned <-chan error, why string) {
|
||||
t.Helper()
|
||||
select {
|
||||
case err := <-returned:
|
||||
t.Fatalf("serveHTTP returned (%v) %s", err, why)
|
||||
case <-time.After(150 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeHTTP_DrainsAnInFlightRequestBeforeReturning(t *testing.T) {
|
||||
release := make(chan struct{})
|
||||
entered := make(chan struct{})
|
||||
srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
@@ -44,8 +56,12 @@ func TestServeHTTP_ReturnsOnlyAfterTheInFlightRequestAndTheWorkerHaveFinished(t
|
||||
}))
|
||||
srv.Start()
|
||||
defer srv.Close()
|
||||
var once sync.Once
|
||||
releaseHandler := func() { once.Do(func() { close(release) }) }
|
||||
defer releaseHandler() // runs before srv.Close: a failing test must not hang on the blocked handler
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
workerDone := make(chan struct{})
|
||||
close(workerDone) // the worker is already done: only the request can hold serveHTTP open
|
||||
returned := make(chan error, 1)
|
||||
go func() { returned <- serveHTTP(ctx, srv.Config, srv.Listener, nil, workerDone, 5*time.Second) }()
|
||||
|
||||
@@ -53,17 +69,30 @@ func TestServeHTTP_ReturnsOnlyAfterTheInFlightRequestAndTheWorkerHaveFinished(t
|
||||
<-entered
|
||||
cancel()
|
||||
|
||||
assertPending := func(why string) {
|
||||
t.Helper()
|
||||
select {
|
||||
case err := <-returned:
|
||||
t.Fatalf("serveHTTP returned (%v) %s", err, why)
|
||||
case <-time.After(150 * time.Millisecond):
|
||||
pendingFor(t, returned, "while a request was still in flight")
|
||||
releaseHandler()
|
||||
select {
|
||||
case err := <-returned:
|
||||
if err != nil {
|
||||
t.Fatalf("serveHTTP: %v", err)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("serveHTTP did not return once the request finished")
|
||||
}
|
||||
assertPending("while a request was still in flight")
|
||||
close(release)
|
||||
assertPending("before the worker finished")
|
||||
}
|
||||
|
||||
func TestServeHTTP_WaitsForTheWorkerBeforeReturning(t *testing.T) {
|
||||
srv := httptest.NewUnstartedServer(http.NotFoundHandler())
|
||||
srv.Start()
|
||||
defer srv.Close()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
workerDone := make(chan struct{})
|
||||
returned := make(chan error, 1)
|
||||
go func() { returned <- serveHTTP(ctx, srv.Config, srv.Listener, nil, workerDone, 5*time.Second) }() // no request in flight
|
||||
|
||||
cancel()
|
||||
|
||||
pendingFor(t, returned, "before the worker finished")
|
||||
close(workerDone)
|
||||
select {
|
||||
case err := <-returned:
|
||||
@@ -71,7 +100,7 @@ func TestServeHTTP_ReturnsOnlyAfterTheInFlightRequestAndTheWorkerHaveFinished(t
|
||||
t.Fatalf("serveHTTP: %v", err)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("serveHTTP did not return once the request and the worker had finished")
|
||||
t.Fatal("serveHTTP did not return once the worker finished")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user