From 35ddd0ad2215760bb1d3dc7724480f179ea33fa6 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Wed, 16 Sep 2026 21:05:39 -0400 Subject: fix: login account race, casino chip double-refund, room-create rollback, rename collision, fatal transport errors --- internal/net/transport_failure_test.go | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 internal/net/transport_failure_test.go (limited to 'internal/net/transport_failure_test.go') diff --git a/internal/net/transport_failure_test.go b/internal/net/transport_failure_test.go new file mode 100644 index 0000000..ecd41e8 --- /dev/null +++ b/internal/net/transport_failure_test.go @@ -0,0 +1,44 @@ +package net + +// Regression: a fatal transport failure (a listener that cannot bind, an +// Accept loop that dies outside shutdown) must unblock ListenAndServe with +// the error — a server must never sit running with no way in — and a +// failure followed by Shutdown must not panic on a double close of done. + +import ( + "fmt" + "net" + "net/http" + "testing" + "time" +) + +func TestTransportFailureStopsListenAndServe(t *testing.T) { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + port := fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port) + + s := &Server{hub: NewHub(), done: make(chan struct{})} + s.httpServer = &http.Server{Addr: port, Handler: http.NewServeMux()} + + result := make(chan error, 1) + go func() { + go s.serveHTTP() + <-s.done + result <- s.listenErr + }() + + select { + case err := <-result: + if err == nil { + t.Fatal("transport failure unblocked ListenAndServe without an error") + } + // Shutdown after a failure must not double-close done. + s.Shutdown() + case <-time.After(2 * time.Second): + t.Fatal("a failed listener left the server running") + } +} -- cgit v1.2.3