Skip to main content

Response Header Assertions

The [assert.headers] block allows you to validate metadata returned in response headers, ensuring correct caching, content typing, security configurations, and custom application metadata.

1. Syntax & Configuration

Rumour supports two equivalent TOML syntaxes for declaring response header assertions:

Define a separate subtable for each target header:

[request]
method = "GET"
url = "{{base_url}}/response-headers?X-Custom-Header=HelloHeader"

[assert.headers."X-Custom-Header"]
equal = "HelloHeader"
contains = "loHea"

[assert.headers."content-type"]
contains = "application/json"

Option B: Inline Table Syntax (Sleeker for single-constraint assertions)

Group all header assertions under a single [assert.headers] block using inline TOML tables:

[request]
method = "GET"
url = "{{base_url}}/response-headers?X-Custom-Header=HelloHeader"

[assert.headers]
"X-Custom-Header" = { equal = "HelloHeader", contains = "loHea" }
"content-type" = { contains = "application/json" }

2. Operators Reference

Header assertions support the following evaluation operators:

OperatorTypeDescription
equalStringAsserts that the header value is exactly equal to the specified string.
not_equalStringAsserts that the header value does not match the specified string.
containsStringAsserts that the header value contains the specified substring.
existsBooleanChecks if the header is present (true) or absent (false) in the response.
regexStringAsserts that the header value matches the specified regular expression.

⚠️ Numeric Headers Gotcha (greater_than / less_than)

All header values are processed internally as string values. Therefore, numeric comparison operators like greater_than and less_than are not supported for header assertions (they will always fail to parse as float values and evaluate to false).

To validate numerical constraints (e.g., checking if Content-Length is within limits), use the regex operator:

# Assert that Content-Length is between 100 and 999 bytes
[assert.headers."content-length"]
regex = "^[1-9][0-9]{2}$"

3. Case Sensitivity

In accordance with the HTTP/1.1 and HTTP/2 specifications, header name lookups in Rumour are case-insensitive. Declaring [assert.headers."Content-Type"] or [assert.headers."content-type"] will target the exact same header node.

4. Header Assertion Example (httpbin.org)

A. Dotted Subtable Syntax Example

# test_operators.toml
[request]
method = "GET"
url = "{{base_url}}/response-headers?X-Custom-Header=HelloHeader"

[headers]
User-Agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

[assert.headers."X-Custom-Header"]
equal = "HelloHeader"
not_equal = "WrongValue"
contains = "loHea"
regex = "^Hello.*$"
exists = true

[assert.headers."content-type"]
contains = "application/json"

[assert.headers."x-non-existent"]
exists = false

Successful Execution Output Trace

rumour run header_assert_example/users/requests/test_operators.toml -tv
~/workspace/rumour suiteImplementation 8s ❯ rumour run /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators.toml -tv
GET https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
Header: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
URL: https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
✓ SUCCESS: /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators.toml (1391ms)
✓ /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators.toml → PASS (1 Pass, 0 Fail, 0 Skip)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 1
│ Successful: 1
│ Failed: 0
│ Skipped: 0
│ Success Rate: 100.0% │
│ Total Time: 1394ms │
╰──────────────────────────────────────────────────────────────────────────╯

✓ Successful Requests:
- /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators.toml [200] [1394ms]

Actionable Recommendations:
→ Run with --json to export this report for your CI/CD pipeline.

Let's break down what just happened:

  1. The Live Action: Rumour checked all the response headers against our rules. It verified X-Custom-Header existed and contained the right text, confirmed content-type was correct, and made sure x-non-existent wasn't sneaking in there. Since everything matched perfectly, we get a green ✓ SUCCESS!
  2. The Final Report: The summary logs the entire request, giving you the confidence that your server is returning the exact metadata your application expects.

B. Inline Table Syntax Example

# test_operators_inline.toml
[request]
method = "GET"
url = "{{base_url}}/response-headers?X-Custom-Header=HelloHeader"

[headers]
User-Agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

[assert.headers]
"X-Custom-Header" = { equal = "HelloHeader", not_equal = "WrongValue", contains = "loHea", regex = "^Hello.*$", exists = true }
"content-type" = { contains = "application/json" }
"x-non-existent" = { exists = false }

Successful Execution Output Trace

