Load Test Pipeline Synthetic Campaign Runner
File: client_backend/src/tests/load-test-pipeline.ts
Why
Integration tests prove correctness. Load tests prove your system handles real-world throughput. This script creates a synthetic campaign with N contacts and simulates the full webhook pipeline for each one at configurable concurrency no real SIP calls, no real phone numbers.
Use this to answer questions like:
- Can the backend handle 500 concurrent webhook pipelines without data corruption?
- How many contacts/second can we process?
- Do credits add up correctly across hundreds of calls?
- Are there any stuck contacts after a high-throughput run?
How To Run
bash
cd client_backend
# Quick smoke test (50 contacts, 10 concurrent)
npx tsx src/tests/load-test-pipeline.ts --contacts 50 --concurrency 10
# Realistic load (500 contacts, 50 concurrent)
npx tsx src/tests/load-test-pipeline.ts --contacts 500 --concurrency 50
# Heavy load with verbose output
npx tsx src/tests/load-test-pipeline.ts --contacts 1000 --concurrency 100 --verbose
# Keep test data for inspection (skip auto-cleanup)
npx tsx src/tests/load-test-pipeline.ts --contacts 100 --concurrency 20 --skip-cleanupOptions
| Flag | Default | Description |
|---|---|---|
--contacts N | 100 | Total contacts to simulate |
--concurrency N | 20 | Max parallel webhook pipelines |
--verbose | off | Extra logging per contact |
--skip-cleanup | off | Don't delete test data after run |
What It Does
- Creates a test Organization, Customer, Campaign, and ServicePricing
- Bulk-inserts N Contact documents
- For each contact, simulates the full webhook pipeline based on a realistic outcome distribution:
- 60% answered (full pipeline: join → record → leave → billing → transcription → analysis)
- 15% rejected
- 15% not picked
- 5% media failure
- 5% timeout
- Prints throughput metrics, outcome breakdown, billing totals, and data integrity checks
- Cleans up all test data (unless
--skip-cleanup)
Reading The Output
--- Throughput ---
Total time: 8.6s
Contacts processed: 50/50 ← should equal total contacts
Throughput: 5.8 contacts/sec
Avg processing time: 1570ms per contact
--- Outcomes ---
answered 28 (56.0%) ← should be ~60% of total
notPicked 9 (18.0%)
rejected 5 (10.0%)
...
--- Data Integrity Check ---
Done: 28 ← should match answered count
Failed: 22 ← should match non-answered count
Stuck: 0 ← MUST be 0
With billing: 28 ← should match done count
--- VERDICT ---
ALL CHECKS PASSED ← what you want to seeRed flags:
Stuck > 0contacts didn't complete the pipelineStatus mismatchdone + failed doesn't equal totalBilling mismatchsome answered calls weren't billedProcessing errorsexceptions during simulation
Database
The load test runs against config.dbName (the main database, e.g., Oktivo-Dev), NOT a _test suffix database. It cleans up after itself unless --skip-cleanup is used.
If you use --skip-cleanup, you can validate the campaign data with:
bash
npx tsx src/scripts/validate-campaign.ts <campaignUID>The campaign UID is printed at the end of the load test output.
Known Issues
- ServicePricing legacy indexes: The collection may have legacy unique indexes using old field names (
serviceType,organizationId,customerId). If you encounterE11000 duplicate key error, runPOST /internal/scripts/fix-service-pricing-indexesto drop legacy indexes and clean up invalid records. See SERVICE-PRICING.md for details. - Mongoose disconnect can be slow on Windows the script may appear to hang for a few seconds after printing results. The test itself has already completed.