Skip to content

Commit 655dcfc

Browse files
committed
Add test for handler crash with stderr capture
Adds TestHandler_Crash to verify the runner correctly handles handlers that crash while processing requests. The test confirms ErrHandlerClosed is returned and that panic messages from stderr are captured in the error.
1 parent 7bb0694 commit 655dcfc

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

runner/handler_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"os"
8+
"strings"
89
"testing"
910
"time"
1011
)
@@ -16,14 +17,17 @@ const (
1617
// envTestHelperName specifies which helper function to execute in subprocess mode.
1718
envTestHelperName = "TEST_HELPER_NAME"
1819

20+
// Handler simulation test identifiers.
1921
helperNameNormal = "normal"
2022
helperNameUnresponsive = "unresponsive"
23+
helperNameCrash = "crash"
2124
)
2225

2326
// testHelpers maps helper names to functions that simulate different handler behaviors.
2427
var testHelpers = map[string]func(){
2528
helperNameNormal: helperNormal,
2629
helperNameUnresponsive: helperUnresponsive,
30+
helperNameCrash: helperCrash,
2731
}
2832

2933
// TestMain allows the test binary to serve two purposes:
@@ -135,6 +139,49 @@ func helperUnresponsive() {
135139
}
136140
}
137141

142+
// TestHandler_Crash tests that the runner correctly handles a handler that crashes
143+
// while processing a request
144+
func TestHandler_Crash(t *testing.T) {
145+
h, err := newHandlerForTest(t, helperNameCrash, 0)
146+
if err != nil {
147+
t.Fatalf("Failed to create handler: %v", err)
148+
}
149+
defer h.Close()
150+
151+
// Send a request to the handler
152+
request := `{"id":1,"method":"test"}`
153+
if err := h.SendLine([]byte(request)); err != nil {
154+
t.Fatalf("Failed to send request: %v", err)
155+
}
156+
157+
// Try to read the response - should get ErrHandlerClosed
158+
_, err = h.ReadLine()
159+
160+
if err == nil {
161+
t.Fatal("Expected error from crashed handler, got nil")
162+
}
163+
164+
// Verify it's the handler closed error we expect
165+
if !errors.Is(err, ErrHandlerClosed) {
166+
t.Errorf("Expected ErrHandlerClosed, got: %v", err)
167+
}
168+
169+
// Verify the error message contains the panic string from stderr
170+
if !strings.Contains(err.Error(), "simulated handler crash") {
171+
t.Errorf("Expected error to contain 'simulated handler crash', got: %v", err)
172+
}
173+
}
174+
175+
// helperCrash simulates a handler that crashes while processing a request,
176+
// triggering the ErrHandlerClosed error in the runner.
177+
func helperCrash() {
178+
// Read requests from stdin but panic instead of responding
179+
scanner := bufio.NewScanner(os.Stdin)
180+
for scanner.Scan() {
181+
panic("simulated handler crash")
182+
}
183+
}
184+
138185
// newHandlerForTest creates a Handler that runs a test helper as a subprocess.
139186
// The helperName identifies which helper to run (e.g., "normal", "crash", "hang").
140187
// The timeout parameter sets the per-request timeout (0 uses default).

0 commit comments

Comments
 (0)