Skip to content

Commit 05f05a6

Browse files
committed
Update docs.
1 parent 670b824 commit 05f05a6

File tree

7 files changed

+115
-9
lines changed

7 files changed

+115
-9
lines changed

sites/hurl.dev/_data/docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
items:
119119
- title: Debug Logs
120120
- title: HTTP Responses
121+
- title: Stress and Performance Tests
121122
- title: Generating Report
122123
items:
123124
- title: HTML Report

sites/hurl.dev/_docs/asserting-response.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ Predicates consist of a predicate function and a predicate value. Predicate func
418418
| __`isString`__ | Query returns a string | `jsonpath "$.name" isString` |
419419
| __`isIpv4`__ | Query returns an IPv4 address | `ip isIpv4` |
420420
| __`isIpv6`__ | Query returns an IPv6 address | `ip isIpv6` |
421-
| __`isUuid`__ | Query returns a UUID | `ip isUuid` |
421+
| __`isUuid`__ | Query returns a [UUID v4] | `ip isUuid` |
422422

423423

424424
Each predicate can be negated by prefixing it with `not` (for instance, `not contains` or `not exists`)
@@ -1011,3 +1011,4 @@ certificate "Serial-Number" matches "[0-9af]+"
10111011
[`Content-Type` header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type
10121012
[`body` assert]: #body-assert
10131013
[`location` filter]: {% link _docs/filters.md %}#location
1014+
[UUID v4]: https://en.wikipedia.org/wiki/Universally_unique_identifier

sites/hurl.dev/_docs/capturing-response.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ HTTP 302
3636
{% endraw %}
3737

3838

39+
Body responses can be encoded by server (see [`Content-Encoding` HTTP header]) but captures in Hurl files are not
40+
affected by this content compression. All body captures (`body`, `bytes`, `sha256` etc...) work _after_ content decoding.
41+
42+
Finally, body text captures (`body`, `jsonpath`, `xpath` etc...) are also decoded to strings based on [`Content-Type` header]
43+
so these queries can be captures as usual strings.
44+
45+
3946
Structure of a capture:
4047

4148
<div class="schema-container schema-container u-font-size-2 u-font-size-3-sm">
@@ -175,6 +182,8 @@ HTTP 200
175182
my_body: bytes decode "gb2312"
176183
```
177184

185+
`body` capture works _after_ content encoding decompression (so the captured value is not affected by `Content-Encoding` response header).
186+
178187
### Bytes capture
179188

180189
Capture the entire body (as a raw bytestream) from the received HTTP response
@@ -186,6 +195,9 @@ HTTP 200
186195
my_data: bytes
187196
```
188197

198+
Like `body` capture, `bytes` capture works _after_ content encoding decompression (so the captured value is not
199+
affected by `Content-Encoding` response header).
200+
189201
### XPath capture
190202

191203
Capture a [XPath] query from the received HTTP body decoded as a string.

sites/hurl.dev/_docs/hurl-file.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ In the following example:
5353

5454
```hurl
5555
GET https://example.org/api
56-
x-token: BEEF \#STEACK # Some comment
56+
x-token: BEEF \#STEAK # Some comment
5757
HTTP 200
5858
```
5959

60-
We're sending a header `x-token` with value `BEEF #STEACK`
60+
We're sending a header `x-token` with value `BEEF #STEAK`
6161

sites/hurl.dev/_docs/installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,4 @@ Please follow the [contrib on Windows section].
214214
[NixOS / Nix package]: https://search.nixos.org/packages?from=0&size=1&sort=relevance&type=packages&query=hurl
215215
[`conda-forge`]: https://conda-forge.org
216216
[`pixi`]: https://prefix.dev
217-
[extra]: https://archlinux.org/packages/extra/x86 _64/hurl/
217+
[extra]: https://archlinux.org/packages/extra/x86_64/hurl/

sites/hurl.dev/_docs/running-tests.md

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,17 @@ Failed files: 1 (50.0%)
6464
Duration: 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+
6770
In 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
7578
in parallel:
7679
7780
```shell
@@ -204,6 +207,90 @@ Failed files: 0 (0.0%)
204207
Duration: 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
258345
You 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

sites/hurl.dev/_docs/tutorial/your-first-hurl-file.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ section: Tutorial
88
# Your First Hurl File
99

1010
Throughout this tutorial, we'll walk through the creation of multiple
11-
Hurl files to test a basic web application about movies called _Movies Box_. We'll show how to test
12-
this site locally, and how to automate these integration tests in a CI/CD
13-
chain like [GitHub Action] and [GitLab CI/CD].
11+
Hurl files to test a basic web application about movies called _Movies Box_. The source code of the project is at
12+
<https://github.com/jcamiel/hurl-express-tutorial>. We'll show how to test this site locally, and how to automate these
13+
integration tests in a CI/CD chain like [GitHub Action] and [GitLab CI/CD].
1414

1515
Our Movies Box website consists of:
1616

0 commit comments

Comments
 (0)