QA How-To
Toxiproxy vs Chaos Mesh Testing (2026)
Compare toxiproxy vs chaos mesh testing with runnable Docker and Kubernetes examples, fault scope, CI trade-offs, safety controls, and a clear 2026 verdict.
18 min read | 3,283 words
TL;DR
Toxiproxy is the better default for application-level integration tests because it is small, deterministic, and easy to control from a test process. Chaos Mesh is the stronger choice for Kubernetes-native resilience testing because it can select workloads and inject network, pod, stress, I/O, DNS, time, and other faults at cluster scope. Many teams should use both at different test layers rather than force one tool into every job.
Key Takeaways
- Choose Toxiproxy for deterministic dependency failures in local, integration, and CI tests where you can route traffic through a proxy.
- Choose Chaos Mesh for Kubernetes-native experiments that target pods, namespaces, percentages, or infrastructure components without changing application endpoints.
- Toxiproxy is a TCP proxy controlled through an HTTP API, while Chaos Mesh is a controller and daemon platform driven by Kubernetes custom resources.
- Compare equivalent latency, direction, target traffic, request count, and recovery behavior before judging either tool.
- Treat fault restoration as a test assertion, not an optional cleanup task.
- Use Toxiproxy for fast pull-request checks and Chaos Mesh for broader staging or preproduction resilience exercises when both layers matter.
- Keep selectors, proxy routes, timeouts, and blast-radius controls in version control so the experiment is reproducible and reviewable.
Toxiproxy vs chaos mesh testing comes down to where you need to inject failure. Use Toxiproxy when a test can redirect one dependency connection through a lightweight TCP proxy. Use Chaos Mesh when the system runs on Kubernetes and you need pod-aware selection, cluster-level orchestration, or faults beyond a single proxied connection.
The tools overlap on delay, connection disruption, packet loss, and bandwidth constraints, but their operating models are different. Toxiproxy changes a route in your test topology and exposes a small HTTP control API. Chaos Mesh installs controllers, custom resource definitions, a privileged daemon on each node, and optional dashboard components.
This guide applies the same 750 ms downstream-style delay to a disposable HTTP service with both tools. You will verify the fault, remove it, and prove recovery. For the broader discipline around hypotheses, steady-state signals, abort rules, and blast radius, start with the chaos testing guide.
Toxiproxy vs Chaos Mesh Testing: TL;DR
| Decision area | Toxiproxy | Chaos Mesh | Better fit |
|---|---|---|---|
| Primary environment | Processes, containers, local integration stacks, CI services | Kubernetes clusters | Depends on deployment target |
| Injection point | Explicit TCP proxy between client and dependency | Target pod network namespace or other selected infrastructure | Chaos Mesh for transparent cluster injection |
| Setup weight | One server container plus proxy definitions | Helm release, CRDs, controllers, daemon set, RBAC | Toxiproxy |
| Network faults | Latency, timeout, bandwidth, reset, slow close, data limit, slicing, packet loss | Delay, loss, duplicate, corruption, reorder, partition, bandwidth | Chaos Mesh for packet-level breadth |
| Non-network faults | None | Pod, stress, I/O, DNS, time, JVM, cloud, and other experiment types | Chaos Mesh |
| Target selection | Named proxy and upstream route | Namespace, labels, pod mode, percentage, node, and direction | Chaos Mesh |
| Test control | HTTP API or language client | Kubernetes YAML, API, workflow, or dashboard | Toxiproxy inside a unit or integration test |
| Application changes | Client endpoint must point at the proxy | Usually no application endpoint change | Chaos Mesh |
| Permissions | Container access and control-port access | Cluster install rights and privileged node daemon | Toxiproxy |
| Fast pull-request checks | Excellent | Possible, but cluster startup and installation add cost | Toxiproxy |
| Staging blast-radius exercises | Limited to routed connections | Strong selectors and multi-fault orchestration | Chaos Mesh |
| Recovery mechanism | Delete toxic, reset, or re-enable proxy | Delete, pause, or let a duration expire | Tie, if recovery is asserted |
The practical verdict is simple. Pick Toxiproxy when the test owns dependency configuration and needs a precise fault around one connection. Pick Chaos Mesh when Kubernetes topology is part of what you are validating. If an application has both rich integration tests and a production-like cluster stage, keep Toxiproxy low in the pyramid and Chaos Mesh near the top.
What You Will Build
You will create two equivalent experiments:
- An Nginx upstream behind Toxiproxy 2.12.0 in Docker Compose.
- A named proxy on port
8666, controlled through Toxiproxy's port8474. - A 750 ms response-path latency toxic, followed by explicit removal and recovery proof.
- An Nginx service plus a curl probe in a local kind cluster.
- A Chaos Mesh 2.8.3
NetworkChaosresource that delays probe traffic to the service by 750 ms. - A comparison record that separates fault accuracy, selection, setup, observability, and CI cost.
Both targets return the standard Nginx page. That response is intentionally plain: the exercise measures the injector and recovery path, not application business logic. In a real suite, replace the page check with a meaningful fallback, retry-budget, circuit-breaker, queueing, or error-contract assertion.
Prerequisites
The examples use a tested 2026-compatible stack: Docker Engine 28.x with Docker Compose 2.36 or newer, curl 8.x, jq 1.7 or newer, kind 0.29.0, kubectl 1.33 or newer, and Helm 3.18 or newer. The container and chart versions are pinned to Toxiproxy 2.12.0, Chaos Mesh 2.8.3, Nginx 1.28 Alpine, and curl 8.12.1.
Check the local commands before creating either environment:
docker version --format '{{.Server.Version}}'
docker compose version
curl --version | head -n 1
jq --version
kind version
kubectl version --client
helm version --short
Expect every command to print a version and exit with status zero. You can complete only the Toxiproxy half with Docker, curl, and jq. The Chaos Mesh half also needs enough local container resources for a kind control-plane node and the Chaos Mesh components.
Use a disposable cluster for this tutorial. Chaos Mesh's daemon needs privileged access to node networking, so do not install it into a shared cluster without platform-team review. If you need a repeatable disposable environment strategy, read the ephemeral test environments guide.
Step 1: Define the Failure Hypothesis and Measurement
Write the experiment statement before choosing syntax: when the catalog dependency adds 750 ms to the response path, the client must still receive HTTP 200 within a two-second budget; after the fault is removed, measured latency must return close to the local baseline. This gives both injectors the same pass condition.
Record at least three baseline requests and three faulted requests. A single request can be distorted by image warm-up, DNS resolution, connection establishment, or host scheduling. Do not compare the exact third decimal place between Docker and Kubernetes. The two network paths have different overhead. Compare whether each injector creates the intended order-of-magnitude change and whether the application behavior remains acceptable.
The direction also matters. Toxiproxy calls server-to-client traffic downstream; Chaos Mesh applies a delay to packets selected from a pod and can narrow the peer with direction plus target. In this tutorial the probe pod is selected and traffic going to the Nginx pods is delayed. HTTP requests and responses share that network path, so the total observed request time should increase by roughly the configured delay.
Verify the test contract on paper before continuing:
Steady state: HTTP 200 from the catalog endpoint
Fault: 750 ms network delay, zero jitter
Tolerance: total request time below 2 seconds
Sample: 3 baseline requests and 3 faulted requests
Recovery: HTTP 200 and latency near the baseline after cleanup
Abort: stop if the fault affects any target outside the disposable lab
The verification result for this step is a reviewable contract with a numeric fault, a user-visible expectation, a bounded target, and a recovery condition. Without those fields, tool output can look successful while the resilience requirement remains undefined.
Step 2: Start the Toxiproxy Docker Compose Lab
Save the following as compose.yaml in an empty directory. The upstream is reachable only inside the Compose network. Clients on the host reach it through Toxiproxy's published port, which prevents an accidental direct-path test.
services:
upstream:
image: nginx:1.28-alpine
toxiproxy:
image: ghcr.io/shopify/toxiproxy:2.12.0
ports:
- '8474:8474'
- '8666:8666'
depends_on:
- upstream
Start both containers and wait for the control API:
docker compose up -d
until curl -fsS http://localhost:8474/version; do sleep 1; done
The version endpoint should print 2.12.0. Create a named proxy whose listener is reachable on every interface inside the Toxiproxy container and whose upstream uses the Compose service name:
curl -fsS -X POST http://localhost:8474/proxies \
-H 'Content-Type: application/json' \
-d '{"name":"catalog_api","listen":"0.0.0.0:8666","upstream":"upstream:80","enabled":true}' | jq .
Toxiproxy is a TCP proxy. It does not know that port 8666 carries HTTP, and it cannot select a request by URL or status code. That protocol neutrality lets the same server proxy PostgreSQL, Redis, SMTP, gRPC over TCP, or a custom socket protocol. It also means the test must route every relevant connection through the proxy.
Verify the clean path:
curl -fsS http://localhost:8474/proxies/catalog_api | jq '{name,listen,upstream,enabled}'
for sample in 1 2 3; do
curl -sS -o /dev/null -w "baseline ${sample}: %{http_code} %{time_total}s\n" http://localhost:8666/
done
Expect catalog_api, an enabled state, upstream upstream:80, and three HTTP 200 responses. Save those baseline times. A connection to http://localhost:8666 that fails now is topology trouble, not a resilience failure. For more detail on reusable service topologies, see Docker Compose for test environments.
Step 3: Inject and Remove Toxiproxy Faults
Create a latency toxic through the documented HTTP API. The downstream stream affects bytes moving from upstream to client. Toxicity 1 applies the toxic to every connection, while jitter 0 keeps this comparison deterministic.
curl -fsS -X POST http://localhost:8474/proxies/catalog_api/toxics \
-H 'Content-Type: application/json' \
-d '{"name":"catalog_latency","type":"latency","stream":"downstream","toxicity":1,"attributes":{"latency":750,"jitter":0}}' | jq .
Verify both control state and user-visible effect:
curl -fsS http://localhost:8474/proxies/catalog_api/toxics | jq .
for sample in 1 2 3; do
curl -sS -o /dev/null -w "faulted ${sample}: %{http_code} %{time_total}s\n" --max-time 2 http://localhost:8666/
done
Expect a toxic named catalog_latency, three HTTP 200 responses, and totals around 0.75 seconds above the baseline. The two-second curl limit enforces the stated client budget. On a busy laptop the times may be higher, so judge the increase and status together.
Toxiproxy can model a harder outage by updating the proxy with enabled: false, but keep that as a separate test because connection refusal answers a different question than slow responses. Other toxics cover bandwidth, timeout, slow close, connection reset, data limits, slicing, and packet loss. Combine faults only after each isolated hypothesis works.
Remove the exact toxic and prove restoration:
curl -fsS -X DELETE http://localhost:8474/proxies/catalog_api/toxics/catalog_latency
curl -fsS http://localhost:8474/proxies/catalog_api/toxics | jq 'length'
curl -sS -o /dev/null -w 'recovered: %{http_code} %{time_total}s\n' http://localhost:8666/
The list length should be 0; the recovery request should return 200 without the added 750 ms. Use a cleanup hook in automated tests even when the assertion fails. Otherwise one toxic can contaminate every test that reuses the proxy.
Step 4: Build the Equivalent Kubernetes Target
Create the local cluster and switch explicitly to its context. Naming the context in verification commands reduces the risk of injecting a fault into whichever cluster happened to be current.
kind create cluster --name chaos-qa --wait 120s
kubectl config use-context kind-chaos-qa
kubectl cluster-info --context kind-chaos-qa
Expect the control plane to report a reachable address. Save this as lab.yaml and apply it. The probe is a long-running curl container; the target has two Nginx replicas behind a ClusterIP service. Labels provide the selection boundary used later.
apiVersion: v1
kind: Namespace
metadata:
name: chaos-lab
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: catalog-api
namespace: chaos-lab
spec:
replicas: 2
selector:
matchLabels:
app: catalog-api
template:
metadata:
labels:
app: catalog-api
spec:
containers:
- name: nginx
image: nginx:1.28-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: catalog-api
namespace: chaos-lab
spec:
selector:
app: catalog-api
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: probe-client
namespace: chaos-lab
spec:
replicas: 1
selector:
matchLabels:
app: probe-client
template:
metadata:
labels:
app: probe-client
spec:
containers:
- name: curl
image: curlimages/curl:8.12.1
command: ['sh', '-c', 'sleep infinity']
Apply the resources and wait for both deployments:
kubectl apply -f lab.yaml
kubectl -n chaos-lab rollout status deployment/catalog-api --timeout=120s
kubectl -n chaos-lab rollout status deployment/probe-client --timeout=120s
kubectl -n chaos-lab get pods -o wide
You should see two ready catalog pods and one ready probe pod. Capture the Kubernetes baseline from inside the probe rather than from the host:
kubectl -n chaos-lab exec deployment/probe-client -- sh -c \
'for i in 1 2 3; do curl -sS -o /dev/null -w "baseline: %{http_code} %{time_total}s\n" http://catalog-api/; done'
All three calls should return 200. If service DNS fails, inspect endpoints with kubectl -n chaos-lab get endpoints catalog-api; do not install Chaos Mesh until the clean cluster path works.
Step 5: Install Chaos Mesh Safely on kind
Add the official chart repository and install the pinned release. kind uses containerd inside its nodes, so set the runtime and socket path explicitly. Disabling leader election reduces the local controller-manager replica count for this disposable single-node exercise.
helm repo add chaos-mesh https://charts.chaos-mesh.org
helm repo update
helm upgrade --install chaos-mesh chaos-mesh/chaos-mesh \
--namespace chaos-mesh \
--create-namespace \
--version 2.8.3 \
--set chaosDaemon.runtime=containerd \
--set chaosDaemon.socketPath=/run/containerd/containerd.sock \
--set controllerManager.leaderElection.enabled=false
This is much more infrastructure than Toxiproxy because Chaos Mesh changes pod and node behavior through Kubernetes controllers and node daemons. That architecture enables selectors and many experiment types, but it also requires RBAC, admission webhooks, CRDs, privileged host access, and an explicit security review.
Verify the release, pods, daemon coverage, and API resource:
helm -n chaos-mesh status chaos-mesh
kubectl -n chaos-mesh wait --for=condition=Ready pod \
-l app.kubernetes.io/instance=chaos-mesh --timeout=180s
kubectl -n chaos-mesh get pods
kubectl get crd networkchaos.chaos-mesh.org
Every listed pod should be Running and ready, and the CRD command should return networkchaos.chaos-mesh.org. A missing chaos daemon usually points to a runtime socket or privileged-workload policy. A webhook error means the controller installation is not ready even if some pods are green.
Step 6: Run a Chaos Mesh NetworkChaos Delay
Save this as network-delay.yaml. The outer selector chooses only the probe client in chaos-lab; the target selector narrows affected traffic to catalog pods; direction: to limits the peer direction. Duration automatically requests recovery after 45 seconds, while manual deletion below makes the test finish promptly.
apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: catalog-delay
namespace: chaos-lab
spec:
action: delay
mode: all
selector:
namespaces:
- chaos-lab
labelSelectors:
app: probe-client
direction: to
target:
mode: all
selector:
namespaces:
- chaos-lab
labelSelectors:
app: catalog-api
delay:
latency: '750ms'
correlation: '100'
jitter: '0ms'
duration: '45s'
Apply the resource, wait for the controller's AllInjected condition, then measure from the same probe used for the baseline:
kubectl apply -f network-delay.yaml
kubectl -n chaos-lab wait --for=condition=AllInjected \
networkchaos/catalog-delay --timeout=30s
kubectl -n chaos-lab exec deployment/probe-client -- sh -c \
'for i in 1 2 3; do curl --max-time 2 -sS -o /dev/null -w "faulted: %{http_code} %{time_total}s\n" http://catalog-api/; done'
Expect HTTP 200 and roughly 0.75 seconds of added time. Inspect the custom resource if the condition does not become true:
kubectl -n chaos-lab describe networkchaos catalog-delay
kubectl -n chaos-lab get events --sort-by=.lastTimestamp | tail -n 20
Chaos Mesh can broaden this experiment by selecting one random pod, a fixed count, a fixed percentage, or every matching pod. It can also inject partition, loss, duplicate, corruption, reordering, and bandwidth faults. Those capabilities are valuable only when selectors are narrow and verified. An empty selector causes no useful test; an overly broad selector can damage control-plane communication or unrelated workloads.
Delete the resource and assert recovery:
kubectl -n chaos-lab delete -f network-delay.yaml --wait=true
kubectl -n chaos-lab exec deployment/probe-client -- \
curl -sS -o /dev/null -w 'recovered: %{http_code} %{time_total}s\n' http://catalog-api/
The resource deletion must complete, the request must return 200, and the added delay must disappear. Recovery is a first-class result because a chaos platform that injects successfully but cannot restore network state is unsafe.
Step 7: Compare Results, CI Fit, and Operational Cost
Put the two runs into one experiment record. Include tool and image versions, baseline samples, faulted samples, recovery sample, selected target, fault direction, configured duration, client timeout, and test exit status. This evidence prevents a later reviewer from comparing a Docker loopback request with a Kubernetes service request as if the raw totals were a tool benchmark.
For Toxiproxy, inspect GET /proxies, GET /metrics, container logs, and client assertions. Its Prometheus-format metrics expose proxy traffic, but application-level success still belongs in the test. For Chaos Mesh, preserve the custom resource, status conditions, Kubernetes events, controller logs, daemon logs, and application telemetry. AllInjected=True proves controller state, not user correctness; the curl result proves the steady-state behavior.
A pull-request lane usually favors Toxiproxy. Start one container, populate proxies, run integration tests, and remove toxics in afterEach or a shell trap. A Kubernetes lane can install Chaos Mesh once into a protected test cluster, then apply short-lived resources per test. Creating a fresh kind cluster and Helm release for every small commit is reproducible but slower and more resource-intensive. Use the guide to adding CI to a test framework to separate smoke, integration, and resilience jobs cleanly.
Build these gates into either lane:
- Fail if the pre-fault steady state is already broken.
- Fail if the injector never reaches its active state.
- Assert the expected fallback or bounded response during the fault.
- Always execute cleanup, even after an assertion or process error.
- Fail if recovery does not restore the steady state within a defined grace period.
- Archive injector state and application telemetry under a unique run ID.
Do not rank the tools by setup speed alone. Toxiproxy's narrow scope is an advantage for dependency contracts, while Chaos Mesh's operational weight buys topology-aware experiments that a proxy cannot represent.
Which Should You Choose for Toxiproxy vs Chaos Mesh Testing
Choose Toxiproxy when you own the test client's host and port configuration, need failures around one TCP dependency, and want fault control inside normal test code. It is especially effective for retry policies, connection pools, circuit breakers, database failover behavior, cache outages, partial reads, and slow downstream responses. The named proxy makes the affected path obvious, and the HTTP API supports deterministic setup and cleanup.
Choose Chaos Mesh when the hypothesis depends on Kubernetes identity or infrastructure behavior. Examples include isolating one availability-zone label, delaying traffic from a percentage of API pods to a backing service, killing pods during rollout, applying CPU pressure, corrupting network packets, or chaining several faults in a workflow. It also fits staging exercises where changing every application connection string would undermine the test.
Use both when the test pyramid has two distinct questions. Toxiproxy can prove in every pull request that the catalog client stops after three retries and returns a typed fallback. Chaos Mesh can later prove that the deployed service, sidecar, service discovery, load balancing, telemetry, and recovery automation behave correctly when selected pods lose connectivity. The first catches code regression quickly; the second validates the assembled system.
Avoid both when a simpler test double answers the question with less risk. An HTTP stub is better for a specific 429 body or malformed JSON because Toxiproxy cannot understand HTTP semantics. Kubernetes readiness manipulation may be better than chaos injection when you only need to test a documented rollout condition. Tool choice should follow the failure mechanism, not the appeal of a dashboard.
Interview Questions and Answers
A strong interview explanation starts with the injection boundary. Describe Toxiproxy as a controllable TCP hop and Chaos Mesh as a Kubernetes-native fault platform. Then state how you would establish steady state, constrain blast radius, observe both control state and user behavior, guarantee cleanup, and verify recovery.
Be ready to discuss why a proxy cannot model every cluster failure, why a successful custom-resource status is not a business assertion, and how you would split fast deterministic checks from staging experiments. The structured question bank below provides seven model answers without repeating the tutorial steps.
Common Mistakes
- Sending traffic directly to the upstream. A healthy direct request proves nothing about a Toxiproxy toxic. Make the proxied endpoint the only reachable test route, then inspect the named proxy before injection.
- Treating Toxiproxy as an HTTP stub. It operates on TCP byte streams. Use WireMock, MockServer, or an application stub for status-aware or body-aware behavior.
- Using a broad Chaos Mesh selector.
mode: allis safe only when namespace and labels are deliberately narrow. Print selected pods before applying the resource. - Forgetting the traffic direction. Request and response faults are not interchangeable. Document the client, server, stream,
direction, and target peer for every experiment. - Skipping the clean baseline. A pre-existing two-second response can make a 750 ms injector look ineffective. Stop immediately when steady state is unhealthy.
- Asserting injector state only. A toxic in the API and
AllInjected=Trueshow control-plane success. Neither demonstrates graceful application behavior. - Combining several faults too early. Delay plus loss plus pod termination creates a dramatic demo but weak diagnosis. Prove each mechanism independently before orchestration.
- Leaving recovery implicit. A
finallyblock, shell trap, duration, or workflow deadline must restore the environment. Follow it with an active health assertion. - Running chaos against shared production scope from CI. Credentials, context, namespace policy, and approval gates must prevent a pull request from reaching sensitive clusters.
- Comparing raw latency across different topologies. Docker Compose and Kubernetes add different DNS, proxying, and scheduling costs. Compare deltas and outcomes, not a misleading winner by milliseconds.
Troubleshooting
Toxiproxy returns address already in use -> Check host port 8666 and existing proxy listeners. Change the published port and proxy listen together, or remove the stale container and proxy definition.
The toxic exists but latency does not change -> Confirm the application connects to localhost:8666, not directly to Nginx. Inspect the toxic stream and run a fresh connection so pooling does not hide setup mistakes.
The Toxiproxy API returns a conflict on proxy creation -> Query GET /proxies/catalog_api. Reuse a matching proxy, update it deliberately, or delete and recreate only that named proxy. Do not call the global reset endpoint in a parallel suite unless the whole server belongs to one test.
Chaos Mesh pods are not ready on kind -> Verify the context, containerd runtime, /run/containerd/containerd.sock, available memory, and privileged workload policy. Describe the failing pod and read its events before reinstalling.
NetworkChaos stays in Injecting -> Check that the probe-client label and namespace match, the chaos daemon runs on the probe's node, and the kernel provides network emulation support. The custom-resource events usually identify selector or daemon errors.
The custom resource is injected but curl stays fast -> Confirm the selected source pod, direction: to, target selector, service endpoints, and measured command location. Running curl from the host bypasses the probe pod's network namespace.
Deletion hangs or latency remains after the test -> Inspect finalizers, controller and daemon health, and AllRecovered status. Do not force-remove finalizers until you understand whether node network state still needs restoration.
Where To Go Next
Turn the local delay into one product-level experiment. Assert a circuit-breaker transition, capped retry count, fallback response, queued write, or explicit error object. Then add server metrics and tracing so the result explains why the user outcome changed rather than merely reporting that it changed.
Next, create separate tests for timeout, connection reset, packet loss, and partition. Keep one failure mechanism per test until the expected behavior and recovery are stable. Use the canary testing guide when you want to combine resilience validation with controlled release exposure.
Destroy the disposable resources when you finish:
docker compose down
kind delete cluster --name chaos-qa
Verify cleanup with docker compose ps and kind get clusters. The Compose project should show no running services, and chaos-qa should no longer appear in the cluster list.
Conclusion
For toxiproxy vs chaos mesh testing, Toxiproxy wins at focused, code-adjacent dependency fault tests, while Chaos Mesh wins at Kubernetes-aware system experiments and broader fault coverage. They solve overlapping network scenarios through different injection boundaries, permission models, and operational costs.
Start with the smallest experiment that can disprove your resilience assumption. Put Toxiproxy around one critical dependency in CI, or apply a tightly selected Chaos Mesh resource in a disposable cluster. In either case, measure steady state, inject one bounded fault, assert the user outcome, remove the fault, and prove recovery before expanding the blast radius.
Interview Questions and Answers
How would you choose between Toxiproxy and Chaos Mesh for a new project?
I would identify the failure boundary first. If the test owns a dependency endpoint and needs deterministic connection faults inside integration tests, I would use Toxiproxy. If the hypothesis depends on Kubernetes pod identity, traffic between workload groups, or non-network faults, I would use Chaos Mesh. I would use both in separate layers when code behavior and deployed-system behavior need independent evidence.
Why must a Toxiproxy test change the connection endpoint?
Toxiproxy only manipulates bytes that pass through its listener. The proxy then forwards those bytes to the configured upstream and applies toxics on the upstream or downstream stream. A client that connects directly to the dependency bypasses the injector, so the test topology must make the proxy route explicit.
How do Chaos Mesh selectors control blast radius?
Selectors combine namespaces, labels, pods, nodes, and other criteria, while mode chooses one, all, a fixed count, or a percentage of matches. NetworkChaos can further constrain direction and target peers. I preview matching pods, use a dedicated namespace, set a duration, and verify the current cluster context before applying an experiment.
What would you assert during a latency injection test?
I would first prove the clean steady state and record baseline samples. During injection I would assert the business outcome, client timeout budget, fallback or retry behavior, and the intended latency delta. After cleanup I would require the steady state to recover within a defined grace period and preserve injector plus application telemetry.
Why is AllInjected status insufficient as a test result?
It reports that the Chaos Mesh controller applied the requested fault to its selected targets. It does not tell me whether users received a correct response, retry limits worked, data stayed consistent, or an SLO held. I pair control-plane status with client assertions and service metrics.
How would you run Toxiproxy tests safely in parallel?
I would give each worker unique proxy and toxic names plus non-conflicting listener ports, or isolate workers with separate Toxiproxy containers. Cleanup would delete only resources owned by that worker. I would avoid the global reset endpoint because it can remove another test's toxics.
What are the main operational risks of Chaos Mesh?
The daemon has privileged node access, selectors can affect more pods than intended, and loss of controller-to-daemon communication can complicate recovery. I reduce those risks with dedicated clusters or namespaces, least-privilege access, admission controls, short durations, abort criteria, and active post-experiment recovery checks.
Frequently Asked Questions
What is the main difference between Toxiproxy and Chaos Mesh?
Toxiproxy is a TCP proxy that a test controls through an HTTP API, so the application must connect through its listener. Chaos Mesh is a Kubernetes-native platform that injects faults into selected workloads and infrastructure through custom resources, controllers, and node daemons. The first is connection-focused; the second is topology-aware.
Can Toxiproxy be used with Kubernetes?
Yes. You can run Toxiproxy as a pod or sidecar and point clients at its service or container port. That arrangement remains explicit proxy routing, so it does not gain Chaos Mesh's transparent pod selection or non-network experiment types.
Does Chaos Mesh require application code changes?
NetworkChaos usually does not require endpoint changes because it alters traffic in selected pod network namespaces. You still need test hooks or telemetry to observe the application's response. Some experiment designs may require labels, namespace policy, or dedicated probe workloads, but not a proxy URL in production code.
Which tool is better for CI network fault testing?
Toxiproxy is usually the faster fit for pull-request integration tests because one container and a few API calls are enough. Chaos Mesh suits CI stages that already have a Kubernetes cluster or need to validate deployed topology. Separate the lanes when quick feedback and system realism have different time budgets.
Can both tools simulate packet loss and latency?
Yes, both can create delay and packet-loss conditions, but they act at different points. Toxiproxy applies toxics to traffic routed through a named proxy, while Chaos Mesh applies network emulation to selected pod traffic and can narrow peer direction. Equivalent configuration requires matching scope, direction, intensity, and observation point.
Is Toxiproxy a full chaos engineering platform?
No. It is intentionally focused on controllable network and connection conditions around TCP dependencies. It does not provide pod failure, CPU stress, disk I/O, time skew, cloud fault, workflow, or Kubernetes percentage-selection features.
How do you clean up faults safely after a failed test?
Place Toxiproxy toxic deletion or Chaos Mesh resource deletion in an unconditional cleanup path such as `finally`, `afterEach`, or a shell trap. Add a duration or deadline as a secondary guard where supported. Finish by making a real request and asserting that the steady state has returned.