11package frankenphp_test
22
33import (
4- "io"
54 "log/slog"
65 "net/http"
76 "net/http/httptest"
87 "strings"
98 "sync"
109 "testing"
11- "time"
1210
1311 "github.com/dunglas/frankenphp"
1412 "github.com/stretchr/testify/assert"
15- "github.com/stretchr/testify/require"
1613)
1714
1815// TestModuleMaxRequests verifies that regular (non-worker) PHP threads restart
@@ -24,30 +21,19 @@ func TestModuleMaxRequests(t *testing.T) {
2421 var buf syncBuffer
2522 logger := slog .New (slog .NewTextHandler (& buf , & slog.HandlerOptions {Level : slog .LevelDebug }))
2623
27- runTest (t , func (_ func (http.ResponseWriter , * http.Request ), ts * httptest.Server , _ int ) {
28- require .NotNil (t , ts )
29- client := & http.Client {Timeout : 5 * time .Second }
30-
24+ runTest (t , func (handler func (http.ResponseWriter , * http.Request ), _ * httptest.Server , _ int ) {
3125 for i := 0 ; i < totalRequests ; i ++ {
32- resp , err := client .Get (ts .URL + "/index.php" )
33- require .NoError (t , err , "request %d should succeed" , i )
34-
35- body , err := io .ReadAll (resp .Body )
36- require .NoError (t , err )
37- _ = resp .Body .Close ()
38-
39- assert .Equal (t , 200 , resp .StatusCode , "request %d should return 200, got body: %s" , i , string (body ))
40- assert .Contains (t , string (body ), "I am by birth a Genevese" ,
41- "request %d should return correct body" , i )
26+ body , resp := testGet ("http://example.com/index.php" , handler , t )
27+ assert .Equal (t , 200 , resp .StatusCode )
28+ assert .Contains (t , body , "I am by birth a Genevese" )
4229 }
4330
4431 restartCount := strings .Count (buf .String (), "max requests reached, restarting thread" )
4532 t .Logf ("Thread restarts observed: %d" , restartCount )
4633 assert .GreaterOrEqual (t , restartCount , 2 ,
4734 "with maxRequests=%d and %d requests on 2 threads, at least 2 restarts should occur" , maxRequests , totalRequests )
4835 }, & testOptions {
49- realServer : true ,
50- logger : logger ,
36+ logger : logger ,
5137 initOpts : []frankenphp.Option {
5238 frankenphp .WithNumThreads (2 ),
5339 frankenphp .WithMaxRequests (maxRequests ),
@@ -60,69 +46,24 @@ func TestModuleMaxRequests(t *testing.T) {
6046func TestModuleMaxRequestsConcurrent (t * testing.T ) {
6147 const maxRequests = 10
6248 const totalRequests = 200
63- const concurrency = 20
6449
65- runTest (t , func (_ func (http.ResponseWriter , * http.Request ), ts * httptest.Server , _ int ) {
66- require .NotNil (t , ts )
67- client := & http.Client {Timeout : 10 * time .Second }
68-
69- var successCount int
70- var mu sync.Mutex
71- sem := make (chan struct {}, concurrency )
50+ runTest (t , func (handler func (http.ResponseWriter , * http.Request ), _ * httptest.Server , _ int ) {
7251 var wg sync.WaitGroup
7352
7453 for i := 0 ; i < totalRequests ; i ++ {
7554 wg .Add (1 )
76- sem <- struct {}{}
77- go func (i int ) {
78- defer func () { <- sem ; wg .Done () }()
79-
80- resp , err := client .Get (ts .URL + "/index.php" )
81- if err != nil {
82- return
83- }
84- body , _ := io .ReadAll (resp .Body )
85- _ = resp .Body .Close ()
86-
87- if resp .StatusCode == 200 && strings .Contains (string (body ), "I am by birth a Genevese" ) {
88- mu .Lock ()
89- successCount ++
90- mu .Unlock ()
91- }
92- }(i )
55+ go func () {
56+ defer wg .Done ()
57+ body , resp := testGet ("http://example.com/index.php" , handler , t )
58+ assert .Equal (t , 200 , resp .StatusCode )
59+ assert .Contains (t , body , "I am by birth a Genevese" )
60+ }()
9361 }
9462 wg .Wait ()
95-
96- t .Logf ("Success: %d/%d" , successCount , totalRequests )
97- assert .GreaterOrEqual (t , successCount , int (totalRequests * 0.95 ),
98- "at least 95%% of requests should succeed despite regular thread restarts" )
9963 }, & testOptions {
100- realServer : true ,
10164 initOpts : []frankenphp.Option {
10265 frankenphp .WithNumThreads (8 ),
10366 frankenphp .WithMaxRequests (maxRequests ),
10467 },
10568 })
10669}
107-
108- // TestModuleMaxRequestsZeroIsUnlimited verifies that max_requests=0 (default)
109- // means threads never restart.
110- func TestModuleMaxRequestsZeroIsUnlimited (t * testing.T ) {
111- runTest (t , func (_ func (http.ResponseWriter , * http.Request ), ts * httptest.Server , _ int ) {
112- require .NotNil (t , ts )
113- client := & http.Client {Timeout : 5 * time .Second }
114-
115- for i := 0 ; i < 50 ; i ++ {
116- resp , err := client .Get (ts .URL + "/index.php" )
117- require .NoError (t , err )
118- body , _ := io .ReadAll (resp .Body )
119- _ = resp .Body .Close ()
120-
121- assert .Equal (t , 200 , resp .StatusCode )
122- assert .Contains (t , string (body ), "I am by birth a Genevese" )
123- }
124- }, & testOptions {
125- realServer : true ,
126- initOpts : []frankenphp.Option {frankenphp .WithNumThreads (2 )},
127- })
128- }
0 commit comments