|
25 | 25 | import org.apache.pulsar.client.api.ProducerBuilder;
|
26 | 26 | import org.apache.pulsar.client.api.PulsarClient;
|
27 | 27 | import org.apache.pulsar.client.api.ReaderBuilder;
|
| 28 | +import org.apache.pulsar.client.api.SubscriptionType; |
28 | 29 | import org.apache.pulsar.client.api.interceptor.ProducerInterceptor;
|
29 | 30 | import org.apache.pulsar.common.schema.SchemaType;
|
| 31 | +import org.assertj.core.api.InstanceOfAssertFactories; |
30 | 32 | import org.junit.jupiter.api.Nested;
|
31 | 33 | import org.junit.jupiter.api.Test;
|
32 | 34 | import org.junit.jupiter.params.ParameterizedTest;
|
|
47 | 49 | import org.springframework.pulsar.config.DefaultPulsarReaderContainerFactory;
|
48 | 50 | import org.springframework.pulsar.config.PulsarListenerContainerFactory;
|
49 | 51 | import org.springframework.pulsar.config.PulsarListenerEndpointRegistry;
|
| 52 | +import org.springframework.pulsar.config.PulsarReaderContainerFactory; |
50 | 53 | import org.springframework.pulsar.config.PulsarReaderEndpointRegistry;
|
51 | 54 | import org.springframework.pulsar.core.CachingPulsarProducerFactory;
|
52 | 55 | import org.springframework.pulsar.core.ConsumerBuilderCustomizer;
|
|
65 | 68 | import org.springframework.pulsar.core.ReaderBuilderCustomizer;
|
66 | 69 | import org.springframework.pulsar.core.SchemaResolver;
|
67 | 70 | import org.springframework.pulsar.core.TopicResolver;
|
| 71 | +import org.springframework.pulsar.reader.PulsarReaderContainerProperties; |
68 | 72 |
|
69 | 73 | import static org.assertj.core.api.Assertions.assertThat;
|
70 | 74 | import static org.mockito.Mockito.mock;
|
@@ -390,7 +394,7 @@ ConsumerBuilderCustomizer<?> customizerBar() {
|
390 | 394 | }
|
391 | 395 |
|
392 | 396 | @Nested
|
393 |
| - class ListenerTests { |
| 397 | + class ListenerContainerTests { |
394 | 398 |
|
395 | 399 | private final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;
|
396 | 400 |
|
@@ -464,6 +468,53 @@ void whenObservationsDisabledDoesNotEnableObservation() {
|
464 | 468 | .hasFieldOrPropertyWithValue("containerProperties.observationEnabled", false));
|
465 | 469 | }
|
466 | 470 |
|
| 471 | + @Test |
| 472 | + void whenHasUserDefinedCustomizersAppliesInCorrectOrder() { |
| 473 | + this.contextRunner.withPropertyValues("spring.pulsar.consumer.subscription.type=Shared") |
| 474 | + .withUserConfiguration(ContainerPropertiesCustomizerConfig.class) |
| 475 | + .run((context) -> { |
| 476 | + ConcurrentPulsarListenerContainerFactory<?> containerFactory = context |
| 477 | + .getBean(ConcurrentPulsarListenerContainerFactory.class); |
| 478 | + // We use subscriptionType to prove user customizers come after base |
| 479 | + // props customizer. |
| 480 | + // We use subscriptionName to prove user customizers are applied in |
| 481 | + // their order. |
| 482 | + assertThat(containerFactory) |
| 483 | + .extracting(ConcurrentPulsarListenerContainerFactory::getContainerProperties) |
| 484 | + .satisfies((containerProps) -> { |
| 485 | + assertThat(containerProps.getSubscriptionType()).isEqualTo(SubscriptionType.Failover); |
| 486 | + assertThat(containerProps.getSubscriptionName()).isEqualTo("/customizer1/customizer2"); |
| 487 | + }); |
| 488 | + }); |
| 489 | + } |
| 490 | + |
| 491 | + @TestConfiguration(proxyBeanMethods = false) |
| 492 | + static class ContainerPropertiesCustomizerConfig { |
| 493 | + |
| 494 | + @Bean |
| 495 | + @Order(200) |
| 496 | + PulsarContainerPropertiesCustomizer customizerFoo() { |
| 497 | + return (props) -> { |
| 498 | + props.setSubscriptionType(SubscriptionType.Failover); |
| 499 | + String name = "%s/customizer2" |
| 500 | + .formatted((props.getSubscriptionName() != null) ? props.getSubscriptionName() : ""); |
| 501 | + props.setSubscriptionName(name); |
| 502 | + }; |
| 503 | + } |
| 504 | + |
| 505 | + @Bean |
| 506 | + @Order(100) |
| 507 | + PulsarContainerPropertiesCustomizer customizerBar() { |
| 508 | + return (props) -> { |
| 509 | + props.setSubscriptionType(SubscriptionType.Failover); |
| 510 | + String name = "%s/customizer1" |
| 511 | + .formatted((props.getSubscriptionName() != null) ? props.getSubscriptionName() : ""); |
| 512 | + props.setSubscriptionName(name); |
| 513 | + }; |
| 514 | + } |
| 515 | + |
| 516 | + } |
| 517 | + |
467 | 518 | }
|
468 | 519 |
|
469 | 520 | @Nested
|
@@ -517,4 +568,88 @@ ReaderBuilderCustomizer<?> customizerBar() {
|
517 | 568 |
|
518 | 569 | }
|
519 | 570 |
|
| 571 | + @Nested |
| 572 | + class ReaderContainerTests { |
| 573 | + |
| 574 | + private final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner; |
| 575 | + |
| 576 | + @Test |
| 577 | + void whenHasUserDefinedReaderContainerFactoryBeanDoesNotAutoConfigureBean() { |
| 578 | + PulsarReaderContainerFactory readerContainerFactory = mock(PulsarReaderContainerFactory.class); |
| 579 | + this.contextRunner |
| 580 | + .withBean("pulsarReaderContainerFactory", PulsarReaderContainerFactory.class, |
| 581 | + () -> readerContainerFactory) |
| 582 | + .run((context) -> assertThat(context).getBean(PulsarReaderContainerFactory.class) |
| 583 | + .isSameAs(readerContainerFactory)); |
| 584 | + } |
| 585 | + |
| 586 | + @Test |
| 587 | + @SuppressWarnings("rawtypes") |
| 588 | + void injectsExpectedBeans() { |
| 589 | + PulsarReaderFactory<?> readerFactory = mock(PulsarReaderFactory.class); |
| 590 | + SchemaResolver schemaResolver = mock(SchemaResolver.class); |
| 591 | + this.contextRunner.withBean("pulsarReaderFactory", PulsarReaderFactory.class, () -> readerFactory) |
| 592 | + .withBean("schemaResolver", SchemaResolver.class, () -> schemaResolver) |
| 593 | + .run((context) -> assertThat(context).getBean(DefaultPulsarReaderContainerFactory.class) |
| 594 | + .hasFieldOrPropertyWithValue("readerFactory", readerFactory) |
| 595 | + .extracting(DefaultPulsarReaderContainerFactory::getContainerProperties) |
| 596 | + .hasFieldOrPropertyWithValue("schemaResolver", schemaResolver)); |
| 597 | + } |
| 598 | + |
| 599 | + @Test |
| 600 | + @SuppressWarnings("unchecked") |
| 601 | + void whenHasUserDefinedReaderAnnotationBeanPostProcessorBeanDoesNotAutoConfigureBean() { |
| 602 | + PulsarReaderAnnotationBeanPostProcessor<String> readerAnnotationBeanPostProcessor = mock( |
| 603 | + PulsarReaderAnnotationBeanPostProcessor.class); |
| 604 | + this.contextRunner |
| 605 | + .withBean("org.springframework.pulsar.config.internalPulsarReaderAnnotationProcessor", |
| 606 | + PulsarReaderAnnotationBeanPostProcessor.class, () -> readerAnnotationBeanPostProcessor) |
| 607 | + .run((context) -> assertThat(context).getBean(PulsarReaderAnnotationBeanPostProcessor.class) |
| 608 | + .isSameAs(readerAnnotationBeanPostProcessor)); |
| 609 | + } |
| 610 | + |
| 611 | + @Test |
| 612 | + void whenHasCustomProperties() { |
| 613 | + List<String> properties = new ArrayList<>(); |
| 614 | + properties.add("spring.pulsar.reader.topics=fromPropsCustomizer"); |
| 615 | + this.contextRunner.withPropertyValues(properties.toArray(String[]::new)).run((context) -> { |
| 616 | + DefaultPulsarReaderContainerFactory<?> factory = context |
| 617 | + .getBean(DefaultPulsarReaderContainerFactory.class); |
| 618 | + assertThat(factory.getContainerProperties().getTopics()).containsExactly("fromPropsCustomizer"); |
| 619 | + }); |
| 620 | + } |
| 621 | + |
| 622 | + @Test |
| 623 | + void whenHasUserDefinedCustomizersAppliesInCorrectOrder() { |
| 624 | + this.contextRunner.withPropertyValues("spring.pulsar.reader.topics=fromPropsCustomizer") |
| 625 | + .withUserConfiguration(ReaderContainerPropertiesCustomizerConfig.class) |
| 626 | + .run((context) -> { |
| 627 | + DefaultPulsarReaderContainerFactory<?> containerFactory = context |
| 628 | + .getBean(DefaultPulsarReaderContainerFactory.class); |
| 629 | + assertThat(containerFactory).extracting(DefaultPulsarReaderContainerFactory::getContainerProperties) |
| 630 | + .extracting(PulsarReaderContainerProperties::getTopics, |
| 631 | + InstanceOfAssertFactories.list(String.class)) |
| 632 | + .containsExactly("fromPropsCustomizer", "customizer1", "customizer2"); |
| 633 | + }); |
| 634 | + } |
| 635 | + |
| 636 | + @TestConfiguration(proxyBeanMethods = false) |
| 637 | + static class ReaderContainerPropertiesCustomizerConfig { |
| 638 | + |
| 639 | + @Bean |
| 640 | + @Order(200) |
| 641 | + PulsarReaderContainerPropertiesCustomizer customizerFoo() { |
| 642 | + return (props) -> props.getTopics().add("customizer2"); |
| 643 | + } |
| 644 | + |
| 645 | + @Bean |
| 646 | + @Order(100) |
| 647 | + PulsarReaderContainerPropertiesCustomizer customizerBar() { |
| 648 | + return (props) -> props.getTopics().add("customizer1"); |
| 649 | + } |
| 650 | + |
| 651 | + } |
| 652 | + |
| 653 | + } |
| 654 | + |
520 | 655 | }
|
0 commit comments