or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-org-testcontainers--toxiproxy

Testcontainers module for Shopify's Toxiproxy TCP proxy that simulates network failure conditions for resilience testing

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.testcontainers/toxiproxy@1.21.x

To install, run

npx @tessl/cli install tessl/maven-org-testcontainers--toxiproxy@1.21.0

index.mddocs/

Testcontainers Toxiproxy

Testcontainers module for Shopify's Toxiproxy TCP proxy that simulates network failure conditions for resilience testing. This module enables developers to test application resilience by introducing network toxics (failures) between containers or between test code and containers in isolated test environments.

Package Information

  • Package Name: org.testcontainers:toxiproxy

  • Package Type: Maven

  • Language: Java

  • Installation:

    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>toxiproxy</artifactId>
      <version>1.21.3</version>
      <scope>test</scope>
    </dependency>

    Gradle:

    testImplementation 'org.testcontainers:toxiproxy:1.21.3'

Core Imports

import org.testcontainers.containers.ToxiproxyContainer;
import eu.rekawek.toxiproxy.ToxiproxyClient;
import eu.rekawek.toxiproxy.Proxy;
import eu.rekawek.toxiproxy.model.ToxicDirection;

Basic Usage

import org.testcontainers.containers.ToxiproxyContainer;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import eu.rekawek.toxiproxy.ToxiproxyClient;
import eu.rekawek.toxiproxy.Proxy;
import eu.rekawek.toxiproxy.model.ToxicDirection;

// Create a common docker network
Network network = Network.newNetwork();

// Target container (could be any service)
GenericContainer<?> redis = new GenericContainer<>("redis:6-alpine")
    .withExposedPorts(6379)
    .withNetwork(network)
    .withNetworkAliases("redis");

// Toxiproxy container on same network
ToxiproxyContainer toxiproxy = new ToxiproxyContainer("ghcr.io/shopify/toxiproxy:2.5.0")
    .withNetwork(network);

// Start containers
redis.start();
toxiproxy.start();

// Create Toxiproxy client and proxy
ToxiproxyClient client = new ToxiproxyClient(
    toxiproxy.getHost(), 
    toxiproxy.getControlPort()
);
Proxy proxy = client.createProxy("redis", "0.0.0.0:8666", "redis:6379");

// Connect to service via proxy
String proxyHost = toxiproxy.getHost();
int proxyPort = toxiproxy.getMappedPort(8666);

// Apply network toxics for testing
proxy.toxics().latency("latency", ToxicDirection.DOWNSTREAM, 1000);
proxy.toxics().bandwidth("slow_connection", ToxicDirection.UPSTREAM, 100);

Architecture

The Toxiproxy module is built around these key components:

  • ToxiproxyContainer: Main container wrapper that manages the Toxiproxy Docker container lifecycle
  • ToxiproxyClient: Client from toxiproxy-java library for creating and managing proxies via HTTP API
  • Proxy: Represents individual proxy connections with toxic management capabilities
  • ContainerProxy: Deprecated wrapper class providing convenience methods for proxy management
  • Network Integration: Requires containers to be on same Docker network for inter-container communication

Capabilities

Container Management

Create and manage the Toxiproxy Docker container with automatic port exposure and lifecycle management.

/**
 * Testcontainers implementation for Toxiproxy.
 * Supported images: ghcr.io/shopify/toxiproxy, shopify/toxiproxy
 * Exposed ports: HTTP: 8474, Proxied Ports: 8666-8697
 */
public class ToxiproxyContainer extends GenericContainer<ToxiproxyContainer> {
    
    /**
     * @deprecated use ToxiproxyContainer(DockerImageName) instead
     */
    @Deprecated
    public ToxiproxyContainer();
    
    public ToxiproxyContainer(String dockerImageName);
    
    public ToxiproxyContainer(DockerImageName dockerImageName);
    
    /**
     * @return Publicly exposed Toxiproxy HTTP API control port
     */
    public int getControlPort();
}

Usage Examples:

// Using default image
ToxiproxyContainer toxiproxy = new ToxiproxyContainer();

// Using specific image version
ToxiproxyContainer toxiproxy = new ToxiproxyContainer("ghcr.io/shopify/toxiproxy:2.5.0");

// Using DockerImageName
DockerImageName imageName = DockerImageName.parse("shopify/toxiproxy:2.1.0");
ToxiproxyContainer toxiproxy = new ToxiproxyContainer(imageName);

// Get control port for client creation
int controlPort = toxiproxy.getControlPort();

Proxy Creation and Management

Create TCP proxies between services and apply network failure conditions using the ToxiproxyClient.

/**
 * Client for managing Toxiproxy proxies via HTTP API
 */
public class ToxiproxyClient {
    public ToxiproxyClient(String host, int port);
    
    /**
     * Create a new proxy
     * @param name proxy name (must be unique)
     * @param listen listen address in format "host:port" 
     * @param upstream upstream address in format "host:port"
     * @return Proxy instance for managing toxics
     */
    public Proxy createProxy(String name, String listen, String upstream) throws IOException;
}

/**
 * Represents a single proxy connection
 */
public class Proxy {
    /**
     * @return proxy name
     */
    public String getName();
    
    /**
     * @return ToxicList for managing network failure conditions
     */
    public ToxicList toxics();
}

Usage Examples:

// Create client
ToxiproxyClient client = new ToxiproxyClient(toxiproxy.getHost(), toxiproxy.getControlPort());

// Create proxy for Redis container
Proxy redisProxy = client.createProxy("redis", "0.0.0.0:8666", "redis:6379");

// Create proxy for external service
Proxy apiProxy = client.createProxy("api", "0.0.0.0:8667", "api.example.com:80");

// Get proxy details
String proxyName = redisProxy.getName(); // "redis"

