@@ -64,14 +64,17 @@ Failed files: 1 (50.0%)
6464Duration: 10 ms
6565```
6666
67+ > With or without `--test`, all asserts are always executed. `--test` adds a run recap and disables the output of the
68+ > last response. To ignore asserts execution, you can use [`--ignore-asserts`].
69+
6770In test mode, files are executed in parallel to speed-ud the execution. If a sequential run is needed, you can use
6871[`--jobs 1`] option to execute tests one by one.
6972
7073```shell
7174$ hurl --test --jobs 1 *.hurl
7275```
7376
74- [`--repeat` option] can be used to repeat run files and do performance check. For instance, this call will run 1000 tests
77+ [`--repeat` option] can be used to repeat run files and do [ performance check] . For instance, this call will run 1000 tests
7578in parallel:
7679
7780```shell
@@ -204,6 +207,90 @@ Failed files: 0 (0.0%)
204207Duration: 187 ms
205208```
206209
210+ ## Stress and Performance Tests
211+
212+ Hurl can be used to perform stress tests:
213+
214+ - with [query duration]:
215+
216+ ```hurl
217+ GET https://example.org/foo
218+ HTTP 200
219+ [Asserts]
220+ duration < 1200
221+ ```
222+
223+ - [response metrics] with [`--very-verbose`] or [`--json`] to get structured timing data:
224+
225+ ```shell
226+ $ hurl --json foo.hurl | jq
227+ ...
228+ "timings": {
229+ "app_connect": 0,
230+ "begin_call": "2025-10-06T07:00:57.127794Z",
231+ "connect": 120915,
232+ "end_call": "2025-10-06T07:00:57.280724Z",
233+ "name_lookup": 92987,
234+ "pre_transfer": 121014,
235+ "start_transfer": 152721,
236+ "total": 152807
237+ }
238+ ...
239+ ```
240+
241+ In performance uses-cases, it' s important to know how Hurl is working to get the best request per second load. Each Hurl file
242+ is processed by its own libcurl instance (roughly speaking a living HTTP connection). Let' s say we want to stress our
243+ application with 100,000 HTTP requests and see how it' s behaving. The simplest idea would be to make a single Hurl file
244+ repeating 100,000 requests:
245+
246+ ` ` ` hurl
247+ GET https://my-website/health
248+ [Options]
249+ repeat: 100000
250+ ` ` `
251+
252+ and run it:
253+
254+ ` ` ` shell
255+ $ hurl --test perf.hurl
256+ ` ` `
257+
258+ With a single Hurl file, we won' t benefit from any parallel runs (files are run in parallel, requests _within_ a file are
259+ run sequentially). To benefit from parallel run, we can use [`--repeat`] as a CLI argument to repeat file execution. It' s
260+ as if we' ve written 100,000 identical Hurl files and run them:
261+
262+
263+ ```hurl
264+ GET https://my-website/health
265+ ```
266+
267+ and run it:
268+
269+ ```shell
270+ $ hurl --test --repeat 100000 perf.hurl
271+ ```
272+
273+ In this case, we' re running 100,000 Hurl files in parallel. Now, we have another problem: as each file is basically a
274+ HTTP connection, we can run out of TCP port, a phenomenon known as [ephemeral ports exhaustion]. So, to recap:
275+
276+ - running 100,000 requests in a single file won' t benefit from parallel run
277+ - running 100,000 one request files can lead to TCP port resources issues
278+
279+ The solution is to combine the two approaches: running 10 files of 10,000 HTTP requests. With 10 files of 10,000
280+ requests, we' re going to execute those files in parallel in their own worker. Each worker will be working sequentially,
281+ maximizing the usage and not running into TCP ports exhaustion. We can force jobs count to be exactly 10 so
282+ all workers start at the same time and no one is waiting to get a job done:
283+
284+ ` ` ` hurl
285+ GET https://my-website/health
286+ [Options]
287+ repeat: 10000
288+ ` ` `
289+
290+ ` ` ` shell
291+ $ hurl --test --repeat 10 --jobs 10 perf.hurl
292+ ` ` `
293+
207294
208295
209296# # Generating Report
@@ -257,7 +344,6 @@ To use variables in your tests, you can:
257344
258345You will find a detailed description in the [Injecting Variables] section of the docs.
259346
260-
261347[` --output /dev/null` ]: {% link _docs/manual.md %}# output
262348[` --test` ]: {% link _docs/manual.md %}# test
263349[` --report-html DIR` ]: {% link _docs/manual.md %}# report-html
@@ -280,3 +366,9 @@ You will find a detailed description in the [Injecting Variables] section of the
280366[` very-verbose` ]: {% link _docs/manual.md %}# very-verbose
281367[` --output` option]: {% link _docs/manual.md %}# output
282368[` --repeat` option]: {% link _docs/manual.md %}# repeat
369+ [query duration]: {% link _docs/asserting-response.md %}# duration-assert
370+ [response metrics]: {% link _docs/response.md %}# timings
371+ [` --ignore-asserts` ]: {% link _docs/manual.md %}# ignore-asserts
372+ [performance check]: {% link _docs/running-tests.md %}# stress-and-performance-tests
373+ [ephemeral ports exhaustion]: https://blog.cloudflare.com/how-to-stop-running-out-of-ephemeral-ports-and-start-to-love-long-lived-connections/
374+ [` --repeat` ]: {% link _docs/manual.md %}# repeat
0 commit comments