Skip to content

Commit 46d2beb

Browse files
authored
Add docker related unit tests in new projects (#825)
1 parent 76155ab commit 46d2beb

42 files changed

Lines changed: 2208 additions & 85 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pom.xml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,19 @@
7979
<module>storage/spring-cloud-azure-starter-storage-file-share/storage-file-sample</module>
8080
<module>storage/spring-cloud-azure-starter-storage-queue/storage-queue-client</module>
8181
<module>storage/spring-messaging-azure-storage-queue/storage-queue-spring-messaging</module>
82-
<module>testcontainers/spring-cloud-azure-testcontainers-for-cosmos-sample</module>
83-
<module>testcontainers/spring-cloud-azure-testcontainers-for-storage-blob-sample</module>
84-
<module>testcontainers/spring-cloud-azure-testcontainers-for-storage-queue-sample</module>
82+
<module>spring-cloud-azure-docker-compose/event-hubs/client</module>
83+
<module>spring-cloud-azure-docker-compose/event-hubs/spring-cloud-stream-binders</module>
84+
<module>spring-cloud-azure-docker-compose/service-bus/spring-cloud-stream-binders</module>
85+
<module>spring-cloud-azure-docker-compose/service-bus/spring-messaging</module>
86+
<module>spring-cloud-azure-docker-compose/storage-blob</module>
87+
<module>spring-cloud-azure-docker-compose/storage-queue</module>
88+
<module>spring-cloud-azure-testcontainers/cosmos</module>
89+
<module>spring-cloud-azure-testcontainers/event-hubs/client</module>
90+
<module>spring-cloud-azure-testcontainers/event-hubs/spring-cloud-stream-binders</module>
91+
<module>spring-cloud-azure-testcontainers/service-bus/spring-cloud-stream-binders</module>
92+
<module>spring-cloud-azure-testcontainers/service-bus/spring-messaging</module>
93+
<module>spring-cloud-azure-testcontainers/storage-blob</module>
94+
<module>spring-cloud-azure-testcontainers/storage-queue</module>
8595
</modules>
8696

8797
</project>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns="http://maven.apache.org/POM/4.0.0"
5+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<parent>
9+
<groupId>org.springframework.boot</groupId>
10+
<artifactId>spring-boot-starter-parent</artifactId>
11+
<version>4.0.3</version>
12+
<relativePath/> <!-- lookup parent from repository -->
13+
</parent>
14+
15+
<groupId>com.azure.spring</groupId>
16+
<artifactId>spring-cloud-azure-docker-compose-for-event-hubs-client-sample</artifactId>
17+
<version>1.0.0</version>
18+
<packaging>jar</packaging>
19+
20+
<properties>
21+
<maven.compiler.source>17</maven.compiler.source>
22+
<maven.compiler.target>17</maven.compiler.target>
23+
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
24+
</properties>
25+
26+
<dependencyManagement>
27+
<dependencies>
28+
<dependency>
29+
<groupId>com.azure.spring</groupId>
30+
<artifactId>spring-cloud-azure-dependencies</artifactId>
31+
<version>${version.spring.cloud.azure}</version>
32+
<type>pom</type>
33+
<scope>import</scope>
34+
</dependency>
35+
</dependencies>
36+
</dependencyManagement>
37+
38+
<dependencies>
39+
<dependency>
40+
<groupId>com.azure.spring</groupId>
41+
<artifactId>spring-cloud-azure-starter-eventhubs</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.springframework.boot</groupId>
45+
<artifactId>spring-boot-starter-test</artifactId>
46+
<scope>test</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>com.azure.spring</groupId>
50+
<artifactId>spring-cloud-azure-docker-compose</artifactId>
51+
<scope>test</scope>
52+
</dependency>
53+
</dependencies>
54+
55+
</project>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import com.azure.messaging.eventhubs.EventData;
2+
import com.azure.messaging.eventhubs.EventHubProducerClient;
3+
import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
4+
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
5+
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
6+
import org.junit.jupiter.api.Test;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
9+
import org.springframework.boot.test.context.SpringBootTest;
10+
import org.springframework.context.annotation.Configuration;
11+
12+
import java.time.Duration;
13+
import java.util.Collections;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
import static org.awaitility.Awaitility.waitAtMost;
17+
18+
@SpringBootTest(properties = {
19+
"spring.docker.compose.skip.in-tests=false",
20+
"spring.docker.compose.file=classpath:eventhubs-compose.yaml",
21+
"spring.docker.compose.stop.command=down",
22+
"spring.docker.compose.readiness.timeout=PT5M",
23+
"spring.cloud.azure.eventhubs.event-hub-name=eh1",
24+
"spring.cloud.azure.eventhubs.producer.event-hub-name=eh1"
25+
})
26+
class EventHubsDockerComposeTest {
27+
28+
@Autowired
29+
private AzureEventHubsConnectionDetails connectionDetails;
30+
31+
@Autowired
32+
private EventHubProducerClient producerClient;
33+
34+
@Test
35+
void connectionDetailsShouldBeProvidedByFactory() {
36+
assertThat(connectionDetails).isNotNull();
37+
assertThat(connectionDetails.getConnectionString())
38+
.isNotBlank()
39+
.startsWith("Endpoint=sb://");
40+
}
41+
42+
@Test
43+
void producerClientCanSendMessage() {
44+
// Wait for Event Hubs emulator to be fully ready and event hub entity to be available
45+
waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
46+
EventData event = new EventData("Hello World!");
47+
this.producerClient.send(Collections.singletonList(event));
48+
});
49+
}
50+
51+
@Configuration(proxyBeanMethods = false)
52+
@ImportAutoConfiguration(classes = {
53+
AzureGlobalPropertiesAutoConfiguration.class,
54+
AzureEventHubsAutoConfiguration.class})
55+
static class Config {
56+
}
57+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"UserConfig": {
3+
"NamespaceConfig": [
4+
{
5+
"Type": "EventHub",
6+
"Name": "emulatorns1",
7+
"Entities": [
8+
{
9+
"Name": "eh1",
10+
"PartitionCount": "2",
11+
"ConsumerGroups": []
12+
}
13+
]
14+
}
15+
],
16+
"LoggingConfig": {
17+
"Type": "File"
18+
}
19+
}
20+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
services:
2+
eventhubs:
3+
image: mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest
4+
pull_policy: always
5+
volumes:
6+
# Mount the emulator configuration to the path expected by the emulator image
7+
- "./Config.json:/Eventhubs_Emulator/ConfigFiles/Config.json"
8+
ports:
9+
- "5672"
10+
environment:
11+
# Event Hubs emulator requires external blob/metadata storage provided by azurite
12+
BLOB_SERVER: azurite
13+
METADATA_SERVER: azurite
14+
ACCEPT_EULA: Y
15+
depends_on:
16+
- azurite
17+
networks:
18+
eh-emulator:
19+
aliases:
20+
- "eh-emulator"
21+
22+
azurite:
23+
image: "mcr.microsoft.com/azure-storage/azurite:latest"
24+
ports:
25+
- "10000"
26+
- "10001"
27+
- "10002"
28+
networks:
29+
eh-emulator:
30+
aliases:
31+
- "azurite"
32+
33+
networks:
34+
eh-emulator:
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns="http://maven.apache.org/POM/4.0.0"
5+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<parent>
9+
<groupId>org.springframework.boot</groupId>
10+
<artifactId>spring-boot-starter-parent</artifactId>
11+
<version>4.0.3</version>
12+
<relativePath/> <!-- lookup parent from repository -->
13+
</parent>
14+
15+
<groupId>com.azure.spring</groupId>
16+
<artifactId>spring-cloud-azure-docker-compose-for-event-hubs-spring-cloud-stream-sample</artifactId>
17+
<version>1.0.0</version>
18+
<packaging>jar</packaging>
19+
20+
<properties>
21+
<maven.compiler.source>17</maven.compiler.source>
22+
<maven.compiler.target>17</maven.compiler.target>
23+
<version.spring.cloud.azure>7.1.0</version.spring.cloud.azure>
24+
</properties>
25+
26+
<dependencyManagement>
27+
<dependencies>
28+
<dependency>
29+
<groupId>com.azure.spring</groupId>
30+
<artifactId>spring-cloud-azure-dependencies</artifactId>
31+
<version>${version.spring.cloud.azure}</version>
32+
<type>pom</type>
33+
<scope>import</scope>
34+
</dependency>
35+
</dependencies>
36+
</dependencyManagement>
37+
38+
<dependencies>
39+
<dependency>
40+
<groupId>com.azure</groupId>
41+
<artifactId>azure-messaging-eventhubs</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>com.azure.spring</groupId>
45+
<artifactId>spring-cloud-azure-stream-binder-eventhubs</artifactId>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.springframework.boot</groupId>
49+
<artifactId>spring-boot-starter-test</artifactId>
50+
<scope>test</scope>
51+
</dependency>
52+
<dependency>
53+
<groupId>com.azure.spring</groupId>
54+
<artifactId>spring-cloud-azure-docker-compose</artifactId>
55+
<scope>test</scope>
56+
</dependency>
57+
</dependencies>
58+
59+
</project>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import com.azure.messaging.eventhubs.checkpointstore.blob.BlobCheckpointStore;
2+
import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
3+
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
4+
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsMessagingAutoConfiguration;
5+
import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobConnectionDetails;
6+
import com.azure.spring.messaging.checkpoint.Checkpointer;
7+
import com.azure.storage.blob.BlobContainerAsyncClient;
8+
import com.azure.storage.blob.BlobServiceAsyncClient;
9+
import com.azure.storage.blob.BlobServiceClientBuilder;
10+
import org.junit.jupiter.api.Test;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
13+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
14+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
15+
import org.springframework.boot.test.context.SpringBootTest;
16+
import org.springframework.context.annotation.Bean;
17+
import org.springframework.context.annotation.Configuration;
18+
import org.springframework.messaging.Message;
19+
import org.springframework.messaging.support.MessageBuilder;
20+
21+
import java.time.Duration;
22+
import java.util.Set;
23+
import java.util.concurrent.ConcurrentHashMap;
24+
import java.util.concurrent.atomic.AtomicInteger;
25+
import java.util.function.Consumer;
26+
import java.util.function.Supplier;
27+
28+
import static com.azure.spring.messaging.AzureHeaders.CHECKPOINTER;
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.awaitility.Awaitility.waitAtMost;
31+
32+
@SpringBootTest(properties = {
33+
"spring.docker.compose.skip.in-tests=false",
34+
"spring.docker.compose.file=classpath:eventhubs-compose.yaml",
35+
"spring.docker.compose.stop.command=down",
36+
"spring.docker.compose.readiness.timeout=PT5M",
37+
"spring.cloud.function.definition=consume;supply",
38+
"spring.cloud.stream.bindings.consume-in-0.destination=eh1",
39+
"spring.cloud.stream.bindings.consume-in-0.group=$Default",
40+
"spring.cloud.stream.bindings.supply-out-0.destination=eh1",
41+
"spring.cloud.stream.eventhubs.bindings.consume-in-0.consumer.checkpoint.mode=MANUAL",
42+
"spring.cloud.stream.poller.fixed-delay=1000",
43+
"spring.cloud.stream.poller.initial-delay=0"
44+
})
45+
class EventHubsDockerComposeTest {
46+
47+
private static final Logger LOGGER = LoggerFactory.getLogger(EventHubsDockerComposeTest.class);
48+
private static final Set<String> RECEIVED_MESSAGES = ConcurrentHashMap.newKeySet();
49+
private static final AtomicInteger MESSAGE_SEQUENCE = new AtomicInteger(0);
50+
51+
@Test
52+
void supplierAndConsumerShouldWorkThroughEventHub() {
53+
waitAtMost(Duration.ofSeconds(120))
54+
.pollDelay(Duration.ofSeconds(2))
55+
.pollInterval(Duration.ofSeconds(2))
56+
.untilAsserted(() -> {
57+
assertThat(RECEIVED_MESSAGES).isNotEmpty();
58+
LOGGER.info("✓ Test passed - Consumer received {} message(s)", RECEIVED_MESSAGES.size());
59+
});
60+
}
61+
62+
@Configuration(proxyBeanMethods = false)
63+
@EnableAutoConfiguration
64+
@ImportAutoConfiguration(classes = {
65+
AzureGlobalPropertiesAutoConfiguration.class,
66+
AzureEventHubsAutoConfiguration.class,
67+
AzureEventHubsMessagingAutoConfiguration.class})
68+
static class Config {
69+
70+
private static final String CHECKPOINT_CONTAINER_NAME = "eventhubs-checkpoint";
71+
72+
@Bean
73+
public BlobCheckpointStore blobCheckpointStore(AzureStorageBlobConnectionDetails connectionDetails) {
74+
BlobServiceAsyncClient blobServiceAsyncClient = new BlobServiceClientBuilder()
75+
.connectionString(connectionDetails.getConnectionString())
76+
.buildAsyncClient();
77+
BlobContainerAsyncClient containerAsyncClient = blobServiceAsyncClient
78+
.getBlobContainerAsyncClient(CHECKPOINT_CONTAINER_NAME);
79+
if (Boolean.FALSE.equals(containerAsyncClient.exists().block(Duration.ofSeconds(3)))) {
80+
containerAsyncClient.create().block(Duration.ofSeconds(3));
81+
}
82+
return new BlobCheckpointStore(containerAsyncClient);
83+
}
84+
85+
@Bean
86+
public Supplier<Message<String>> supply() {
87+
return () -> {
88+
int sequence = MESSAGE_SEQUENCE.getAndIncrement();
89+
String payload = "Hello world, " + sequence;
90+
LOGGER.info("[Supplier] Invoked - message sequence: {}", sequence);
91+
return MessageBuilder.withPayload(payload).build();
92+
};
93+
}
94+
95+
@Bean
96+
public Consumer<Message<String>> consume() {
97+
return message -> {
98+
String payload = message.getPayload();
99+
RECEIVED_MESSAGES.add(payload);
100+
LOGGER.info("[Consumer] Received message: {}", payload);
101+
102+
Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
103+
if (checkpointer != null) {
104+
checkpointer.success()
105+
.doOnSuccess(s -> LOGGER.info("[Consumer] Message checkpointed"))
106+
.doOnError(e -> LOGGER.error("[Consumer] Checkpoint failed", e))
107+
.block();
108+
}
109+
};
110+
}
111+
}
112+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"UserConfig": {
3+
"NamespaceConfig": [
4+
{
5+
"Type": "EventHub",
6+
"Name": "emulatorns1",
7+
"Entities": [
8+
{
9+
"Name": "eh1",
10+
"PartitionCount": "2",
11+
"ConsumerGroups": []
12+
}
13+
]
14+
}
15+
],
16+
"LoggingConfig": {
17+
"Type": "File"
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)