Skip to content

Commit

Permalink
Use new credential APIs in Spring Service Bus and Event Hubs and add …
Browse files Browse the repository at this point in the history
…more test cases (Azure#29484)

* use new credential APIs in Service Bus and Event Hubs and add more test cases
* fix compatibility error across spring boot versions
* add more tests
  • Loading branch information
saragluna authored and kwonus-msft committed Jun 24, 2022
1 parent 2b77977 commit e2183be
Show file tree
Hide file tree
Showing 47 changed files with 1,220 additions and 409 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
import com.azure.messaging.eventhubs.EventHubClientBuilder;
import com.azure.spring.cloud.autoconfigure.condition.ConditionalOnAnyProperty;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties;
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
import com.azure.spring.cloud.core.implementation.util.AzureSpringIdentifier;
import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider;
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
import com.azure.spring.cloud.core.service.AzureServiceType;
import com.azure.spring.cloud.service.implementation.eventhubs.factory.EventHubClientBuilderFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

Expand All @@ -26,7 +25,6 @@
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = { "connection-string", "namespace" })
@ConditionalOnProperty(prefix = "spring.cloud.azure.eventhubs", name = "event-hub-name")
class AzureEventHubsClientBuilderConfiguration {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ void configureGlobalShouldApplyToAzureCosmosProperties() {
AzureGlobalProperties azureProperties = new AzureGlobalProperties();
azureProperties.getCredential().setClientId("global-client-id");
azureProperties.getCredential().setClientSecret("global-client-secret");
azureProperties.getClient().setApplicationId("global-application-id");
azureProperties.getClient().setApplicationId("app");
azureProperties.getClient().getAmqp().setTransportType(AmqpTransportType.AMQP_WEB_SOCKETS);
azureProperties.getClient().getHttp().setConnectTimeout(Duration.ofMinutes(1));
azureProperties.getClient().getHttp().getLogging().setLevel(HttpLogDetailLevel.HEADERS);
Expand Down Expand Up @@ -82,7 +82,7 @@ void configureGlobalShouldApplyToAzureCosmosProperties() {
final AzureCosmosProperties properties = context.getBean(AzureCosmosProperties.class);
assertThat(properties).extracting("credential.clientId").isEqualTo("global-client-id");
assertThat(properties).extracting("credential.clientSecret").isEqualTo("global-client-secret");
assertThat(properties).extracting("client.applicationId").isEqualTo("global-application-id");
assertThat(properties).extracting("client.applicationId").isEqualTo("app");
assertThat(properties).extracting("proxy.hostname").isEqualTo("localhost");
assertThat(properties).extracting("proxy.nonProxyHosts").isEqualTo("localhost");

Expand Down Expand Up @@ -159,7 +159,7 @@ void configureGlobalShouldApplyToAmqpAzureEventHubsProperties() {
AzureGlobalProperties azureProperties = new AzureGlobalProperties();
azureProperties.getCredential().setClientId("global-client-id");
azureProperties.getCredential().setClientSecret("global-client-secret");
azureProperties.getClient().setApplicationId("global-application-id");
azureProperties.getClient().setApplicationId("app");
azureProperties.getClient().getAmqp().setTransportType(AmqpTransportType.AMQP_WEB_SOCKETS);
azureProperties.getClient().getHttp().getHeaders().add(headerProperties);
azureProperties.getClient().getHttp().setConnectTimeout(Duration.ofMinutes(1));
Expand Down Expand Up @@ -188,7 +188,7 @@ void configureGlobalShouldApplyToAmqpAzureEventHubsProperties() {
assertThat(properties).extracting("credential.clientId").isEqualTo("global-client-id");
assertThat(properties).extracting("credential.clientSecret").isEqualTo("global-client-secret");

assertThat(properties).extracting("client.applicationId").isEqualTo("global-application-id");
assertThat(properties).extracting("client.applicationId").isEqualTo("app");
assertThat(properties).extracting("client.transportType").isEqualTo(AmqpTransportType.AMQP_WEB_SOCKETS);

assertThat(properties).extracting("proxy.hostname").isEqualTo("localhost");
Expand Down Expand Up @@ -229,7 +229,7 @@ void configureGlobalShouldApplyToHttpAzureKeyVaultSecretProperties() {
AzureGlobalProperties azureProperties = new AzureGlobalProperties();
azureProperties.getCredential().setClientId("global-client-id");
azureProperties.getCredential().setClientSecret("global-client-secret");
azureProperties.getClient().setApplicationId("global-application-id");
azureProperties.getClient().setApplicationId("app");
azureProperties.getClient().getAmqp().setTransportType(AmqpTransportType.AMQP_WEB_SOCKETS);
azureProperties.getClient().getHttp().getHeaders().add(headerProperties);
azureProperties.getClient().getHttp().setConnectTimeout(Duration.ofMinutes(1));
Expand Down Expand Up @@ -259,7 +259,7 @@ void configureGlobalShouldApplyToHttpAzureKeyVaultSecretProperties() {
assertThat(properties).extracting("credential.clientId").isEqualTo("global-client-id");
assertThat(properties).extracting("credential.clientSecret").isEqualTo("global-client-secret");

assertThat(properties).extracting("client.applicationId").isEqualTo("global-application-id");
assertThat(properties).extracting("client.applicationId").isEqualTo("app");
assertThat(properties).extracting("client.connectTimeout").isEqualTo(Duration.ofMinutes(1));
assertThat(properties).extracting("client.logging.level").isEqualTo(HttpLogDetailLevel.HEADERS);
Set<String> allowedHeaderNames = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

class AzureEventHubsAutoConfigurationTests extends AbstractAzureServiceConfigurationTests<
EventHubClientBuilderFactory, AzureEventHubsProperties> {

private static final String CONNECTION_STRING = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(AzureEventHubsAutoConfiguration.class));

Expand Down Expand Up @@ -87,7 +87,7 @@ void configureWithNamespace() {
@Test
void configureWithConnectionString() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.eventhubs.connection-string=test-connection-string")
.withPropertyValues("spring.cloud.azure.eventhubs.connection-string=" + CONNECTION_STRING)
.withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.run(context -> assertThat(context).hasSingleBean(AzureEventHubsProperties.class));
}
Expand All @@ -105,7 +105,7 @@ void configureAzureEventHubsPropertiesWithGlobalDefaults() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.credential.client-id=eventhubs-client-id",
"spring.cloud.azure.eventhubs.retry.exponential.base-delay=2m",
"spring.cloud.azure.eventhubs.connection-string=test-connection-string"
"spring.cloud.azure.eventhubs.connection-string=" + CONNECTION_STRING
)
.run(context -> {
assertThat(context).hasSingleBean(AzureEventHubsProperties.class);
Expand All @@ -114,7 +114,7 @@ void configureAzureEventHubsPropertiesWithGlobalDefaults() {
assertThat(properties.getCredential().getClientSecret()).isEqualTo("azure-client-secret");
assertThat(properties.getRetry().getExponential().getBaseDelay()).isEqualTo(Duration.ofMinutes(2));
assertThat(properties.getRetry().getFixed().getDelay()).isEqualTo(Duration.ofSeconds(3));
assertThat(properties.getConnectionString()).isEqualTo("test-connection-string");
assertThat(properties.getConnectionString()).isEqualTo(CONNECTION_STRING);

assertThat(azureProperties.getCredential().getClientId()).isEqualTo("azure-client-id");
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,24 @@ void noConnectionInfoProvidedShouldNotConfigure() {
}

@Test
@SuppressWarnings("rawtypes")
void connectionStringProvidedShouldConfigure() {
contextRunner
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.eventhubs.event-hub-name=test-event-hub"
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
.withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(AzureEventHubsClientBuilderConfiguration.class);
assertThat(context).hasSingleBean(EventHubClientBuilderFactory.class);
assertThat(context).hasSingleBean(EventHubClientBuilder.class);
});
}

@Test
void namespaceProvidedShouldConfigure() {
contextRunner
.withPropertyValues(
"spring.cloud.azure.eventhubs.namespace=test-namespace"
)
.withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.run(context -> {
Expand All @@ -45,8 +57,7 @@ void customizerShouldBeCalled() {
EventHubBuilderCustomizer customizer = new EventHubBuilderCustomizer();
this.contextRunner
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.eventhubs.event-hub-name=test-event-hub"
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
.withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.withBean("customizer1", EventHubBuilderCustomizer.class, () -> customizer)
Expand All @@ -60,8 +71,7 @@ void otherCustomizerShouldNotBeCalled() {
OtherBuilderCustomizer otherBuilderCustomizer = new OtherBuilderCustomizer();
this.contextRunner
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.eventhubs.event-hub-name=test-event-hub"
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
.withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.withBean("customizer1", EventHubBuilderCustomizer.class, () -> customizer)
Expand All @@ -74,11 +84,10 @@ void otherCustomizerShouldNotBeCalled() {
}

@Test
void userDefinedEventHubsClientBuilderProvidedShouldNotConfigureTheAuto() {
void userDefinedEventHubsClientBuilderProvidedShouldNotAutoconfigure() {
this.contextRunner
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.eventhubs.event-hub-name=test-event-hub"
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
.withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.withBean("user-defined-builder", EventHubClientBuilder.class, EventHubClientBuilder::new)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;

class AzureStorageBlobAutoConfigurationTests extends AbstractAzureServiceConfigurationTests<
BlobServiceClientBuilderFactory, AzureStorageBlobProperties> {
Expand Down Expand Up @@ -209,6 +210,10 @@ void configurationPropertiesShouldBind() {
"spring.cloud.azure.storage.blob.blob-name=test-blob"
)
.withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.withBean(BlobServiceAsyncClient.class, () -> mock(BlobServiceAsyncClient.class))
.withBean(BlobServiceClient.class, () -> mock(BlobServiceClient.class))
.withBean(BlobAsyncClient.class, () -> mock(BlobAsyncClient.class))
.withBean(BlobClient.class, () -> mock(BlobClient.class))
.run(context -> {
assertThat(context).hasSingleBean(AzureStorageBlobProperties.class);
AzureStorageBlobProperties properties = context.getBean(AzureStorageBlobProperties.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ protected List<AuthenticationDescriptor<?>> getAuthenticationDescriptors(Configu
protected void configureService(ConfigurationClientBuilder builder) {
PropertyMapper map = new PropertyMapper();
map.from(configurationClientProperties.getEndpoint()).to(builder::endpoint);
map.from(configurationClientProperties.getConnectionString()).to(builder::connectionString);
map.from(configurationClientProperties.getServiceVersion()).to(builder::serviceVersion);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
import com.azure.core.amqp.AmqpRetryOptions;
import com.azure.core.amqp.AmqpTransportType;
import com.azure.core.amqp.ProxyOptions;
import com.azure.core.amqp.implementation.ConnectionStringProperties;
import com.azure.core.credential.TokenCredential;
import com.azure.core.util.ClientOptions;
import com.azure.core.util.Configuration;
import com.azure.messaging.eventhubs.EventHubClientBuilder;
import com.azure.messaging.eventhubs.implementation.ClientConstants;
import com.azure.messaging.eventhubs.implementation.EventHubSharedKeyCredential;
import com.azure.spring.cloud.core.implementation.credential.descriptor.AuthenticationDescriptor;
import com.azure.spring.cloud.core.implementation.credential.descriptor.NamedKeyAuthenticationDescriptor;
import com.azure.spring.cloud.core.implementation.credential.descriptor.SasAuthenticationDescriptor;
Expand All @@ -20,6 +23,9 @@
import com.azure.spring.cloud.service.implementation.eventhubs.properties.EventHubClientCommonProperties;
import com.azure.spring.cloud.service.implementation.eventhubs.properties.EventHubConsumerProperties;
import com.azure.spring.cloud.service.implementation.eventhubs.properties.EventHubsNamespaceProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
Expand All @@ -31,6 +37,8 @@
*/
public class EventHubClientBuilderFactory extends AbstractAzureAmqpClientBuilderFactory<EventHubClientBuilder> {

public static final Logger LOGGER = LoggerFactory.getLogger(EventHubClientBuilderFactory.class);

private final EventHubClientCommonProperties eventHubsProperties;

/**
Expand Down Expand Up @@ -68,14 +76,21 @@ protected BiConsumer<EventHubClientBuilder, Configuration> consumeConfiguration(

@Override
protected BiConsumer<EventHubClientBuilder, TokenCredential> consumeDefaultTokenCredential() {
return (builder, tokenCredential) -> builder.credential(eventHubsProperties.getFullyQualifiedNamespace(),
eventHubsProperties.getEventHubName(),
tokenCredential);
return (builder, tokenCredential) -> builder.credential(tokenCredential);
}

@Override
protected BiConsumer<EventHubClientBuilder, String> consumeConnectionString() {
return (builder, connectionString) -> builder.connectionString(connectionString, this.eventHubsProperties.getEventHubName());
return (builder, connectionString) -> {
if (StringUtils.hasText(this.eventHubsProperties.getEventHubName())) {
builder.connectionString(connectionString, this.eventHubsProperties.getEventHubName());
} else {
LOGGER.info("The eventhub name is not configured, will call credential method instead of connectionString method.");
final ConnectionStringProperties properties = new ConnectionStringProperties(connectionString);
TokenCredential tokenCredential = getTokenCredential(properties);
builder.credential(tokenCredential);
}
};
}

@Override
Expand All @@ -96,6 +111,8 @@ protected void configureService(EventHubClientBuilder builder) {
PropertyMapper mapper = new PropertyMapper();

mapper.from(eventHubsProperties.getCustomEndpointAddress()).to(builder::customEndpointAddress);
mapper.from(eventHubsProperties.getFullyQualifiedNamespace()).to(builder::fullyQualifiedNamespace);
mapper.from(eventHubsProperties.getEventHubName()).to(builder::eventHubName);

if (this.eventHubsProperties instanceof EventHubsNamespaceProperties) {
mapper.from(((EventHubsNamespaceProperties) this.eventHubsProperties).getSharedConnection())
Expand All @@ -119,13 +136,21 @@ protected void configureService(EventHubClientBuilder builder) {
@Override
protected List<AuthenticationDescriptor<?>> getAuthenticationDescriptors(EventHubClientBuilder builder) {
return Arrays.asList(
new NamedKeyAuthenticationDescriptor(c -> builder.credential(
eventHubsProperties.getFullyQualifiedNamespace(), eventHubsProperties.getEventHubName(), c)),
new SasAuthenticationDescriptor(c -> builder.credential(
eventHubsProperties.getFullyQualifiedNamespace(), eventHubsProperties.getEventHubName(), c)),
new TokenAuthenticationDescriptor(this.tokenCredentialResolver, c -> builder.credential(
eventHubsProperties.getFullyQualifiedNamespace(), eventHubsProperties.getEventHubName(), c))
new NamedKeyAuthenticationDescriptor(builder::credential),
new SasAuthenticationDescriptor(builder::credential),
new TokenAuthenticationDescriptor(this.tokenCredentialResolver, c -> builder.credential(c))
);
}

private TokenCredential getTokenCredential(ConnectionStringProperties properties) {
TokenCredential tokenCredential;
if (properties.getSharedAccessSignature() == null) {
tokenCredential = new EventHubSharedKeyCredential(properties.getSharedAccessKeyName(),
properties.getSharedAccessKey(), ClientConstants.TOKEN_VALIDITY);
} else {
tokenCredential = new EventHubSharedKeyCredential(properties.getSharedAccessSignature());
}
return tokenCredential;
}

}
Loading

0 comments on commit e2183be

Please sign in to comment.