From 48af20378b4f04eeee0697dafee165cfac8e7c42 Mon Sep 17 00:00:00 2001 From: Alliballibaba Date: Sun, 3 Aug 2025 00:15:18 +0200 Subject: [PATCH 1/4] Removes test duplications. --- frankenphp_test.go | 358 ++++++++++++++++----------------------------- watcher_test.go | 4 +- 2 files changed, 127 insertions(+), 235 deletions(-) diff --git a/frankenphp_test.go b/frankenphp_test.go index 24241e058b..836d7091b5 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -107,19 +107,36 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * wg.Wait() } +func testRequest(req *http.Request, handler func(http.ResponseWriter, *http.Request)) (string, *http.Response) { + w := httptest.NewRecorder() + handler(w, req) + resp := w.Result() + body, _ := io.ReadAll(resp.Body) + + return string(body), resp +} + +func testGet(url string, handler func(http.ResponseWriter, *http.Request)) (string, *http.Response) { + req := httptest.NewRequest(http.MethodGet, url, nil) + + return testRequest(req, handler) +} + +func testPost(url string, body string, handler func(http.ResponseWriter, *http.Request)) (string, *http.Response) { + req := httptest.NewRequest(http.MethodPost, url, nil) + req.Body = io.NopCloser(strings.NewReader(body)) + + return testRequest(req, handler) +} + func TestHelloWorld_module(t *testing.T) { testHelloWorld(t, nil) } func TestHelloWorld_worker(t *testing.T) { testHelloWorld(t, &testOptions{workerScript: "index.php"}) } func testHelloWorld(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/index.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - assert.Equal(t, fmt.Sprintf("I am by birth a Genevese (%d)", i), string(body)) + body, _ := testGet(fmt.Sprintf("http://example.com/index.php?i=%d", i), handler) + assert.Equal(t, fmt.Sprintf("I am by birth a Genevese (%d)", i), body) }, opts) } @@ -129,13 +146,8 @@ func TestFinishRequest_worker(t *testing.T) { } func testFinishRequest(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/finish-request.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - assert.Equal(t, fmt.Sprintf("This is output %d\n", i), string(body)) + body, _ := testGet(fmt.Sprintf("http://example.com/finish-request.php?i=%d", i), handler) + assert.Equal(t, fmt.Sprintf("This is output %d\n", i), body) }, opts) } @@ -150,39 +162,33 @@ func testServerVariable(t *testing.T, opts *testOptions) { req := httptest.NewRequest("POST", fmt.Sprintf("http://example.com/server-variable.php/baz/bat?foo=a&bar=b&i=%d#hash", i), strings.NewReader("foo")) req.SetBasicAuth(strings.Clone("kevin"), strings.Clone("password")) req.Header.Add(strings.Clone("Content-Type"), strings.Clone("text/plain")) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - - strBody := string(body) - - assert.Contains(t, strBody, "[REMOTE_HOST]") - assert.Contains(t, strBody, "[REMOTE_USER] => kevin") - assert.Contains(t, strBody, "[PHP_AUTH_USER] => kevin") - assert.Contains(t, strBody, "[PHP_AUTH_PW] => password") - assert.Contains(t, strBody, "[HTTP_AUTHORIZATION] => Basic a2V2aW46cGFzc3dvcmQ=") - assert.Contains(t, strBody, "[DOCUMENT_ROOT]") - assert.Contains(t, strBody, "[PHP_SELF] => /server-variable.php/baz/bat") - assert.Contains(t, strBody, "[CONTENT_TYPE] => text/plain") - assert.Contains(t, strBody, fmt.Sprintf("[QUERY_STRING] => foo=a&bar=b&i=%d#hash", i)) - assert.Contains(t, strBody, fmt.Sprintf("[REQUEST_URI] => /server-variable.php/baz/bat?foo=a&bar=b&i=%d#hash", i)) - assert.Contains(t, strBody, "[CONTENT_LENGTH]") - assert.Contains(t, strBody, "[REMOTE_ADDR]") - assert.Contains(t, strBody, "[REMOTE_PORT]") - assert.Contains(t, strBody, "[REQUEST_SCHEME] => http") - assert.Contains(t, strBody, "[DOCUMENT_URI]") - assert.Contains(t, strBody, "[AUTH_TYPE]") - assert.Contains(t, strBody, "[REMOTE_IDENT]") - assert.Contains(t, strBody, "[REQUEST_METHOD] => POST") - assert.Contains(t, strBody, "[SERVER_NAME] => example.com") - assert.Contains(t, strBody, "[SERVER_PROTOCOL] => HTTP/1.1") - assert.Contains(t, strBody, "[SCRIPT_FILENAME]") - assert.Contains(t, strBody, "[SERVER_SOFTWARE] => FrankenPHP") - assert.Contains(t, strBody, "[REQUEST_TIME_FLOAT]") - assert.Contains(t, strBody, "[REQUEST_TIME]") - assert.Contains(t, strBody, "[SERVER_PORT] => 80") + body, _ := testRequest(req, handler) + + assert.Contains(t, body, "[REMOTE_HOST]") + assert.Contains(t, body, "[REMOTE_USER] => kevin") + assert.Contains(t, body, "[PHP_AUTH_USER] => kevin") + assert.Contains(t, body, "[PHP_AUTH_PW] => password") + assert.Contains(t, body, "[HTTP_AUTHORIZATION] => Basic a2V2aW46cGFzc3dvcmQ=") + assert.Contains(t, body, "[DOCUMENT_ROOT]") + assert.Contains(t, body, "[PHP_SELF] => /server-variable.php/baz/bat") + assert.Contains(t, body, "[CONTENT_TYPE] => text/plain") + assert.Contains(t, body, fmt.Sprintf("[QUERY_STRING] => foo=a&bar=b&i=%d#hash", i)) + assert.Contains(t, body, fmt.Sprintf("[REQUEST_URI] => /server-variable.php/baz/bat?foo=a&bar=b&i=%d#hash", i)) + assert.Contains(t, body, "[CONTENT_LENGTH]") + assert.Contains(t, body, "[REMOTE_ADDR]") + assert.Contains(t, body, "[REMOTE_PORT]") + assert.Contains(t, body, "[REQUEST_SCHEME] => http") + assert.Contains(t, body, "[DOCUMENT_URI]") + assert.Contains(t, body, "[AUTH_TYPE]") + assert.Contains(t, body, "[REMOTE_IDENT]") + assert.Contains(t, body, "[REQUEST_METHOD] => POST") + assert.Contains(t, body, "[SERVER_NAME] => example.com") + assert.Contains(t, body, "[SERVER_PROTOCOL] => HTTP/1.1") + assert.Contains(t, body, "[SCRIPT_FILENAME]") + assert.Contains(t, body, "[SERVER_SOFTWARE] => FrankenPHP") + assert.Contains(t, body, "[REQUEST_TIME_FLOAT]") + assert.Contains(t, body, "[REQUEST_TIME]") + assert.Contains(t, body, "[SERVER_PORT] => 80") }, opts) } @@ -210,19 +216,12 @@ func testPathInfo(t *testing.T, opts *testOptions) { assert.NoError(t, err) } - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/pathinfo/%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) + body, _ := testGet(fmt.Sprintf("http://example.com/pathinfo/%d", i), handler) - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - - strBody := string(body) - - assert.Contains(t, strBody, "[PATH_INFO] => /pathinfo") - assert.Contains(t, strBody, fmt.Sprintf("[REQUEST_URI] => /pathinfo/%d", i)) - assert.Contains(t, strBody, "[PATH_TRANSLATED] =>") - assert.Contains(t, strBody, "[SCRIPT_NAME] => /server-variable.php") + assert.Contains(t, body, "[PATH_INFO] => /pathinfo") + assert.Contains(t, body, fmt.Sprintf("[REQUEST_URI] => /pathinfo/%d", i)) + assert.Contains(t, body, "[PATH_TRANSLATED] =>") + assert.Contains(t, body, "[SCRIPT_NAME] => /server-variable.php") }, opts) } @@ -231,14 +230,9 @@ func TestHeaders_module(t *testing.T) { testHeaders(t, nil) } func TestHeaders_worker(t *testing.T) { testHeaders(t, &testOptions{workerScript: "headers.php"}) } func testHeaders(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/headers.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, resp := testGet(fmt.Sprintf("http://example.com/headers.php?i=%d", i), handler) - assert.Equal(t, "Hello", string(body)) + assert.Equal(t, "Hello", body) assert.Equal(t, 201, resp.StatusCode) assert.Equal(t, "bar", resp.Header.Get("Foo")) assert.Equal(t, "bar2", resp.Header.Get("Foo2")) @@ -254,12 +248,7 @@ func TestResponseHeaders_worker(t *testing.T) { } func testResponseHeaders(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/response-headers.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, resp := testGet(fmt.Sprintf("http://example.com/response-headers.php?i=%d", i), handler) if i%3 != 0 { assert.Equal(t, i+100, resp.StatusCode) @@ -267,11 +256,11 @@ func testResponseHeaders(t *testing.T, opts *testOptions) { assert.Equal(t, 200, resp.StatusCode) } - assert.Contains(t, string(body), "'X-Powered-By' => 'PH") - assert.Contains(t, string(body), "'Foo' => 'bar',") - assert.Contains(t, string(body), "'Foo2' => 'bar2',") - assert.Contains(t, string(body), fmt.Sprintf("'I' => '%d',", i)) - assert.NotContains(t, string(body), "Invalid") + assert.Contains(t, body, "'X-Powered-By' => 'PH") + assert.Contains(t, body, "'Foo' => 'bar',") + assert.Contains(t, body, "'Foo2' => 'bar2',") + assert.Contains(t, body, fmt.Sprintf("'I' => '%d',", i)) + assert.NotContains(t, body, "Invalid") }, opts) } @@ -279,14 +268,9 @@ func TestInput_module(t *testing.T) { testInput(t, nil) } func TestInput_worker(t *testing.T) { testInput(t, &testOptions{workerScript: "input.php"}) } func testInput(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("POST", "http://example.com/input.php", strings.NewReader(fmt.Sprintf("post data %d", i))) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, resp := testPost("http://example.com/input.php", fmt.Sprintf("post data %d", i), handler) - assert.Equal(t, fmt.Sprintf("post data %d", i), string(body)) + assert.Equal(t, fmt.Sprintf("post data %d", i), body) assert.Equal(t, "bar", resp.Header.Get("Foo")) }, opts) } @@ -300,16 +284,12 @@ func testPostSuperGlobals(t *testing.T, opts *testOptions) { formData := url.Values{"baz": {"bat"}, "i": {fmt.Sprintf("%d", i)}} req := httptest.NewRequest("POST", fmt.Sprintf("http://example.com/super-globals.php?foo=bar&iG=%d", i), strings.NewReader(formData.Encode())) req.Header.Set("Content-Type", strings.Clone("application/x-www-form-urlencoded")) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testRequest(req, handler) - assert.Contains(t, string(body), "'foo' => 'bar'") - assert.Contains(t, string(body), fmt.Sprintf("'i' => '%d'", i)) - assert.Contains(t, string(body), "'baz' => 'bat'") - assert.Contains(t, string(body), fmt.Sprintf("'iG' => '%d'", i)) + assert.Contains(t, body, "'foo' => 'bar'") + assert.Contains(t, body, fmt.Sprintf("'i' => '%d'", i)) + assert.Contains(t, body, "'baz' => 'bat'") + assert.Contains(t, body, fmt.Sprintf("'iG' => '%d'", i)) }, opts) } @@ -320,14 +300,10 @@ func testCookies(t *testing.T, opts *testOptions) { req := httptest.NewRequest("GET", "http://example.com/cookies.php", nil) req.AddCookie(&http.Cookie{Name: "foo", Value: "bar"}) req.AddCookie(&http.Cookie{Name: "i", Value: fmt.Sprintf("%d", i)}) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testRequest(req, handler) - assert.Contains(t, string(body), "'foo' => 'bar'") - assert.Contains(t, string(body), fmt.Sprintf("'i' => '%d'", i)) + assert.Contains(t, body, "'foo' => 'bar'") + assert.Contains(t, body, fmt.Sprintf("'i' => '%d'", i)) }, opts) } @@ -337,21 +313,17 @@ func TestMalformedCookie(t *testing.T) { req.Header.Add("Cookie", "foo =bar; ===;;==; .dot.=val ;\x00 ; PHPSESSID=1234") // Multiple Cookie header should be joined https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2.5 req.Header.Add("Cookie", "secondCookie=test; secondCookie=overwritten") - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testRequest(req, handler) - assert.Contains(t, string(body), "'foo_' => 'bar'") - assert.Contains(t, string(body), "'_dot_' => 'val '") + assert.Contains(t, body, "'foo_' => 'bar'") + assert.Contains(t, body, "'_dot_' => 'val '") // PHPSESSID should still be present since we remove the null byte - assert.Contains(t, string(body), "'PHPSESSID' => '1234'") + assert.Contains(t, body, "'PHPSESSID' => '1234'") // The cookie in the second headers should be present, // but it should not be overwritten by following values - assert.Contains(t, string(body), "'secondCookie' => 'test'") + assert.Contains(t, body, "'secondCookie' => 'test'") }, &testOptions{nbParallelRequests: 1}) } @@ -391,19 +363,14 @@ func TestPhpInfo_worker(t *testing.T) { testPhpInfo(t, &testOptions{workerScript func testPhpInfo(t *testing.T, opts *testOptions) { var logOnce sync.Once runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/phpinfo.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testGet(fmt.Sprintf("http://example.com/phpinfo.php?i=%d", i), handler) logOnce.Do(func() { - t.Log(string(body)) + t.Log(body) }) - assert.Contains(t, string(body), "frankenphp") - assert.Contains(t, string(body), fmt.Sprintf("i=%d", i)) + assert.Contains(t, body, "frankenphp") + assert.Contains(t, body, fmt.Sprintf("i=%d", i)) }, opts) } @@ -413,17 +380,12 @@ func TestPersistentObject_worker(t *testing.T) { } func testPersistentObject(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/persistent-object.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testGet(fmt.Sprintf("http://example.com/persistent-object.php?i=%d", i), handler) assert.Equal(t, fmt.Sprintf(`request: %d class exists: 1 id: obj1 -object id: 1`, i), string(body)) +object id: 1`, i), body) }, opts) } @@ -433,15 +395,10 @@ func TestAutoloader_worker(t *testing.T) { } func testAutoloader(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/autoloader.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testGet(fmt.Sprintf("http://example.com/autoloader.php?i=%d", i), handler) assert.Equal(t, fmt.Sprintf(`request %d -my_autoloader`, i), string(body)) +my_autoloader`, i), body) }, opts) } @@ -498,15 +455,10 @@ func TestException_worker(t *testing.T) { } func testException(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/exception.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testGet(fmt.Sprintf("http://example.com/exception.php?i=%d", i), handler) - assert.Contains(t, string(body), "hello") - assert.Contains(t, string(body), fmt.Sprintf(`Uncaught Exception: request %d`, i)) + assert.Contains(t, body, "hello") + assert.Contains(t, body, fmt.Sprintf(`Uncaught Exception: request %d`, i)) }, opts) } @@ -585,18 +537,13 @@ func TestLargeRequest_worker(t *testing.T) { } func testLargeRequest(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest( - "POST", + body, _ := testPost( fmt.Sprintf("http://example.com/large-request.php?i=%d", i), - strings.NewReader(strings.Repeat("f", 6_048_576)), + strings.Repeat("f", 6_048_576), + handler, ) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - assert.Contains(t, string(body), fmt.Sprintf("Request body size: 6048576 (%d)", i)) + assert.Contains(t, body, fmt.Sprintf("Request body size: 6048576 (%d)", i)) }, opts) } @@ -616,14 +563,8 @@ func TestFiberNonCgo_worker(t *testing.T) { } func testFiberNoCgo(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/fiber-no-cgo.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - - assert.Equal(t, string(body), fmt.Sprintf("Fiber %d", i)) + body, _ := testGet(fmt.Sprintf("http://example.com/fiber-no-cgo.php?i=%d", i), handler) + assert.Equal(t, body, fmt.Sprintf("Fiber %d", i)) }, opts) } @@ -633,14 +574,8 @@ func TestFiberBasic_worker(t *testing.T) { } func testFiberBasic(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/fiber-basic.php?i=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - - assert.Equal(t, string(body), fmt.Sprintf("Fiber %d", i)) + body, _ := testGet(fmt.Sprintf("http://example.com/fiber-basic.php?i=%d", i), handler) + assert.Equal(t, body, fmt.Sprintf("Fiber %d", i)) }, opts) } @@ -653,27 +588,17 @@ func testRequestHeaders(t *testing.T, opts *testOptions) { req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/request-headers.php?i=%d", i), nil) req.Header.Add(strings.Clone("Content-Type"), strings.Clone("text/plain")) req.Header.Add(strings.Clone("Frankenphp-I"), strings.Clone(strconv.Itoa(i))) + body, _ := testRequest(req, handler) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - - assert.Contains(t, string(body), "[Content-Type] => text/plain") - assert.Contains(t, string(body), fmt.Sprintf("[Frankenphp-I] => %d", i)) + assert.Contains(t, body, "[Content-Type] => text/plain") + assert.Contains(t, body, fmt.Sprintf("[Frankenphp-I] => %d", i)) }, opts) } func TestFailingWorker(t *testing.T) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", "http://example.com/failing-worker.php", nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - assert.Contains(t, string(body), "ok") + body, _ := testGet("http://example.com/failing-worker.php", handler) + assert.Contains(t, body, "ok") }, &testOptions{workerScript: "failing-worker.php"}) } @@ -689,12 +614,7 @@ func testEnv(t *testing.T, opts *testOptions) { assert.NoError(t, os.Setenv("EMPTY", "")) runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/env/test-env.php?var=%d", i), nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testGet(fmt.Sprintf("http://example.com/env/test-env.php?var=%d", i), handler) // execute the script as regular php script cmd := exec.Command("php", "testdata/env/test-env.php", strconv.Itoa(i)) @@ -704,18 +624,18 @@ func testEnv(t *testing.T, opts *testOptions) { stdoutStderr = []byte("Set MY_VAR successfully.\nMY_VAR = HelloWorld\nUnset MY_VAR successfully.\nMY_VAR is unset.\nMY_VAR set to empty successfully.\nMY_VAR = \nUnset NON_EXISTING_VAR successfully.\n") } - assert.Equal(t, string(stdoutStderr), string(body)) + assert.Equal(t, string(stdoutStderr), body) }, opts) } func TestEnvIsResetInNonWorkerMode(t *testing.T) { assert.NoError(t, os.Setenv("test", "")) runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - putResult := fetchBody("GET", fmt.Sprintf("http://example.com/env/putenv.php?key=test&put=%d", i), handler) + putResult, _ := testGet(fmt.Sprintf("http://example.com/env/putenv.php?key=test&put=%d", i), handler) assert.Equal(t, fmt.Sprintf("test=%d", i), putResult, "putenv and then echo getenv") - getResult := fetchBody("GET", "http://example.com/env/putenv.php?key=test", handler) + getResult, _ := testGet("http://example.com/env/putenv.php?key=test", handler) assert.Equal(t, "test=", getResult, "putenv should be reset across requests") }, &testOptions{}) @@ -725,11 +645,11 @@ func TestEnvIsResetInNonWorkerMode(t *testing.T) { func TestEnvIsNotResetInWorkerMode(t *testing.T) { assert.NoError(t, os.Setenv("index", "")) runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - putResult := fetchBody("GET", fmt.Sprintf("http://example.com/env/remember-env.php?index=%d", i), handler) + putResult, _ := testGet(fmt.Sprintf("http://example.com/env/remember-env.php?index=%d", i), handler) assert.Equal(t, "success", putResult, "putenv and then echo getenv") - getResult := fetchBody("GET", "http://example.com/env/remember-env.php", handler) + getResult, _ := testGet("http://example.com/env/remember-env.php", handler) assert.Equal(t, "success", getResult, "putenv should not be reset across worker requests") }, &testOptions{workerScript: "env/remember-env.php"}) @@ -739,7 +659,7 @@ func TestEnvIsNotResetInWorkerMode(t *testing.T) { func TestModificationsToEnvPersistAcrossRequests(t *testing.T) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { for j := 0; j < 3; j++ { - result := fetchBody("GET", "http://example.com/env/overwrite-env.php", handler) + result, _ := testGet("http://example.com/env/overwrite-env.php", handler) assert.Equal(t, "custom_value", result, "a var directly added to $_ENV should persist") } }, &testOptions{ @@ -765,11 +685,7 @@ func testFileUpload(t *testing.T, opts *testOptions) { req := httptest.NewRequest("POST", "http://example.com/file-upload.php", requestBody) req.Header.Add("Content-Type", writer.FormDataContentType()) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, _ := testRequest(req, handler) assert.Contains(t, string(body), "Upload OK") }, opts) @@ -1015,15 +931,10 @@ func testRejectInvalidHeaders(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) { req := httptest.NewRequest("GET", "http://example.com/headers.php", nil) req.Header.Add(header[0], header[1]) - - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, resp := testRequest(req, handler) assert.Equal(t, 400, resp.StatusCode) - assert.Contains(t, string(body), "invalid") + assert.Contains(t, body, "invalid") }, opts) } } @@ -1035,11 +946,7 @@ func TestFlushEmptyRespnse_worker(t *testing.T) { func testFlushEmptyResponse(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) { - req := httptest.NewRequest("GET", "http://example.com/only-headers.php", nil) - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() + _, resp := testGet("http://example.com/only-headers.php", handler) assert.Equal(t, 204, resp.StatusCode) }, opts) } @@ -1048,13 +955,13 @@ func testFlushEmptyResponse(t *testing.T, opts *testOptions) { // Make sure referenced streams are not cleaned up func TestFileStreamInWorkerMode(t *testing.T) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) { - resp1 := fetchBody("GET", "http://example.com/file-stream.php", handler) + resp1, _ := testGet("http://example.com/file-stream.php", handler) assert.Equal(t, resp1, "word1") - resp2 := fetchBody("GET", "http://example.com/file-stream.php", handler) + resp2, _ := testGet("http://example.com/file-stream.php", handler) assert.Equal(t, resp2, "word2") - resp3 := fetchBody("GET", "http://example.com/file-stream.php", handler) + resp3, _ := testGet("http://example.com/file-stream.php", handler) assert.Equal(t, resp3, "word3") }, &testOptions{workerScript: "file-stream.php", nbParallelRequests: 1, nbWorkers: 1}) } @@ -1074,38 +981,23 @@ func FuzzRequest(f *testing.F) { req.URL = &url.URL{RawQuery: "test=" + fuzzedString, Path: "/server-variable.php/" + fuzzedString} req.Header.Add(strings.Clone("Fuzzed"), strings.Clone(fuzzedString)) req.Header.Add(strings.Clone("Content-Type"), fuzzedString) - - w := httptest.NewRecorder() - handler(w, req) - - resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, resp := testRequest(req, handler) // The response status must be 400 if the request path contains null bytes if strings.Contains(req.URL.Path, "\x00") { assert.Equal(t, 400, resp.StatusCode) - assert.Contains(t, string(body), "Invalid request path") + assert.Contains(t, body, "Invalid request path") return } // The fuzzed string must be present in the path - assert.Contains(t, string(body), fmt.Sprintf("[PATH_INFO] => /%s", fuzzedString)) - assert.Contains(t, string(body), fmt.Sprintf("[PATH_TRANSLATED] => %s", filepath.Join(absPath, fuzzedString))) + assert.Contains(t, body, fmt.Sprintf("[PATH_INFO] => /%s", fuzzedString)) + assert.Contains(t, body, fmt.Sprintf("[PATH_TRANSLATED] => %s", filepath.Join(absPath, fuzzedString))) // Headers should always be present even if empty - assert.Contains(t, string(body), fmt.Sprintf("[CONTENT_TYPE] => %s", fuzzedString)) - assert.Contains(t, string(body), fmt.Sprintf("[HTTP_FUZZED] => %s", fuzzedString)) + assert.Contains(t, body, fmt.Sprintf("[CONTENT_TYPE] => %s", fuzzedString)) + assert.Contains(t, body, fmt.Sprintf("[HTTP_FUZZED] => %s", fuzzedString)) }, &testOptions{workerScript: "request-headers.php"}) }) } - -func fetchBody(method string, url string, handler func(http.ResponseWriter, *http.Request)) string { - req := httptest.NewRequest(method, url, nil) - w := httptest.NewRecorder() - handler(w, req) - resp := w.Result() - body, _ := io.ReadAll(resp.Body) - - return string(body) -} diff --git a/watcher_test.go b/watcher_test.go index afd4e8c88c..14921bc55c 100644 --- a/watcher_test.go +++ b/watcher_test.go @@ -42,14 +42,14 @@ func TestWorkersShouldNotReloadOnExcludingPattern(t *testing.T) { func pollForWorkerReset(t *testing.T, handler func(http.ResponseWriter, *http.Request), limit int) bool { // first we make an initial request to start the request counter - body := fetchBody("GET", "http://example.com/worker-with-counter.php", handler) + body, _ := testGet("http://example.com/worker-with-counter.php", handler) assert.Equal(t, "requests:1", body) // now we spam file updates and check if the request counter resets for i := 0; i < limit; i++ { updateTestFile("./testdata/files/test.txt", "updated", t) time.Sleep(pollingTime * time.Millisecond) - body := fetchBody("GET", "http://example.com/worker-with-counter.php", handler) + body, _ := testGet("http://example.com/worker-with-counter.php", handler) if body == "requests:1" { return true } From 31a3623ee4da8a14d25e676c8f557170755d3f34 Mon Sep 17 00:00:00 2001 From: Alliballibaba Date: Tue, 5 Aug 2025 21:15:30 +0200 Subject: [PATCH 2/4] Adds t.Helper(). --- frankenphp_test.go | 82 +++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/frankenphp_test.go b/frankenphp_test.go index 836d7091b5..6393c0761e 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -91,7 +91,7 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * var ts *httptest.Server if opts.realServer { - ts = httptest.NewServer(http.HandlerFunc(handler)) + ts = httptest.NewServer(http.HandlerFunc(handler, t)) defer ts.Close() } @@ -107,26 +107,32 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * wg.Wait() } -func testRequest(req *http.Request, handler func(http.ResponseWriter, *http.Request)) (string, *http.Response) { +func testRequest(req *http.Request, handler func(http.ResponseWriter, *http.Request), t *testing.T) (string, *http.Response) { + t.Helper() w := httptest.NewRecorder() handler(w, req) resp := w.Result() - body, _ := io.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Errorf("failed to read response body: %v", err) + } return string(body), resp } -func testGet(url string, handler func(http.ResponseWriter, *http.Request)) (string, *http.Response) { +func testGet(url string, handler func(http.ResponseWriter, *http.Request), t *testing.T) (string, *http.Response) { + t.Helper() req := httptest.NewRequest(http.MethodGet, url, nil) - return testRequest(req, handler) + return testRequest(req, handler, t) } -func testPost(url string, body string, handler func(http.ResponseWriter, *http.Request)) (string, *http.Response) { +func testPost(url string, body string, handler func(http.ResponseWriter, *http.Request), t *testing.T) (string, *http.Response) { + t.Helper() req := httptest.NewRequest(http.MethodPost, url, nil) req.Body = io.NopCloser(strings.NewReader(body)) - return testRequest(req, handler) + return testRequest(req, handler, t) } func TestHelloWorld_module(t *testing.T) { testHelloWorld(t, nil) } @@ -135,7 +141,7 @@ func TestHelloWorld_worker(t *testing.T) { } func testHelloWorld(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/index.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/index.php?i=%d", i), handler, t) assert.Equal(t, fmt.Sprintf("I am by birth a Genevese (%d)", i), body) }, opts) } @@ -146,7 +152,7 @@ func TestFinishRequest_worker(t *testing.T) { } func testFinishRequest(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/finish-request.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/finish-request.php?i=%d", i), handler, t) assert.Equal(t, fmt.Sprintf("This is output %d\n", i), body) }, opts) } @@ -162,7 +168,7 @@ func testServerVariable(t *testing.T, opts *testOptions) { req := httptest.NewRequest("POST", fmt.Sprintf("http://example.com/server-variable.php/baz/bat?foo=a&bar=b&i=%d#hash", i), strings.NewReader("foo")) req.SetBasicAuth(strings.Clone("kevin"), strings.Clone("password")) req.Header.Add(strings.Clone("Content-Type"), strings.Clone("text/plain")) - body, _ := testRequest(req, handler) + body, _ := testRequest(req, handler, t) assert.Contains(t, body, "[REMOTE_HOST]") assert.Contains(t, body, "[REMOTE_USER] => kevin") @@ -216,7 +222,7 @@ func testPathInfo(t *testing.T, opts *testOptions) { assert.NoError(t, err) } - body, _ := testGet(fmt.Sprintf("http://example.com/pathinfo/%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/pathinfo/%d", i), handler, t) assert.Contains(t, body, "[PATH_INFO] => /pathinfo") assert.Contains(t, body, fmt.Sprintf("[REQUEST_URI] => /pathinfo/%d", i)) @@ -230,7 +236,7 @@ func TestHeaders_module(t *testing.T) { testHeaders(t, nil) } func TestHeaders_worker(t *testing.T) { testHeaders(t, &testOptions{workerScript: "headers.php"}) } func testHeaders(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, resp := testGet(fmt.Sprintf("http://example.com/headers.php?i=%d", i), handler) + body, resp := testGet(fmt.Sprintf("http://example.com/headers.php?i=%d", i), handler, t) assert.Equal(t, "Hello", body) assert.Equal(t, 201, resp.StatusCode) @@ -248,7 +254,7 @@ func TestResponseHeaders_worker(t *testing.T) { } func testResponseHeaders(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, resp := testGet(fmt.Sprintf("http://example.com/response-headers.php?i=%d", i), handler) + body, resp := testGet(fmt.Sprintf("http://example.com/response-headers.php?i=%d", i), handler, t) if i%3 != 0 { assert.Equal(t, i+100, resp.StatusCode) @@ -268,7 +274,7 @@ func TestInput_module(t *testing.T) { testInput(t, nil) } func TestInput_worker(t *testing.T) { testInput(t, &testOptions{workerScript: "input.php"}) } func testInput(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, resp := testPost("http://example.com/input.php", fmt.Sprintf("post data %d", i), handler) + body, resp := testPost("http://example.com/input.php", fmt.Sprintf("post data %d", i), handler, t) assert.Equal(t, fmt.Sprintf("post data %d", i), body) assert.Equal(t, "bar", resp.Header.Get("Foo")) @@ -284,7 +290,7 @@ func testPostSuperGlobals(t *testing.T, opts *testOptions) { formData := url.Values{"baz": {"bat"}, "i": {fmt.Sprintf("%d", i)}} req := httptest.NewRequest("POST", fmt.Sprintf("http://example.com/super-globals.php?foo=bar&iG=%d", i), strings.NewReader(formData.Encode())) req.Header.Set("Content-Type", strings.Clone("application/x-www-form-urlencoded")) - body, _ := testRequest(req, handler) + body, _ := testRequest(req, handler, t) assert.Contains(t, body, "'foo' => 'bar'") assert.Contains(t, body, fmt.Sprintf("'i' => '%d'", i)) @@ -300,7 +306,7 @@ func testCookies(t *testing.T, opts *testOptions) { req := httptest.NewRequest("GET", "http://example.com/cookies.php", nil) req.AddCookie(&http.Cookie{Name: "foo", Value: "bar"}) req.AddCookie(&http.Cookie{Name: "i", Value: fmt.Sprintf("%d", i)}) - body, _ := testRequest(req, handler) + body, _ := testRequest(req, handler, t) assert.Contains(t, body, "'foo' => 'bar'") assert.Contains(t, body, fmt.Sprintf("'i' => '%d'", i)) @@ -313,7 +319,7 @@ func TestMalformedCookie(t *testing.T) { req.Header.Add("Cookie", "foo =bar; ===;;==; .dot.=val ;\x00 ; PHPSESSID=1234") // Multiple Cookie header should be joined https://www.rfc-editor.org/rfc/rfc7540#section-8.1.2.5 req.Header.Add("Cookie", "secondCookie=test; secondCookie=overwritten") - body, _ := testRequest(req, handler) + body, _ := testRequest(req, handler, t) assert.Contains(t, body, "'foo_' => 'bar'") assert.Contains(t, body, "'_dot_' => 'val '") @@ -363,7 +369,7 @@ func TestPhpInfo_worker(t *testing.T) { testPhpInfo(t, &testOptions{workerScript func testPhpInfo(t *testing.T, opts *testOptions) { var logOnce sync.Once runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/phpinfo.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/phpinfo.php?i=%d", i), handler, t) logOnce.Do(func() { t.Log(body) @@ -380,7 +386,7 @@ func TestPersistentObject_worker(t *testing.T) { } func testPersistentObject(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/persistent-object.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/persistent-object.php?i=%d", i), handler, t) assert.Equal(t, fmt.Sprintf(`request: %d class exists: 1 @@ -395,7 +401,7 @@ func TestAutoloader_worker(t *testing.T) { } func testAutoloader(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/autoloader.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/autoloader.php?i=%d", i), handler, t) assert.Equal(t, fmt.Sprintf(`request %d my_autoloader`, i), body) @@ -455,7 +461,7 @@ func TestException_worker(t *testing.T) { } func testException(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/exception.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/exception.php?i=%d", i), handler, t) assert.Contains(t, body, "hello") assert.Contains(t, body, fmt.Sprintf(`Uncaught Exception: request %d`, i)) @@ -563,7 +569,7 @@ func TestFiberNonCgo_worker(t *testing.T) { } func testFiberNoCgo(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/fiber-no-cgo.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/fiber-no-cgo.php?i=%d", i), handler, t) assert.Equal(t, body, fmt.Sprintf("Fiber %d", i)) }, opts) } @@ -574,7 +580,7 @@ func TestFiberBasic_worker(t *testing.T) { } func testFiberBasic(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/fiber-basic.php?i=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/fiber-basic.php?i=%d", i), handler, t) assert.Equal(t, body, fmt.Sprintf("Fiber %d", i)) }, opts) } @@ -588,7 +594,7 @@ func testRequestHeaders(t *testing.T, opts *testOptions) { req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/request-headers.php?i=%d", i), nil) req.Header.Add(strings.Clone("Content-Type"), strings.Clone("text/plain")) req.Header.Add(strings.Clone("Frankenphp-I"), strings.Clone(strconv.Itoa(i))) - body, _ := testRequest(req, handler) + body, _ := testRequest(req, handler, t) assert.Contains(t, body, "[Content-Type] => text/plain") assert.Contains(t, body, fmt.Sprintf("[Frankenphp-I] => %d", i)) @@ -597,7 +603,7 @@ func testRequestHeaders(t *testing.T, opts *testOptions) { func TestFailingWorker(t *testing.T) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet("http://example.com/failing-worker.php", handler) + body, _ := testGet("http://example.com/failing-worker.php", handler, t) assert.Contains(t, body, "ok") }, &testOptions{workerScript: "failing-worker.php"}) } @@ -614,7 +620,7 @@ func testEnv(t *testing.T, opts *testOptions) { assert.NoError(t, os.Setenv("EMPTY", "")) runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - body, _ := testGet(fmt.Sprintf("http://example.com/env/test-env.php?var=%d", i), handler) + body, _ := testGet(fmt.Sprintf("http://example.com/env/test-env.php?var=%d", i), handler, t) // execute the script as regular php script cmd := exec.Command("php", "testdata/env/test-env.php", strconv.Itoa(i)) @@ -631,11 +637,11 @@ func testEnv(t *testing.T, opts *testOptions) { func TestEnvIsResetInNonWorkerMode(t *testing.T) { assert.NoError(t, os.Setenv("test", "")) runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - putResult, _ := testGet(fmt.Sprintf("http://example.com/env/putenv.php?key=test&put=%d", i), handler) + putResult, _ := testGet(fmt.Sprintf("http://example.com/env/putenv.php?key=test&put=%d", i), handler, t) assert.Equal(t, fmt.Sprintf("test=%d", i), putResult, "putenv and then echo getenv") - getResult, _ := testGet("http://example.com/env/putenv.php?key=test", handler) + getResult, _ := testGet("http://example.com/env/putenv.php?key=test", handler, t) assert.Equal(t, "test=", getResult, "putenv should be reset across requests") }, &testOptions{}) @@ -645,11 +651,11 @@ func TestEnvIsResetInNonWorkerMode(t *testing.T) { func TestEnvIsNotResetInWorkerMode(t *testing.T) { assert.NoError(t, os.Setenv("index", "")) runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { - putResult, _ := testGet(fmt.Sprintf("http://example.com/env/remember-env.php?index=%d", i), handler) + putResult, _ := testGet(fmt.Sprintf("http://example.com/env/remember-env.php?index=%d", i), handler, t) assert.Equal(t, "success", putResult, "putenv and then echo getenv") - getResult, _ := testGet("http://example.com/env/remember-env.php", handler) + getResult, _ := testGet("http://example.com/env/remember-env.php", handler, t) assert.Equal(t, "success", getResult, "putenv should not be reset across worker requests") }, &testOptions{workerScript: "env/remember-env.php"}) @@ -659,7 +665,7 @@ func TestEnvIsNotResetInWorkerMode(t *testing.T) { func TestModificationsToEnvPersistAcrossRequests(t *testing.T) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { for j := 0; j < 3; j++ { - result, _ := testGet("http://example.com/env/overwrite-env.php", handler) + result, _ := testGet("http://example.com/env/overwrite-env.php", handler, t) assert.Equal(t, "custom_value", result, "a var directly added to $_ENV should persist") } }, &testOptions{ @@ -685,7 +691,7 @@ func testFileUpload(t *testing.T, opts *testOptions) { req := httptest.NewRequest("POST", "http://example.com/file-upload.php", requestBody) req.Header.Add("Content-Type", writer.FormDataContentType()) - body, _ := testRequest(req, handler) + body, _ := testRequest(req, handler, t) assert.Contains(t, string(body), "Upload OK") }, opts) @@ -931,7 +937,7 @@ func testRejectInvalidHeaders(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) { req := httptest.NewRequest("GET", "http://example.com/headers.php", nil) req.Header.Add(header[0], header[1]) - body, resp := testRequest(req, handler) + body, resp := testRequest(req, handler, t) assert.Equal(t, 400, resp.StatusCode) assert.Contains(t, body, "invalid") @@ -946,7 +952,7 @@ func TestFlushEmptyRespnse_worker(t *testing.T) { func testFlushEmptyResponse(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) { - _, resp := testGet("http://example.com/only-headers.php", handler) + _, resp := testGet("http://example.com/only-headers.php", handler, t) assert.Equal(t, 204, resp.StatusCode) }, opts) } @@ -955,13 +961,13 @@ func testFlushEmptyResponse(t *testing.T, opts *testOptions) { // Make sure referenced streams are not cleaned up func TestFileStreamInWorkerMode(t *testing.T) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, _ int) { - resp1, _ := testGet("http://example.com/file-stream.php", handler) + resp1, _ := testGet("http://example.com/file-stream.php", handler, t) assert.Equal(t, resp1, "word1") - resp2, _ := testGet("http://example.com/file-stream.php", handler) + resp2, _ := testGet("http://example.com/file-stream.php", handler, t) assert.Equal(t, resp2, "word2") - resp3, _ := testGet("http://example.com/file-stream.php", handler) + resp3, _ := testGet("http://example.com/file-stream.php", handler, t) assert.Equal(t, resp3, "word3") }, &testOptions{workerScript: "file-stream.php", nbParallelRequests: 1, nbWorkers: 1}) } @@ -981,7 +987,7 @@ func FuzzRequest(f *testing.F) { req.URL = &url.URL{RawQuery: "test=" + fuzzedString, Path: "/server-variable.php/" + fuzzedString} req.Header.Add(strings.Clone("Fuzzed"), strings.Clone(fuzzedString)) req.Header.Add(strings.Clone("Content-Type"), fuzzedString) - body, resp := testRequest(req, handler) + body, resp := testRequest(req, handler, t) // The response status must be 400 if the request path contains null bytes if strings.Contains(req.URL.Path, "\x00") { From eacf6f3c1b8b7452e6be9e97e99445d31929c434 Mon Sep 17 00:00:00 2001 From: Alliballibaba Date: Tue, 5 Aug 2025 21:18:43 +0200 Subject: [PATCH 3/4] Fixes tests. --- frankenphp_test.go | 3 ++- watcher_test.go | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/frankenphp_test.go b/frankenphp_test.go index 6393c0761e..f8ec771386 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -91,7 +91,7 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * var ts *httptest.Server if opts.realServer { - ts = httptest.NewServer(http.HandlerFunc(handler, t)) + ts = httptest.NewServer(http.HandlerFunc(handler)) defer ts.Close() } @@ -547,6 +547,7 @@ func testLargeRequest(t *testing.T, opts *testOptions) { fmt.Sprintf("http://example.com/large-request.php?i=%d", i), strings.Repeat("f", 6_048_576), handler, + t, ) assert.Contains(t, body, fmt.Sprintf("Request body size: 6048576 (%d)", i)) diff --git a/watcher_test.go b/watcher_test.go index 14921bc55c..ea5134a9e8 100644 --- a/watcher_test.go +++ b/watcher_test.go @@ -42,14 +42,14 @@ func TestWorkersShouldNotReloadOnExcludingPattern(t *testing.T) { func pollForWorkerReset(t *testing.T, handler func(http.ResponseWriter, *http.Request), limit int) bool { // first we make an initial request to start the request counter - body, _ := testGet("http://example.com/worker-with-counter.php", handler) + body, _ := testGet("http://example.com/worker-with-counter.php", handler, t) assert.Equal(t, "requests:1", body) // now we spam file updates and check if the request counter resets for i := 0; i < limit; i++ { updateTestFile("./testdata/files/test.txt", "updated", t) time.Sleep(pollingTime * time.Millisecond) - body, _ := testGet("http://example.com/worker-with-counter.php", handler) + body, _ := testGet("http://example.com/worker-with-counter.php", handler, t) if body == "requests:1" { return true } From 8d5b6ad3c7a07d1ead1a54bb859f3286ffca2134 Mon Sep 17 00:00:00 2001 From: Alexander Stecher <45872305+AlliBalliBaba@users.noreply.github.com> Date: Thu, 7 Aug 2025 21:12:42 +0200 Subject: [PATCH 4/4] UUpdate frankenphp_test.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kévin Dunglas --- frankenphp_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frankenphp_test.go b/frankenphp_test.go index f8ec771386..4c36e0c38f 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -113,9 +113,7 @@ func testRequest(req *http.Request, handler func(http.ResponseWriter, *http.Requ handler(w, req) resp := w.Result() body, err := io.ReadAll(resp.Body) - if err != nil { - t.Errorf("failed to read response body: %v", err) - } + require.NoError(t, err) return string(body), resp }