From c947a06d488fde2b36cf318a24c6da771f749238 Mon Sep 17 00:00:00 2001 From: Umputun Date: Sun, 23 Aug 2026 17:51:52 -0500 Subject: [PATCH] Release the response before tearing the test server down (#2212) TestRest_securityHeaders and TestRest_frameAncestors both start a server, read one response, and then call teardown() partway through the test to start a second server with different options. The first response body is only closed by a defer, which does not run until the test returns. httptest.Server.Close waits on connections still in use, so it blocks on a body that will not be closed until after it returns. The tests deadlock and the whole rest/api package dies on the timeout rather than on an assertion. CI pins go 1.25, where the responses are small enough that the connection goes back to the pool on its own and nothing hangs. On go 1.27 both tests hang, which is how this surfaced. Close the body and the client's idle connections before teardown() in both. --- backend/app/rest/api/middleware_test.go | 5 ++++- backend/app/rest/api/rest_test.go | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/app/rest/api/middleware_test.go b/backend/app/rest/api/middleware_test.go index 4e7fda35..616abbcf 100644 --- a/backend/app/rest/api/middleware_test.go +++ b/backend/app/rest/api/middleware_test.go @@ -271,11 +271,14 @@ func TestRest_securityHeaders(t *testing.T) { client := http.Client{} resp, err := client.Get(ts.URL + "/web/index.html") require.NoError(t, err) - defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Contains(t, resp.Header.Get("Content-Security-Policy"), "img-src *;") assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options")) assert.Equal(t, "strict-origin-when-cross-origin", resp.Header.Get("Referrer-Policy")) + // httptest.Server.Close waits on connections still in use, and a deferred close does not run + // until the test ends, so the body has to be released before the server is torn down here + require.NoError(t, resp.Body.Close()) + client.CloseIdleConnections() teardown() // check CSP with proxy enabled diff --git a/backend/app/rest/api/rest_test.go b/backend/app/rest/api/rest_test.go index 7441a024..b7db4387 100644 --- a/backend/app/rest/api/rest_test.go +++ b/backend/app/rest/api/rest_test.go @@ -573,9 +573,12 @@ func TestRest_frameAncestors(t *testing.T) { client := http.Client{} resp, err := client.Get(ts.URL + "/web/index.html") require.NoError(t, err) - defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Contains(t, resp.Header.Get("Content-Security-Policy"), "frame-ancestors 'self' https://example.com;") + // httptest.Server.Close waits on connections still in use, and a deferred close does not run + // until the test ends, so the body has to be released before the server is torn down here + require.NoError(t, resp.Body.Close()) + client.CloseIdleConnections() teardown() // test case without frame-ancestors