Network Toxic Management

Apply various network failure conditions to test application resilience.

/**
 * Interface for managing toxic conditions on a proxy
 */
public interface ToxicList {
    /**
     * Limit connection bandwidth
     * @param name toxic name
     * @param direction traffic direction (UPSTREAM/DOWNSTREAM)  
     * @param rate maximum kilobytes per second
     * @return Toxic instance
     */
    Toxic bandwidth(String name, ToxicDirection direction, long rate);
    
    /**
     * Add latency with optional jitter
     * @param name toxic name
     * @param direction traffic direction
     * @param latency latency in milliseconds
     * @return Toxic instance for further configuration
     */
    Toxic latency(String name, ToxicDirection direction, long latency);
    
    /**
     * Slice TCP data into small packets
     * @param name toxic name
     * @param direction traffic direction
     * @param averageSize average packet size in bytes
     * @param sizeVariation size variation in bytes
     * @param delay delay between packets in microseconds
     * @return Toxic instance
     */
    Toxic slicer(String name, ToxicDirection direction, int averageSize, int sizeVariation, int delay);
    
    /**
     * Delay socket closing
     * @param name toxic name
     * @param direction traffic direction
     * @param delay delay in milliseconds
     * @return Toxic instance
     */
    Toxic slowClose(String name, ToxicDirection direction, long delay);
    
    /**
     * Stop data transmission and close connection after timeout
     * @param name toxic name
     * @param direction traffic direction
     * @param timeout timeout in milliseconds (0 = never close)
     * @return Toxic instance
     */  
    Toxic timeout(String name, ToxicDirection direction, long timeout);
    
    /**
     * Close connection when data limit exceeded
     * @param name toxic name
     * @param direction traffic direction
     * @param bytes data limit in bytes
     * @return Toxic instance
     */
    Toxic limitData(String name, ToxicDirection direction, long bytes);
    
    /**
     * Get existing toxic by name
     * @param name toxic name
     * @return Toxic instance
     */
    Toxic get(String name);
}

/**
 * Represents an individual toxic condition
 */
public interface Toxic {
    /**
     * Remove this toxic
     */
    void remove() throws IOException;
    
    /**
     * Set jitter for latency toxics
     * @param jitter jitter in milliseconds
     * @return this toxic for chaining
     */
    Toxic setJitter(int jitter);
}

/**
 * Traffic direction for toxic application
 */
public enum ToxicDirection {
    UPSTREAM,   // Client to server
    DOWNSTREAM  // Server to client
}

Usage Examples:

// Add 1 second latency with 100ms jitter to downstream traffic
proxy.toxics()
    .latency("latency", ToxicDirection.DOWNSTREAM, 1000)
    .setJitter(100);

// Limit bandwidth to 100 KB/s upstream
proxy.toxics().bandwidth("slow_upload", ToxicDirection.UPSTREAM, 100);

// Completely cut connection (0 bandwidth both directions)
proxy.toxics().bandwidth("cut_down", ToxicDirection.DOWNSTREAM, 0);
proxy.toxics().bandwidth("cut_up", ToxicDirection.UPSTREAM, 0);

// Add connection timeout after 5 seconds
proxy.toxics().timeout("connection_timeout", ToxicDirection.DOWNSTREAM, 5000);

// Slice packets into 32-byte chunks with 10ms delay
proxy.toxics().slicer("packet_slicer", ToxicDirection.DOWNSTREAM, 32, 8, 10000);

// Remove a toxic
proxy.toxics().get("latency").remove();

Legacy Proxy Management (Deprecated)

Legacy convenience methods for proxy creation and management. These methods are deprecated and will be removed in future versions.

public class ToxiproxyContainer extends GenericContainer<ToxiproxyContainer> {
    
    /**
     * @deprecated ToxiproxyContainer will not build the client. Proxies should be provided manually.
     */
    @Deprecated  
    public ContainerProxy getProxy(GenericContainer<?> container, int port);
    
    /**
     * @deprecated ToxiproxyContainer will not build the client. Proxies should be provided manually.
     */
    @Deprecated
    public ContainerProxy getProxy(String hostname, int port);
    
    /**
     * @deprecated Legacy proxy wrapper class
     */
    @Deprecated
    public static class ContainerProxy {
        
        /**
         * The IP address that this proxy container may be reached on from the host machine
         */
        public String getContainerIpAddress();
        
        /**
         * The mapped port of this proxy. This is a port of the host machine
         */  
        public int getProxyPort();
        
        /**
         * The original (exposed) port of this proxy. This is a port of the Toxiproxy Docker container
         */
        public int getOriginalProxyPort();
        
        public String getName();
        
        public ToxicList toxics();
        
        /**
         * Cuts the connection by setting bandwidth in both directions to zero
         * @param shouldCutConnection true to cut connection, false to restore
         */
        public void setConnectionCut(boolean shouldCutConnection);
    }
}

Error Handling

The module may throw these exceptions during operation:

/**
 * Common exceptions
 */
IOException // Thrown during proxy creation or toxic manipulation
IllegalStateException // Thrown when maximum proxy limit (32) exceeded  
RuntimeException // Wrapper for IOException in proxy operations

Error Handling Examples:

try {
    Proxy proxy = client.createProxy("service", "0.0.0.0:8666", "service:8080");
    proxy.toxics().latency("test_latency", ToxicDirection.DOWNSTREAM, 1000);
} catch (IOException e) {
    // Handle proxy creation or toxic application failure
    System.err.println("Failed to configure proxy: " + e.getMessage());
}

try {
    // This will fail if more than 32 proxies are created
    ToxiproxyContainer.ContainerProxy proxy = toxiproxy.getProxy("host", 8080);
} catch (IllegalStateException e) {
    System.err.println("Maximum number of proxies exceeded");
}