|
32 | 32 | import java.util.concurrent.ConcurrentHashMap;
|
33 | 33 | import java.util.concurrent.atomic.AtomicInteger;
|
34 | 34 | import java.util.function.Consumer;
|
| 35 | +import java.util.stream.Collectors; |
35 | 36 | import org.junit.jupiter.api.*;
|
36 | 37 | import org.junit.jupiter.params.ParameterizedTest;
|
37 | 38 | import org.junit.jupiter.params.provider.EnumSource;
|
@@ -213,7 +214,7 @@ void consumeFromMovingQq() {
|
213 | 214 | }
|
214 | 215 |
|
215 | 216 | @Test
|
216 |
| - void publishConsumeQqWhenLeaderChanges() { |
| 217 | + void publishConsumeQuorumQueueWhenLeaderChanges() { |
217 | 218 | try {
|
218 | 219 | management.queue(q).type(Management.QueueType.QUORUM).declare();
|
219 | 220 |
|
@@ -271,6 +272,80 @@ void publishConsumeQqWhenLeaderChanges() {
|
271 | 272 | }
|
272 | 273 | }
|
273 | 274 |
|
| 275 | + @Test |
| 276 | + void consumeFromQuorumQueueWhenLeaderIsPaused() { |
| 277 | + management.queue(q).type(Management.QueueType.QUORUM).declare(); |
| 278 | + Management.QueueInfo queueInfo = queueInfo(); |
| 279 | + String initialLeader = queueInfo.leader(); |
| 280 | + boolean nodePaused = false; |
| 281 | + try { |
| 282 | + AmqpConnection consumeConnection = connection(b -> b.affinity().queue(q).operation(CONSUME)); |
| 283 | + assertThat(consumeConnection).isOnFollower(queueInfo()); |
| 284 | + Management mgmt = consumeConnection.management(); |
| 285 | + |
| 286 | + Set<Long> messageIds = ConcurrentHashMap.newKeySet(); |
| 287 | + Sync consumeSync = sync(); |
| 288 | + consumeConnection |
| 289 | + .consumerBuilder() |
| 290 | + .queue(q) |
| 291 | + .messageHandler( |
| 292 | + (ctx, msg) -> { |
| 293 | + messageIds.add(msg.messageIdAsLong()); |
| 294 | + consumeSync.down(); |
| 295 | + ctx.accept(); |
| 296 | + }) |
| 297 | + .build(); |
| 298 | + |
| 299 | + AmqpConnection publishConnection = connection(b -> b.affinity().queue(q).operation(CONSUME)); |
| 300 | + Publisher publisher = publishConnection.publisherBuilder().queue(q).build(); |
| 301 | + assertThat(publishConnection).isOnFollower(queueInfo()); |
| 302 | + |
| 303 | + Sync publishSync = sync(); |
| 304 | + publisher.publish(publisher.message().messageId(1L), ctx -> publishSync.down()); |
| 305 | + assertThat(publishSync).completes(); |
| 306 | + publishSync.reset(); |
| 307 | + |
| 308 | + assertThat(consumeSync).completes(); |
| 309 | + assertThat(messageIds).containsExactlyInAnyOrder(1L); |
| 310 | + consumeSync.reset(); |
| 311 | + |
| 312 | + List<String> initialFollowers = |
| 313 | + queueInfo.replicas().stream() |
| 314 | + .filter(n -> !n.equals(initialLeader)) |
| 315 | + .collect(Collectors.toList()); |
| 316 | + assertThat(initialFollowers).isNotEmpty(); |
| 317 | + |
| 318 | + Cli.pauseNode(initialLeader); |
| 319 | + nodePaused = true; |
| 320 | + |
| 321 | + publisher.publish(publisher.message().messageId(2L), ctx -> publishSync.down()); |
| 322 | + assertThat(publishSync).completes(); |
| 323 | + publishSync.reset(); |
| 324 | + |
| 325 | + assertThat(consumeSync).completes(); |
| 326 | + assertThat(messageIds).containsExactlyInAnyOrder(1L, 2L); |
| 327 | + consumeSync.reset(); |
| 328 | + |
| 329 | + Cli.unpauseNode(initialLeader); |
| 330 | + nodePaused = false; |
| 331 | + |
| 332 | + publisher.publish(publisher.message().messageId(3L), ctx -> publishSync.down()); |
| 333 | + assertThat(publishSync).completes(); |
| 334 | + publishSync.reset(); |
| 335 | + |
| 336 | + assertThat(consumeSync).completes(); |
| 337 | + assertThat(messageIds).containsExactlyInAnyOrder(1L, 2L, 3L); |
| 338 | + consumeSync.reset(); |
| 339 | + |
| 340 | + waitAtMost(() -> initialFollowers.contains(mgmt.queueInfo(q).leader())); |
| 341 | + } finally { |
| 342 | + if (nodePaused) { |
| 343 | + Cli.unpauseNode(initialLeader); |
| 344 | + } |
| 345 | + management.queueDeletion().delete(q); |
| 346 | + } |
| 347 | + } |
| 348 | + |
274 | 349 | @Test
|
275 | 350 | void publishToRestartedStream() {
|
276 | 351 | try {
|
|
0 commit comments