|
25 | 25 | import static org.testng.Assert.assertEquals;
|
26 | 26 | import static org.testng.Assert.assertFalse;
|
27 | 27 | import static org.testng.Assert.assertNotEquals;
|
| 28 | +import static org.testng.Assert.assertNotNull; |
28 | 29 | import static org.testng.Assert.assertNull;
|
29 | 30 | import static org.testng.Assert.assertTrue;
|
30 | 31 | import static org.testng.Assert.fail;
|
|
34 | 35 | import java.lang.reflect.Method;
|
35 | 36 | import java.time.Duration;
|
36 | 37 | import java.util.Arrays;
|
| 38 | +import java.util.Collections; |
37 | 39 | import java.util.Optional;
|
38 | 40 | import java.util.UUID;
|
39 | 41 | import java.util.concurrent.CompletableFuture;
|
|
68 | 70 | import org.apache.pulsar.client.impl.ProducerImpl;
|
69 | 71 | import org.apache.pulsar.client.impl.PulsarClientImpl;
|
70 | 72 | import org.apache.pulsar.client.impl.conf.ProducerConfigurationData;
|
| 73 | +import org.apache.pulsar.common.policies.data.RetentionPolicies; |
| 74 | +import org.apache.pulsar.common.policies.data.TopicStats; |
| 75 | +import org.apache.pulsar.common.util.collections.ConcurrentOpenHashMap; |
71 | 76 | import org.apache.pulsar.common.naming.TopicName;
|
72 | 77 | import org.apache.pulsar.common.partition.PartitionedTopicMetadata;
|
73 |
| -import org.apache.pulsar.common.policies.data.TopicStats; |
74 | 78 | import org.apache.pulsar.common.util.FutureUtil;
|
75 |
| -import org.apache.pulsar.common.util.collections.ConcurrentOpenHashMap; |
76 | 79 | import org.awaitility.Awaitility;
|
77 | 80 | import org.awaitility.reflect.WhiteboxImpl;
|
78 | 81 | import org.mockito.Mockito;
|
@@ -903,4 +906,100 @@ public void testReloadWithTopicLevelGeoReplication(ReplicationLevel replicationL
|
903 | 906 | });
|
904 | 907 | }
|
905 | 908 | }
|
| 909 | + |
| 910 | + protected void enableReplication(String topic) throws Exception { |
| 911 | + admin1.topics().setReplicationClusters(topic, Arrays.asList(cluster1, cluster2)); |
| 912 | + } |
| 913 | + |
| 914 | + protected void disableReplication(String topic) throws Exception { |
| 915 | + admin1.topics().setReplicationClusters(topic, Arrays.asList(cluster1, cluster2)); |
| 916 | + } |
| 917 | + |
| 918 | + @Test |
| 919 | + public void testConfigReplicationStartAt() throws Exception { |
| 920 | + // Initialize. |
| 921 | + String ns1 = defaultTenant + "/ns_" + UUID.randomUUID().toString().replace("-", ""); |
| 922 | + String subscription1 = "s1"; |
| 923 | + admin1.namespaces().createNamespace(ns1); |
| 924 | + if (!usingGlobalZK) { |
| 925 | + admin2.namespaces().createNamespace(ns1); |
| 926 | + } |
| 927 | + |
| 928 | + RetentionPolicies retentionPolicies = new RetentionPolicies(60 * 24, 1024); |
| 929 | + admin1.namespaces().setRetention(ns1, retentionPolicies); |
| 930 | + admin2.namespaces().setRetention(ns1, retentionPolicies); |
| 931 | + |
| 932 | + // 1. default config. |
| 933 | + // Enable replication for topic1. |
| 934 | + final String topic1 = BrokerTestUtil.newUniqueName("persistent://" + ns1 + "/tp_"); |
| 935 | + admin1.topics().createNonPartitionedTopicAsync(topic1); |
| 936 | + admin1.topics().createSubscription(topic1, subscription1, MessageId.earliest); |
| 937 | + Producer<String> p1 = client1.newProducer(Schema.STRING).topic(topic1).create(); |
| 938 | + p1.send("msg-1"); |
| 939 | + p1.close(); |
| 940 | + enableReplication(topic1); |
| 941 | + // Verify: since the replication was started at latest, there is no message to consume. |
| 942 | + Consumer<String> c1 = client2.newConsumer(Schema.STRING).topic(topic1).subscriptionName(subscription1) |
| 943 | + .subscribe(); |
| 944 | + Message<String> msg1 = c1.receive(2, TimeUnit.SECONDS); |
| 945 | + assertNull(msg1); |
| 946 | + c1.close(); |
| 947 | + disableReplication(topic1); |
| 948 | + |
| 949 | + // 2.Update config: start at "earliest". |
| 950 | + admin1.brokers().updateDynamicConfiguration("replicationStartAt", MessageId.earliest.toString()); |
| 951 | + Awaitility.await().untilAsserted(() -> { |
| 952 | + pulsar1.getConfiguration().getReplicationStartAt().equalsIgnoreCase("earliest"); |
| 953 | + }); |
| 954 | + |
| 955 | + final String topic2 = BrokerTestUtil.newUniqueName("persistent://" + ns1 + "/tp_"); |
| 956 | + admin1.topics().createNonPartitionedTopicAsync(topic2); |
| 957 | + admin1.topics().createSubscription(topic2, subscription1, MessageId.earliest); |
| 958 | + Producer<String> p2 = client1.newProducer(Schema.STRING).topic(topic2).create(); |
| 959 | + p2.send("msg-1"); |
| 960 | + p2.close(); |
| 961 | + enableReplication(topic2); |
| 962 | + // Verify: since the replication was started at earliest, there is one message to consume. |
| 963 | + Consumer<String> c2 = client2.newConsumer(Schema.STRING).topic(topic2).subscriptionName(subscription1) |
| 964 | + .subscribe(); |
| 965 | + Message<String> msg2 = c2.receive(2, TimeUnit.SECONDS); |
| 966 | + assertNotNull(msg2); |
| 967 | + assertEquals(msg2.getValue(), "msg-1"); |
| 968 | + c2.close(); |
| 969 | + disableReplication(topic2); |
| 970 | + |
| 971 | + // 2.Update config: start at "latest". |
| 972 | + admin1.brokers().updateDynamicConfiguration("replicationStartAt", MessageId.latest.toString()); |
| 973 | + Awaitility.await().untilAsserted(() -> { |
| 974 | + pulsar1.getConfiguration().getReplicationStartAt().equalsIgnoreCase("latest"); |
| 975 | + }); |
| 976 | + |
| 977 | + final String topic3 = BrokerTestUtil.newUniqueName("persistent://" + ns1 + "/tp_"); |
| 978 | + admin1.topics().createNonPartitionedTopicAsync(topic3); |
| 979 | + admin1.topics().createSubscription(topic3, subscription1, MessageId.earliest); |
| 980 | + Producer<String> p3 = client1.newProducer(Schema.STRING).topic(topic3).create(); |
| 981 | + p3.send("msg-1"); |
| 982 | + p3.close(); |
| 983 | + enableReplication(topic3); |
| 984 | + // Verify: since the replication was started at latest, there is no message to consume. |
| 985 | + Consumer<String> c3 = client2.newConsumer(Schema.STRING).topic(topic3).subscriptionName(subscription1) |
| 986 | + .subscribe(); |
| 987 | + Message<String> msg3 = c3.receive(2, TimeUnit.SECONDS); |
| 988 | + assertNull(msg3); |
| 989 | + c3.close(); |
| 990 | + disableReplication(topic3); |
| 991 | + |
| 992 | + // cleanup. |
| 993 | + // There is no good way to delete topics when using global ZK, skip cleanup. |
| 994 | + admin1.namespaces().setNamespaceReplicationClusters(ns1, Collections.singleton(cluster1)); |
| 995 | + admin1.namespaces().unload(ns1); |
| 996 | + admin2.namespaces().setNamespaceReplicationClusters(ns1, Collections.singleton(cluster2)); |
| 997 | + admin2.namespaces().unload(ns1); |
| 998 | + admin1.topics().delete(topic1, false); |
| 999 | + admin2.topics().delete(topic1, false); |
| 1000 | + admin1.topics().delete(topic2, false); |
| 1001 | + admin2.topics().delete(topic2, false); |
| 1002 | + admin1.topics().delete(topic3, false); |
| 1003 | + admin2.topics().delete(topic3, false); |
| 1004 | + } |
906 | 1005 | }
|
0 commit comments