Skip to content

Commit b33d906

Browse files
committed
Add unit test to confirm 'token-credential-bean-name' property work in spring-cloud-azure-stream-binder
1 parent 70079af commit b33d906

File tree

2 files changed

+245
-3
lines changed

2 files changed

+245
-3
lines changed

sdk/spring/spring-cloud-azure-stream-binder-eventhubs/src/test/java/com/azure/spring/cloud/stream/binder/eventhubs/implementation/config/EventHubsBinderConfigurationTests.java

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
package com.azure.spring.cloud.stream.binder.eventhubs.implementation.config;
55

6+
import com.azure.core.credential.TokenCredential;
67
import com.azure.messaging.eventhubs.CheckpointStore;
78
import com.azure.messaging.eventhubs.EventHubClientBuilder;
89
import com.azure.messaging.eventhubs.EventProcessorClientBuilder;
910
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties;
11+
import com.azure.spring.cloud.core.credential.AzureCredentialResolver;
1012
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
1113
import com.azure.spring.cloud.resourcemanager.implementation.provisioning.EventHubsProvisioner;
1214
import com.azure.spring.cloud.stream.binder.eventhubs.config.EventHubsProcessorFactoryCustomizer;
@@ -19,6 +21,8 @@
1921
import com.azure.spring.cloud.stream.binder.eventhubs.core.implementation.provisioning.EventHubsChannelProvisioner;
2022
import com.azure.spring.cloud.stream.binder.eventhubs.implementation.provisioning.EventHubsChannelResourceManagerProvisioner;
2123
import com.azure.spring.integration.eventhubs.inbound.EventHubsInboundChannelAdapter;
24+
import com.azure.spring.messaging.eventhubs.core.DefaultEventHubsNamespaceProducerFactory;
25+
import com.azure.spring.messaging.eventhubs.core.EventHubsTemplate;
2226
import com.azure.spring.messaging.eventhubs.core.checkpoint.CheckpointMode;
2327
import com.azure.spring.messaging.eventhubs.core.listener.EventHubsMessageListenerContainer;
2428
import com.azure.spring.messaging.eventhubs.core.properties.EventHubsContainerProperties;
@@ -32,7 +36,9 @@
3236
import org.springframework.cloud.stream.binder.Binder;
3337
import org.springframework.context.annotation.Bean;
3438
import org.springframework.context.annotation.Configuration;
39+
import org.springframework.test.util.ReflectionTestUtils;
3540

41+
import java.lang.reflect.Field;
3642
import java.time.Duration;
3743
import java.time.Instant;
3844

@@ -93,9 +99,6 @@ void shouldConfigureArmChannelProvisionerWhenResourceManagerProvided() {
9399
});
94100
}
95101

96-
// conniey: Remove warning suppression when azure-messaging-eventhubs is updated to 5.21.0.
97-
// https://github.com/Azure/azure-sdk-for-java/issues/46359
98-
@SuppressWarnings("deprecation")
99102
@Test
100103
void testExtendedBindingPropertiesShouldBind() {
101104
String producerConnectionString = String.format(CONNECTION_STRING_FORMAT, "fake-producer-namespace");
@@ -281,4 +284,116 @@ public void customize(Object builder) {
281284
}
282285
}
283286

