Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f5ef43c
Create project: spring-cloud-azure-testcontainers-for-service-bus-spr…
rujche Feb 26, 2026
84aa466
Create project: spring-cloud-azure-testcontainers-for-service-bus-spr…
rujche Feb 26, 2026
a59a4be
Change folder name
rujche Feb 26, 2026
ac11e2d
Create project: spring-cloud-azure-docker-compose/storage-blob
rujche Feb 26, 2026
116b70d
Create new project: spring-cloud-azure-docker-compose/service-bus/spr…
rujche Feb 26, 2026
5013b68
Create new project: spring-cloud-azure-docker-compose/service-bus/spr…
rujche Feb 26, 2026
4154381
Delete 'name' in pom files
rujche Feb 26, 2026
a5c59a7
Create new project: spring-cloud-azure-docker-compose/storage-queue
rujche Feb 26, 2026
8c7ce86
Create new project: spring-cloud-azure-docker-compose/event-hubs/client
rujche Feb 26, 2026
0e1f2b6
Create new project: spring-cloud-azure-docker-compose/event-hubs/spr…
rujche Feb 26, 2026
d2d64da
Create new project: spring-cloud-azure-testcontainers/event-hubs
rujche Feb 26, 2026
b3d87c8
Create new project: spring-cloud-azure-testcontainers/event-hubs/spr…
rujche Feb 26, 2026
ad7f616
Delete '-beta.1' in the spring cloud azure version
rujche Feb 26, 2026
d553193
Fix test failure by sync java code from blog
rujche Feb 26, 2026
8e8649d
Resolve comments from blog
rujche Feb 26, 2026
78e4655
Resolve PR comments
rujche Feb 26, 2026
ff2fdcf
Resolve PR comment
rujche Feb 26, 2026
110e3d8
Resolve the PR comment
rujche Feb 26, 2026
83ea201
Delete useless property
rujche Feb 27, 2026
1456d67
Update spring-cloud-azure-docker-compose/storage-blob/src/test/java/A…
rujche Feb 27, 2026
31e08e7
Resolve PR comment about block with duration
rujche Feb 27, 2026
5c23959
Sync content from blog
rujche Feb 27, 2026
5e08706
Remove unnecessary dependency: testcontainers-azure
rujche Mar 2, 2026
6b0d375
Sync dependencies between doc and samples
rujche Mar 11, 2026
7cef020
Merge branch 'main' into rujche/main/add-unit-test-about-docker-in-ne…
rujche Mar 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,19 @@
<module>storage/spring-cloud-azure-starter-storage-file-share/storage-file-sample</module>
<module>storage/spring-cloud-azure-starter-storage-queue/storage-queue-client</module>
<module>storage/spring-messaging-azure-storage-queue/storage-queue-spring-messaging</module>
<module>testcontainers/spring-cloud-azure-testcontainers-for-cosmos-sample</module>
<module>testcontainers/spring-cloud-azure-testcontainers-for-storage-blob-sample</module>
<module>testcontainers/spring-cloud-azure-testcontainers-for-storage-queue-sample</module>
<module>spring-cloud-azure-docker-compose/event-hubs/client</module>
<module>spring-cloud-azure-docker-compose/event-hubs/spring-cloud-stream-binders</module>
<module>spring-cloud-azure-docker-compose/service-bus/spring-cloud-stream-binders</module>
<module>spring-cloud-azure-docker-compose/service-bus/spring-messaging</module>
<module>spring-cloud-azure-docker-compose/storage-blob</module>
<module>spring-cloud-azure-docker-compose/storage-queue</module>
<module>spring-cloud-azure-testcontainers/cosmos</module>
<module>spring-cloud-azure-testcontainers/event-hubs/client</module>
<module>spring-cloud-azure-testcontainers/event-hubs/spring-cloud-stream-binders</module>
<module>spring-cloud-azure-testcontainers/service-bus/spring-cloud-stream-binders</module>
<module>spring-cloud-azure-testcontainers/service-bus/spring-messaging</module>
<module>spring-cloud-azure-testcontainers/storage-blob</module>
<module>spring-cloud-azure-testcontainers/storage-queue</module>
</modules>

</project>
55 changes: 55 additions & 0 deletions spring-cloud-azure-docker-compose/event-hubs/client/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose-for-event-hubs-client-sample</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-eventhubs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import com.azure.messaging.eventhubs.EventData;
import com.azure.messaging.eventhubs.EventHubProducerClient;
import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;
import java.util.Collections;

import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.waitAtMost;
Comment thread
rujche marked this conversation as resolved.

@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:eventhubs-compose.yaml",
"spring.docker.compose.stop.command=down",
"spring.docker.compose.readiness.timeout=PT5M",
"spring.cloud.azure.eventhubs.event-hub-name=eh1",
"spring.cloud.azure.eventhubs.producer.event-hub-name=eh1"
})
Comment thread
rujche marked this conversation as resolved.
Comment thread
rujche marked this conversation as resolved.
class EventHubsDockerComposeTest {

@Autowired
private AzureEventHubsConnectionDetails connectionDetails;

@Autowired
private EventHubProducerClient producerClient;

@Test
void connectionDetailsShouldBeProvidedByFactory() {
assertThat(connectionDetails).isNotNull();
assertThat(connectionDetails.getConnectionString())
.isNotBlank()
.startsWith("Endpoint=sb://");
}

@Test
void producerClientCanSendMessage() {
// Wait for Event Hubs emulator to be fully ready and event hub entity to be available
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
EventData event = new EventData("Hello World!");
this.producerClient.send(Collections.singletonList(event));
});
}

