|
14 | 14 | import com.github.sonus21.rqueue.core.RqueueMessage; |
15 | 15 | import com.github.sonus21.rqueue.listener.QueueDetail; |
16 | 16 | import com.github.sonus21.rqueue.nats.js.JetStreamMessageBroker; |
| 17 | +import com.github.sonus21.rqueue.serdes.SerializationUtils; |
| 18 | +import java.util.ArrayList; |
| 19 | +import java.util.List; |
| 20 | +import java.util.UUID; |
| 21 | +import lombok.AllArgsConstructor; |
| 22 | +import lombok.Data; |
| 23 | +import lombok.NoArgsConstructor; |
17 | 24 | import org.junit.jupiter.api.Test; |
18 | 25 | import reactor.core.publisher.Flux; |
19 | 26 | import reactor.test.StepVerifier; |
| 27 | +import tools.jackson.databind.ObjectMapper; |
20 | 28 |
|
21 | 29 | /** |
22 | | - * End-to-end producer-only smoke test: the broker enqueues messages but never pops or acks them. |
23 | | - * Covers plain enqueue, priority enqueue, and reactive enqueue — verifying that all variants land |
24 | | - * in JetStream and are reflected by {@link JetStreamMessageBroker#size}. |
| 30 | + * End-to-end producer-only smoke test: the broker enqueues typed domain events but never pops or |
| 31 | + * acks them, mirroring the producer-only application mode where the process only publishes work. |
| 32 | + * |
| 33 | + * <p>Covers plain enqueue, priority enqueue, and reactive enqueue — verifying that all variants |
| 34 | + * land in JetStream and are reflected by {@link JetStreamMessageBroker#size}. |
25 | 35 | */ |
26 | 36 | @NatsIntegrationTest |
27 | 37 | class JetStreamMessageBrokerProducerOnlyIT extends AbstractJetStreamIT { |
28 | 38 |
|
| 39 | + private static final ObjectMapper MAPPER = SerializationUtils.objectMapper; |
| 40 | + |
| 41 | + // ---- minimal domain events used as message payloads -------------------- |
| 42 | + |
| 43 | + @Data |
| 44 | + @NoArgsConstructor |
| 45 | + @AllArgsConstructor |
| 46 | + static class EmailEvent { |
| 47 | + private String id; |
| 48 | + private String to; |
| 49 | + private String subject; |
| 50 | + } |
| 51 | + |
| 52 | + @Data |
| 53 | + @NoArgsConstructor |
| 54 | + @AllArgsConstructor |
| 55 | + static class JobEvent { |
| 56 | + private String id; |
| 57 | + private String type; |
| 58 | + } |
| 59 | + |
| 60 | + @Data |
| 61 | + @NoArgsConstructor |
| 62 | + @AllArgsConstructor |
| 63 | + static class NotificationEvent { |
| 64 | + private String id; |
| 65 | + private String message; |
| 66 | + } |
| 67 | + |
| 68 | + // ---- helpers ----------------------------------------------------------- |
| 69 | + |
| 70 | + private static String serialize(Object event) throws Exception { |
| 71 | + return MAPPER.writeValueAsString(event); |
| 72 | + } |
| 73 | + |
| 74 | + private static RqueueMessage rqueueMessage(String id, Object event) throws Exception { |
| 75 | + return RqueueMessage.builder().id(id).message(serialize(event)).build(); |
| 76 | + } |
| 77 | + |
| 78 | + // ---- tests ------------------------------------------------------------- |
| 79 | + |
29 | 80 | @Test |
30 | | - void enqueue_messagesAccumulateInStream() throws Exception { |
31 | | - QueueDetail q = mockQueue("po-plain-" + System.nanoTime()); |
| 81 | + void enqueueEmailEvents_accumulateInStream() throws Exception { |
| 82 | + QueueDetail emailQueue = mockQueue("email-queue-" + System.nanoTime()); |
32 | 83 | try (JetStreamMessageBroker broker = |
33 | 84 | JetStreamMessageBroker.builder().connection(connection).build()) { |
34 | | - int count = 10; |
| 85 | + int count = 5; |
35 | 86 | for (int i = 0; i < count; i++) { |
36 | | - broker.enqueue( |
37 | | - q, RqueueMessage.builder().id("m-" + i).message("payload-" + i).build()); |
| 87 | + EmailEvent event = new EmailEvent(UUID.randomUUID().toString(), |
| 88 | + "user" + i + "@example.com", "Subject " + i); |
| 89 | + broker.enqueue(emailQueue, rqueueMessage("email-" + i, event)); |
38 | 90 | } |
39 | | - assertEquals(count, broker.size(q), "all enqueued messages should be visible in the stream"); |
| 91 | + assertEquals(count, broker.size(emailQueue), |
| 92 | + "all email events should be visible in the stream"); |
40 | 93 | } |
41 | 94 | } |
42 | 95 |
|
43 | 96 | @Test |
44 | | - void enqueueWithPriority_messagesAccumulateInPriorityStreams() throws Exception { |
45 | | - QueueDetail q = mockQueue("po-prio-" + System.nanoTime()); |
| 97 | + void enqueueJobEvents_accumulateInStream() throws Exception { |
| 98 | + QueueDetail jobQueue = mockQueue("job-queue-" + System.nanoTime()); |
46 | 99 | try (JetStreamMessageBroker broker = |
47 | 100 | JetStreamMessageBroker.builder().connection(connection).build()) { |
48 | | - String[] priorities = {"high", "low", "critical"}; |
49 | | - int perPriority = 5; |
| 101 | + String[] types = {"FULL_TIME", "PART_TIME", "CONTRACT"}; |
| 102 | + for (int i = 0; i < types.length; i++) { |
| 103 | + JobEvent event = new JobEvent(UUID.randomUUID().toString(), types[i]); |
| 104 | + broker.enqueue(jobQueue, rqueueMessage("job-" + i, event)); |
| 105 | + } |
| 106 | + assertEquals(types.length, broker.size(jobQueue), |
| 107 | + "all job events should be visible in the stream"); |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + @Test |
| 112 | + void enqueueWithPriority_notificationEvents_accumulateInPriorityStreams() throws Exception { |
| 113 | + QueueDetail notifQueue = mockQueue("notif-queue-" + System.nanoTime()); |
| 114 | + try (JetStreamMessageBroker broker = |
| 115 | + JetStreamMessageBroker.builder().connection(connection).build()) { |
| 116 | + String[] priorities = {"high", "low"}; |
| 117 | + int perPriority = 4; |
50 | 118 | for (String priority : priorities) { |
51 | 119 | for (int i = 0; i < perPriority; i++) { |
52 | | - broker.enqueue( |
53 | | - q, |
54 | | - priority, |
55 | | - RqueueMessage.builder() |
56 | | - .id(priority + "-m-" + i) |
57 | | - .message("payload-" + i) |
58 | | - .build()); |
| 120 | + NotificationEvent event = new NotificationEvent( |
| 121 | + UUID.randomUUID().toString(), priority + "-notification-" + i); |
| 122 | + broker.enqueue(notifQueue, priority, rqueueMessage(priority + "-notif-" + i, event)); |
59 | 123 | } |
60 | 124 | } |
61 | | - // Each priority maps to its own JetStream stream; verify each independently. |
62 | | - // subjectFor(q, priority) = prefix + q.getName() + "_" + priority, so size(pq) where |
63 | | - // pq.getName() = q.getName() + "_" + priority resolves to the same stream. |
64 | 125 | for (String priority : priorities) { |
65 | | - QueueDetail pq = mockQueue(q.getName() + "_" + priority); |
66 | | - assertEquals( |
67 | | - perPriority, |
68 | | - broker.size(pq), |
69 | | - "priority=" + priority + " stream should hold " + perPriority + " messages"); |
| 126 | + QueueDetail pq = mockQueue(notifQueue.getName() + "_" + priority); |
| 127 | + assertEquals(perPriority, broker.size(pq), |
| 128 | + "priority=" + priority + " stream should hold " + perPriority + " notification events"); |
70 | 129 | } |
71 | 130 | } |
72 | 131 | } |
73 | 132 |
|
74 | 133 | @Test |
75 | | - void enqueueReactive_messagesAccumulateInStream() { |
76 | | - QueueDetail q = mockQueue("po-reactive-" + System.nanoTime()); |
| 134 | + void enqueueReactive_emailEvents_accumulateInStream() throws Exception { |
| 135 | + QueueDetail emailQueue = mockQueue("email-reactive-" + System.nanoTime()); |
77 | 136 | try (JetStreamMessageBroker broker = |
78 | 137 | JetStreamMessageBroker.builder().connection(connection).build()) { |
79 | | - int count = 8; |
80 | | - Flux<Void> publishes = Flux.range(0, count) |
81 | | - .flatMap(i -> broker.enqueueReactive( |
82 | | - q, |
83 | | - RqueueMessage.builder() |
84 | | - .id("rm-" + i) |
85 | | - .message("reactive-payload-" + i) |
86 | | - .build())); |
87 | | - |
| 138 | + int count = 6; |
| 139 | + List<RqueueMessage> messages = new ArrayList<>(); |
| 140 | + for (int i = 0; i < count; i++) { |
| 141 | + EmailEvent event = new EmailEvent( |
| 142 | + UUID.randomUUID().toString(), "user" + i + "@example.com", "RE: item " + i); |
| 143 | + messages.add(rqueueMessage("re-email-" + i, event)); |
| 144 | + } |
| 145 | + Flux<Void> publishes = Flux.fromIterable(messages) |
| 146 | + .flatMap(m -> broker.enqueueReactive(emailQueue, m)); |
88 | 147 | StepVerifier.create(publishes).verifyComplete(); |
89 | | - |
90 | | - assertEquals( |
91 | | - count, broker.size(q), "all reactively enqueued messages should be in the stream"); |
| 148 | + assertEquals(count, broker.size(emailQueue), |
| 149 | + "all reactively enqueued email events should be in the stream"); |
92 | 150 | } |
93 | 151 | } |
94 | 152 |
|
95 | 153 | @Test |
96 | | - void mixedEnqueue_allVariantsLandInCorrectStreams() { |
97 | | - String base = "po-mixed-" + System.nanoTime(); |
98 | | - QueueDetail mainQ = mockQueue(base); |
99 | | - QueueDetail highQ = mockQueue(base + "_high"); |
| 154 | + void mixedEvents_allVariantsLandInCorrectStreams() throws Exception { |
| 155 | + String base = "mixed-events-" + System.nanoTime(); |
| 156 | + QueueDetail mainQueue = mockQueue(base); |
| 157 | + QueueDetail highQueue = mockQueue(base + "_high"); |
100 | 158 |
|
101 | 159 | try (JetStreamMessageBroker broker = |
102 | 160 | JetStreamMessageBroker.builder().connection(connection).build()) { |
103 | 161 |
|
104 | | - // 3 plain messages on the main queue |
| 162 | + // 3 email events on the main queue |
105 | 163 | for (int i = 0; i < 3; i++) { |
106 | | - broker.enqueue( |
107 | | - mainQ, RqueueMessage.builder().id("plain-" + i).message("p" + i).build()); |
| 164 | + EmailEvent email = new EmailEvent(UUID.randomUUID().toString(), |
| 165 | + "to" + i + "@example.com", "Hello " + i); |
| 166 | + broker.enqueue(mainQueue, rqueueMessage("email-" + i, email)); |
108 | 167 | } |
109 | | - // 2 priority messages on the "high" sub-queue |
| 168 | + // 2 job events on the "high" priority sub-queue |
110 | 169 | for (int i = 0; i < 2; i++) { |
111 | | - broker.enqueue( |
112 | | - mainQ, |
113 | | - "high", |
114 | | - RqueueMessage.builder().id("high-" + i).message("h" + i).build()); |
| 170 | + JobEvent job = new JobEvent(UUID.randomUUID().toString(), "CONTRACT"); |
| 171 | + broker.enqueue(mainQueue, "high", rqueueMessage("job-high-" + i, job)); |
115 | 172 | } |
116 | | - // 1 reactive message on the main queue |
117 | | - StepVerifier.create(broker.enqueueReactive( |
118 | | - mainQ, RqueueMessage.builder().id("react-0").message("r0").build())) |
| 173 | + // 1 notification reactively on the main queue |
| 174 | + NotificationEvent notif = new NotificationEvent(UUID.randomUUID().toString(), "reactive notif"); |
| 175 | + StepVerifier.create(broker.enqueueReactive(mainQueue, rqueueMessage("notif-0", notif))) |
119 | 176 | .verifyComplete(); |
120 | 177 |
|
121 | | - assertEquals(4L, broker.size(mainQ), "main stream: 3 plain + 1 reactive"); |
122 | | - assertEquals(2L, broker.size(highQ), "high-priority stream: 2 messages"); |
| 178 | + assertEquals(4L, broker.size(mainQueue), "main stream: 3 email + 1 reactive notification"); |
| 179 | + assertEquals(2L, broker.size(highQueue), "high-priority stream: 2 job events"); |
123 | 180 | } |
124 | 181 | } |
125 | 182 | } |
0 commit comments