Skip to content

Commit eabdfd2

Browse files
committed
test: add thread API tests
Test Thread(), PHPThread.Pin(), and request handling. Fix nil pointer dereference in Thread() when no request is active or index is out of bounds.
1 parent 9963c7f commit eabdfd2

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

frankenphp.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,23 @@ func Thread(index int) (*PHPThread, bool) {
152152
return nil, false
153153
}
154154

155+
if index >= len(phpThreads) {
156+
return nil, false
157+
}
158+
155159
thread := phpThreads[index]
156-
if thread != nil {
157-
return &PHPThread{thread.frankenPHPContext().request, thread}, true
160+
if thread == nil {
161+
return nil, false
158162
}
159163

164+
fc := thread.frankenPHPContext()
165+
var request *http.Request
166+
if fc != nil {
167+
request = fc.request
168+
}
169+
170+
return &PHPThread{request, thread}, true
171+
160172
return nil, false
161173
}
162174

thread_api_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package frankenphp
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestThreadReturnsNilWhenNotRunning(t *testing.T) {
13+
// Before Init(), Thread() should return nil
14+
thread, ok := Thread(0)
15+
assert.Nil(t, thread)
16+
assert.False(t, ok)
17+
}
18+
19+
func TestThreadReturnsValidThread(t *testing.T) {
20+
t.Cleanup(Shutdown)
21+
22+
require.NoError(t, Init(
23+
WithNumThreads(2),
24+
WithMaxThreads(2),
25+
))
26+
27+
// Thread 0 should exist after init
28+
thread, ok := Thread(0)
29+
assert.True(t, ok)
30+
assert.NotNil(t, thread)
31+
}
32+
33+
func TestThreadReturnsNilForInvalidIndex(t *testing.T) {
34+
t.Cleanup(Shutdown)
35+
36+
require.NoError(t, Init(
37+
WithNumThreads(2),
38+
WithMaxThreads(2),
39+
))
40+
41+
// Index beyond thread count should return nil
42+
thread, ok := Thread(999)
43+
assert.Nil(t, thread)
44+
assert.False(t, ok)
45+
}
46+
47+
func TestThreadExposesRequestDuringExecution(t *testing.T) {
48+
t.Cleanup(Shutdown)
49+
50+
require.NoError(t, Init(
51+
WithNumThreads(2),
52+
WithMaxThreads(2),
53+
))
54+
55+
handler := func(w http.ResponseWriter, r *http.Request) {
56+
req, err := NewRequestWithContext(r,
57+
WithRequestDocumentRoot(testDataPath, false),
58+
)
59+
assert.NoError(t, err)
60+
61+
err = ServeHTTP(w, req)
62+
assert.NoError(t, err)
63+
}
64+
65+
req := httptest.NewRequest("GET", "http://localhost/echo.php", nil)
66+
w := httptest.NewRecorder()
67+
handler(w, req)
68+
69+
assert.Equal(t, http.StatusOK, w.Code)
70+
}
71+
72+
func TestPHPThreadPin(t *testing.T) {
73+
t.Cleanup(Shutdown)
74+
75+
require.NoError(t, Init(
76+
WithNumThreads(2),
77+
WithMaxThreads(2),
78+
))
79+
80+
thread, ok := Thread(0)
81+
require.True(t, ok)
82+
83+
// Pin should not panic
84+
data := "test data"
85+
assert.NotPanics(t, func() {
86+
thread.Pin(&data)
87+
})
88+
}

0 commit comments

Comments
 (0)