Nested Orchestration Suites
A suite file can reference other .suite.toml files in its requests array. Rumour recursively expands nested suites, merging their nodes and variables into the parent workflow. This lets you build large, composable regression pipelines from smaller, independently maintainable sub-suites.
How It Works
When Rumour encounters a .suite.toml path in a requests array, it:
- Parses the nested suite file.
- Merges the nested suite's
[variables]into the parent's variable scope. - Recursively expands the nested suite's
requests(including any further nesting). - Deduplicates nodes — if the same request file appears in multiple nested suites, it is only added once.
- Appends the expanded nodes to the parent's ordered sequence.
This happens at graph-build time, before any requests are executed.
Example Structure
regression/
├── workspace.env.toml
├── full_regression.suite.toml ← parent suite
├── auth/
│ ├── auth.suite.toml ← nested suite 1
│ └── get_user.toml
└── posts/
├── posts.suite.toml ← nested suite 2
└── get_post.toml
# full_regression.suite.toml
[suite]
name = "Full Regression"
ordered = true
requests = [
"auth/auth.suite.toml", # expanded first
"posts/posts.suite.toml", # expanded second
]
[variables]
test_run = "regression"
# auth/auth.suite.toml
[suite]
name = "Auth Suite"
ordered = true
requests = [
"get_user.toml",
]
[variables]
auth_scope = "read"
# posts/posts.suite.toml
[suite]
name = "Posts Suite"
ordered = true
requests = [
"get_post.toml",
]
[variables]
posts_scope = "read"
When full_regression.suite.toml is run, the effective execution order is:
auth/get_user.toml → posts/get_post.toml
Variables from all levels are merged:
| Variable | Source |
|---|---|
base_url | workspace.env.toml |
test_run | full_regression.suite.toml |
auth_scope | auth/auth.suite.toml |
posts_scope | posts/posts.suite.toml |
Variable Merge Order
Nested suite variables are merged in the order the nested suites are expanded — later suites override earlier ones for the same key.
# parent.suite.toml
[suite]
requests = [
"suite_a.suite.toml", # sets timeout = "10"
"suite_b.suite.toml", # sets timeout = "30" → wins
]
The parent's own [variables] are merged before any nested suites expand, so nested suites can override parent variables.
Deduplication
If the same request file is referenced multiple times—either directly within a parent suite or transitively through nested suites—Rumour automatically deduplicates the requests based on their canonical paths. Only the first encountered instance of the request is added to the execution workflow.
For example, given a suite referencing both a setup request and a nested suite that also relies on that setup:
# parent.suite.toml
requests = [
"shared/setup.toml", # Added and scheduled first
"auth/auth.suite.toml", # Transitively includes shared/setup.toml -> Skipped (already included)
]
This prevents redundant calls (such as re-authenticating or re-initializing test state) and keeps suite runs efficient.
Example
To verify the deduplication logic, we run a test suite containing three duplicate declarations of the same request:
1. Suite Setup (dedup.suite.toml)
[suite]
name = "Deduplication Test"
ordered = true
requests = [
"auth/get_user.toml", # Direct inclusion (First encounter)
"auth/auth.suite.toml", # Nested suite (Contains get_user.toml - Duplicate)
"auth/get_user.toml", # Direct inclusion (Duplicate)
]
2. Execution Run
We run this suite using the following command:
rumour run ./suite_examples/03_nested_suites/dedup.suite.toml -v
3. Captured Output
The execution report shows that only 1 request is executed, proving that duplicates are successfully deduplicated:
~/workspace/testing main ❯ rumour run ./suite_examples/03_nested_suites/dedup.suite.toml -v
GET http://localhost:4000/api/v2/users/1
URL: http://localhost:4000/api/v2/users/1
✓ SUCCESS: /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/auth/get_user.toml (0ms)
✓ /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/dedup.suite.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: 2ms │
╰──────────────────────────────────────────────────────────────────────────╯
✓ Successful Requests:
- /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/auth/get_user.toml [200] [1ms]
Actionable Recommendations:
→ Run with --json to export this report for your CI/CD pipeline.
Both the second inclusion (from the nested suite auth.suite.toml) and the third direct inclusion are skipped automatically.
Why Duplication is Prevented
Allowing duplicate requests to execute multiple times within the same workflow would introduce several severe execution and logic conflicts:
1. Unexpected Server Side-Effects & Assertion Failures
Many API requests modify server state. Executing them multiple times can break expectations:
- Creation Requests (
POST): Submitting the same resource creation request multiple times might violate database constraints (e.g., duplicate email addresses) or result in unwanted duplicate records. - Deletion Requests (
DELETE): The first execution deletes the resource successfully, but subsequent duplicate executions will fail with a404 Not Foundresponse. Since assertions check for success status codes, this would cause the entire workflow run to fail.
2. Variable Pollution & Race Conditions
Rumour stores extracted response variables in a shared session namespace:
- If a request like
auth/get_user.tomlextractsuser_idand executes twice, the second run will overwrite the value from the first run. - Any downstream requests relying on
{{user_id}}will consume inconsistent values depending on when they are executed, resulting in non-deterministic and flaky tests.
3. Performance Overhead
Re-running heavy setup files (such as database seeding or multi-factor authentication flows) repeatedly during a single test suite run wastes network bandwidth, server capacity, and execution time.
How to Run a Request Multiple Times
Depending on your use case, there are different ways to execute request configurations multiple times:
-
For Sequenced Verification (Within a single workflow): Since Rumour's deduplication is based on canonical file paths, if you want to run the same request multiple times in different parts of a suite (e.g., verifying a resource's state before and after an update), create separate copies of the request file with different names (e.g.,
get_profile_initial.tomlandget_profile_final.toml). Because they reside at different paths, they are treated as distinct nodes and executed in sequence.# parent.suite.tomlrequests = ["get_profile_initial.toml","update_profile.toml","get_profile_final.toml",]rumour run ./parent.suite.toml -
For Repeated Execution (Benchmarking): Use the
benchcommand to run a request or entire workflow multiple times in parallel and collect latency statistics (RPS, avg, min, max, p50, p90, p99):# Run get_user.toml 200 times with up to 20 concurrent requestsrumour bench ./auth/get_user.toml -n 200 -c 20Flag Default Description -n, --iterations100Total number of times to run the request -c, --concurrency10Max number of concurrent requests -e, --env-file— Custom environment file -V, --variable— Override variables (key=value) benchalso works on a workflow directory (runs the full workflow for each iteration):rumour bench ./auth/ -n 50 -
For Iterative Run (Data-Driven Testing): Use the
--dataflag to run a request or workflow once per row in a CSV or JSON file. Each row's columns become runtime variables available to all requests in that iteration:CSV format (
users.csv):user_id,username1,alice2,bob3,carolJSON format (
users.json):[{ "user_id": "1", "username": "alice" },{ "user_id": "2", "username": "bob" }]# Runs the full workflow 3 times — once per row in users.csvrumour run ./auth/get_user.toml --data ./users.csvInside your request file, consume the row columns as variables:
[request]method = "GET"url = "{{base_url}}/users/{{user_id}}"
Example of Nested Suite
Verified against the local mock server.
File Layout
suite_examples/03_nested_suites/
├── workspace.env.toml
├── full_regression.suite.toml
├── auth/
│ ├── auth.suite.toml
│ └── get_user.toml
└── posts/
├── posts.suite.toml
└── get_post.toml
full_regression.suite.toml
[suite]
name = "Full Regression"
description = "Nested: auth + posts suites in sequence"
ordered = true
requests = [
"auth/auth.suite.toml",
"posts/posts.suite.toml",
]
[variables]
test_run = "regression"
auth/auth.suite.toml
[suite]
name = "Auth Suite"
ordered = true
requests = [
"get_user.toml",
]
[variables]
auth_scope = "read"
posts/posts.suite.toml
[suite]
name = "Posts Suite"
ordered = true
requests = [
"get_post.toml",
]
[variables]
posts_scope = "read"
auth/get_user.toml
name = "auth_get_user"
[request]
method = "GET"
url = "{{base_url}}/users/1"
[assert]
status = 200
[extract]
user_id = "id"
posts/get_post.toml
name = "posts_get_post"
[request]
method = "GET"
url = "{{base_url}}/users/2"
[assert]
status = 200
[assert.json."id"]
equal = 2
Run
rumour run ./suite_examples/03_nested_suites/full_regression.suite.toml -v
Output
~/workspace/testing main ❯ rumour run ./suite_examples/03_nested_suites/full_regression.suite.toml -v
GET http://localhost:4000/api/v2/users/1
URL: http://localhost:4000/api/v2/users/1
✓ SUCCESS: /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/auth/get_user.toml (0ms)
GET http://localhost:4000/api/v2/users/2
URL: http://localhost:4000/api/v2/users/2
✓ SUCCESS: /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/posts/get_post.toml (0ms)
✓ /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/full_regression.suite.toml → PASS (2 Pass, 0 Fail, 0 Skip)
╭──────────────────────────────────────────────────────────────────────────╮
│ RUMOUR EXECUTION REPORT │
├──────────────────────────────────────────────────────────────────────────┤
│ Total Requests: 2 │
│ Successful: 2 │
│ Failed: 0 │
│ Skipped: 0 │
│ Success Rate: 100.0% │
│ Total Time: 3ms │
╰──────────────────────────────────────────────────────────────────────────╯
✓ Successful Requests:
- /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/auth/get_user.toml [200] [1ms]
- /home/bugsfounder/workspace/testing/suite_examples/03_nested_suites/posts/get_post.toml [200] [1ms]
Actionable Recommendations:
→ Run with --json to export this report for your CI/CD pipeline.
Both nested suites are expanded in order — auth first, posts second. Variables from all three suite files (test_run, auth_scope, posts_scope) are merged and made available to the requests.
Nesting Depth
There is no hard limit on nesting depth. Rumour recursively expands nested suites to support arbitrarily deep suite structures. However, circular references (e.g., Suite A referencing Suite B, which in turn references Suite A) are not supported and should be avoided.