Skip to content

Commit 72607e6

Browse files
committed
test: stop autoscale tests failing on connection resets under load
The load loops asserted every request with caddytest.AssertGetResponse, which calls t.Fatalf on a connection error. Under 200 concurrent requests the macOS runner resets connections, failing the whole test even though auto-scaling worked. Both tests only care that the thread count climbs above baseline, so spam with a plain http.Get that tolerates per-request errors; a total failure to serve still surfaces as no scaling. Extracted the shared loop into loadUntilScaled.
1 parent b4c8dfd commit 72607e6

1 file changed

Lines changed: 35 additions & 42 deletions

File tree

caddy/admin_test.go

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,42 @@ func TestThreadDebugStateMetricsAfterRequests(t *testing.T) {
123123
assert.True(t, hasRequestCount, "at least one thread should have RequestCount > 0 after serving requests")
124124
}
125125

126-
func TestAutoScaleWorkerThreads(t *testing.T) {
126+
// loadUntilScaled spams endpoint with concurrent requests until getNumThreads
127+
// climbs above baseline or the tries run out, returning the final thread count.
128+
// Connection errors under heavy load (e.g. resets on the macOS runner) are
129+
// expected and ignored: the auto-scaling assertion is what the caller checks,
130+
// and a total failure to serve still surfaces as no scaling.
131+
func loadUntilScaled(t *testing.T, tester *caddytest.Tester, endpoint string, baseline int) int {
132+
t.Helper()
127133
wg := sync.WaitGroup{}
128134
maxTries := 10
129135
requestsPerTry := 200
136+
threads := baseline
137+
for range maxTries {
138+
wg.Add(requestsPerTry)
139+
for range requestsPerTry {
140+
go func() {
141+
defer wg.Done()
142+
resp, err := http.Get(endpoint)
143+
if err != nil {
144+
return
145+
}
146+
_, _ = io.Copy(io.Discard, resp.Body)
147+
_ = resp.Body.Close()
148+
}()
149+
}
150+
wg.Wait()
151+
152+
threads = getNumThreads(t, tester)
153+
if threads > baseline {
154+
break
155+
}
156+
}
157+
158+
return threads
159+
}
160+
161+
func TestAutoScaleWorkerThreads(t *testing.T) {
130162
tester := caddytest.NewTester(t)
131163
tester.InitServer(`
132164
{
@@ -155,35 +187,14 @@ func TestAutoScaleWorkerThreads(t *testing.T) {
155187

156188
// spam an endpoint that simulates IO
157189
endpoint := "http://localhost:" + testPort + "/?sleep=2&work=1000"
158-
amountOfThreads := getNumThreads(t, tester)
159-
160-
// try to spawn the additional threads by spamming the server
161-
for range maxTries {
162-
wg.Add(requestsPerTry)
163-
for range requestsPerTry {
164-
go func() {
165-
// deferred so a t.Fatalf from a failed request doesn't leak the WaitGroup
166-
defer wg.Done()
167-
tester.AssertGetResponse(endpoint, http.StatusOK, "slept for 2 ms and worked for 1000 iterations")
168-
}()
169-
}
170-
wg.Wait()
171-
172-
amountOfThreads = getNumThreads(t, tester)
173-
if amountOfThreads > 2 || t.Failed() {
174-
break
175-
}
176-
}
190+
amountOfThreads := loadUntilScaled(t, tester, endpoint, 2)
177191

178192
assert.NotEqual(t, amountOfThreads, 2, "at least one thread should have been auto-scaled")
179193
assert.LessOrEqual(t, amountOfThreads, 4, "at most 3 max_threads + 1 regular thread should be present")
180194
}
181195

182196
// Note this test requires at least 2x40MB available memory for the process
183197
func TestAutoScaleRegularThreadsOnAutomaticThreadLimit(t *testing.T) {
184-
wg := sync.WaitGroup{}
185-
maxTries := 10
186-
requestsPerTry := 200
187198
tester := caddytest.NewTester(t)
188199
tester.InitServer(`
189200
{
@@ -208,25 +219,7 @@ func TestAutoScaleRegularThreadsOnAutomaticThreadLimit(t *testing.T) {
208219

209220
// spam an endpoint that simulates IO
210221
endpoint := "http://localhost:" + testPort + "/sleep.php?sleep=2&work=1000"
211-
amountOfThreads := getNumThreads(t, tester)
212-
213-
// try to spawn the additional threads by spamming the server
214-
for range maxTries {
215-
wg.Add(requestsPerTry)
216-
for range requestsPerTry {
217-
go func() {
218-
// deferred so a t.Fatalf from a failed request doesn't leak the WaitGroup
219-
defer wg.Done()
220-
tester.AssertGetResponse(endpoint, http.StatusOK, "slept for 2 ms and worked for 1000 iterations")
221-
}()
222-
}
223-
wg.Wait()
224-
225-
amountOfThreads = getNumThreads(t, tester)
226-
if amountOfThreads > 1 || t.Failed() {
227-
break
228-
}
229-
}
222+
amountOfThreads := loadUntilScaled(t, tester, endpoint, 1)
230223

231224
// assert that there are now more threads present
232225
assert.NotEqual(t, amountOfThreads, 1)

0 commit comments

Comments
 (0)