All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.testcontainers.containers.ToxiproxyContainer Maven / Gradle / Ivy

The newest version!
package org.testcontainers.containers;

import com.github.dockerjava.api.command.InspectContainerResponse;
import eu.rekawek.toxiproxy.Proxy;
import eu.rekawek.toxiproxy.ToxiproxyClient;
import eu.rekawek.toxiproxy.model.ToxicDirection;
import eu.rekawek.toxiproxy.model.ToxicList;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
import org.testcontainers.utility.DockerImageName;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Testcontainers implementation for Toxiproxy.
 * 

* Supported images: {@code ghcr.io/shopify/toxiproxy}, {@code shopify/toxiproxy} *

* Exposed ports: *

    *
  • HTTP: 8474
  • *
  • Proxied Ports: 8666-8697
  • *
*/ public class ToxiproxyContainer extends GenericContainer { private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("shopify/toxiproxy"); private static final String DEFAULT_TAG = "2.1.0"; private static final DockerImageName GHCR_IMAGE_NAME = DockerImageName.parse("ghcr.io/shopify/toxiproxy"); private static final int TOXIPROXY_CONTROL_PORT = 8474; private static final int FIRST_PROXIED_PORT = 8666; private static final int LAST_PROXIED_PORT = 8666 + 31; private ToxiproxyClient client; private final Map proxies = new HashMap<>(); private final AtomicInteger nextPort = new AtomicInteger(FIRST_PROXIED_PORT); /** * @deprecated use {@link #ToxiproxyContainer(DockerImageName)} instead */ @Deprecated public ToxiproxyContainer() { this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); } public ToxiproxyContainer(String dockerImageName) { this(DockerImageName.parse(dockerImageName)); } public ToxiproxyContainer(final DockerImageName dockerImageName) { super(dockerImageName); dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, GHCR_IMAGE_NAME); addExposedPorts(TOXIPROXY_CONTROL_PORT); setWaitStrategy(new HttpWaitStrategy().forPath("/version").forPort(TOXIPROXY_CONTROL_PORT)); // allow up to 32 ports to be proxied (arbitrary value). Here we make the ports exposed; whether or not // Toxiproxy will listen is controlled at runtime using getProxy(...) for (int i = FIRST_PROXIED_PORT; i <= LAST_PROXIED_PORT; i++) { addExposedPort(i); } } @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { client = new ToxiproxyClient(getHost(), getMappedPort(TOXIPROXY_CONTROL_PORT)); } /** * @return Publicly exposed Toxiproxy HTTP API control port. */ public int getControlPort() { return getMappedPort(TOXIPROXY_CONTROL_PORT); } /** * Obtain a {@link ContainerProxy} instance for target container that is managed by Testcontainers. The target * container should be routable from this {@link ToxiproxyContainer} instance (e.g. on the same * Docker {@link Network}). * * @param container target container * @param port port number on the target service that should be proxied * @return a {@link ContainerProxy} instance * @deprecated {@link ToxiproxyContainer} will not build the client. Proxies should be provided manually. */ @Deprecated public ContainerProxy getProxy(GenericContainer container, int port) { return this.getProxy(container.getNetworkAliases().get(0), port); } /** * Obtain a {@link ContainerProxy} instance for a specific hostname and port, which can be for any host * that is routable from this {@link ToxiproxyContainer} instance (e.g. on the same * Docker {@link Network} or on routable from the Docker host). * *

It is expected that {@link ToxiproxyContainer#getProxy(GenericContainer, int)} will be more * useful in most scenarios, but this method is present to allow use of Toxiproxy in front of containers * or external servers that are not managed by Testcontainers.

* * @param hostname hostname of target server to be proxied * @param port port number on the target server that should be proxied * @return a {@link ContainerProxy} instance * @deprecated {@link ToxiproxyContainer} will not build the client. Proxies should be provided manually. */ @Deprecated public ContainerProxy getProxy(String hostname, int port) { String upstream = hostname + ":" + port; return proxies.computeIfAbsent( upstream, __ -> { try { final int toxiPort = nextPort.getAndIncrement(); if (toxiPort > LAST_PROXIED_PORT) { throw new IllegalStateException("Maximum number of proxies exceeded"); } final Proxy proxy = client.createProxy(upstream, "0.0.0.0:" + toxiPort, upstream); final int mappedPort = getMappedPort(toxiPort); return new ContainerProxy(proxy, getHost(), mappedPort, toxiPort); } catch (IOException e) { throw new RuntimeException("Proxy could not be created", e); } } ); } @RequiredArgsConstructor(access = AccessLevel.PROTECTED) @Deprecated public static class ContainerProxy { private static final String CUT_CONNECTION_DOWNSTREAM = "CUT_CONNECTION_DOWNSTREAM"; private static final String CUT_CONNECTION_UPSTREAM = "CUT_CONNECTION_UPSTREAM"; private final Proxy toxi; /** * The IP address that this proxy container may be reached on from the host machine. */ @Getter private final String containerIpAddress; /** * The mapped port of this proxy. This is a port of the host machine. It can be used to * access the Toxiproxy container from the host machine. */ @Getter private final int proxyPort; /** * The original (exposed) port of this proxy. This is a port of the Toxiproxy Docker * container. It can be used to access this container from a different Docker container * on the same network. */ @Getter private final int originalProxyPort; private boolean isCurrentlyCut; public String getName() { return toxi.getName(); } public ToxicList toxics() { return toxi.toxics(); } /** * Cuts the connection by setting bandwidth in both directions to zero. * @param shouldCutConnection true if the connection should be cut, or false if it should be re-enabled */ public void setConnectionCut(boolean shouldCutConnection) { try { if (shouldCutConnection) { toxics().bandwidth(CUT_CONNECTION_DOWNSTREAM, ToxicDirection.DOWNSTREAM, 0); toxics().bandwidth(CUT_CONNECTION_UPSTREAM, ToxicDirection.UPSTREAM, 0); isCurrentlyCut = true; } else if (isCurrentlyCut) { toxics().get(CUT_CONNECTION_DOWNSTREAM).remove(); toxics().get(CUT_CONNECTION_UPSTREAM).remove(); isCurrentlyCut = false; } } catch (IOException e) { throw new RuntimeException("Could not control proxy", e); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy