diff --git a/docs/examples.md b/docs/examples.md index cdacd0dad89..29e1ca643f3 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -2,6 +2,7 @@ Examples of different use cases provided by Testcontainers can be found below: +- [Hazelcast](https://github.com/testcontainers/testcontainers-java/tree/main/examples/hazelcast) - [Kafka Cluster with multiple brokers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/kafka-cluster) - [Linked containers](https://github.com/testcontainers/testcontainers-java/tree/main/examples/linked-container) - [Neo4j](https://github.com/testcontainers/testcontainers-java/tree/main/examples/neo4j-container) diff --git a/examples/hazelcast/build.gradle b/examples/hazelcast/build.gradle new file mode 100644 index 00000000000..11eb6cb0d3d --- /dev/null +++ b/examples/hazelcast/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.testcontainers:testcontainers' + testImplementation 'com.hazelcast:hazelcast:5.2.0' + testImplementation 'ch.qos.logback:logback-classic:1.3.4' + testImplementation 'org.assertj:assertj-core:3.23.1' +} diff --git a/examples/hazelcast/src/test/java/org/testcontainers/examples/HazelcastTest.java b/examples/hazelcast/src/test/java/org/testcontainers/examples/HazelcastTest.java new file mode 100644 index 00000000000..18fc6df6455 --- /dev/null +++ b/examples/hazelcast/src/test/java/org/testcontainers/examples/HazelcastTest.java @@ -0,0 +1,125 @@ +package org.testcontainers.examples; + +import com.hazelcast.client.HazelcastClient; +import com.hazelcast.client.config.ClientConfig; +import com.hazelcast.core.HazelcastInstance; +import org.junit.After; +import org.junit.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.lifecycle.Startables; +import org.testcontainers.utility.DockerImageName; + +import java.util.concurrent.BlockingQueue; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Examples with Hazelcast using both a single container and a cluster with two containers. + */ +public class HazelcastTest { + + // Hazelcast values + private static final String HZ_IMAGE_NAME = "hazelcast/hazelcast:5.2.0"; + + private static final String HZ_CLUSTERNAME_ENV_NAME = "HZ_CLUSTERNAME"; + + private static final String HZ_NETWORK_JOIN_AZURE_ENABLED_ENV_NAME = "HZ_NETWORK_JOIN_AZURE_ENABLED"; + + private static final String HZ_NETWORK_JOIN_MULTICAST_ENABLED_ENV_NAME = "HZ_NETWORK_JOIN_MULTICAST_ENABLED"; + + private static final int DEFAULT_EXPOSED_PORT = 5701; + + // Test values + private static final String CLUSTER_STARTUP_LOG_MESSAGE_REGEX = ".*Members \\{size:2.*"; + + private static final String HOST_PORT_SEPARATOR = ":"; + + private static final String TEST_QUEUE_NAME = "test-queue"; + + private static final String TEST_CLUSTER_NAME = "test-cluster"; + + private static final String TEST_VALUE = "Hello!"; + + private static final String FALSE_VALUE = "false"; + + private static final String TRUE_VALUE = "true"; + + @After + public void cleanUp() { + HazelcastClient.shutdownAll(); + } + + @Test + public void singleHazelcastContainer() { + try ( + GenericContainer container = new GenericContainer<>(DockerImageName.parse(HZ_IMAGE_NAME)) + .withExposedPorts(DEFAULT_EXPOSED_PORT) + ) { + container.start(); + assertThat(container.isRunning()).isTrue(); + + ClientConfig clientConfig = new ClientConfig(); + clientConfig + .getNetworkConfig() + .addAddress(container.getHost() + HOST_PORT_SEPARATOR + container.getFirstMappedPort()); + HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig); + + BlockingQueue queue = client.getQueue(TEST_QUEUE_NAME); + queue.put(TEST_VALUE); + assertThat(queue.take()).isEqualTo(TEST_VALUE); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted during singleHazelcastContainer test", e); + } + } + + @Test + public void hazelcastCluster() { + Network network = Network.newNetwork(); + try ( + GenericContainer container1 = new GenericContainer<>(DockerImageName.parse(HZ_IMAGE_NAME)) + .withExposedPorts(DEFAULT_EXPOSED_PORT) + .withEnv(HZ_CLUSTERNAME_ENV_NAME, TEST_CLUSTER_NAME) + // Flags necessary to run on Github Actions which runs on an Azure VM + .withEnv(HZ_NETWORK_JOIN_AZURE_ENABLED_ENV_NAME, FALSE_VALUE) + .withEnv(HZ_NETWORK_JOIN_MULTICAST_ENABLED_ENV_NAME, TRUE_VALUE) + .waitingFor(Wait.forLogMessage(CLUSTER_STARTUP_LOG_MESSAGE_REGEX, 1)) + .withNetwork(network); + GenericContainer container2 = new GenericContainer<>(DockerImageName.parse(HZ_IMAGE_NAME)) + .withExposedPorts(DEFAULT_EXPOSED_PORT) + .withEnv(HZ_CLUSTERNAME_ENV_NAME, TEST_CLUSTER_NAME) + // Flags necessary to run on Github Actions which runs on an Azure VM + .withEnv(HZ_NETWORK_JOIN_AZURE_ENABLED_ENV_NAME, FALSE_VALUE) + .withEnv(HZ_NETWORK_JOIN_MULTICAST_ENABLED_ENV_NAME, TRUE_VALUE) + .waitingFor(Wait.forLogMessage(CLUSTER_STARTUP_LOG_MESSAGE_REGEX, 1)) + .withNetwork(network) + ) { + Startables.deepStart(container1, container2).join(); + assertThat(container1.isRunning()).isTrue(); + assertThat(container2.isRunning()).isTrue(); + + ClientConfig clientConfig = new ClientConfig(); + clientConfig + .setClusterName(TEST_CLUSTER_NAME) + .getNetworkConfig() + // Uncomment the next line to remove the "WARNING: ...Could not connect to member..." message + //.setSmartRouting(false) + .addAddress(container1.getHost() + HOST_PORT_SEPARATOR + container1.getFirstMappedPort()) + .addAddress(container2.getHost() + HOST_PORT_SEPARATOR + container2.getFirstMappedPort()); + + HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig); + + assertThat(client.getCluster().getMembers()).hasSize(2); + + BlockingQueue queue = client.getQueue(TEST_QUEUE_NAME); + queue.put(TEST_VALUE); + + assertThat(queue.take()).isEqualTo(TEST_VALUE); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted during hazelcastCluster test", e); + } + } +} diff --git a/examples/hazelcast/src/test/resources/logback-test.xml b/examples/hazelcast/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..be4ebaed2c8 --- /dev/null +++ b/examples/hazelcast/src/test/resources/logback-test.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + diff --git a/examples/settings.gradle b/examples/settings.gradle index ea7dacdbb56..b7285eeabd2 100644 --- a/examples/settings.gradle +++ b/examples/settings.gradle @@ -32,6 +32,7 @@ include 'cucumber' include 'spring-boot-kotlin-redis' include 'immudb' include 'zookeeper' +include 'hazelcast' ext.isCI = System.getenv("CI") != null