287+
@Test
288+
void testCustomTokenCredentialConfiguration() {
289+
String connectionString = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
290+
291+
this.contextRunner
292+
.withConfiguration(AutoConfigurations.of(CustomTokenCredentialConfiguration.class))
293+
.withPropertyValues(
294+
"spring.cloud.azure.eventhubs.connection-string=" + connectionString,
295+
"spring.cloud.azure.eventhubs.credential.token-credential-bean-name=customTokenCredential"
296+
)
297+
.run(context -> {
298+
// Verify that the custom token credential bean exists
299+
assertThat(context).hasBean("customTokenCredential");
300+
TokenCredential customCredential = context.getBean("customTokenCredential", TokenCredential.class);
301+
assertThat(customCredential).isNotNull();
302+
303+
// Verify that the properties contain the correct credential bean name
304+
AzureEventHubsProperties eventHubsProperties = context.getBean(AzureEventHubsProperties.class);
305+
assertThat(eventHubsProperties).isNotNull();
306+
assertThat(eventHubsProperties.getCredential()).isNotNull();
307+
assertThat(eventHubsProperties.getCredential().getTokenCredentialBeanName())
308+
.as("The token-credential-bean-name property should be set to customTokenCredential")
309+
.isEqualTo("customTokenCredential");
310+
311+
// Verify the EventHubsProducerFactoryCustomizer is configured and can apply credential settings
312+
assertThat(context).hasSingleBean(EventHubsProducerFactoryCustomizer.class);
313+
EventHubsProducerFactoryCustomizer producerFactoryCustomizer =
314+
context.getBean(EventHubsProducerFactoryCustomizer.class);
315+
assertThat(producerFactoryCustomizer).isNotNull();
316+
317+
// Verify it's the default customizer with token credential resolver
318+
assertThat(producerFactoryCustomizer)
319+
.isInstanceOf(EventHubsBinderConfiguration.DefaultProducerFactoryCustomizer.class);
320+
});
321+
}
322+
323+
@Test
324+
void testCustomTokenCredentialConfigurationWithBinder() {
325+
String connectionString = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
326+
327+
this.contextRunner
328+
.withConfiguration(AutoConfigurations.of(CustomTokenCredentialConfiguration.class))
329+
.withBean(CheckpointStore.class, () -> mock(CheckpointStore.class))
330+
.withPropertyValues(
331+
"spring.cloud.azure.eventhubs.connection-string=" + connectionString,
332+
"spring.cloud.azure.eventhubs.credential.token-credential-bean-name=customTokenCredential",
333+
"spring.cloud.azure.eventhubs.namespace=test-namespace"
334+
)
335+
.run(context -> {
336+
assertThat(context).hasSingleBean(EventHubsMessageChannelBinder.class);
337+
EventHubsMessageChannelBinder binder = context.getBean(EventHubsMessageChannelBinder.class);
338+
339+
TokenCredential customCredential = context.getBean("customTokenCredential", TokenCredential.class);
340+
AzureEventHubsProperties eventHubsProperties = context.getBean(AzureEventHubsProperties.class);
341+
342+
// Test Producer Factory
343+
// Verify that credential resolver is properly configured in the producer factory created by binder
344+
EventHubsTemplate eventHubsTemplate = ReflectionTestUtils.invokeMethod(binder, "getEventHubTemplate");
345+
assertThat(eventHubsTemplate).isNotNull();
346+
347+
DefaultEventHubsNamespaceProducerFactory producerFactory = (DefaultEventHubsNamespaceProducerFactory) ReflectionTestUtils.getField(eventHubsTemplate, "producerFactory");
348+
assertThat(producerFactory).isNotNull();
349+
350+
// Use reflection to access the tokenCredentialResolver field in producer factory
351+
Field producerResolverField = producerFactory.getClass().getDeclaredField("tokenCredentialResolver");
352+
producerResolverField.setAccessible(true);
353+
Object producerResolver = producerResolverField.get(producerFactory);
354+
assertThat(producerResolver)
355+
.as("TokenCredentialResolver should be configured in the binder's producer factory")
356+
.isNotNull();
357+
358+
// Verify that producer resolver can resolve the custom credential
359+
@SuppressWarnings("unchecked")
360+
AzureCredentialResolver<TokenCredential> typedProducerResolver =
361+
(AzureCredentialResolver<TokenCredential>) producerResolver;
362+
TokenCredential producerResolvedCredential = typedProducerResolver.resolve(eventHubsProperties);
363+
assertThat(producerResolvedCredential)
364+
.as("The resolved credential in binder's producer factory should be the customTokenCredential bean")
365+
.isSameAs(customCredential);
366+
367+
// Test Processor Factory
368+
// Get the ProcessorFactory through reflection (it's created lazily in getProcessorFactory)
369+
Object processorFactory = ReflectionTestUtils.invokeMethod(binder, "getProcessorFactory");
370+
assertThat(processorFactory).isNotNull();
371+
372+
// Use reflection to access the tokenCredentialResolver field in processor factory
373+
Field processorResolverField = processorFactory.getClass().getDeclaredField("tokenCredentialResolver");
374+
processorResolverField.setAccessible(true);
375+
Object processorResolver = processorResolverField.get(processorFactory);
376+
assertThat(processorResolver)
377+
.as("TokenCredentialResolver should be configured in the binder's processor factory")
378+
.isNotNull();
379+
380+
// Verify that processor resolver can resolve the custom credential
381+
@SuppressWarnings("unchecked")
382+
AzureCredentialResolver<TokenCredential> typedProcessorResolver =
383+
(AzureCredentialResolver<TokenCredential>) processorResolver;
384+
TokenCredential processorResolvedCredential = typedProcessorResolver.resolve(eventHubsProperties);
385+
assertThat(processorResolvedCredential)
386+
.as("The resolved credential in binder's processor factory should be the customTokenCredential bean")
387+
.isSameAs(customCredential);
388+
});
389+
}
390+
391+
@Configuration
392+
public static class CustomTokenCredentialConfiguration {
393+
@Bean
394+
public TokenCredential customTokenCredential() {
395+
return mock(TokenCredential.class);
396+
}
397+
}
398+
284399
}

sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/test/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfigurationTests.java

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
package com.azure.spring.cloud.stream.binder.servicebus.implementation.config;
55

6+
import com.azure.core.credential.TokenCredential;
67
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
78
import com.azure.messaging.servicebus.models.ServiceBusReceiveMode;
9+
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
10+
import com.azure.spring.cloud.core.credential.AzureCredentialResolver;
811
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
912
import com.azure.spring.cloud.resourcemanager.implementation.provisioning.ServiceBusProvisioner;
1013
import com.azure.spring.cloud.service.servicebus.properties.ServiceBusEntityType;
@@ -16,13 +19,17 @@
1619
import com.azure.spring.cloud.stream.binder.servicebus.core.properties.ServiceBusProducerProperties;
1720
import com.azure.spring.cloud.stream.binder.servicebus.core.implementation.provisioning.ServiceBusChannelProvisioner;
1821
import com.azure.spring.cloud.stream.binder.servicebus.implementation.provisioning.ServiceBusChannelResourceManagerProvisioner;
22+
import com.azure.spring.messaging.servicebus.core.DefaultServiceBusNamespaceProducerFactory;
1923
import com.azure.spring.messaging.servicebus.implementation.support.converter.ServiceBusMessageConverter;
2024
import org.junit.jupiter.api.Test;
2125
import org.springframework.boot.autoconfigure.AutoConfigurations;
2226
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2327
import org.springframework.cloud.stream.binder.Binder;
28+
import org.springframework.context.annotation.Bean;
29+
import org.springframework.context.annotation.Configuration;
2430
import org.springframework.test.util.ReflectionTestUtils;
2531

32+
import java.lang.reflect.Field;
2633
import java.time.Duration;
2734

2835
import static com.azure.messaging.servicebus.models.SubQueue.DEAD_LETTER_QUEUE;
@@ -255,4 +262,124 @@ public void customize(Object builder) {
255262
}
256263
}
257264

