Skip to content

Hashicorp Consul Module

Testcontainers module for Consul. Consul is a tool for managing key value properties. More information on Consul here.

Usage example

package org.testcontainers.consul;

import com.ecwid.consul.v1.ConsulClient;
import com.ecwid.consul.v1.Response;
import com.ecwid.consul.v1.kv.model.GetValue;
import io.restassured.RestAssured;
import org.junit.ClassRule;
import org.junit.Test;
import org.testcontainers.containers.GenericContainer;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * This test shows the pattern to use the ConsulContainer @ClassRule for a junit test. It also has tests that ensure
 * the properties were added correctly by reading from Consul with the CLI and over HTTP.
 */
public class ConsulContainerTest {

    @ClassRule
    public static ConsulContainer consulContainer = new ConsulContainer("hashicorp/consul:1.15")
        .withConsulCommand("kv put config/testing1 value123");

    @Test
    public void readFirstPropertyPathWithCli() throws IOException, InterruptedException {
        GenericContainer.ExecResult result = consulContainer.execInContainer("consul", "kv", "get", "config/testing1");
        final String output = result.getStdout().replaceAll("\\r?\\n", "");
        assertThat(output).contains("value123");
    }

    @Test
    public void readFirstSecretPathOverHttpApi() {
        io.restassured.response.Response response = RestAssured
            .given()
            .when()
            .get("http://" + getHostAndPort() + "/v1/kv/config/testing1")
            .andReturn();

        assertThat(response.body().jsonPath().getString("[0].Value"))
            .isEqualTo(Base64.getEncoder().encodeToString("value123".getBytes(StandardCharsets.UTF_8)));
    }

    @Test
    public void writeAndReadMultipleValuesUsingClient() {
        final ConsulClient consulClient = new ConsulClient(
            consulContainer.getHost(),
            consulContainer.getFirstMappedPort()
        );

        final Map<String, String> properties = new HashMap<>();
        properties.put("value", "world");
        properties.put("other_value", "another world");

        // Write operation
        properties.forEach((key, value) -> {
            Response<Boolean> writeResponse = consulClient.setKVValue(key, value);
            assertThat(writeResponse.getValue()).isTrue();
        });

        // Read operation
        properties.forEach((key, value) -> {
            Response<GetValue> readResponse = consulClient.getKVValue(key);
            assertThat(readResponse.getValue().getDecodedValue()).isEqualTo(value);
        });
    }

    private String getHostAndPort() {
        return consulContainer.getHost() + ":" + consulContainer.getMappedPort(8500);
    }
}

Why Consul in Junit tests?

With the increasing popularity of Consul and config externalization, applications are now needing to source properties from Consul. This can prove challenging in the development phase without a running Consul instance readily on hand. This library aims to solve your apps integration testing with Consul. You can also use it to test how your application behaves with Consul by writing different test scenarios in Junit.

Adding this module to your project dependencies

Add the following dependency to your pom.xml/build.gradle file:

testImplementation "org.testcontainers:consul:1.19.0"
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>consul</artifactId>
    <version>1.19.0</version>
    <scope>test</scope>
</dependency>