From fa3e337d7df7576f03fa1c02c2a7e00bdee0411b Mon Sep 17 00:00:00 2001 From: Esta Nagy Date: Sun, 22 Dec 2024 12:18:55 +0100 Subject: [PATCH 1/8] Add Azure Eventhubs Emulator container to Azure module - Add Azure Eventhubs Emulator container - Implement new test case - Update Azure documentation Signed-off-by: Esta Nagy --- docs/modules/azure.md | 21 +++- modules/azure/build.gradle | 1 + .../AzureEventhubsEmulatorContainer.java | 106 ++++++++++++++++++ .../azure/AzuriteContainer.java | 4 +- .../AzureEventhubsEmulatorContainerTest.java | 85 ++++++++++++++ .../src/test/resources/eventhubs_config.json | 24 ++++ 6 files changed, 237 insertions(+), 4 deletions(-) create mode 100644 modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java create mode 100644 modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java create mode 100644 modules/azure/src/test/resources/eventhubs_config.json diff --git a/docs/modules/azure.md b/docs/modules/azure.md index 19c141c7639..741bedaa1dc 100644 --- a/docs/modules/azure.md +++ b/docs/modules/azure.md @@ -5,11 +5,12 @@ This module is INCUBATING. While it is ready for use and operational in the curr Testcontainers module for the Microsoft Azure's [SDK](https://github.com/Azure/azure-sdk-for-java). -Currently, the module supports `Azurite` and `CosmosDB` emulators. In order to use them, you should use the following classes: +Currently, the module supports `Azurite`, `Azure Eventhubs` and `CosmosDB` emulators. In order to use them, you should use the following classes: Class | Container Image -|- AzuriteContainer | [mcr.microsoft.com/azure-storage/azurite](https://github.com/microsoft/containerregistry) +AzureEventhubsEmulatorContainer | [mcr.microsoft.com/azure-messaging/eventhubs-emulator](https://github.com/microsoft/containerregistry) CosmosDBEmulatorContainer | [mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator](https://github.com/microsoft/containerregistry) ## Usage example @@ -72,6 +73,24 @@ Build Azure Table client: !!! note We can use custom credentials the same way as defined in the Blob section. +### Azure Eventhubs Emulator + + +[Configuring the Azure Eventhubs Emulator container](../../modules/azure/src/test/resources/eventhubs_config.json) + + +Start Azure Eventhubs Emulator during a test: + + +[Starting a Azure Eventhubs Emulator container](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java) inside_block:emulatorContainer + + +Configure the consumer and the producer clients: + + +[Configuring the clients](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java) inside_block:createProducerAndConsumer + + ### CosmosDB Start Azure CosmosDB Emulator during a test: diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index c6cfb6738d0..3dc97d03fce 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -10,4 +10,5 @@ dependencies { testImplementation 'com.azure:azure-storage-blob:12.29.0' testImplementation 'com.azure:azure-storage-queue:12.24.0' testImplementation 'com.azure:azure-data-tables:12.5.0' + testImplementation 'com.azure:azure-messaging-eventhubs:5.19.2' } diff --git a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java new file mode 100644 index 00000000000..5e5e42a2ebb --- /dev/null +++ b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java @@ -0,0 +1,106 @@ +package org.testcontainers.azure; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +/** + * Testcontainers implementation for Azure Eventhubs Emulator. + *

+ * Supported image: {@code "mcr.microsoft.com/azure-messaging/eventhubs-emulator"} + *

+ * Exposed ports: + *

