@@ -11,6 +11,7 @@ import (
1111 "sync"
1212 "sync/atomic"
1313 "testing"
14+ "time"
1415
1516 "github.com/caddyserver/caddy/v2"
1617 "github.com/caddyserver/caddy/v2/caddytest"
@@ -19,6 +20,26 @@ import (
1920 "github.com/stretchr/testify/require"
2021)
2122
23+ // waitForServerReady polls the server with retries until it responds to HTTP requests.
24+ // This handles a race condition during Caddy config reload on macOS where SO_REUSEPORT
25+ // can briefly route connections to the old listener being shut down,
26+ // resulting in "connection reset by peer".
27+ func waitForServerReady (t * testing.T , url string ) {
28+ t .Helper ()
29+
30+ client := & http.Client {Timeout : 1 * time .Second }
31+ for range 10 {
32+ resp , err := client .Get (url )
33+ if err == nil {
34+ require .NoError (t , resp .Body .Close ())
35+
36+ return
37+ }
38+
39+ time .Sleep (100 * time .Millisecond )
40+ }
41+ }
42+
2243var testPort = "9080"
2344
2445func TestPHP (t * testing.T ) {
@@ -406,6 +427,7 @@ func TestPHPServerDirective(t *testing.T) {
406427 }
407428 ` , "caddyfile" )
408429
430+ waitForServerReady (t , "http://localhost:" + testPort )
409431 tester .AssertGetResponse ("http://localhost:" + testPort , http .StatusOK , "I am by birth a Genevese (i not set)" )
410432 tester .AssertGetResponse ("http://localhost:" + testPort + "/hello.txt" , http .StatusOK , "Hello\n " )
411433 tester .AssertGetResponse ("http://localhost:" + testPort + "/not-found.txt" , http .StatusOK , "I am by birth a Genevese (i not set)" )
@@ -431,6 +453,7 @@ func TestPHPServerDirectiveDisableFileServer(t *testing.T) {
431453 }
432454 ` , "caddyfile" )
433455
456+ waitForServerReady (t , "http://localhost:" + testPort )
434457 tester .AssertGetResponse ("http://localhost:" + testPort , http .StatusOK , "I am by birth a Genevese (i not set)" )
435458 tester .AssertGetResponse ("http://localhost:" + testPort + "/not-found.txt" , http .StatusOK , "I am by birth a Genevese (i not set)" )
436459}
0 commit comments