Skip to main content

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:

  1. Parses the nested suite file.
  2. Merges the nested suite's [variables] into the parent's variable scope.
  3. Recursively expands the nested suite's requests (including any further nesting).
  4. Deduplicates nodes — if the same request file appears in multiple nested suites, it is only added once.
  5. 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:

VariableSource
base_urlworkspace.env.toml
test_runfull_regression.suite.toml
auth_scopeauth/auth.suite.toml
posts_scopeposts/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 a 404 Not Found response. 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.toml extracts user_id and 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.

tip

How to Run a Request Multiple Times

Depending on your use case, there are different ways to execute request configurations multiple times:

  1. 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.toml and get_profile_final.toml). Because they reside at different paths, they are treated as distinct nodes and executed in sequence.

    # parent.suite.toml
    requests = [
    "get_profile_initial.toml",
    "update_profile.toml",
    "get_profile_final.toml",
    ]
    rumour run ./parent.suite.toml
  2. For Repeated Execution (Benchmarking): Use the bench command 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 requests
    rumour bench ./auth/get_user.toml -n 200 -c 20
    FlagDefaultDescription
    -n, --iterations100Total number of times to run the request
    -c, --concurrency10Max number of concurrent requests
    -e, --env-fileCustom environment file
    -V, --variableOverride variables (key=value)

    bench also works on a workflow directory (runs the full workflow for each iteration):

    rumour bench ./auth/ -n 50
  3. For Iterative Run (Data-Driven Testing): Use the --data flag 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,username
    1,alice
    2,bob
    3,carol

    JSON format (users.json):

    [
    { "user_id": "1", "username": "alice" },
    { "user_id": "2", "username": "bob" }
    ]
    # Runs the full workflow 3 times — once per row in users.csv
    rumour run ./auth/get_user.toml --data ./users.csv

    Inside 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.