|
20 | 20 |
|
21 | 21 | import static org.assertj.core.api.Assertions.assertThat; |
22 | 22 | import static org.testng.Assert.assertEquals; |
| 23 | +import static org.testng.Assert.assertFalse; |
23 | 24 | import static org.testng.Assert.assertNotEquals; |
24 | 25 | import static org.testng.Assert.assertNotNull; |
25 | 26 | import static org.testng.Assert.assertNull; |
| 27 | +import static org.testng.Assert.assertTrue; |
26 | 28 | import java.lang.reflect.Field; |
27 | 29 | import java.time.Duration; |
28 | 30 | import java.util.Arrays; |
29 | 31 | import java.util.Collections; |
30 | 32 | import java.util.HashSet; |
| 33 | +import java.util.List; |
31 | 34 | import java.util.Set; |
32 | 35 | import java.util.UUID; |
33 | 36 | import java.util.concurrent.TimeUnit; |
| 37 | +import java.util.function.Predicate; |
34 | 38 | import java.util.function.Supplier; |
| 39 | +import java.util.stream.Collectors; |
35 | 40 | import lombok.extern.slf4j.Slf4j; |
36 | 41 | import org.apache.pulsar.broker.BrokerTestUtil; |
37 | 42 | import org.apache.pulsar.broker.resources.ClusterResources; |
|
44 | 49 | import org.apache.pulsar.client.api.Producer; |
45 | 50 | import org.apache.pulsar.client.api.PulsarClient; |
46 | 51 | import org.apache.pulsar.client.api.Schema; |
| 52 | +import org.apache.pulsar.client.api.SubscriptionInitialPosition; |
47 | 53 | import org.apache.pulsar.client.impl.ProducerImpl; |
| 54 | +import org.apache.pulsar.common.naming.TopicName; |
| 55 | +import org.apache.pulsar.common.policies.data.AutoTopicCreationOverride; |
48 | 56 | import org.apache.pulsar.common.policies.data.ClusterData; |
49 | 57 | import org.apache.pulsar.common.policies.data.RetentionPolicies; |
50 | 58 | import org.apache.pulsar.common.policies.data.TenantInfo; |
51 | 59 | import org.apache.pulsar.common.policies.data.TopicStats; |
| 60 | +import org.apache.pulsar.common.policies.data.impl.AutoTopicCreationOverrideImpl; |
52 | 61 | import org.apache.pulsar.common.util.FutureUtil; |
53 | 62 | import org.awaitility.Awaitility; |
54 | 63 | import org.junit.Assert; |
@@ -346,6 +355,7 @@ public void testConfigReplicationStartAt() throws Exception { |
346 | 355 | enableReplication(topic2); |
347 | 356 | // Verify: since the replication was started at earliest, there is one message to consume. |
348 | 357 | Consumer<String> c2 = client2.newConsumer(Schema.STRING).topic(topic2).subscriptionName(subscription1) |
| 358 | + .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest) |
349 | 359 | .subscribe(); |
350 | 360 | Message<String> msg2 = c2.receive(2, TimeUnit.SECONDS); |
351 | 361 | assertNotNull(msg2); |
@@ -387,4 +397,91 @@ public void testConfigReplicationStartAt() throws Exception { |
387 | 397 | admin1.topics().delete(topic3, false); |
388 | 398 | admin2.topics().delete(topic3, false); |
389 | 399 | } |
| 400 | + |
| 401 | + @DataProvider(name = "replicationModes") |
| 402 | + public Object[][] replicationModes() { |
| 403 | + return new Object[][]{ |
| 404 | + {ReplicationMode.OneWay}, |
| 405 | + {ReplicationMode.DoubleWay} |
| 406 | + }; |
| 407 | + } |
| 408 | + |
| 409 | + protected enum ReplicationMode { |
| 410 | + OneWay, |
| 411 | + DoubleWay; |
| 412 | + } |
| 413 | + |
| 414 | + @Test(dataProvider = "replicationModes") |
| 415 | + public void testDifferentTopicCreationRule(ReplicationMode replicationMode) throws Exception { |
| 416 | + String ns = defaultTenant + "/" + UUID.randomUUID().toString().replace("-", ""); |
| 417 | + admin1.namespaces().createNamespace(ns); |
| 418 | + admin2.namespaces().createNamespace(ns); |
| 419 | + |
| 420 | + // Set topic auto-creation rule. |
| 421 | + // c1: no-partitioned topic |
| 422 | + // c2: partitioned topic with 2 partitions. |
| 423 | + AutoTopicCreationOverride autoTopicCreation = |
| 424 | + AutoTopicCreationOverrideImpl.builder().allowAutoTopicCreation(true) |
| 425 | + .topicType("partitioned").defaultNumPartitions(2).build(); |
| 426 | + admin2.namespaces().setAutoTopicCreation(ns, autoTopicCreation); |
| 427 | + Awaitility.await().untilAsserted(() -> { |
| 428 | + assertEquals(admin2.namespaces().getAutoTopicCreationAsync(ns).join().getDefaultNumPartitions(), |
| 429 | + Integer.valueOf(2)); |
| 430 | + // Trigger system topic __change_event's initialize. |
| 431 | + pulsar2.getTopicPoliciesService().getTopicPoliciesAsync(TopicName.get("persistent://" + ns + "/1")); |
| 432 | + }); |
| 433 | + |
| 434 | + // Create non-partitioned topic. |
| 435 | + // Enable replication. |
| 436 | + final String tp = BrokerTestUtil.newUniqueName("persistent://" + ns + "/tp_"); |
| 437 | + admin1.topics().createNonPartitionedTopic(tp); |
| 438 | + admin1.namespaces().setNamespaceReplicationClusters(ns, new HashSet<>(Arrays.asList(cluster1, cluster2))); |
| 439 | + if (replicationMode.equals(ReplicationMode.DoubleWay)) { |
| 440 | + admin2.namespaces().setNamespaceReplicationClusters(ns, new HashSet<>(Arrays.asList(cluster1, cluster2))); |
| 441 | + } |
| 442 | + |
| 443 | + // Trigger and wait for replicator starts. |
| 444 | + Producer<String> p1 = client1.newProducer(Schema.STRING).topic(tp).create(); |
| 445 | + p1.send("msg-1"); |
| 446 | + p1.close(); |
| 447 | + Awaitility.await().untilAsserted(() -> { |
| 448 | + PersistentTopic persistentTopic = (PersistentTopic) broker1.getTopic(tp, false).join().get(); |
| 449 | + assertFalse(persistentTopic.getReplicators().isEmpty()); |
| 450 | + }); |
| 451 | + |
| 452 | + // Verify: the topics are the same between two clusters. |
| 453 | + Predicate<String> topicNameFilter = t -> { |
| 454 | + TopicName topicName = TopicName.get(t); |
| 455 | + if (!topicName.getNamespace().equals(ns)) { |
| 456 | + return false; |
| 457 | + } |
| 458 | + return t.startsWith(tp); |
| 459 | + }; |
| 460 | + Awaitility.await().untilAsserted(() -> { |
| 461 | + List<String> topics1 = pulsar1.getBrokerService().getTopics().keys() |
| 462 | + .stream().filter(topicNameFilter).collect(Collectors.toList()); |
| 463 | + List<String> topics2 = pulsar2.getBrokerService().getTopics().keys() |
| 464 | + .stream().filter(topicNameFilter).collect(Collectors.toList()); |
| 465 | + Collections.sort(topics1); |
| 466 | + Collections.sort(topics2); |
| 467 | + assertEquals(topics1, topics2); |
| 468 | + }); |
| 469 | + |
| 470 | + // cleanup. |
| 471 | + admin1.namespaces().setNamespaceReplicationClusters(ns, new HashSet<>(Arrays.asList(cluster1))); |
| 472 | + if (replicationMode.equals(ReplicationMode.DoubleWay)) { |
| 473 | + admin2.namespaces().setNamespaceReplicationClusters(ns, new HashSet<>(Arrays.asList(cluster2))); |
| 474 | + } |
| 475 | + Awaitility.await().untilAsserted(() -> { |
| 476 | + PersistentTopic persistentTopic = (PersistentTopic) broker1.getTopic(tp, false).join().get(); |
| 477 | + assertTrue(persistentTopic.getReplicators().isEmpty()); |
| 478 | + if (replicationMode.equals(ReplicationMode.DoubleWay)) { |
| 479 | + assertTrue(persistentTopic.getReplicators().isEmpty()); |
| 480 | + } |
| 481 | + }); |
| 482 | + admin1.topics().delete(tp, false); |
| 483 | + admin2.topics().delete(tp, false); |
| 484 | + admin1.namespaces().deleteNamespace(ns, true); |
| 485 | + admin2.namespaces().deleteNamespace(ns, true); |
| 486 | + } |
390 | 487 | } |
0 commit comments