Skip to content

Commit 1c99eaf

Browse files
test(server): reliably detect Start/Shutdown deadlock in SSEServer (#264)
This test demonstrates the deadlock described in #254 and #263 by running `SSEServer.Start` then `SSEServer.Shutdown`. If it deadlocks, the test fails quickly and reliably, rather than hanging indefinitely. References: - #254 - #255 - #263
1 parent 6429019 commit 1c99eaf

File tree

1 file changed

+32
-0
lines changed

1 file changed

+32
-0
lines changed

server/sse_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,38 @@ func TestSSEServer(t *testing.T) {
14001400
t.Fatal("Processing did not complete after client disconnection")
14011401
}
14021402
})
1403+
1404+
t.Run("Start() then Shutdown() should not deadlock", func(t *testing.T) {
1405+
mcpServer := NewMCPServer("test", "1.0.0")
1406+
sseServer := NewSSEServer(mcpServer, WithBaseURL("http://localhost:0"))
1407+
1408+
done := make(chan struct{})
1409+
1410+
go func() {
1411+
_ = sseServer.Start("127.0.0.1:0")
1412+
close(done)
1413+
}()
1414+
1415+
// Wait a bit to ensure the server is running
1416+
time.Sleep(50 * time.Millisecond)
1417+
1418+
shutdownDone := make(chan error, 1)
1419+
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
1420+
defer cancel()
1421+
go func() {
1422+
err := sseServer.Shutdown(ctx)
1423+
shutdownDone <- err
1424+
}()
1425+
1426+
select {
1427+
case err := <-shutdownDone:
1428+
if ctx.Err() == context.DeadlineExceeded {
1429+
t.Fatalf("Shutdown deadlocked (timed out): %v", err)
1430+
}
1431+
case <-time.After(1 * time.Second):
1432+
t.Fatal("Shutdown did not return in time (likely deadlocked)")
1433+
}
1434+
})
14031435
}
14041436

14051437
func readSSEEvent(sseResp *http.Response) (string, error) {

0 commit comments

Comments
 (0)