265+
@Test
266+
void testCustomTokenCredentialConfiguration() {
267+
String connectionString = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
268+
269+
this.contextRunner
270+
.withConfiguration(AutoConfigurations.of(CustomTokenCredentialConfiguration.class))
271+
.withPropertyValues(
272+
"spring.cloud.azure.servicebus.connection-string=" + connectionString,
273+
"spring.cloud.azure.servicebus.credential.token-credential-bean-name=customTokenCredential"
274+
)
275+
.run(context -> {
276+
// Verify that the custom token credential bean exists
277+
assertThat(context).hasBean("customTokenCredential");
278+
TokenCredential customCredential = context.getBean("customTokenCredential", TokenCredential.class);
279+
assertThat(customCredential).isNotNull();
280+
281+
// Verify that the properties contain the correct credential bean name
282+
AzureServiceBusProperties serviceBusProperties = context.getBean(AzureServiceBusProperties.class);
283+
assertThat(serviceBusProperties).isNotNull();
284+
assertThat(serviceBusProperties.getCredential()).isNotNull();
285+
assertThat(serviceBusProperties.getCredential().getTokenCredentialBeanName())
286+
.as("The token-credential-bean-name property should be set to customTokenCredential")
287+
.isEqualTo("customTokenCredential");
288+
289+
// Verify the ServiceBusProducerFactoryCustomizer is configured and can apply credential settings
290+
assertThat(context).hasSingleBean(ServiceBusProducerFactoryCustomizer.class);
291+
ServiceBusProducerFactoryCustomizer producerFactoryCustomizer =
292+
context.getBean(ServiceBusProducerFactoryCustomizer.class);
293+
assertThat(producerFactoryCustomizer).isNotNull();
294+
295+
// Verify it's the default customizer with token credential resolver
296+
assertThat(producerFactoryCustomizer)
297+
.isInstanceOf(ServiceBusBinderConfiguration.DefaultProducerFactoryCustomizer.class);
298+
});
299+
}
300+
301+
@Test
302+
void testCustomTokenCredentialConfigurationWithBinder() {
303+
String connectionString = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
304+
305+
this.contextRunner
306+
.withConfiguration(AutoConfigurations.of(CustomTokenCredentialConfiguration.class))
307+
.withPropertyValues(
308+
"spring.cloud.azure.servicebus.connection-string=" + connectionString,
309+
"spring.cloud.azure.servicebus.credential.token-credential-bean-name=customTokenCredential"
310+
)
311+
.run(context -> {
312+
// Verify that the custom token credential bean exists
313+
assertThat(context).hasBean("customTokenCredential");
314+
TokenCredential customCredential = context.getBean("customTokenCredential", TokenCredential.class);
315+
assertThat(customCredential).isNotNull();
316+
317+
// Verify that the binder is created
318+
assertThat(context).hasSingleBean(ServiceBusMessageChannelBinder.class);
319+
ServiceBusMessageChannelBinder binder = context.getBean(ServiceBusMessageChannelBinder.class);
320+
assertThat(binder).isNotNull();
321+
322+
// Test Producer Factory
323+
// Get the ServiceBusTemplate through reflection (it's created lazily in getServiceBusTemplate)
324+
Object serviceBusTemplate = ReflectionTestUtils.invokeMethod(binder, "getServiceBusTemplate");
325+
assertThat(serviceBusTemplate).isNotNull();
326+
327+
// Get the producer factory from the template
328+
Field producerFactoryField = serviceBusTemplate.getClass().getDeclaredField("producerFactory");
329+
producerFactoryField.setAccessible(true);
330+
Object producerFactory = producerFactoryField.get(serviceBusTemplate);
331+
assertThat(producerFactory).isInstanceOf(DefaultServiceBusNamespaceProducerFactory.class);
332+
333+
// Verify tokenCredentialResolver is configured in the producer factory created by binder
334+
Field producerTokenCredentialResolverField =
335+
producerFactory.getClass().getDeclaredField("tokenCredentialResolver");
336+
producerTokenCredentialResolverField.setAccessible(true);
337+
Object producerTokenCredentialResolver = producerTokenCredentialResolverField.get(producerFactory);
338+
assertThat(producerTokenCredentialResolver)
339+
.as("TokenCredentialResolver should be configured in the binder's producer factory")
340+
.isNotNull();
341+
342+
// Verify it resolves to the custom credential
343+
AzureServiceBusProperties serviceBusProperties = context.getBean(AzureServiceBusProperties.class);
344+
@SuppressWarnings("unchecked")
345+
AzureCredentialResolver<TokenCredential> producerResolver =
346+
(AzureCredentialResolver<TokenCredential>) producerTokenCredentialResolver;
347+
TokenCredential producerResolvedCredential = producerResolver.resolve(serviceBusProperties);
348+
assertThat(producerResolvedCredential)
349+
.as("The resolved credential in binder's producer factory should be the customTokenCredential bean")
350+
.isSameAs(customCredential);
351+
352+
// Test Processor Factory
353+
// Get the ProcessorFactory through reflection (it's created lazily in getProcessorFactory)
354+
Object processorFactory = ReflectionTestUtils.invokeMethod(binder, "getProcessorFactory");
355+
assertThat(processorFactory).isNotNull();
356+
357+
// Verify tokenCredentialResolver is configured in the processor factory created by binder
358+
Field processorTokenCredentialResolverField =
359+
processorFactory.getClass().getDeclaredField("tokenCredentialResolver");
360+
processorTokenCredentialResolverField.setAccessible(true);
361+
Object processorTokenCredentialResolver = processorTokenCredentialResolverField.get(processorFactory);
362+
assertThat(processorTokenCredentialResolver)
363+
.as("TokenCredentialResolver should be configured in the binder's processor factory")
364+
.isNotNull();
365+
366+
// Verify it resolves to the custom credential
367+
@SuppressWarnings("unchecked")
368+
AzureCredentialResolver<TokenCredential> processorResolver =
369+
(AzureCredentialResolver<TokenCredential>) processorTokenCredentialResolver;
370+
TokenCredential processorResolvedCredential = processorResolver.resolve(serviceBusProperties);
371+
assertThat(processorResolvedCredential)
372+
.as("The resolved credential in binder's processor factory should be the customTokenCredential bean")
373+
.isSameAs(customCredential);
374+
});
375+
}
376+
377+
@Configuration
378+
public static class CustomTokenCredentialConfiguration {
379+
@Bean
380+
public TokenCredential customTokenCredential() {
381+
return mock(TokenCredential.class);
382+
}
383+
}
384+
258385
}

0 commit comments

Comments
 (0)