Hi all. I’d like to introduce xk6-sip, an open-source k6 extension for testing SIP/VoIP systems: PBXs, softswitches, contact center platforms.
What it is
SIP subscribers are objects in the k6 script. They register on the PBX under test, call each other through it and check what the other side gets. One VU drives both ends of a call, so the same script runs as a one-iteration functional test or as a load test with thousands of concurrent calls:
const out = A.call({ callee: B });
const inc = B.expectCall({ caller: A, timeout: '10s' });
inc.accept();
check(out, { 'connected': (c) => c.expectConnected('5s') });
check(inc, { 'B hears A': (c) => c.isHeard('3s') });
Monitoring
This is the part I put the most work into, and why I’m posting here.
Telephony metrics as regular k6 metrics, so thresholds and every k6 output work with them:
- call outcome: sip_call_success, sip_call_results by final status, sip_calls answered/ended
- timings: sip_call_setup_time, sip_post_dial_delay, sip_invite_first_response_time
- protocol health: sip_retransmissions by method and kind, an early overload signal that shows up before calls start failing
- media: rtp_jitter, packet loss per RFC 3550, rtp_audio_heard (one-way audio rate), rtp_audio_score (voice quality)
A ready Prometheus + Grafana stack in Docker Compose (monitoring/ in the repo) with a 39-panel dashboard:
-
telecom KPIs as tiles: ASR, SEER, ALOC, share of calls within SLA, calls in progress, CAPS
-
percentiles of setup time and post-dial delay from native histograms (K6_FEATURES=native-histograms)
-
SIP responses by status, retransmissions, one-way audio share, jitter, loss, audio quality score
-
a “generator health” block: the k6 process serves its own CPU, memory, goroutines and SIP/RTP socket traffic on a /metrics endpoint, so you can tell a saturated load generator from a slow PBX
-
testid and pbx_version variables to find a run and compare PBX versions on one graph
In CI, a small script opens the dashboard in headless Chrome for the run’s time window and saves it as one tall PNG, so every build keeps a full picture of what happened.
Everything else, briefly
- Calls: digest auth, CANCEL, reject with any status, caller ID checks (incl. P-Asserted-Identity)
- Hold/resume via re-INVITE, blind and attended transfer (REFER, Replaces), PRACK, session timers
- Media: G.711 PCMU/PCMA RTP, DTMF (RFC 4733), audio playback from WAV
- Voice quality: call recording to stereo WAV and compareAudio() against a reference
- Functional tests: step-by-step checks, JUnit via handleSummary, call.trace() prints the SIP ladder of a failed call
- A bundled test PBX (registrar + B2BUA) to try it on a laptop or in CI
- Performance: ~1,000 concurrent calls with RTP on 62% of one core and 222 MB, ~21 KB per subscriber
Repo (Apache-2.0): GitHub - Dmitry-Fedotov-Dev/xk6-sip: k6 extension for SIP/VoIP load and functional testing: scripted subscribers call each other through the PBX, with RTP, one-way audio detection, voice quality scoring and call recording · GitHub
Docs: xk6-sip/docs/sources/k6/next/javascript-api/k6-x-sip at main · Dmitry-Fedotov-Dev/xk6-sip · GitHub
It’s submitted to the k6 extension registry and under review. Feedback on the metric names and the dashboard layout is very welcome, and I’m curious whether anyone else here load-tests telephony with k6.
p.s. full dashboard screenshot:


