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.
2427var 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