|
34 | 34 | import org.apache.pulsar.client.api.Message; |
35 | 35 | import org.apache.pulsar.client.api.MessageId; |
36 | 36 | import org.apache.pulsar.client.api.MessageIdAdv; |
| 37 | +import org.apache.pulsar.client.api.MessageListener; |
37 | 38 | import org.apache.pulsar.client.api.MessageRouter; |
38 | 39 | import org.apache.pulsar.client.api.MessageRoutingMode; |
39 | 40 | import org.apache.pulsar.client.api.Producer; |
|
57 | 58 | import org.testng.Assert; |
58 | 59 | import org.testng.annotations.AfterMethod; |
59 | 60 | import org.testng.annotations.BeforeMethod; |
| 61 | +import org.testng.annotations.DataProvider; |
60 | 62 | import org.testng.annotations.Test; |
61 | | - |
62 | 63 | import java.util.ArrayList; |
| 64 | +import java.util.Arrays; |
| 65 | +import java.util.Comparator; |
63 | 66 | import java.util.Set; |
64 | 67 | import java.util.HashMap; |
65 | 68 | import java.util.HashSet; |
66 | 69 | import java.util.List; |
67 | 70 | import java.util.Map; |
68 | 71 | import java.util.Optional; |
| 72 | +import java.util.TreeSet; |
69 | 73 | import java.util.concurrent.CompletableFuture; |
| 74 | +import java.util.concurrent.CopyOnWriteArrayList; |
70 | 75 | import java.util.concurrent.CountDownLatch; |
71 | 76 | import java.util.concurrent.ExecutorService; |
72 | 77 | import java.util.concurrent.Executors; |
73 | 78 | import java.util.concurrent.Future; |
74 | 79 | import java.util.concurrent.TimeUnit; |
75 | 80 | import java.util.concurrent.atomic.AtomicInteger; |
| 81 | +import java.util.function.Function; |
76 | 82 | import java.util.stream.Collectors; |
77 | 83 | import java.util.stream.IntStream; |
78 | 84 |
|
@@ -1394,4 +1400,76 @@ public Map<String, String> getActiveConsumers() { |
1394 | 1400 | } |
1395 | 1401 | } |
1396 | 1402 |
|
| 1403 | + @DataProvider |
| 1404 | + public static Object[][] seekByFunction() { |
| 1405 | + return new Object[][] { |
| 1406 | + { true }, { false } |
| 1407 | + }; |
| 1408 | + } |
| 1409 | + |
| 1410 | + @Test(timeOut = 30000, dataProvider = "seekByFunction") |
| 1411 | + public void testSeekToNewerPosition(boolean seekByFunction) throws Exception { |
| 1412 | + final var topic1 = TopicName.get(newTopicName()).toString() |
| 1413 | + .replace("my-property", "public").replace("my-ns", "default"); |
| 1414 | + final var topic2 = TopicName.get(newTopicName()).toString() |
| 1415 | + .replace("my-property", "public").replace("my-ns", "default"); |
| 1416 | + @Cleanup final var producer1 = pulsarClient.newProducer(Schema.STRING).topic(topic1).create(); |
| 1417 | + @Cleanup final var producer2 = pulsarClient.newProducer(Schema.STRING).topic(topic2).create(); |
| 1418 | + producer1.send("1-0"); |
| 1419 | + producer2.send("2-0"); |
| 1420 | + producer1.send("1-1"); |
| 1421 | + producer2.send("2-1"); |
| 1422 | + final var consumer1 = pulsarClient.newConsumer(Schema.STRING) |
| 1423 | + .topics(Arrays.asList(topic1, topic2)).subscriptionName("sub") |
| 1424 | + .ackTimeout(1, TimeUnit.SECONDS) |
| 1425 | + .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest).subscribe(); |
| 1426 | + final var timestamps = new ArrayList<Long>(); |
| 1427 | + for (int i = 0; i < 4; i++) { |
| 1428 | + timestamps.add(consumer1.receive().getPublishTime()); |
| 1429 | + } |
| 1430 | + timestamps.sort(Comparator.naturalOrder()); |
| 1431 | + final var timestamp = timestamps.get(2); |
| 1432 | + consumer1.close(); |
| 1433 | + |
| 1434 | + final Function<Consumer<String>, CompletableFuture<Void>> seekAsync = consumer -> { |
| 1435 | + final var future = seekByFunction ? consumer.seekAsync(__ -> timestamp) : consumer.seekAsync(timestamp); |
| 1436 | + assertEquals(((ConsumerBase<String>) consumer).getIncomingMessageSize(), 0L); |
| 1437 | + assertEquals(((ConsumerBase<String>) consumer).getTotalIncomingMessages(), 0); |
| 1438 | + assertTrue(((ConsumerBase<String>) consumer).getUnAckedMessageTracker().isEmpty()); |
| 1439 | + return future; |
| 1440 | + }; |
| 1441 | + |
| 1442 | + @Cleanup final var consumer2 = pulsarClient.newConsumer(Schema.STRING) |
| 1443 | + .topics(Arrays.asList(topic1, topic2)).subscriptionName("sub-2") |
| 1444 | + .ackTimeout(1, TimeUnit.SECONDS) |
| 1445 | + .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest).subscribe(); |
| 1446 | + seekAsync.apply(consumer2).get(); |
| 1447 | + final var values = new TreeSet<String>(); |
| 1448 | + for (int i = 0; i < 2; i++) { |
| 1449 | + values.add(consumer2.receive().getValue()); |
| 1450 | + } |
| 1451 | + assertEquals(values, new TreeSet<>(Arrays.asList("1-1", "2-1"))); |
| 1452 | + |
| 1453 | + final var valuesInListener = new CopyOnWriteArrayList<String>(); |
| 1454 | + @Cleanup final var consumer3 = pulsarClient.newConsumer(Schema.STRING) |
| 1455 | + .topics(Arrays.asList(topic1, topic2)).subscriptionName("sub-3") |
| 1456 | + .messageListener((MessageListener<String>) (__, msg) -> valuesInListener.add(msg.getValue())) |
| 1457 | + .ackTimeout(1, TimeUnit.SECONDS) |
| 1458 | + .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest).subscribe(); |
| 1459 | + seekAsync.apply(consumer3).get(); |
| 1460 | + if (valuesInListener.isEmpty()) { |
| 1461 | + Awaitility.await().untilAsserted(() -> assertEquals(valuesInListener.size(), 2)); |
| 1462 | + assertEquals(valuesInListener.stream().sorted().toList(), Arrays.asList("1-1", "2-1")); |
| 1463 | + } // else: consumer3 has passed messages to the listener before seek, in this case we cannot assume anything |
| 1464 | + |
| 1465 | + @Cleanup final var consumer4 = pulsarClient.newConsumer(Schema.STRING) |
| 1466 | + .topics(Arrays.asList(topic1, topic2)).subscriptionName("sub-4") |
| 1467 | + .ackTimeout(1, TimeUnit.SECONDS) |
| 1468 | + .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest).subscribe(); |
| 1469 | + seekAsync.apply(consumer4).get(); |
| 1470 | + final var valuesInReceiveAsync = new ArrayList<String>(); |
| 1471 | + valuesInReceiveAsync.add(consumer4.receiveAsync().get().getValue()); |
| 1472 | + valuesInReceiveAsync.add(consumer4.receiveAsync().get().getValue()); |
| 1473 | + assertEquals(valuesInReceiveAsync.stream().sorted().toList(), Arrays.asList("1-1", "2-1")); |
| 1474 | + } |
1397 | 1475 | } |
0 commit comments