Compare commits

...
Author SHA1 Message Date
Emil 44247bd94e Give every wizard test its own port and disable keep-alive pooling
coordinator / test (push) Canceled after 0s
python / test (push) Canceled after 0s
release / binaries (amd64, darwin) (push) Canceled after 0s
release / binaries (amd64, linux) (push) Canceled after 0s
release / binaries (amd64, windows) (push) Canceled after 0s
release / binaries (arm64, darwin) (push) Canceled after 0s
release / binaries (arm64, linux) (push) Canceled after 0s
release / binaries (arm64, windows) (push) Canceled after 0s
release / image (push) Canceled after 0s
users / test (push) Canceled after 0s
release / release (push) Canceled after 0s
2026-08-03 01:43:48 +03:00
@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"io" "io"
"log/slog" "log/slog"
"net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
@@ -25,7 +26,10 @@ func newTestServer(t *testing.T, sup Supervisor) (*Server, string) {
t.Helper() t.Helper()
dir := t.TempDir() dir := t.TempDir()
server := New(testLogger(), Options{ server := New(testLogger(), Options{
Port: 0, // ephemeral: tests must never collide on the default 12700 // A distinct random port per test: Port 0 means "the default 12700" in
// the server, which would let the shared http.Client pool reuse a stale
// keep-alive connection across tests (EOF after a Shutdown).
Port: freePort(t),
ConfigPath: filepath.Join(dir, "config.json"), ConfigPath: filepath.Join(dir, "config.json"),
Dir: dir, Dir: dir,
Supervisor: sup, Supervisor: sup,
@@ -81,7 +85,9 @@ func postJSON(t *testing.T, base, path string, body any) (*httptest.ResponseReco
t.Fatal(err) t.Fatal(err)
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
client := http.Client{} // No keep-alive pooling: a pooled connection to a shut-down test server
// would surface as an EOF instead of a fresh dial.
client := http.Client{Transport: &http.Transport{DisableKeepAlives: true}}
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -94,6 +100,20 @@ func postJSON(t *testing.T, base, path string, body any) (*httptest.ResponseReco
return rec, data return rec, data
} }
// freePort reserves an ephemeral port and returns it. The listener is closed
// immediately; the tiny reuse window is acceptable for tests and each test
// gets a different port, so nothing can collide or share pooled connections.
func freePort(t *testing.T) int {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
port := listener.Addr().(*net.TCPAddr).Port
_ = listener.Close()
return port
}
func mustJSON(t *testing.T, v any) string { func mustJSON(t *testing.T, v any) string {
t.Helper() t.Helper()
raw, err := json.Marshal(v) raw, err := json.Marshal(v)