rumour run header_assert_example/users/requests/test_operators_inline.toml -tv
~/workspace/rumour suiteImplementation ❯ rumour run /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators_inline.toml -tv
GET https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
Header: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
URL: https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
✓ SUCCESS: /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators_inline.toml (5005ms)
✓ /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators_inline.toml → PASS (1 Pass, 0 Fail, 0 Skip)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 1
│ Successful: 1
│ Failed: 0
│ Skipped: 0
│ Success Rate: 100.0% │
│ Total Time: 5008ms │
╰──────────────────────────────────────────────────────────────────────────╯

✓ Successful Requests:
- /home/bugsfounder/workspace/testing/header_assert_example/users/requests/test_operators_inline.toml [200] [5007ms]

Actionable Recommendations:
→ Run with --json to export this report for your CI/CD pipeline.

Let's break down what just happened:

Just like the dotted syntax example above, Rumour completely evaluated the inline assertions and generated an identical success report. The inline syntax is simply a cleaner way to write your .toml files—under the hood, Rumour handles them exactly the same way!

5. Failing Header Assertions & Diagnostics

If one or more header assertions fail, Rumour reports the specific failure details:

Failing Example TOML

[request]
method = "GET"
url = "{{base_url}}/response-headers?X-Custom-Header=HelloHeader"

[headers]
User-Agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"

[assert.headers."X-Custom-Header"]
equal = "WrongValue"

[assert.headers."X-Required-Header"]
exists = true

Diagnostics output:

~/workspace/testing main* ❯ rumour run /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml -tv
GET https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
Header: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
URL: https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
✗ FAILED: /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml (4366ms) - Header: X-Custom-Header: Expected String("WrongValue"), got String("HelloHeader") | Header: X-Required-Header: Existence check: expected true, got false
↻ RETRYING: /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml (Attempt 1/2) [Wait 500ms]
GET https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
Header: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
URL: https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
✗ FAILED: /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml (3436ms) - Header: X-Custom-Header: Expected String("WrongValue"), got String("HelloHeader") | Header: X-Required-Header: Existence check: expected true, got false
↻ RETRYING: /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml (Attempt 2/2) [Wait 1000ms]
GET https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
Header: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
URL: https://httpbin.org/response-headers?X-Custom-Header=HelloHeader
✗ FAILED: /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml (1373ms) - Header: X-Custom-Header: Expected String("WrongValue"), got String("HelloHeader") | Header: X-Required-Header: Existence check: expected true, got false
✗ /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml → FAIL (0 Pass, 1 Fail, 0 Skip)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 1
│ Successful: 0
│ Failed: 1
│ Skipped: 0
│ Success Rate: 0.0% │
│ Total Time: 10688ms │
╰──────────────────────────────────────────────────────────────────────────╯

✗ Failed Requests:
- /home/bugsfounder/workspace/testing/header_assert_example/users/requests/failing_example.toml: [200]
Reason: Header: X-Custom-Header: Expected String("WrongValue"), got String("HelloHeader") | Header: X-Required-Header: Existence check: expected true, got false
Message: {
"Content-Length": "106",
"Content-Type": "application/json",
"X-Custom-Header": "HelloHeader"
}


Actionable Recommendations:
→ Run with -H (Self-Healing) to attempt automatic recovery of failing nodes.

Let's break down what just happened:

When an assertion fails, Rumour's execution engine provides an immense amount of context to help you debug the problem immediately!

  1. The Big Picture Mismatch: Notice how the Reason: field reports both failures at once, separated by a pipe (|). Rumour checks all your rules, rather than quitting on the very first mistake, so you get a complete picture of everything that's broken.
  2. No Guessing Games: For X-Custom-Header, it explicitly states: Expected String("WrongValue"), got String("HelloHeader"). It doesn't just say "failed"; it tells you exactly what the server actually sent back.
  3. The Built-in Retries: Because the request failed, Rumour automatically triggered its built-in retry mechanism (↻ RETRYING), waiting 500ms, then 1000ms, to make sure it wasn't just a random network hiccup before officially failing the test.
  4. The Helpful Payload Dump: Under the Message: field in the final report, Rumour thoughtfully dumps the actual JSON of the headers it received from the server. This lets you visually inspect the payload and confirm for yourself that X-Required-Header was indeed missing!