@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureEventHubsAutoConfiguration.class})
static class Config {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"UserConfig": {
"NamespaceConfig": [
{
"Type": "EventHub",
"Name": "emulatorns1",
"Entities": [
{
"Name": "eh1",
"PartitionCount": "2",
"ConsumerGroups": []
}
]
}
],
"LoggingConfig": {
"Type": "File"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
services:
eventhubs:
image: mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest
pull_policy: always
volumes:
# Mount the emulator configuration to the path expected by the emulator image
- "./Config.json:/Eventhubs_Emulator/ConfigFiles/Config.json"
ports:
- "5672"
environment:
# Event Hubs emulator requires external blob/metadata storage provided by azurite
BLOB_SERVER: azurite
METADATA_SERVER: azurite
ACCEPT_EULA: Y
depends_on:
- azurite
networks:
eh-emulator:
aliases:
- "eh-emulator"

azurite:
image: "mcr.microsoft.com/azure-storage/azurite:latest"
ports:
- "10000"
- "10001"
- "10002"
Comment thread
rujche marked this conversation as resolved.
networks:
eh-emulator:
aliases:
- "azurite"

networks:
eh-emulator:
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose-for-event-hubs-spring-cloud-stream-sample</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-dependencies</artifactId>
<version>${version.spring.cloud.azure}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-messaging-eventhubs</artifactId>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-stream-binder-eventhubs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-docker-compose</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import com.azure.messaging.eventhubs.checkpointstore.blob.BlobCheckpointStore;
import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsMessagingAutoConfiguration;
import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobConnectionDetails;
import com.azure.spring.messaging.checkpoint.Checkpointer;
import com.azure.storage.blob.BlobContainerAsyncClient;
import com.azure.storage.blob.BlobServiceAsyncClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;

import java.time.Duration;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;

import static com.azure.spring.messaging.AzureHeaders.CHECKPOINTER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.waitAtMost;
Comment thread
rujche marked this conversation as resolved.

@SpringBootTest(properties = {
"spring.docker.compose.skip.in-tests=false",
"spring.docker.compose.file=classpath:eventhubs-compose.yaml",
"spring.docker.compose.stop.command=down",
"spring.docker.compose.readiness.timeout=PT5M",
"spring.cloud.function.definition=consume;supply",
"spring.cloud.stream.bindings.consume-in-0.destination=eh1",
"spring.cloud.stream.bindings.consume-in-0.group=$Default",
"spring.cloud.stream.bindings.supply-out-0.destination=eh1",
"spring.cloud.stream.eventhubs.bindings.consume-in-0.consumer.checkpoint.mode=MANUAL",
"spring.cloud.stream.poller.fixed-delay=1000",
"spring.cloud.stream.poller.initial-delay=0"
})
class EventHubsDockerComposeTest {
Comment thread
rujche marked this conversation as resolved.

private static final Logger LOGGER = LoggerFactory.getLogger(EventHubsDockerComposeTest.class);
private static final Set<String> RECEIVED_MESSAGES = ConcurrentHashMap.newKeySet();
private static final AtomicInteger MESSAGE_SEQUENCE = new AtomicInteger(0);

@Test
void supplierAndConsumerShouldWorkThroughEventHub() {
waitAtMost(Duration.ofSeconds(120))
.pollDelay(Duration.ofSeconds(2))
.pollInterval(Duration.ofSeconds(2))
.untilAsserted(() -> {
assertThat(RECEIVED_MESSAGES).isNotEmpty();
LOGGER.info("✓ Test passed - Consumer received {} message(s)", RECEIVED_MESSAGES.size());
});
}

@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@ImportAutoConfiguration(classes = {
AzureGlobalPropertiesAutoConfiguration.class,
AzureEventHubsAutoConfiguration.class,
AzureEventHubsMessagingAutoConfiguration.class})
static class Config {

private static final String CHECKPOINT_CONTAINER_NAME = "eventhubs-checkpoint";

@Bean
public BlobCheckpointStore blobCheckpointStore(AzureStorageBlobConnectionDetails connectionDetails) {
BlobServiceAsyncClient blobServiceAsyncClient = new BlobServiceClientBuilder()
.connectionString(connectionDetails.getConnectionString())
.buildAsyncClient();
BlobContainerAsyncClient containerAsyncClient = blobServiceAsyncClient
.getBlobContainerAsyncClient(CHECKPOINT_CONTAINER_NAME);
if (Boolean.FALSE.equals(containerAsyncClient.exists().block(Duration.ofSeconds(3)))) {
containerAsyncClient.create().block(Duration.ofSeconds(3));
}
return new BlobCheckpointStore(containerAsyncClient);
}

@Bean
public Supplier<Message<String>> supply() {
return () -> {
int sequence = MESSAGE_SEQUENCE.getAndIncrement();
String payload = "Hello world, " + sequence;
LOGGER.info("[Supplier] Invoked - message sequence: {}", sequence);
return MessageBuilder.withPayload(payload).build();
};
}

@Bean
public Consumer<Message<String>> consume() {
return message -> {
String payload = message.getPayload();
RECEIVED_MESSAGES.add(payload);
LOGGER.info("[Consumer] Received message: {}", payload);

Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
if (checkpointer != null) {
checkpointer.success()
.doOnSuccess(s -> LOGGER.info("[Consumer] Message checkpointed"))
.doOnError(e -> LOGGER.error("[Consumer] Checkpoint failed", e))
.block();
}
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"UserConfig": {
"NamespaceConfig": [
{
"Type": "EventHub",
"Name": "emulatorns1",
"Entities": [
{
"Name": "eh1",
"PartitionCount": "2",
"ConsumerGroups": []
}
]
}
],
"LoggingConfig": {
"Type": "File"
}
}
}
Loading
Loading