Skip to content

Commit 55c61c7

Browse files
codebase/introduction-to-automq [BAEL-8707] (#18070)
* add article codebase * add comment for removing container_name property * update indentation * update indentation * update topic name property key * update listener to use shorthand for topics attribute * add logback-spring.xml * override default forkedProcessExitTimeoutInSeconds surefire configuration * add comment for overriding forkedProcessExitTimeoutInSeconds * remove unused import
1 parent 1873492 commit 55c61c7

File tree

10 files changed

+264
-1
lines changed

10 files changed

+264
-1
lines changed

messaging-modules/automq/pom.xml

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<artifactId>automq</artifactId>
7+
<version>0.0.1</version>
8+
<packaging>jar</packaging>
9+
<name>automq</name>
10+
<description>codebase demonstrating integration of AutoMQ with Spring Boot</description>
11+
12+
<parent>
13+
<groupId>com.baeldung</groupId>
14+
<artifactId>messaging-modules</artifactId>
15+
<version>0.0.1-SNAPSHOT</version>
16+
</parent>
17+
18+
<dependencies>
19+
<dependency>
20+
<groupId>org.springframework.boot</groupId>
21+
<artifactId>spring-boot-starter-web</artifactId>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.springframework.kafka</groupId>
25+
<artifactId>spring-kafka</artifactId>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>org.springframework.boot</groupId>
30+
<artifactId>spring-boot-starter-test</artifactId>
31+
<scope>test</scope>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-testcontainers</artifactId>
36+
<scope>test</scope>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.awaitility</groupId>
40+
<artifactId>awaitility</artifactId>
41+
<scope>test</scope>
42+
</dependency>
43+
</dependencies>
44+
45+
<build>
46+
<plugins>
47+
<plugin>
48+
<groupId>org.springframework.boot</groupId>
49+
<artifactId>spring-boot-maven-plugin</artifactId>
50+
</plugin>
51+
<plugin>
52+
<groupId>org.apache.maven.plugins</groupId>
53+
<artifactId>maven-surefire-plugin</artifactId>
54+
<!-- Reducing forked process timeout to 2 seconds for faster test execution.
55+
In production, consider using longer timeouts to ensure proper container cleanup.
56+
-->
57+
<configuration>
58+
<forkedProcessExitTimeoutInSeconds>2</forkedProcessExitTimeoutInSeconds>
59+
</configuration>
60+
</plugin>
61+
<plugin>
62+
<groupId>org.apache.maven.plugins</groupId>
63+
<artifactId>maven-compiler-plugin</artifactId>
64+
<configuration>
65+
<source>17</source>
66+
<target>17</target>
67+
</configuration>
68+
</plugin>
69+
</plugins>
70+
</build>
71+
72+
<properties>
73+
<spring-boot.version>3.4.0</spring-boot.version>
74+
</properties>
75+
76+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.automq;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class Application {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(Application.class, args);
11+
}
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.baeldung.automq;
2+
3+
public record User(String email) {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.baeldung.automq;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.kafka.annotation.KafkaListener;
7+
8+
@Configuration
9+
public class UserOnboardingInitiatedListener {
10+
11+
private static final Logger log = LoggerFactory.getLogger(UserOnboardingInitiatedListener.class);
12+
13+
@KafkaListener(topics = "${com.baeldung.topic.onboarding-initiated}", groupId = "user-service")
14+
public void listen(final User user) {
15+
log.info("Dispatching user account confirmation email to {}", user.email());
16+
}
17+
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
spring:
2+
kafka:
3+
consumer:
4+
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
5+
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
6+
producer:
7+
key-serializer: org.apache.kafka.common.serialization.StringSerializer
8+
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
9+
properties:
10+
spring.json.value.default.type: com.baeldung.automq.User
11+
allow.auto.create.topics: true
12+
13+
com:
14+
baeldung:
15+
topic:
16+
onboarding-initiated: user-service.onboarding.initiated.v1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<configuration>
2+
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
3+
<encoder>
4+
<pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%p] [%c{1}] - %m%n</pattern>
5+
</encoder>
6+
</appender>
7+
8+
<root level="INFO">
9+
<appender-ref ref="CONSOLE" />
10+
</root>
11+
12+
<logger name="org.springframework" level="INFO" additivity="false">
13+
<appender-ref ref="CONSOLE" />
14+
</logger>
15+
</configuration>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.automq;
2+
3+
import org.springframework.boot.SpringApplication;
4+
5+
public class TestApplication {
6+
7+
public static void main(String[] args) {
8+
SpringApplication.from(Application::main)
9+
.with(TestcontainersConfiguration.class)
10+
.run(args);
11+
}
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.baeldung.automq;
2+
3+
import org.springframework.boot.test.context.TestConfiguration;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.test.context.DynamicPropertyRegistrar;
6+
import org.testcontainers.containers.ComposeContainer;
7+
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
8+
9+
import java.io.File;
10+
import java.io.IOException;
11+
import java.net.URI;
12+
import java.nio.file.Files;
13+
import java.util.List;
14+
15+
@TestConfiguration(proxyBeanMethods = false)
16+
class TestcontainersConfiguration {
17+
18+
private static final String COMPOSE_URL = "https://download.automq.com/community_edition/standalone_deployment/docker-compose.yaml";
19+
20+
@Bean
21+
public ComposeContainer composeContainer() throws IOException {
22+
File dockerCompose = downloadComposeFile();
23+
return new ComposeContainer(dockerCompose)
24+
.withLocalCompose(true);
25+
}
26+
27+
@Bean
28+
public DynamicPropertyRegistrar dynamicPropertyRegistrar() {
29+
return registry -> {
30+
registry.add("spring.kafka.bootstrap-servers", () -> "localhost:9094,localhost:9095");
31+
};
32+
}
33+
34+
private File downloadComposeFile() throws IOException {
35+
File dockerCompose = Files.createTempFile("docker-compose", ".yaml").toFile();
36+
dockerCompose.deleteOnExit();
37+
FileUtils.copyURLToFile(URI.create(COMPOSE_URL).toURL(), dockerCompose);
38+
return removeContainerNames(dockerCompose);
39+
}
40+
41+
/**
42+
* The container_name property of Docker Compose is not currently supported by Testcontainers.
43+
* The issue can be tracked at https://github.com/testcontainers/testcontainers-java/issues/2472
44+
*/
45+
private File removeContainerNames(File composeFile) throws IOException {
46+
List<String> filteredLines = Files.readAllLines(composeFile.toPath())
47+
.stream()
48+
.filter(line -> !line.contains("container_name:"))
49+
.toList();
50+
Files.write(composeFile.toPath(), filteredLines);
51+
return composeFile;
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.baeldung.automq;
2+
3+
import org.awaitility.Awaitility;
4+
import org.awaitility.Durations;
5+
import org.junit.jupiter.api.BeforeAll;
6+
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.api.TestInstance;
8+
import org.junit.jupiter.api.extension.ExtendWith;
9+
import org.springframework.beans.factory.annotation.Autowired;
10+
import org.springframework.beans.factory.annotation.Value;
11+
import org.springframework.boot.test.context.SpringBootTest;
12+
import org.springframework.boot.test.system.CapturedOutput;
13+
import org.springframework.boot.test.system.OutputCaptureExtension;
14+
import org.springframework.context.annotation.Import;
15+
import org.springframework.kafka.core.KafkaTemplate;
16+
17+
import java.util.concurrent.TimeUnit;
18+
19+
@SpringBootTest
20+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
21+
@ExtendWith(OutputCaptureExtension.class)
22+
@Import(TestcontainersConfiguration.class)
23+
class UserOnboardingInitiatedListenerLiveTest {
24+
25+
@Autowired
26+
private KafkaTemplate<String, User> kafkaTemplate;
27+
28+
@Value("${com.baeldung.topic.onboarding-initiated}")
29+
private String onboardingInitiatedTopic;
30+
31+
@BeforeAll
32+
void setUp(CapturedOutput capturedOutput) {
33+
String expectedLog = "partitions assigned";
34+
Awaitility
35+
.await()
36+
.atMost(Durations.ONE_MINUTE)
37+
.pollDelay(Durations.ONE_SECOND)
38+
.until(() -> capturedOutput.getAll().contains(expectedLog));
39+
}
40+
41+
@Test
42+
void whenMessagePublishedToTopic_thenProcessedByListener(CapturedOutput capturedOutput) {
43+
User user = new User("[email protected]");
44+
kafkaTemplate.send(onboardingInitiatedTopic, user);
45+
46+
String expectedConsumerLog = String.format("Dispatching user account confirmation email to %s", user.email());
47+
Awaitility
48+
.await()
49+
.atMost(1, TimeUnit.SECONDS)
50+
.until(() -> capturedOutput.getAll().contains(expectedConsumerLog));
51+
}
52+
53+
}

messaging-modules/pom.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<modules>
1818
<module>apache-camel</module>
1919
<module>apache-rocketmq</module>
20+
<module>automq</module>
2021
<module>jgroups</module>
2122
<module>java-redpanda</module>
2223
<module>rabbitmq</module>
@@ -27,4 +28,4 @@
2728
<module>ibm-mq</module>
2829
</modules>
2930

30-
</project>
31+
</project>

0 commit comments

Comments
 (0)