|
34 | 34 | import java.util.Set; |
35 | 35 | import java.util.UUID; |
36 | 36 | import java.util.concurrent.CompletableFuture; |
| 37 | +import java.util.concurrent.ConcurrentHashMap; |
37 | 38 | import java.util.concurrent.ExecutionException; |
38 | 39 | import java.util.concurrent.Executors; |
39 | 40 | import java.util.concurrent.ScheduledExecutorService; |
40 | 41 | import java.util.concurrent.TimeUnit; |
| 42 | +import lombok.extern.slf4j.Slf4j; |
| 43 | +import org.apache.commons.lang3.reflect.FieldUtils; |
41 | 44 | import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; |
42 | 45 | import org.apache.pulsar.broker.service.BrokerServiceException.TopicPoliciesCacheNotInitException; |
43 | 46 | import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; |
|
54 | 57 | import org.apache.pulsar.common.policies.data.TenantInfoImpl; |
55 | 58 | import org.apache.pulsar.common.policies.data.TopicPolicies; |
56 | 59 | import org.apache.pulsar.common.util.FutureUtil; |
| 60 | +import org.assertj.core.api.Assertions; |
57 | 61 | import org.awaitility.Awaitility; |
| 62 | +import org.mockito.Mockito; |
58 | 63 | import org.testng.Assert; |
59 | 64 | import org.testng.annotations.AfterMethod; |
60 | 65 | import org.testng.annotations.BeforeMethod; |
61 | 66 | import org.testng.annotations.Test; |
62 | 67 |
|
63 | 68 | @Test(groups = "broker") |
| 69 | +@Slf4j |
64 | 70 | public class SystemTopicBasedTopicPoliciesServiceTest extends MockedPulsarServiceBaseTest { |
65 | 71 |
|
66 | 72 | private static final String NAMESPACE1 = "system-topic/namespace-1"; |
@@ -384,4 +390,71 @@ public void testHandleNamespaceBeingDeleted() throws Exception { |
384 | 390 | }); |
385 | 391 | service.deleteTopicPoliciesAsync(TOPIC1).get(); |
386 | 392 | } |
| 393 | + |
| 394 | + @Test |
| 395 | + public void testGetTopicPoliciesWithCleanCache() throws Exception { |
| 396 | + final String topic = "persistent://" + NAMESPACE1 + "/test" + UUID.randomUUID(); |
| 397 | + pulsarClient.newProducer().topic(topic).create().close(); |
| 398 | + |
| 399 | + SystemTopicBasedTopicPoliciesService topicPoliciesService = |
| 400 | + (SystemTopicBasedTopicPoliciesService) pulsar.getTopicPoliciesService(); |
| 401 | + |
| 402 | + ConcurrentHashMap<TopicName, TopicPolicies> spyPoliciesCache = spy(new ConcurrentHashMap<TopicName, TopicPolicies>()); |
| 403 | + FieldUtils.writeDeclaredField(topicPoliciesService, "policiesCache", spyPoliciesCache, true); |
| 404 | + |
| 405 | + Awaitility.await().untilAsserted(() -> { |
| 406 | + Assertions.assertThat(topicPoliciesService.getTopicPolicies(TopicName.get(topic))).isNull(); |
| 407 | + }); |
| 408 | + |
| 409 | + admin.topicPolicies().setMaxConsumersPerSubscription(topic, 1); |
| 410 | + Awaitility.await().untilAsserted(() -> { |
| 411 | + Assertions.assertThat(pulsar.getTopicPoliciesService().getTopicPolicies(TopicName.get(topic))).isNotNull(); |
| 412 | + }); |
| 413 | + |
| 414 | + Map<NamespaceName, CompletableFuture<SystemTopicClient.Reader<PulsarEvent>>> readers = |
| 415 | + (Map<NamespaceName, CompletableFuture<SystemTopicClient.Reader<PulsarEvent>>>) |
| 416 | + FieldUtils.readDeclaredField(topicPoliciesService, "readerCaches", true); |
| 417 | + |
| 418 | + Mockito.doAnswer(invocation -> { |
| 419 | + Thread.sleep(1000); |
| 420 | + return invocation.callRealMethod(); |
| 421 | + }).when(spyPoliciesCache).get(Mockito.any()); |
| 422 | + |
| 423 | + CompletableFuture<Void> result = new CompletableFuture<>(); |
| 424 | + Thread thread = new Thread(() -> { |
| 425 | + TopicPolicies topicPolicies; |
| 426 | + for (int i = 0; i < 10; i++) { |
| 427 | + try { |
| 428 | + topicPolicies = topicPoliciesService.getTopicPolicies(TopicName.get(topic)); |
| 429 | + Assert.assertNotNull(topicPolicies); |
| 430 | + Thread.sleep(500); |
| 431 | + } catch (BrokerServiceException.TopicPoliciesCacheNotInitException e) { |
| 432 | + log.warn("topic policies cache not init, retry..."); |
| 433 | + } catch (Throwable e) { |
| 434 | + log.error("ops: ", e); |
| 435 | + result.completeExceptionally(e); |
| 436 | + return; |
| 437 | + } |
| 438 | + } |
| 439 | + result.complete(null); |
| 440 | + }); |
| 441 | + |
| 442 | + Thread thread2 = new Thread(() -> { |
| 443 | + for (int i = 0; i < 10; i++) { |
| 444 | + CompletableFuture<SystemTopicClient.Reader<PulsarEvent>> readerCompletableFuture = |
| 445 | + readers.get(TopicName.get(topic).getNamespaceObject()); |
| 446 | + if (readerCompletableFuture != null) { |
| 447 | + readerCompletableFuture.join().closeAsync().join(); |
| 448 | + } |
| 449 | + } |
| 450 | + }); |
| 451 | + |
| 452 | + thread.start(); |
| 453 | + thread2.start(); |
| 454 | + |
| 455 | + thread.join(); |
| 456 | + thread2.join(); |
| 457 | + |
| 458 | + result.join(); |
| 459 | + } |
387 | 460 | } |
0 commit comments