(t *testing.T)
| 124 | } |
| 125 | |
| 126 | func TestAutoScaleWorkerThreads(t *testing.T) { |
| 127 | wg := sync.WaitGroup{} |
| 128 | maxTries := 10 |
| 129 | requestsPerTry := 200 |
| 130 | tester := caddytest.NewTester(t) |
| 131 | tester.InitServer(` |
| 132 | { |
| 133 | skip_install_trust |
| 134 | admin localhost:2999 |
| 135 | http_port `+testPort+` |
| 136 | |
| 137 | frankenphp { |
| 138 | max_threads 10 |
| 139 | num_threads 2 |
| 140 | worker ../testdata/sleep.php { |
| 141 | num 1 |
| 142 | max_threads 3 |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | localhost:`+testPort+` { |
| 148 | route { |
| 149 | root ../testdata |
| 150 | rewrite sleep.php |
| 151 | php |
| 152 | } |
| 153 | } |
| 154 | `, "caddyfile") |
| 155 | |
| 156 | // spam an endpoint that simulates IO |
| 157 | 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 | } |
| 177 | |
| 178 | assert.NotEqual(t, amountOfThreads, 2, "at least one thread should have been auto-scaled") |
| 179 | assert.LessOrEqual(t, amountOfThreads, 4, "at most 3 max_threads + 1 regular thread should be present") |
| 180 | } |
| 181 | |
| 182 | // Note this test requires at least 2x40MB available memory for the process |
| 183 | func TestAutoScaleRegularThreadsOnAutomaticThreadLimit(t *testing.T) { |
nothing calls this directly
no test coverage detected