VirtuProbe Studio
Get the app
← All posts
Walkthrough 30 June 2026 7 min read

Chaining requests, across protocols.

Most real tests aren't one request. They're a sequence where each step depends on the last: log in, take the token, call the authenticated endpoint, check the result. VirtuProbe models that as a chain, and it doesn't much care whether the next step is HTTP, DNS, SMTP or LDAP. Here's exactly how a value gets from one step to the next.

The whole idea: extract → variable → resolve

A chain is an ordered list of steps. You attach an extractor to a step; it pulls a value out of that step's response into a named variable; and any later step references it as {{variable}}. That one loop is the entire mechanism, and everything else is convenience on top of it.

# Log in, keep the token, call an authenticated endpoint

01  HTTP  POST /login  {"user":"x","pass":"y"}
          extract  HTTP_JSON_PATH  $.token            → {{token}}
          assert   HTTP_STATUS     EQUALS 200

02  HTTP  GET /me   Authorization: Bearer {{token}}
          assert   HTTP_STATUS     EQUALS 200

Pulling the value out: extractors

Every protocol ships its own extractors, and two generic ones work on any response:

  • HTTP: HTTP_STATUS, HTTP_JSON_PATH, HTTP_HEADER, HTTP_BODY_RAW.
  • DNS: DNS_ANSWER_VALUE (and DNS_SUCCESS).
  • SMTP / IMAP / LDAP: a *_SUCCESS flag plus an exchange reader (SMTP_EXCHANGE_LINES, IMAP_EXCHANGE_LINES, LDAP_EXCHANGE_RESULT_CODE).
  • Generic: CONSTANT (a fixed value) and REGEX (the first capture group of a pattern over the raw response). REGEX is the escape hatch. It's how you lift a link out of an email body or an id out of plain text when there's no purpose-built extractor.

Injecting it back: {{variables}}

A resolved variable drops in anywhere in the following steps: a URL, a request body, a header, an LDAP DN or filter, a DNS name. One small piece of honesty the tool enforces for you: a single brace like {token} is almost always a typo, so VirtuProbe stops with a clear error rather than sending the literal text and letting you wonder why the request 401'd.

When it isn't a straight line: control flow

Steps aren't only protocol calls. A handful of control-flow steps handle the shapes real tests take:

  • ITERATE: run child steps once per item from an inline list or a file, with optional jitter between iterations and stop-on-first-success.
  • CONDITION: branch on a JavaScript or Groovy expression over your variables ({{status}} == '200').
  • ASSERT: gate the run with EQUALS, NOT_EQUALS, CONTAINS, NOT_CONTAINS, MATCHES, GT/LT/GTE/LTE.
  • PARALLEL: fan steps out, and each branch gets a snapshot of the variables, merged back last-writer-wins.
  • CHAIN_REF: call another chain with explicit input/output variable mapping.
  • PRINT: render a line into the run log for readability.

The part that's actually different: protocols mix freely

Because a step is just a step, you can cross protocols mid-chain, which is where this stops being a nicer HTTP runner and starts being the point. Resolve a domain's MX over DNS, hand the hostname to an SMTP step, deliver a message, and confirm it landed over IMAP, all in one runnable artefact. Or the signup case: register over HTTP, catch the mail over IMAP, bind the new account over LDAP.

What you keep afterwards

A run streams its progress back as it goes, so each step is marked running, passed or failed the moment it happens, and the last 20 runs are saved per chain. Compare two runs to see exactly which step's response changed, and export any run as JSON evidence with no re-run and no re-auth. A chain isn't just a test you ran; it's one you can hand to someone else and have them run identically.

Build your first chain. VirtuProbe Studio is free to download, with no account, no cloud and no telemetry. Chaining, environments and request history are all on the free tier.

Join our Discord