Skip to content

Commit ec0ced4

Browse files
committed
Start an embedded Redis in NatsBackendEndToEndIT
The dashboard controller chain (RqueueRestController → RqueueDashboardChartServiceImpl → RqueueQStatsDaoImpl → RqueueConfig) currently still hard-requires a RedisConnectionFactory bean even when rqueue.backend=nats, so excluding DataRedisAutoConfiguration left the Spring context unable to load on the CI runner. Until those beans are made conditional on the broker's usesPrimaryHandlerDispatch capability (tracked as a v1.x follow-up), this e2e test starts an embedded Redis on a free port purely to satisfy the bean graph. The actual produce-and-consume flow runs entirely through JetStream — Redis is never touched by the message path. Assisted-By: Claude Code
1 parent 0bbc6f4 commit ec0ced4

1 file changed

Lines changed: 41 additions & 29 deletions

File tree

rqueue-spring-boot-starter/src/test/java/com/github/sonus21/rqueue/spring/boot/integration/NatsBackendEndToEndIT.java

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,18 @@
1919

2020
import com.github.sonus21.rqueue.annotation.RqueueListener;
2121
import com.github.sonus21.rqueue.core.RqueueMessageEnqueuer;
22+
import java.net.ServerSocket;
2223
import java.util.ArrayList;
2324
import java.util.Collections;
2425
import java.util.List;
2526
import java.util.concurrent.CountDownLatch;
2627
import java.util.concurrent.TimeUnit;
28+
import org.junit.jupiter.api.AfterAll;
29+
import org.junit.jupiter.api.BeforeAll;
2730
import org.junit.jupiter.api.Tag;
2831
import org.junit.jupiter.api.Test;
2932
import org.springframework.beans.factory.annotation.Autowired;
3033
import org.springframework.boot.autoconfigure.SpringBootApplication;
31-
import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;
32-
import org.springframework.boot.data.redis.autoconfigure.DataRedisReactiveAutoConfiguration;
3334
import org.springframework.boot.test.context.SpringBootTest;
3435
import org.springframework.stereotype.Component;
3536
import org.springframework.test.context.DynamicPropertyRegistry;
@@ -39,6 +40,7 @@
3940
import org.testcontainers.junit.jupiter.Container;
4041
import org.testcontainers.junit.jupiter.Testcontainers;
4142
import org.testcontainers.utility.DockerImageName;
43+
import redis.embedded.RedisServer;
4244

4345
/**
4446
* End-to-end integration test wiring a Spring Boot application against a Testcontainers-managed
@@ -50,21 +52,14 @@
5052
* -> BrokerMessagePoller.pop -> @RqueueListener invocation -> broker.ack
5153
* </pre>
5254
*
53-
* <h2>Why Redis auto-config is excluded</h2>
55+
* <h2>Why an embedded Redis is started</h2>
5456
*
55-
* The starter declares {@code spring-boot-starter-data-redis} as an {@code api} dependency, so
56-
* Spring Boot would try to auto-configure a {@code LettuceConnectionFactory} at startup and fail
57-
* the context because no Redis instance is available in this test. Excluding the Redis
58-
* auto-config classes on {@link TestApp} (rather than via property) keeps the exclusion local to
59-
* this test and visible to readers.
60-
*
61-
* <h2>Producer path</h2>
62-
*
63-
* The sync producer flows through {@code BaseMessageSender#enqueue} which now delegates to
64-
* {@code MessageBroker.enqueue(QueueDetail, RqueueMessage)} when the active broker advertises
65-
* {@code !usesPrimaryHandlerDispatch()}, and {@code storeMessageMetadata} short-circuits on the
66-
* same flag so no Redis HASH write is attempted. Together with the broker-driven poller this
67-
* exercises the full produce-and-consume loop without touching Redis.
57+
* Several rqueue beans (notably {@code RqueueConfig}, {@code RqueueQStatsDaoImpl}, and the
58+
* dashboard controller chain) currently still require a {@code RedisConnectionFactory} as a hard
59+
* Spring dependency, even when {@code rqueue.backend=nats}. Pure NATS-only deployments without
60+
* Redis on the classpath will need those beans to become conditional — tracked as a v1.x
61+
* follow-up. Until then this test starts an embedded Redis purely to satisfy the bean graph;
62+
* the actual message flow runs entirely through JetStream and never hits Redis.
6863
*/
6964
@SpringBootTest(
7065
classes = NatsBackendEndToEndIT.TestApp.class,
@@ -73,25 +68,43 @@
7368
@Tag("nats")
7469
class NatsBackendEndToEndIT {
7570

71+
private static RedisServer REDIS;
72+
private static int REDIS_PORT;
73+
7674
@Container
77-
static final GenericContainer<?> NATS = new GenericContainer<>(
78-
DockerImageName.parse("nats:2.10-alpine"))
79-
.withCommand("-js")
80-
.withExposedPorts(4222)
81-
.waitingFor(Wait.forLogMessage(".*Server is ready.*\\n", 1));
75+
static final GenericContainer<?> NATS =
76+
new GenericContainer<>(DockerImageName.parse("nats:2.10-alpine"))
77+
.withCommand("-js")
78+
.withExposedPorts(4222)
79+
.waitingFor(Wait.forLogMessage(".*Server is ready.*\\n", 1));
80+
81+
@BeforeAll
82+
static void startRedis() throws Exception {
83+
try (ServerSocket s = new ServerSocket(0)) {
84+
REDIS_PORT = s.getLocalPort();
85+
}
86+
REDIS = new RedisServer(REDIS_PORT);
87+
REDIS.start();
88+
}
89+
90+
@AfterAll
91+
static void stopRedis() throws Exception {
92+
if (REDIS != null) {
93+
REDIS.stop();
94+
}
95+
}
8296

8397
@DynamicPropertySource
84-
static void natsProps(DynamicPropertyRegistry r) {
98+
static void registerProps(DynamicPropertyRegistry r) {
8599
r.add(
86100
"rqueue.nats.connection.url",
87101
() -> "nats://" + NATS.getHost() + ":" + NATS.getMappedPort(4222));
102+
r.add("spring.data.redis.host", () -> "localhost");
103+
r.add("spring.data.redis.port", () -> REDIS_PORT);
88104
}
89105

90-
@Autowired
91-
RqueueMessageEnqueuer enqueuer;
92-
93-
@Autowired
94-
TestListener listener;
106+
@Autowired RqueueMessageEnqueuer enqueuer;
107+
@Autowired TestListener listener;
95108

96109
@Test
97110
void enqueueIsReceivedByListener() throws Exception {
@@ -103,8 +116,7 @@ void enqueueIsReceivedByListener() throws Exception {
103116
.containsExactlyInAnyOrder("payload-0", "payload-1", "payload-2", "payload-3", "payload-4");
104117
}
105118

106-
@SpringBootApplication(
107-
exclude = {DataRedisAutoConfiguration.class, DataRedisReactiveAutoConfiguration.class})
119+
@SpringBootApplication
108120
static class TestApp {}
109121

110122
@Component

0 commit comments

Comments
 (0)