Simulate a bad network in CI
The window is optional. The same executable runs as a command-line tool, ends by itself after a set time, and reports what happened in a way a pipeline can read.
The shape of a step
Impair for the length of the test, then let it stop on its own. No cleanup step to forget:
BeanNetworkTester.exe --loss 10 --latency 200 --target myapp.exe --duration 60
In a GitHub Actions job, on a self-hosted Windows runner:
- name: Test the app on a poor connection
shell: pwsh
run: |
Start-Process -FilePath BeanNetworkTester.exe `
-ArgumentList '--loss 10 --latency 200 --target myapp.exe --duration 90'
npm test
Two things about the runner: capturing traffic needs administrator rights, and a hosted runner will not give you those, so this belongs on a self-hosted Windows machine.
Every ending has an exit code
Nothing ends with a traceback. Each way a run can finish has a number, so a pipeline can tell "your app failed" from "the tool could not start":
| Code | What it means |
|---|---|
| 0 | Finished as asked. |
| 1 | Something failed while running. |
| 2 | The command line was wrong. |
| 3 | A setting or a value was invalid. |
| 4 | A scenario file was rejected. |
| 5 | A file could not be read or written. |
| 6 | An assertion about the run did not hold. |
| 7 | No administrator rights, so the driver cannot load. |
| 130 | Interrupted, usually by Ctrl+C. |
| 143 | Terminated from outside. |
Machine-readable output
--format json writes one JSON object per line - samples while the run goes, a
summary at the end - so a later step can assert on it:
BeanNetworkTester.exe --loss 5 --duration 30 --format json > run.ndjson
Log lines go to standard error and data to standard output, so redirecting the data never mixes
the two. --seed makes the run repeatable, which is what a flaky test needs before
anybody can argue about it.
A dry run that touches nothing
Two flags make this safe to wire up before you trust it: --dry-run reports what
the settings would do and exits, and --simulate runs the whole engine against
synthetic traffic, without loading the driver and without touching the network. Both are useful in
a build that must not impair the machine it runs on.