Skip to main content
VoiceGateway does not place calls, and loadtest does not either. An external SIP load generator drives the load: this reads what it left on disk, correlates it against scraped fleet metrics, and writes a report. VoiceGateway vendors no such generator. See What you can profile for how this fits the rest of the stack.

Synopsis

import

voicegw loadtest import DIRECTORY reads one test’s artifacts. A directory of subdirectories imports one test per subdirectory, sorted lexicographically by name, not numerically. Pad step numbers to equal width (ramp-0250, not ramp-250): unpadded, ramp-1000 sorts before ramp-250. Re-importing the same directory updates that run (id defaults to the directory name) rather than creating a second one. What the directory must hold. Either surface below is enough alone; both absent, nothing imports:
  • summary.json, schema gossipper_summary_v1: run totals.
  • A stat CSV, found by header (not name or extension), carrying elapsed_ms, total_calls, success_calls, failed_calls, active_calls.
calls.jsonl (schema gossipper_call_record_v1) is optional: per-call media, read only to count calls that answered, sent RTP, and got none back. Flags

Provenance defaults to synthetic

An import is recorded synthetic unless --captured is passed. The checksum is computed either way, but only --captured promotes it to artifact_sha256, the column a report reads to decide whether it may call itself measured. Without it, every report built from the run stamps data_provenance: synthetic, with SYNTHETIC DATA: NOT A DELIVERABLE as the first visible element of the HTML. No flag overrides this: a forgotten --captured under-claims; it never lets a report pass fixture numbers off as measured.

--plan and --network-baseline are declarations, not measurements

Neither is recorded by any artifact. Both are the operator writing down what nothing on the wire can measure. --plan: test name to declared target concurrency, powering the capacity table across a multi-step ramp.
The peak a step actually reached still comes from the artifacts, never overwritten by the plan; a declared target the run did not reach produces a plateau finding, not a capacity figure. A step under five minutes measures call-setup CPU, not held concurrency, and does not count toward the figure. An unmatched test name is refused. --network-baseline: node name to its published bandwidth floor, both directions required, because the AWS ENA driver publishes no link speed.
It is the only source for the bandwidth-headroom gate’s denominator. A node with no entry reports UNKNOWN, never a percentage of a guess. It is a floor, not a ceiling: an instance bursts above it, so utilisation computed against it reads high, the safe direction for a headroom check. Both files ignore top-level keys starting with _, so a declaration can carry its own provenance and the copy in your repo can be the copy that runs:
Import warns about nodes you did not declare. When the scrape shows a node carrying throughput and no baseline was declared for it, the import names it:
Import is the only point where the declared names and the scraped names are both in hand, so it is the only place a tier that scaled since the file was written can be caught. Fix it by adding the node and re-importing the same artifacts: nothing was missing from the scrape, so re-capturing the run cannot help.

runs

voicegw loadtest runs lists imported runs, newest first, with each row’s provenance read off whether artifact_sha256 is set. Flags: --config, -c; --project, -p to filter; --limit, -n for how many (default 20).

report

voicegw loadtest report RUN_ID writes one run’s profile as JSON plus a self-contained HTML file. RUN_ID is a required positional argument.

Exit code

--acceptance exits 0 only on a clean PASS. WAIVED, WARN, UNKNOWN, and FAIL all exit 1. WAIVED is not clean: a gate nobody held the run to should not turn a pipeline green. UNKNOWN is not clean either: the run failed to measure something, not the same as demonstrating it passed. Without --acceptance, report never exits non-zero; a profile makes no claim to judge.

Node correlation

Peak CPU and memory come from node_samples, correlated to a test’s window by time overlap, never call attribution. That table is filled by a background scrape that runs only inside a long-lived voicegw serve process with VOICEGW_NODE_SCRAPE_TARGETS (or _FILE) configured. loadtest never scrapes on its own; it reads only what a running serve already collected. See Node metrics for configuring the scrape.