+ */ +public class AzureEventhubsEmulatorContainer extends GenericContainer { + + private static final int DEFAULT_AMQP_PORT = 5672; + + private static final int DEFAULT_KAFKA_PORT = 9092; + + private static final String CONNECTION_STRING_FORMAT = + "Endpoint=sb://%s:%d;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "mcr.microsoft.com/azure-messaging/eventhubs-emulator" + ); + + private AzuriteContainer azuriteContainer; + + private MountableFile config; + + /** + * @param dockerImageName specified docker image name to run + */ + public AzureEventhubsEmulatorContainer(final DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + + waitingFor(Wait.forLogMessage(".*Emulator Service is Successfully Up!.*", 1)); + withExposedPorts(DEFAULT_AMQP_PORT, DEFAULT_KAFKA_PORT); + } + + @Override + public void start() { + if (this.azuriteContainer == null) { + this.azuriteContainer = + new AzuriteContainer(AzuriteContainer.DEFAULT_IMAGE_NAME.withTag("3.33.0")).withNetwork(getNetwork()); + } + this.azuriteContainer.start(); + + super.start(); + } + + @Override + public void stop() { + super.stop(); + if (this.azuriteContainer != null) { + this.azuriteContainer.stop(); + } + } + + /** + * Provide the broker configuration to the container. + * + * @param config The file containing the broker configuration + * @return this + */ + public AzureEventhubsEmulatorContainer withConfig(final MountableFile config) { + this.config = config; + return this; + } + + /** + * Accepts the EULA of the container. + * + * @return this + */ + public AzureEventhubsEmulatorContainer acceptEula() { + return withEnv("ACCEPT_EULA", "Y"); + } + + @Override + protected void configure() { + dependsOn(azuriteContainer); + final String azuriteHost = azuriteContainer.getNetworkAliases().get(0); + withEnv("BLOB_SERVER", azuriteHost); + withEnv("METADATA_SERVER", azuriteHost); + if (this.config != null) { + logger().info("Using path for configuration file: '{}'", this.config); + withCopyFileToContainer(this.config, "/Eventhubs_Emulator/ConfigFiles/Config.json"); + } + } + + /** + * Returns the connection string. + * + * @return connection string + */ + public String getConnectionString() { + return String.format(CONNECTION_STRING_FORMAT, getHost(), getMappedPort(DEFAULT_AMQP_PORT)); + } +} diff --git a/modules/azure/src/main/java/org/testcontainers/azure/AzuriteContainer.java b/modules/azure/src/main/java/org/testcontainers/azure/AzuriteContainer.java index 56c58df1f1d..6df6ffe7b4d 100644 --- a/modules/azure/src/main/java/org/testcontainers/azure/AzuriteContainer.java +++ b/modules/azure/src/main/java/org/testcontainers/azure/AzuriteContainer.java @@ -40,9 +40,7 @@ public class AzuriteContainer extends GenericContainer { private static final String WELL_KNOWN_ACCOUNT_KEY = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="; - private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( - "mcr.microsoft.com/azure-storage/azurite" - ); + static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mcr.microsoft.com/azure-storage/azurite"); private MountableFile cert = null; diff --git a/modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java b/modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java new file mode 100644 index 00000000000..7445a355efe --- /dev/null +++ b/modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java @@ -0,0 +1,85 @@ +package org.testcontainers.azure; + +import com.azure.core.util.IterableStream; +import com.azure.messaging.eventhubs.EventData; +import com.azure.messaging.eventhubs.EventHubClientBuilder; +import com.azure.messaging.eventhubs.EventHubConsumerClient; +import com.azure.messaging.eventhubs.EventHubProducerClient; +import com.azure.messaging.eventhubs.models.EventPosition; +import com.azure.messaging.eventhubs.models.PartitionEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.containers.Network; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.time.Duration; +import java.util.Collections; +import java.util.Optional; +import java.util.Properties; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.waitAtMost; + +public class AzureEventhubsEmulatorContainerTest { + + private static Properties originalSystemProperties; + + @BeforeClass + public static void captureOriginalSystemProperties() { + originalSystemProperties = (Properties) System.getProperties().clone(); + } + + @AfterClass + public static void restoreOriginalSystemProperties() { + System.setProperties(originalSystemProperties); + } + + @Rule + // emulatorContainer { + public AzureEventhubsEmulatorContainer emulator = new AzureEventhubsEmulatorContainer( + DockerImageName.parse("mcr.microsoft.com/azure-messaging/eventhubs-emulator:2.0.1") + ) + .acceptEula() + .withNetwork(Network.newNetwork()) + .withConfig(MountableFile.forClasspathResource("/eventhubs_config.json")); + + // } + + @Test + public void testWithEventhubsClient() { + try ( + // createProducerAndConsumer { + EventHubProducerClient producer = new EventHubClientBuilder() + .connectionString(emulator.getConnectionString()) + .fullyQualifiedNamespace("emulatorNs1") + .eventHubName("eh1") + .buildProducerClient(); + EventHubConsumerClient consumer = new EventHubClientBuilder() + .connectionString(emulator.getConnectionString()) + .fullyQualifiedNamespace("emulatorNs1") + .eventHubName("eh1") + .consumerGroup("cg1") + .buildConsumerClient() + // } + ) { + producer.send(Collections.singletonList(new EventData("test"))); + + waitAtMost(Duration.ofSeconds(30)) + .pollDelay(Duration.ofSeconds(5)) + .untilAsserted(() -> { + IterableStream events = consumer.receiveFromPartition( + "0", + 1, + EventPosition.earliest(), + Duration.ofSeconds(2) + ); + Optional event = events.stream().findFirst(); + assertThat(event).isPresent(); + assertThat(event.get().getData().getBodyAsString()).isEqualTo("test"); + }); + } + } +} diff --git a/modules/azure/src/test/resources/eventhubs_config.json b/modules/azure/src/test/resources/eventhubs_config.json new file mode 100644 index 00000000000..554be9d7cbf --- /dev/null +++ b/modules/azure/src/test/resources/eventhubs_config.json @@ -0,0 +1,24 @@ +{ + "UserConfig": { + "NamespaceConfig": [ + { + "Type": "EventHub", + "Name": "emulatorNs1", + "Entities": [ + { + "Name": "eh1", + "PartitionCount": "1", + "ConsumerGroups": [ + { + "Name": "cg1" + } + ] + } + ] + } + ], + "LoggingConfig": { + "Type": "File" + } + } +} From ce13e06147196553251cec8d73705a11d3b0a8a9 Mon Sep 17 00:00:00 2001 From: Esta Nagy Date: Fri, 10 Jan 2025 00:04:22 +0100 Subject: [PATCH 2/8] Add Azure Eventhubs Emulator container to Azure module - Fix license acceptance - Use Transferable - Remove unnecessary code from tests Signed-off-by: Esta Nagy --- .../azure/AzureEventhubsEmulatorContainer.java | 16 +++++++++++----- .../AzureEventhubsEmulatorContainerTest.java | 17 +---------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java index 5e5e42a2ebb..9a7ef2f3094 100644 --- a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java +++ b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java @@ -2,8 +2,9 @@ import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.MountableFile; +import org.testcontainers.utility.LicenseAcceptance; /** * Testcontainers implementation for Azure Eventhubs Emulator. @@ -31,7 +32,7 @@ public class AzureEventhubsEmulatorContainer extends GenericContainer Date: Fri, 10 Jan 2025 22:10:24 +0100 Subject: [PATCH 3/8] Add Azure Event Hubs Emulator container to Azure module - Fix Typo in the container's name - Require AzuriteContainer as dependency - Add Kafka Event Hubs test - Add Kafka option to Azure documentation Signed-off-by: Esta Nagy --- docs/modules/azure.md | 32 +++- modules/azure/build.gradle | 1 + ...a => AzureEventHubsEmulatorContainer.java} | 62 ++++--- .../azure/AzuriteContainer.java | 4 +- .../AzureEventHubsEmulatorContainerTest.java | 158 ++++++++++++++++++ .../AzureEventhubsEmulatorContainerTest.java | 70 -------- 6 files changed, 224 insertions(+), 103 deletions(-) rename modules/azure/src/main/java/org/testcontainers/azure/{AzureEventhubsEmulatorContainer.java => AzureEventHubsEmulatorContainer.java} (69%) create mode 100644 modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java delete mode 100644 modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java diff --git a/docs/modules/azure.md b/docs/modules/azure.md index 741bedaa1dc..c54ae22a4aa 100644 --- a/docs/modules/azure.md +++ b/docs/modules/azure.md @@ -5,12 +5,12 @@ This module is INCUBATING. While it is ready for use and operational in the curr Testcontainers module for the Microsoft Azure's [SDK](https://github.com/Azure/azure-sdk-for-java). -Currently, the module supports `Azurite`, `Azure Eventhubs` and `CosmosDB` emulators. In order to use them, you should use the following classes: +Currently, the module supports `Azurite`, `Azure Event Hubs` and `CosmosDB` emulators. In order to use them, you should use the following classes: Class | Container Image -|- AzuriteContainer | [mcr.microsoft.com/azure-storage/azurite](https://github.com/microsoft/containerregistry) -AzureEventhubsEmulatorContainer | [mcr.microsoft.com/azure-messaging/eventhubs-emulator](https://github.com/microsoft/containerregistry) +AzureEventHubsEmulatorContainer | [mcr.microsoft.com/azure-messaging/eventhubs-emulator](https://github.com/microsoft/containerregistry) CosmosDBEmulatorContainer | [mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator](https://github.com/microsoft/containerregistry) ## Usage example @@ -73,22 +73,40 @@ Build Azure Table client: !!! note We can use custom credentials the same way as defined in the Blob section. -### Azure Eventhubs Emulator +### Azure Event Hubs Emulator -[Configuring the Azure Eventhubs Emulator container](../../modules/azure/src/test/resources/eventhubs_config.json) +[Configuring the Azure Event Hubs Emulator container](../../modules/azure/src/test/resources/eventhubs_config.json) -Start Azure Eventhubs Emulator during a test: +Start Azure Event Hubs Emulator during a test: -[Starting a Azure Eventhubs Emulator container](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java) inside_block:emulatorContainer +[Setting uo a network](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:network + +[Starting an Azurite container as dependency](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:azuriteContainer + + + +[Starting a Azure Event Hubs Emulator container](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:emulatorContainer + + +#### Using Azure Event Hubs clients + +Configure the consumer and the producer clients: + + +[Configuring the clients](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:createProducerAndConsumer + + +#### Using Kafka clients + Configure the consumer and the producer clients: -[Configuring the clients](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java) inside_block:createProducerAndConsumer +[Obtaining the Kafka connection properties](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:kafkaProperties ### CosmosDB diff --git a/modules/azure/build.gradle b/modules/azure/build.gradle index 3dc97d03fce..6b23fe17493 100644 --- a/modules/azure/build.gradle +++ b/modules/azure/build.gradle @@ -11,4 +11,5 @@ dependencies { testImplementation 'com.azure:azure-storage-queue:12.24.0' testImplementation 'com.azure:azure-data-tables:12.5.0' testImplementation 'com.azure:azure-messaging-eventhubs:5.19.2' + testImplementation 'org.apache.kafka:kafka-clients:3.8.0' } diff --git a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java similarity index 69% rename from modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java rename to modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java index 9a7ef2f3094..a69291e0f35 100644 --- a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventhubsEmulatorContainer.java +++ b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java @@ -17,7 +17,7 @@ *
  • Kafka: 9092
  • * */ -public class AzureEventhubsEmulatorContainer extends GenericContainer { +public class AzureEventHubsEmulatorContainer extends GenericContainer { private static final int DEFAULT_AMQP_PORT = 5672; @@ -26,6 +26,8 @@ public class AzureEventhubsEmulatorContainer extends GenericContainer { private static final String WELL_KNOWN_ACCOUNT_KEY = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw=="; - static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("mcr.microsoft.com/azure-storage/azurite"); + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse( + "mcr.microsoft.com/azure-storage/azurite" + ); private MountableFile cert = null; diff --git a/modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java b/modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java new file mode 100644 index 00000000000..5f72f9eb741 --- /dev/null +++ b/modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java @@ -0,0 +1,158 @@ +package org.testcontainers.azure; + +import com.azure.core.util.IterableStream; +import com.azure.messaging.eventhubs.EventData; +import com.azure.messaging.eventhubs.EventHubClientBuilder; +import com.azure.messaging.eventhubs.EventHubConsumerClient; +import com.azure.messaging.eventhubs.EventHubProducerClient; +import com.azure.messaging.eventhubs.models.EventPosition; +import com.azure.messaging.eventhubs.models.PartitionEvent; +import com.google.common.collect.ImmutableMap; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.awaitility.Awaitility; +import org.junit.Rule; +import org.junit.Test; +import org.testcontainers.containers.Network; +import org.testcontainers.utility.DockerImageName; +import org.testcontainers.utility.MountableFile; + +import java.time.Duration; +import java.util.Collections; +import java.util.Optional; +import java.util.Properties; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.awaitility.Awaitility.waitAtMost; + +public class AzureEventHubsEmulatorContainerTest { + + @Rule + // network { + public Network network = Network.newNetwork(); + + // } + + @Rule + // azuriteContainer { + public AzuriteContainer azuriteContainer = new AzuriteContainer("mcr.microsoft.com/azure-storage/azurite:3.33.0") + .withNetwork(network); + + // } + + @Rule + // emulatorContainer { + public AzureEventHubsEmulatorContainer emulator = new AzureEventHubsEmulatorContainer( + DockerImageName.parse("mcr.microsoft.com/azure-messaging/eventhubs-emulator:2.0.1"), + azuriteContainer + ) + .acceptLicense() + .enableKafka() //optional + .withNetwork(network) + .withConfig(MountableFile.forClasspathResource("/eventhubs_config.json")); + + // } + + @Test + public void testWithEventhubsClient() { + try ( + // createProducerAndConsumer { + EventHubProducerClient producer = new EventHubClientBuilder() + .connectionString(emulator.getConnectionString()) + .fullyQualifiedNamespace("emulatorNs1") + .eventHubName("eh1") + .buildProducerClient(); + EventHubConsumerClient consumer = new EventHubClientBuilder() + .connectionString(emulator.getConnectionString()) + .fullyQualifiedNamespace("emulatorNs1") + .eventHubName("eh1") + .consumerGroup("cg1") + .buildConsumerClient() + // } + ) { + producer.send(Collections.singletonList(new EventData("test"))); + + waitAtMost(Duration.ofSeconds(30)) + .pollDelay(Duration.ofSeconds(5)) + .untilAsserted(() -> { + IterableStream events = consumer.receiveFromPartition( + "0", + 1, + EventPosition.earliest(), + Duration.ofSeconds(2) + ); + Optional event = events.stream().findFirst(); + assertThat(event).isPresent(); + assertThat(event.get().getData().getBodyAsString()).isEqualTo("test"); + }); + } + } + + @Test + public void testWithKafkaClient() throws Exception { + // kafkaProperties { + ImmutableMap commonProperties = ImmutableMap + .builder() + .put("bootstrap.servers", emulator.getBootstrapServers()) + .put("sasl.mechanism", "PLAIN") + .put("security.protocol", "SASL_PLAINTEXT") + .put( + "sasl.jaas.config", + String.format( + "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"$ConnectionString\" password=\"%s\";", + emulator.getConnectionString() + ) + ) + .build(); + // } + + Properties producerProperties = new Properties(); + producerProperties.put(ProducerConfig.CLIENT_ID_CONFIG, UUID.randomUUID().toString()); + producerProperties.putAll(commonProperties); + + Properties consumerProperties = new Properties(); + consumerProperties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "tc-" + UUID.randomUUID()); + consumerProperties.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + consumerProperties.putAll(commonProperties); + try ( + KafkaProducer producer = new KafkaProducer<>( + producerProperties, + new StringSerializer(), + new StringSerializer() + ); + KafkaConsumer consumer = new KafkaConsumer<>( + consumerProperties, + new StringDeserializer(), + new StringDeserializer() + ); + ) { + String topicName = "eh1"; + consumer.subscribe(Collections.singletonList(topicName)); + + producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); + + Awaitility + .await() + .atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + + assertThat(records) + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + }); + + consumer.unsubscribe(); + } + } +} diff --git a/modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java b/modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java deleted file mode 100644 index 997c6770fad..00000000000 --- a/modules/azure/src/test/java/org/testcontainers/azure/AzureEventhubsEmulatorContainerTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.testcontainers.azure; - -import com.azure.core.util.IterableStream; -import com.azure.messaging.eventhubs.EventData; -import com.azure.messaging.eventhubs.EventHubClientBuilder; -import com.azure.messaging.eventhubs.EventHubConsumerClient; -import com.azure.messaging.eventhubs.EventHubProducerClient; -import com.azure.messaging.eventhubs.models.EventPosition; -import com.azure.messaging.eventhubs.models.PartitionEvent; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.Network; -import org.testcontainers.utility.DockerImageName; -import org.testcontainers.utility.MountableFile; - -import java.time.Duration; -import java.util.Collections; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.awaitility.Awaitility.waitAtMost; - -public class AzureEventhubsEmulatorContainerTest { - - @Rule - // emulatorContainer { - public AzureEventhubsEmulatorContainer emulator = new AzureEventhubsEmulatorContainer( - DockerImageName.parse("mcr.microsoft.com/azure-messaging/eventhubs-emulator:2.0.1") - ) - .acceptLicense() - .withNetwork(Network.newNetwork()) - .withConfig(MountableFile.forClasspathResource("/eventhubs_config.json")); - - // } - - @Test - public void testWithEventhubsClient() { - try ( - // createProducerAndConsumer { - EventHubProducerClient producer = new EventHubClientBuilder() - .connectionString(emulator.getConnectionString()) - .fullyQualifiedNamespace("emulatorNs1") - .eventHubName("eh1") - .buildProducerClient(); - EventHubConsumerClient consumer = new EventHubClientBuilder() - .connectionString(emulator.getConnectionString()) - .fullyQualifiedNamespace("emulatorNs1") - .eventHubName("eh1") - .consumerGroup("cg1") - .buildConsumerClient() - // } - ) { - producer.send(Collections.singletonList(new EventData("test"))); - - waitAtMost(Duration.ofSeconds(30)) - .pollDelay(Duration.ofSeconds(5)) - .untilAsserted(() -> { - IterableStream events = consumer.receiveFromPartition( - "0", - 1, - EventPosition.earliest(), - Duration.ofSeconds(2) - ); - Optional event = events.stream().findFirst(); - assertThat(event).isPresent(); - assertThat(event.get().getData().getBodyAsString()).isEqualTo("test"); - }); - } - } -} From 1a65bf3ee5d5cc9c462aadc0f6f043fce09e7261 Mon Sep 17 00:00:00 2001 From: Esta Nagy Date: Fri, 10 Jan 2025 22:14:18 +0100 Subject: [PATCH 4/8] Add Azure Event Hubs Emulator container to Azure module - Fix typos Signed-off-by: Esta Nagy --- docs/modules/azure.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/azure.md b/docs/modules/azure.md index c54ae22a4aa..3984a8caa1f 100644 --- a/docs/modules/azure.md +++ b/docs/modules/azure.md @@ -82,7 +82,7 @@ Build Azure Table client: Start Azure Event Hubs Emulator during a test: -[Setting uo a network](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:network +[Setting up a network](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:network @@ -90,7 +90,7 @@ Start Azure Event Hubs Emulator during a test: -[Starting a Azure Event Hubs Emulator container](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:emulatorContainer +[Starting an Azure Event Hubs Emulator container](../../modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java) inside_block:emulatorContainer #### Using Azure Event Hubs clients From 376617f8ce4bf7b50d0d2a4d27c1af7cd25030d7 Mon Sep 17 00:00:00 2001 From: Esta Nagy Date: Fri, 10 Jan 2025 22:17:33 +0100 Subject: [PATCH 5/8] Add Azure Event Hubs Emulator container to Azure module - Fix test method name Signed-off-by: Esta Nagy --- .../azure/AzureEventHubsEmulatorContainerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java b/modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java index 5f72f9eb741..fbd072881bf 100644 --- a/modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java +++ b/modules/azure/src/test/java/org/testcontainers/azure/AzureEventHubsEmulatorContainerTest.java @@ -63,7 +63,7 @@ public class AzureEventHubsEmulatorContainerTest { // } @Test - public void testWithEventhubsClient() { + public void testWithEventHubsClient() { try ( // createProducerAndConsumer { EventHubProducerClient producer = new EventHubClientBuilder() From 6046fea4a1e2ecd577f7df6d0b279ffba0d422dd Mon Sep 17 00:00:00 2001 From: Esta Nagy Date: Fri, 10 Jan 2025 22:20:28 +0100 Subject: [PATCH 6/8] Add Azure Event Hubs Emulator container to Azure module - Polish Signed-off-by: Esta Nagy --- .../azure/AzureEventHubsEmulatorContainer.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java index a69291e0f35..825d31bc268 100644 --- a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java +++ b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java @@ -32,7 +32,7 @@ public class AzureEventHubsEmulatorContainer extends GenericContainer Date: Wed, 15 Jan 2025 22:15:37 +0100 Subject: [PATCH 7/8] Add Azure Event Hubs Emulator container to Azure module - Simplify config Signed-off-by: Esta Nagy --- .../azure/AzureEventHubsEmulatorContainer.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java index 825d31bc268..7149b73281a 100644 --- a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java +++ b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java @@ -34,8 +34,6 @@ public class AzureEventHubsEmulatorContainer extends GenericContainer Date: Thu, 16 Jan 2025 23:11:09 +0100 Subject: [PATCH 8/8] Add Azure Event Hubs Emulator container to Azure module - Fix code review findings Signed-off-by: Esta Nagy --- .../AzureEventHubsEmulatorContainer.java | 35 ++++- .../AzureEventHubsEmulatorContainerTest.java | 134 +++++++++--------- 2 files changed, 93 insertions(+), 76 deletions(-) diff --git a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java index 7149b73281a..02bf61bff05 100644 --- a/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java +++ b/modules/azure/src/main/java/org/testcontainers/azure/AzureEventHubsEmulatorContainer.java @@ -32,25 +32,39 @@ public class AzureEventHubsEmulatorContainer extends GenericContainer { - IterableStream events = consumer.receiveFromPartition( - "0", - 1, - EventPosition.earliest(), - Duration.ofSeconds(2) - ); - Optional event = events.stream().findFirst(); - assertThat(event).isPresent(); - assertThat(event.get().getData().getBodyAsString()).isEqualTo("test"); - }); + .pollDelay(Duration.ofSeconds(5)) + .untilAsserted(() -> { + IterableStream events = consumer.receiveFromPartition( + "0", + 1, + EventPosition.earliest(), + Duration.ofSeconds(2) + ); + Optional event = events.stream().findFirst(); + assertThat(event).isPresent(); + assertThat(event.get().getData().getBodyAsString()).isEqualTo("test"); + }); } } @@ -101,18 +97,18 @@ public void testWithEventHubsClient() { public void testWithKafkaClient() throws Exception { // kafkaProperties { ImmutableMap commonProperties = ImmutableMap - .builder() - .put("bootstrap.servers", emulator.getBootstrapServers()) - .put("sasl.mechanism", "PLAIN") - .put("security.protocol", "SASL_PLAINTEXT") - .put( - "sasl.jaas.config", - String.format( - "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"$ConnectionString\" password=\"%s\";", - emulator.getConnectionString() + .builder() + .put("bootstrap.servers", emulator.getBootstrapServers()) + .put("sasl.mechanism", "PLAIN") + .put("security.protocol", "SASL_PLAINTEXT") + .put( + "sasl.jaas.config", + String.format( + "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"$ConnectionString\" password=\"%s\";", + emulator.getConnectionString() + ) ) - ) - .build(); + .build(); // } Properties producerProperties = new Properties(); @@ -123,34 +119,34 @@ public void testWithKafkaClient() throws Exception { consumerProperties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "tc-" + UUID.randomUUID()); consumerProperties.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); consumerProperties.putAll(commonProperties); + try ( - KafkaProducer producer = new KafkaProducer<>( - producerProperties, - new StringSerializer(), - new StringSerializer() - ); - KafkaConsumer consumer = new KafkaConsumer<>( - consumerProperties, - new StringDeserializer(), - new StringDeserializer() - ); + KafkaProducer producer = new KafkaProducer<>( + producerProperties, + new StringSerializer(), + new StringSerializer() + ); + KafkaConsumer consumer = new KafkaConsumer<>( + consumerProperties, + new StringDeserializer(), + new StringDeserializer() + ); ) { String topicName = "eh1"; consumer.subscribe(Collections.singletonList(topicName)); producer.send(new ProducerRecord<>(topicName, "testcontainers", "rulezzz")).get(); - Awaitility - .await() - .atMost(Duration.ofSeconds(10)) - .untilAsserted(() -> { - ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); - - assertThat(records) - .hasSize(1) - .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) - .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); - }); + await() + .atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + + assertThat(records) + .hasSize(1) + .extracting(ConsumerRecord::topic, ConsumerRecord::key, ConsumerRecord::value) + .containsExactly(tuple(topicName, "testcontainers", "rulezzz")); + }); consumer.unsubscribe(); }