diff --git a/eng/common/testproxy/test-proxy-standalone-tool.yml b/eng/common/testproxy/test-proxy-standalone-tool.yml
index fb9696e6de1f..1ced596eb648 100644
--- a/eng/common/testproxy/test-proxy-standalone-tool.yml
+++ b/eng/common/testproxy/test-proxy-standalone-tool.yml
@@ -74,6 +74,9 @@ steps:
# nohup does NOT continue beyond the current session if you use it within powershell
- bash: |
+ if [[ "$(uname)" == "Darwin" ]]; then
+ export DOTNET_ROOT="$HOME/.dotnet"
+ fi
echo "nohup $(PROXY_EXE) 1>${{ parameters.rootFolder }}/test-proxy.log 2>${{ parameters.rootFolder }}/test-proxy-error.log &"
nohup $(PROXY_EXE) 1>${{ parameters.rootFolder }}/test-proxy.log 2>${{ parameters.rootFolder }}/test-proxy-error.log &
@@ -84,6 +87,8 @@ steps:
displayName: "Run the testproxy - linux/mac"
condition: and(succeeded(), ne(variables['Agent.OS'],'Windows_NT'), ${{ parameters.condition }})
workingDirectory: "${{ parameters.rootFolder }}"
+ env:
+ DOTNET_ROLL_FORWARD: 'Major'
- pwsh: |
for ($i = 0; $i -lt 10; $i++) {
diff --git a/eng/common/testproxy/test-proxy-tool.yml b/eng/common/testproxy/test-proxy-tool.yml
index 03c9dbaa00c1..f2d0fe6e30b0 100644
--- a/eng/common/testproxy/test-proxy-tool.yml
+++ b/eng/common/testproxy/test-proxy-tool.yml
@@ -87,6 +87,9 @@ steps:
# nohup does NOT continue beyond the current session if you use it within powershell
- bash: |
+ if [[ "$(uname)" == "Darwin" ]]; then
+ export DOTNET_ROOT="$HOME/.dotnet"
+ fi
nohup $(Build.BinariesDirectory)/test-proxy/test-proxy 1>${{ parameters.rootFolder }}/test-proxy.log 2>${{ parameters.rootFolder }}/test-proxy-error.log &
echo $! > $(Build.SourcesDirectory)/test-proxy.pid
diff --git a/eng/pipelines/templates/stages/archetype-java-release-batch.yml b/eng/pipelines/templates/stages/archetype-java-release-batch.yml
index 52ca68764cbf..a4367a280af6 100644
--- a/eng/pipelines/templates/stages/archetype-java-release-batch.yml
+++ b/eng/pipelines/templates/stages/archetype-java-release-batch.yml
@@ -92,7 +92,7 @@ stages:
# the Validation step below publishes a package to a "burner" feed which is cleaned up after the
# pipeline completes.
- ${{if and(in(variables['Build.Reason'], 'Manual', ''), eq(variables['System.TeamProject'], 'internal'))}}:
- - stage:
+ - stage: Release
displayName: 'Releasing: ${{ length(parameters.Artifacts) }} libraries'
dependsOn: Signing
condition: and(succeeded(), ne(variables['SetDevVersion'], 'true'), ne(variables['Skip.Release'], 'true'), ne(variables['Build.Repository.Name'], 'Azure/azure-sdk-for-java-pr'))
diff --git a/eng/pipelines/templates/stages/archetype-java-release-patch.yml b/eng/pipelines/templates/stages/archetype-java-release-patch.yml
index eedda64b29c6..dc9becd0233d 100644
--- a/eng/pipelines/templates/stages/archetype-java-release-patch.yml
+++ b/eng/pipelines/templates/stages/archetype-java-release-patch.yml
@@ -80,7 +80,7 @@ stages:
# the Validation step below publishes a package to a "burner" feed which is cleaned up after the
# pipeline completes.
- ${{if and(in(variables['Build.Reason'], 'Manual', ''), eq(variables['System.TeamProject'], 'internal'))}}:
- - stage:
+ - stage: Release
displayName: 'Releasing: ${{ length(parameters.Artifacts) }} libraries'
dependsOn: Signing
variables:
diff --git a/eng/pipelines/templates/stages/archetype-java-release-pom-only.yml b/eng/pipelines/templates/stages/archetype-java-release-pom-only.yml
index 244bb973bd0c..2f092fc9b72a 100644
--- a/eng/pipelines/templates/stages/archetype-java-release-pom-only.yml
+++ b/eng/pipelines/templates/stages/archetype-java-release-pom-only.yml
@@ -74,7 +74,7 @@ stages:
# pipeline completes.
- ${{if and(eq(variables['Build.Reason'], 'Manual'), eq(variables['System.TeamProject'], 'internal'))}}:
- ${{ each artifact in parameters.Artifacts }}:
- - stage:
+ - stage: Release_${{artifact.safeName}}
displayName: 'Release: ${{artifact.name}}'
dependsOn: Signing
variables:
diff --git a/eng/pipelines/templates/steps/install-latest-jdk.yml b/eng/pipelines/templates/steps/install-latest-jdk.yml
index 8149c86e16d1..3c7273d81938 100644
--- a/eng/pipelines/templates/steps/install-latest-jdk.yml
+++ b/eng/pipelines/templates/steps/install-latest-jdk.yml
@@ -31,3 +31,13 @@ steps:
Write-Host "Latest JDK: $Env:JAVA_HOME_${{ parameters.LatestJdkFeatureVersion }}_X64"
displayName: 'Verify Latest JDK Install'
condition: eq(variables['IsLatestNonLtsJdk'], 'true')
+
+ - task: PowerShell@2
+ displayName: 'Install JDK 8 on macOS'
+ inputs:
+ pwsh: true
+ arguments: >
+ -JdkFeatureVersion 8
+ workingDirectory: $(Agent.BuildDirectory)
+ filePath: eng/scripts/Install-Latest-JDK.ps1
+ condition: eq(variables['Agent.OS'], 'Darwin')
diff --git a/eng/scripts/Install-Latest-JDK.ps1 b/eng/scripts/Install-Latest-JDK.ps1
index c5ae818508b8..4a6c472a7285 100644
--- a/eng/scripts/Install-Latest-JDK.ps1
+++ b/eng/scripts/Install-Latest-JDK.ps1
@@ -16,6 +16,19 @@ if ($IsWindows) {
$os = "linux"
}
+$jdkFeatureVersionJavaHome = "JAVA_HOME_" + $JdkFeatureVersion + "_X64"
+Write-Host "Checking if $jdkFeatureVersionJavaHome is already set and exists..."
+$javaHomeValue = [System.Environment]::GetEnvironmentVariable($jdkFeatureVersionJavaHome)
+if ($javaHomeValue) {
+ $jdkBinPath = Join-Path -Path $javaHomeValue -ChildPath "bin/java"
+ if (Test-Path -Path $jdkBinPath) {
+ Write-Host "$jdkFeatureVersionJavaHome is already set to $javaHomeValue"
+ exit 0
+ }
+} else {
+ Write-Host "$jdkFeatureVersionJavaHome is not set, proceeding with installation..."
+}
+
$getInstalls = "$adoptiumApiUrl/v3/assets/latest/$JdkFeatureVersion/hotspot?architecture=x64&image_type=jdk&os=$os&vendor=eclipse"
$jdkUnzipName = "jdk-$JdkFeatureVersion"
@@ -43,11 +56,22 @@ if (!(Test-Path -Path $jdkUnzipName -PathType container)) {
}
$javaHome = (Convert-Path $jdkUnzipName)
-Write-Host "Latest JDK: $javaHome"
+if ($IsMacOS) {
+ # On macOS, the JDK is inside a subdirectory of the unzipped folder.
+ $correctJavaHome = Join-Path -Path $javaHome -ChildPath "Contents/Home"
+ $javaBinPath = Join-Path -Path $correctJavaHome -ChildPath "bin/java"
+ if (Test-Path $javaBinPath) {
+ $javaHome = $correctJavaHome
+ Write-Host "Updated JAVA_HOME on macOS: $correctJavaHome"
+ } else {
+ Write-Error "Failed to find Java at: $correctJavaHome"
+ exit 1
+ }
+}
+
+Write-Host "Latest JDK: $javaHome"
Write-Host "Current JAVA_HOME: $Env:JAVA_HOME"
Write-Host "##vso[task.setvariable variable=JAVA_HOME;]$javaHome"
-Write-Host "Updated JAVA_HOME: $Env:JAVA_HOME"
-
-$jdkFeatureVersionJavaHome = "JAVA_HOME_" + $JdkFeatureVersion + "_X64"
+Write-Host "Updated JAVA_HOME to : $javaHome"
Write-Host "##vso[task.setvariable variable=$jdkFeatureVersionJavaHome;]$javaHome"
diff --git a/eng/versioning/external_dependencies.txt b/eng/versioning/external_dependencies.txt
index 536a7a7abccc..3296b24c5f4f 100644
--- a/eng/versioning/external_dependencies.txt
+++ b/eng/versioning/external_dependencies.txt
@@ -141,7 +141,7 @@ commons-cli:commons-cli;1.9.0
org.assertj:assertj-core;3.22.0
org.bouncycastle:bcprov-jdk15to18;1.78.1
org.bouncycastle:bcprov-jdk18on;1.78.1
-org.bouncycastle:bcpkix-lts8on;2.73.6
+org.bouncycastle:bcpkix-lts8on;2.73.8
org.eclipse.jetty:jetty-alpn-conscrypt-server;9.4.57.v20241219
org.eclipse.jetty:jetty-server;9.4.57.v20241219
org.eclipse.jetty:jetty-servlet;9.4.57.v20241219
@@ -411,8 +411,11 @@ springboot3_org.springframework:spring-test;6.2.9
springboot3_org.springframework:spring-tx;6.2.9
springboot3_org.springframework:spring-web;6.2.9
springboot3_org.springframework:spring-webmvc;6.2.9
-springboot3_org.testcontainers:junit-jupiter;1.21.3
-springboot3_org.testcontainers:azure;1.21.3
+springboot3_org.testcontainers:testcontainers-junit-jupiter;2.0.3
+springboot3_org.testcontainers:testcontainers-azure;2.0.3
+springboot3_org.testcontainers:testcontainers;2.0.3
+springboot3_org.awaitility:awaitility;4.3.0
+springboot3_com.microsoft.sqlserver:mssql-jdbc;13.2.1.jre11
# Used for Spring version updates
springboot3_org.springframework.boot:spring-boot-dependencies;3.5.4
springboot3_org.springframework.cloud:spring-cloud-dependencies;2025.0.0
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/pom.xml b/sdk/keyvault/azure-security-keyvault-certificates/pom.xml
index fcff7bd24233..e88241df2d9a 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/pom.xml
+++ b/sdk/keyvault/azure-security-keyvault-certificates/pom.xml
@@ -79,7 +79,7 @@
org.bouncycastle
bcpkix-lts8on
- 2.73.6
+ 2.73.8
test
diff --git a/sdk/keyvault/azure-security-keyvault-jca/pom.xml b/sdk/keyvault/azure-security-keyvault-jca/pom.xml
index ed2c196d8cdb..8dcaff887991 100644
--- a/sdk/keyvault/azure-security-keyvault-jca/pom.xml
+++ b/sdk/keyvault/azure-security-keyvault-jca/pom.xml
@@ -32,7 +32,7 @@
org.bouncycastle
bcpkix-lts8on
- 2.73.6
+ 2.73.8
true
@@ -274,7 +274,7 @@
- org.bouncycastle:bcpkix-lts8on:[2.73.6]
+ org.bouncycastle:bcpkix-lts8on:[2.73.8]
org.conscrypt:conscrypt-openjdk-uber:[2.5.2]
org.apache.httpcomponents.client5:httpclient5:[5.4.3]
org.brotli:dec:[0.1.2]
diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md
index 4eb6c594b84d..bbd52e3ef6df 100644
--- a/sdk/spring/CHANGELOG.md
+++ b/sdk/spring/CHANGELOG.md
@@ -1,5 +1,34 @@
# Release History
+## 5.25.0 (Not Released)
+
+### Spring Cloud Azure Autoconfigure
+
+This section includes changes in `spring-cloud-azure-autoconfigure` module.
+
+#### New Features
+
+- Add ConnectionDetails for ServiceBus. [#44019](https://github.com/Azure/azure-sdk-for-java/pull/44019).
+- Add ConnectionDetails for EventHubs. [#47926](https://github.com/Azure/azure-sdk-for-java/pull/47926).
+
+### Spring Cloud Azure Docker Compose
+
+This section includes changes in `spring-cloud-azure-docker-compose` module.
+
+#### New Features
+
+- Add ServiceBusDockerComposeConnectionDetailsFactory. [#44019](https://github.com/Azure/azure-sdk-for-java/pull/44019).
+- Add EventHubsDockerComposeConnectionDetailsFactory. [#47926](https://github.com/Azure/azure-sdk-for-java/pull/47926).
+
+### Spring Cloud Azure Test Containers
+
+This section includes changes in `spring-cloud-azure-testcontainers` module.
+
+#### New Features
+
+- Add ServiceBusContainerConnectionDetailsFactory. [#44019](https://github.com/Azure/azure-sdk-for-java/pull/44019).
+- Add EventHubsContainerConnectionDetailsFactory. [#47926](https://github.com/Azure/azure-sdk-for-java/pull/47926).
+
## 5.24.1 (2025-12-09)
- This release is compatible with Spring Boot 3.5.0-3.5.8, 3.4.0-3.4.12, 3.3.0-3.3.13, 3.2.0-3.2.12, 3.1.0-3.1.12, 3.0.0-3.0.13. (Note: 3.5.x (x>8) and 3.4.y (y>12) should be supported, but they aren't tested with this release.)
- This release is compatible with Spring Cloud 2025.0.0, 2024.0.0-2024.0.2, 2023.0.0-2023.0.5, 2022.0.0-2022.0.5. (Note: 2025.0.x(x>0) and 2024.0.y (y>2) should be supported, but they aren't tested with this release.)
diff --git a/sdk/spring/README.md b/sdk/spring/README.md
index ff739590349a..6809b4801868 100644
--- a/sdk/spring/README.md
+++ b/sdk/spring/README.md
@@ -189,7 +189,7 @@ dependencyManagement {
## Spring Boot 3 Support
-The source code of Spring Cloud Azure for Spring Boot 3.x can be found on the [feature/spring-boot-3](https://github.com/Azure/azure-sdk-for-java/tree/feature/spring-boot-3) branch.
+Spring Cloud Azure 5.25.0 is the latest supported version of Spring Boot 3.x.
#### Spring AOT and Spring native images
diff --git a/sdk/spring/azure-spring-data-cosmos/README.md b/sdk/spring/azure-spring-data-cosmos/README.md
index 216b5aaf41f3..0ff09140e7d2 100644
--- a/sdk/spring/azure-spring-data-cosmos/README.md
+++ b/sdk/spring/azure-spring-data-cosmos/README.md
@@ -280,8 +280,8 @@ java -javaagent:"" -jar
#### Using database provisioned throughput
-Cosmos supports both [container](https://learn.microsoft.com/azure/cosmos-db/sql/how-to-provision-container-throughput)
-and [database](https://learn.microsoft.com/azure/cosmos-db/sql/how-to-provision-database-throughput) provisioned
+Cosmos supports both [container](https://learn.microsoft.com/azure/cosmos-db/how-to-provision-container-throughput)
+and [database](https://learn.microsoft.com/azure/cosmos-db/how-to-provision-database-throughput) provisioned
throughput. By default, spring-data-cosmos will provision throughput for each container created. If you prefer
to share throughput between containers, you can enable database provisioned throughput via CosmosConfig.
@@ -608,7 +608,7 @@ public class MyItem {
String _etag;
}
```
-- Read more about Optimistic Locking [here](https://learn.microsoft.com/azure/cosmos-db/sql/database-transactions-optimistic-concurrency#optimistic-concurrency-control)
+- Read more about Optimistic Locking [here](https://learn.microsoft.com/azure/cosmos-db/database-transactions-optimistic-concurrency#optimistic-concurrency-control)
### Spring Data custom query, pageable and sorting
- Azure-spring-data-cosmos supports [spring data custom queries][spring_data_custom_query]
@@ -1148,8 +1148,8 @@ or contact [opencode@microsoft.com][coc_contact] with any additional questions o
[coc_contact]: mailto:opencode@microsoft.com
[azure_subscription]: https://azure.microsoft.com/free/
[samples]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/spring/azure-spring-data-cosmos/src/samples/java/com/azure/spring/data/cosmos
-[sample-for-multi-database]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_v4.3.0/cosmos/azure-spring-data-cosmos/cosmos-multi-database-multi-account
-[sample-for-multi-database-single-account]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_v4.3.0/cosmos/azure-spring-data-cosmos/cosmos-multi-database-single-account
+[sample-for-multi-database]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-boot-3.x/cosmos/azure-spring-data-cosmos/cosmos-multi-database-multi-account
+[sample-for-multi-database-single-account]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-boot-3.x/cosmos/azure-spring-data-cosmos/cosmos-multi-database-single-account
[sql_api_query]: https://learn.microsoft.com/azure/cosmos-db/sql-api-sql-query
[local_emulator]: https://learn.microsoft.com/azure/cosmos-db/local-emulator
[local_emulator_export_ssl_certificates]: https://learn.microsoft.com/azure/cosmos-db/local-emulator-export-ssl-certificates
diff --git a/sdk/spring/pipeline/spring-cloud-azure-supported-spring.json b/sdk/spring/pipeline/spring-cloud-azure-supported-spring.json
index ea26b6a99dde..0156d7f2a5e6 100644
--- a/sdk/spring/pipeline/spring-cloud-azure-supported-spring.json
+++ b/sdk/spring/pipeline/spring-cloud-azure-supported-spring.json
@@ -563,7 +563,7 @@
"current" : false,
"releaseStatus" : "GENERAL_AVAILABILITY",
"snapshot" : false,
- "supportStatus" : "SUPPORTED",
+ "supportStatus" : "END_OF_LIFE",
"spring-boot-version" : "3.0.13",
"spring-cloud-version" : "2022.0.5"
},
diff --git a/sdk/spring/scripts/compatibility_delete_version.py b/sdk/spring/scripts/compatibility_delete_version.py
index e5b59474c2bf..b7b3b011cd4f 100644
--- a/sdk/spring/scripts/compatibility_delete_version.py
+++ b/sdk/spring/scripts/compatibility_delete_version.py
@@ -30,6 +30,20 @@
SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "net.bytebuddy:byte-buddy",
SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "net.bytebuddy:byte-buddy-agent",
SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.mockito:mockito-core"
+ },
+ "3.1.12": {
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.apache.commons:commons-lang3",
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.testcontainers:azure",
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.testcontainers:testcontainers"
+ },
+ "3.2.12": {
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.apache.commons:commons-lang3",
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.testcontainers:azure",
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.testcontainers:testcontainers"
+ },
+ "3.3.13": {
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.testcontainers:azure",
+ SPRING_BOOT_MAJOR_3_VERSION_TAG_PREFIX + "org.testcontainers:testcontainers"
}
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfiguration.java
index c5b09a30c5f7..2b725965744d 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfiguration.java
@@ -4,8 +4,6 @@
package com.azure.spring.cloud.autoconfigure.implementation.cosmos;
import com.azure.cosmos.CosmosClientBuilder;
-import com.azure.spring.cloud.autoconfigure.implementation.AzureServiceConfigurationBase;
-import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
import com.azure.spring.cloud.autoconfigure.implementation.cosmos.properties.AzureCosmosPropertiesConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -21,9 +19,5 @@
CosmosClientConfiguration.class
})
@ConditionalOnClass(CosmosClientBuilder.class)
-public class AzureCosmosAutoConfiguration extends AzureServiceConfigurationBase {
-
- protected AzureCosmosAutoConfiguration(AzureGlobalProperties azureProperties) {
- super(azureProperties);
- }
+public class AzureCosmosAutoConfiguration {
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureBlobCheckpointStoreConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureBlobCheckpointStoreConfiguration.java
index 16fd2746bb4d..48ce309d0e8d 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureBlobCheckpointStoreConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureBlobCheckpointStoreConfiguration.java
@@ -16,6 +16,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -32,6 +33,7 @@
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ BlobCheckpointStore.class, EventHubClientBuilder.class})
+@ConditionalOnBean(AzureEventHubsProperties.class)
@ConditionalOnProperty(prefix = "spring.cloud.azure.eventhubs.processor.checkpoint-store", name = { "container-name", "account-name" })
class AzureBlobCheckpointStoreConfiguration {
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfiguration.java
index 13aef3712767..20bef7bf3721 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfiguration.java
@@ -4,20 +4,10 @@
package com.azure.spring.cloud.autoconfigure.implementation.eventhubs;
import com.azure.messaging.eventhubs.EventHubClientBuilder;
-import com.azure.spring.cloud.autoconfigure.implementation.AzureServiceConfigurationBase;
-import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
-import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
-import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties;
-import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider;
-import com.azure.spring.cloud.core.provider.connectionstring.StaticConnectionStringProvider;
-import com.azure.spring.cloud.core.service.AzureServiceType;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsPropertiesConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
@@ -27,33 +17,14 @@
*/
@ConditionalOnClass(EventHubClientBuilder.class)
@ConditionalOnProperty(value = "spring.cloud.azure.eventhubs.enabled", havingValue = "true", matchIfMissing = true)
-@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = { "connection-string", "namespace" })
@Import({
+ AzureEventHubsPropertiesConfiguration.class,
AzureEventHubsClientBuilderConfiguration.class,
AzureEventHubsConsumerClientConfiguration.class,
AzureEventHubsProducerClientConfiguration.class,
AzureBlobCheckpointStoreConfiguration.class,
AzureEventHubsProcessorClientConfiguration.class
})
-public class AzureEventHubsAutoConfiguration extends AzureServiceConfigurationBase {
-
- AzureEventHubsAutoConfiguration(AzureGlobalProperties azureGlobalProperties) {
- super(azureGlobalProperties);
- }
-
- @Bean
- @ConfigurationProperties(AzureEventHubsProperties.PREFIX)
- AzureEventHubsProperties azureEventHubsProperties() {
- return loadProperties(getAzureGlobalProperties(), new AzureEventHubsProperties());
- }
-
- @Bean
- @ConditionalOnExpression("'${spring.cloud.azure.eventhubs.connection-string:}' != ''")
- @ConditionalOnMissingBean(value = AzureServiceType.EventHubs.class, parameterizedContainer = ServiceConnectionStringProvider.class)
- StaticConnectionStringProvider eventHubsStaticConnectionStringProvider(
- AzureEventHubsProperties eventHubsProperties) {
- return new StaticConnectionStringProvider<>(AzureServiceType.EVENT_HUBS,
- eventHubsProperties.getConnectionString());
- }
+public class AzureEventHubsAutoConfiguration {
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfiguration.java
index 9f4471b9fe0c..43f98426b7ea 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfiguration.java
@@ -4,18 +4,23 @@
package com.azure.spring.cloud.autoconfigure.implementation.eventhubs;
import com.azure.messaging.eventhubs.EventHubClientBuilder;
-import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsPropertiesConfiguration;
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.provider.connectionstring.StaticConnectionStringProvider;
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.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.EVENT_HUB_CLIENT_BUILDER_FACTORY_BEAN_NAME;
@@ -24,9 +29,16 @@
*
*/
@Configuration(proxyBeanMethods = false)
-@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = { "connection-string", "namespace" })
+@Import(AzureEventHubsPropertiesConfiguration.class)
+@ConditionalOnBean(AzureEventHubsProperties.class)
class AzureEventHubsClientBuilderConfiguration {
+ private final AzureEventHubsProperties eventHubsProperties;
+
+ AzureEventHubsClientBuilderConfiguration(AzureEventHubsProperties eventHubsProperties) {
+ this.eventHubsProperties = eventHubsProperties;
+ }
+
@Bean
@ConditionalOnMissingBean
EventHubClientBuilder eventHubClientBuilder(@Qualifier(EVENT_HUB_CLIENT_BUILDER_FACTORY_BEAN_NAME)
@@ -36,10 +48,10 @@ EventHubClientBuilder eventHubClientBuilder(@Qualifier(EVENT_HUB_CLIENT_BUILDER_
@Bean(EVENT_HUB_CLIENT_BUILDER_FACTORY_BEAN_NAME)
@ConditionalOnMissingBean
- EventHubClientBuilderFactory eventHubClientBuilderFactory(AzureEventHubsProperties properties,
+ EventHubClientBuilderFactory eventHubClientBuilderFactory(
ObjectProvider> connectionStringProviders,
ObjectProvider> customizers) {
- final EventHubClientBuilderFactory factory = new EventHubClientBuilderFactory(properties);
+ final EventHubClientBuilderFactory factory = new EventHubClientBuilderFactory(this.eventHubsProperties);
factory.setSpringIdentifier(AzureSpringIdentifier.AZURE_SPRING_EVENT_HUBS);
connectionStringProviders.orderedStream().findFirst().ifPresent(factory::setConnectionStringProvider);
@@ -47,4 +59,21 @@ EventHubClientBuilderFactory eventHubClientBuilderFactory(AzureEventHubsProperti
return factory;
}
+ @Bean
+ @ConditionalOnExpression("'${spring.cloud.azure.eventhubs.connection-string:}' != ''")
+ @ConditionalOnMissingBean(value = AzureServiceType.EventHubs.class, parameterizedContainer = ServiceConnectionStringProvider.class)
+ StaticConnectionStringProvider eventHubsStaticConnectionStringProvider() {
+ return new StaticConnectionStringProvider<>(AzureServiceType.EVENT_HUBS,
+ this.eventHubsProperties.getConnectionString());
+ }
+
+ @Bean
+ @ConditionalOnBean(AzureEventHubsConnectionDetails.class)
+ @ConditionalOnMissingBean(value = AzureServiceType.EventHubs.class, parameterizedContainer = ServiceConnectionStringProvider.class)
+ StaticConnectionStringProvider eventHubsConnectionDetailsStaticConnectionStringProvider(
+ AzureEventHubsConnectionDetails connectionDetails) {
+ return new StaticConnectionStringProvider<>(AzureServiceType.EVENT_HUBS,
+ connectionDetails.getConnectionString());
+ }
+
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsConsumerClientConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsConsumerClientConfiguration.java
index f1a8bc145d36..dc0fc7d1ae07 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsConsumerClientConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsConsumerClientConfiguration.java
@@ -38,11 +38,11 @@
AzureEventHubsConsumerClientConfiguration.SharedConsumerConnectionConfiguration.class
})
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = { "event-hub-name", "consumer.event-hub-name" })
+@ConditionalOnBean(AzureEventHubsProperties.class)
@ConditionalOnProperty(prefix = "spring.cloud.azure.eventhubs.consumer", name = "consumer-group")
class AzureEventHubsConsumerClientConfiguration {
@ConditionalOnMissingProperty(prefix = "spring.cloud.azure.eventhubs.consumer", name = { "connection-string", "namespace" })
- @ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = { "connection-string", "namespace" })
@ConditionalOnBean(EventHubClientBuilder.class)
@Configuration(proxyBeanMethods = false)
static class SharedConsumerConnectionConfiguration {
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfiguration.java
index 5526f7e995a8..d2cf8f30348b 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfiguration.java
@@ -6,7 +6,6 @@
import com.azure.core.credential.TokenCredential;
import com.azure.messaging.eventhubs.CheckpointStore;
import com.azure.messaging.eventhubs.EventData;
-import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties;
import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver;
import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider;
@@ -52,7 +51,6 @@
@ConditionalOnClass(EventHubsTemplate.class)
@AutoConfigureAfter(AzureEventHubsAutoConfiguration.class)
@ConditionalOnProperty(value = "spring.cloud.azure.eventhubs.enabled", havingValue = "true", matchIfMissing = true)
-@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = {"connection-string", "namespace"})
@ConditionalOnBean(AzureEventHubsProperties.class)
@Import({
AzureEventHubsMessagingAutoConfiguration.EventHubsTemplateConfiguration.class,
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProcessorClientConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProcessorClientConfiguration.java
index 75464f665054..3ec7c9426572 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProcessorClientConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProcessorClientConfiguration.java
@@ -33,7 +33,7 @@
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EventProcessorClientBuilder.class)
-@ConditionalOnBean({ MessageListener.class, CheckpointStore.class, EventHubsErrorHandler.class })
+@ConditionalOnBean({ MessageListener.class, CheckpointStore.class, EventHubsErrorHandler.class, AzureEventHubsProperties.class })
@Conditional(AzureEventHubsProcessorClientConfiguration.ProcessorAvailableCondition.class)
class AzureEventHubsProcessorClientConfiguration {
@@ -119,12 +119,5 @@ static class ConsumerGroup {
ConsumerGroup() {
}
}
-
- @ConditionalOnAnyProperty(
- prefix = "spring.cloud.azure.eventhubs",
- name = { "namespace", "connection-string", "processor.namespace", "processor.connection-string" })
- static class ConnectionInfo {
-
- }
}
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfiguration.java
index 25a6bca7d4c8..5e5cae605531 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfiguration.java
@@ -30,11 +30,11 @@
*
*/
@Configuration(proxyBeanMethods = false)
+@ConditionalOnBean(AzureEventHubsProperties.class)
@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = { "event-hub-name", "producer.event-hub-name" })
class AzureEventHubsProducerClientConfiguration {
@ConditionalOnMissingProperty(prefix = "spring.cloud.azure.eventhubs.producer", name = { "connection-string", "namespace" })
- @ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = { "connection-string", "namespace" })
@ConditionalOnBean(EventHubClientBuilder.class)
@Configuration(proxyBeanMethods = false)
static class SharedProducerConnectionConfiguration {
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfiguration.java
index ed73cf8d4337..d018ef936afa 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfiguration.java
@@ -4,6 +4,7 @@
package com.azure.spring.cloud.autoconfigure.implementation.eventhubs.kafka;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
import com.azure.spring.cloud.autoconfigure.implementation.kafka.AzureEventHubsKafkaOAuth2AutoConfiguration;
import com.azure.spring.cloud.autoconfigure.implementation.resourcemanager.AzureEventHubsResourceManagerAutoConfiguration;
import com.azure.spring.cloud.core.implementation.connectionstring.EventHubsConnectionString;
@@ -56,6 +57,23 @@ StaticConnectionStringProvider eventHubsKafkaConnect
return new StaticConnectionStringProvider<>(AzureServiceType.EVENT_HUBS, connectionString);
}
+ @Bean
+ @ConditionalOnBean(AzureEventHubsConnectionDetails.class)
+ @ConditionalOnMissingBean(value = AzureServiceType.EventHubs.class, parameterizedContainer = ServiceConnectionStringProvider.class)
+ StaticConnectionStringProvider eventHubsKafkaConnectionDetailsConnectionString(
+ AzureEventHubsConnectionDetails connectionDetails) {
+
+ String connectionString = connectionDetails.getConnectionString();
+ try {
+ new EventHubsConnectionString(connectionString);
+ } catch (Exception e) {
+ LOGGER.error("A valid Event Hubs connection string must be provided");
+ throw e;
+ }
+
+ return new StaticConnectionStringProvider<>(AzureServiceType.EVENT_HUBS, connectionString);
+ }
+
@Bean
@ConditionalOnBean(value = AzureServiceType.EventHubs.class, parameterizedContainer = ServiceConnectionStringProvider.class)
static KafkaPropertiesBeanPostProcessor kafkaPropertiesBeanPostProcessor() {
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/AzureEventHubsConnectionDetails.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/AzureEventHubsConnectionDetails.java
new file mode 100644
index 000000000000..9d68aa05b60e
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/AzureEventHubsConnectionDetails.java
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties;
+
+import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
+
+public interface AzureEventHubsConnectionDetails extends ConnectionDetails {
+
+ String getConnectionString();
+
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/AzureEventHubsPropertiesConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/AzureEventHubsPropertiesConfiguration.java
new file mode 100644
index 000000000000..b44c3ba37eb2
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/AzureEventHubsPropertiesConfiguration.java
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties;
+
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Import;
+
+@Import({
+ ConfigurationWithConnectionDetailsBean.class,
+ ConfigurationWithoutConnectionDetailsBean.class,
+})
+@EnableConfigurationProperties
+public class AzureEventHubsPropertiesConfiguration {
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/ConfigurationWithConnectionDetailsBean.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/ConfigurationWithConnectionDetailsBean.java
new file mode 100644
index 000000000000..86c763571eef
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/ConfigurationWithConnectionDetailsBean.java
@@ -0,0 +1,47 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties;
+
+import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.properties.utils.AzureGlobalPropertiesUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
+import org.springframework.boot.context.properties.bind.BindResult;
+import org.springframework.boot.context.properties.bind.Bindable;
+import org.springframework.boot.context.properties.bind.Binder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.env.Environment;
+
+@ConditionalOnClass(ConnectionDetails.class)
+@ConditionalOnBean(AzureEventHubsConnectionDetails.class)
+class ConfigurationWithConnectionDetailsBean {
+
+ private final Environment environment;
+ private final AzureGlobalProperties globalProperties;
+ private final AzureEventHubsConnectionDetails connectionDetails;
+
+ ConfigurationWithConnectionDetailsBean(
+ Environment environment,
+ AzureGlobalProperties globalProperties,
+ AzureEventHubsConnectionDetails connectionDetails) {
+ this.environment = environment;
+ this.globalProperties = globalProperties;
+ this.connectionDetails = connectionDetails;
+ }
+
+ @Bean
+ AzureEventHubsProperties azureEventHubsProperties() {
+ AzureEventHubsProperties propertiesLoadFromGlobalProperties =
+ AzureGlobalPropertiesUtils.loadProperties(globalProperties, new AzureEventHubsProperties());
+ BindResult bindResult = Binder.get(environment)
+ .bind(AzureEventHubsProperties.PREFIX, Bindable.ofInstance(propertiesLoadFromGlobalProperties));
+ AzureEventHubsProperties properties = bindResult.isBound() ? bindResult.get()
+ : propertiesLoadFromGlobalProperties;
+ properties.setConnectionString(connectionDetails.getConnectionString());
+ properties.setNamespace(null);
+ return properties;
+ }
+
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/ConfigurationWithoutConnectionDetailsBean.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/ConfigurationWithoutConnectionDetailsBean.java
new file mode 100644
index 000000000000..9e0dbc1537c2
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/properties/ConfigurationWithoutConnectionDetailsBean.java
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties;
+
+import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
+import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.properties.utils.AzureGlobalPropertiesUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+@ConditionalOnMissingBean(type = "com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails")
+@ConditionalOnProperty(value = "spring.cloud.azure.eventhubs.enabled", havingValue = "true", matchIfMissing = true)
+@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.eventhubs", name = {"connection-string", "namespace"})
+class ConfigurationWithoutConnectionDetailsBean {
+
+ private final AzureGlobalProperties azureGlobalProperties;
+
+ ConfigurationWithoutConnectionDetailsBean(AzureGlobalProperties azureGlobalProperties) {
+ this.azureGlobalProperties = azureGlobalProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConfigurationProperties(AzureEventHubsProperties.PREFIX)
+ AzureEventHubsProperties azureEventHubsProperties() {
+ return AzureGlobalPropertiesUtils.loadProperties(azureGlobalProperties, new AzureEventHubsProperties());
+ }
+
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfiguration.java
index f698130b43c9..597cfed54acc 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfiguration.java
@@ -4,14 +4,10 @@
package com.azure.spring.cloud.autoconfigure.implementation.servicebus;
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
-import com.azure.spring.cloud.autoconfigure.implementation.AzureServiceConfigurationBase;
-import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
-import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusPropertiesConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
@@ -22,22 +18,12 @@
@ConditionalOnClass(ServiceBusClientBuilder.class)
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.enabled", havingValue = "true", matchIfMissing = true)
@Import({
+ AzureServiceBusPropertiesConfiguration.class,
AzureServiceBusClientBuilderConfiguration.class,
AzureServiceBusProducerClientConfiguration.class,
AzureServiceBusConsumerClientConfiguration.class,
AzureServiceBusProcessorClientConfiguration.class
})
-public class AzureServiceBusAutoConfiguration extends AzureServiceConfigurationBase {
-
-
- AzureServiceBusAutoConfiguration(AzureGlobalProperties azureGlobalProperties) {
- super(azureGlobalProperties);
- }
-
- @Bean
- @ConfigurationProperties(AzureServiceBusProperties.PREFIX)
- AzureServiceBusProperties azureServiceBusProperties() {
- return loadProperties(getAzureGlobalProperties(), new AzureServiceBusProperties());
- }
+public class AzureServiceBusAutoConfiguration {
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfiguration.java
index ebb532cac4dd..166d6a6593d4 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfiguration.java
@@ -4,8 +4,9 @@
package com.azure.spring.cloud.autoconfigure.implementation.servicebus;
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
-import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusPropertiesConfiguration;
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;
@@ -13,15 +14,18 @@
import com.azure.spring.cloud.core.service.AzureServiceType;
import com.azure.spring.cloud.service.implementation.servicebus.factory.ServiceBusClientBuilderFactory;
import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
@Configuration(proxyBeanMethods = false)
+@Import(AzureServiceBusPropertiesConfiguration.class)
@ConditionalOnClass(ServiceBusClientBuilder.class)
-@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "connection-string", "namespace" })
+@ConditionalOnBean(AzureServiceBusProperties.class)
class AzureServiceBusClientBuilderConfiguration {
private final AzureServiceBusProperties serviceBusProperties;
@@ -59,4 +63,14 @@ StaticConnectionStringProvider staticServiceBusConn
this.serviceBusProperties.getConnectionString());
}
+ @Bean
+ @ConditionalOnBean(AzureServiceBusConnectionDetails.class)
+ @ConditionalOnMissingBean(value = AzureServiceType.ServiceBus.class, parameterizedContainer = ServiceConnectionStringProvider.class)
+ StaticConnectionStringProvider staticServiceBusConnectionDetailsConnectionStringProvider(
+ AzureServiceBusConnectionDetails connectionDetails) {
+
+ return new StaticConnectionStringProvider<>(AzureServiceType.SERVICE_BUS,
+ connectionDetails.getConnectionString());
+ }
+
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java
index 6a410336a85b..c923c3a5a40e 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java
@@ -7,8 +7,8 @@
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
import com.azure.messaging.servicebus.ServiceBusMessage;
import com.azure.messaging.servicebus.ServiceBusReceivedMessage;
-import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusPropertiesConfiguration;
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver;
import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider;
@@ -57,10 +57,10 @@
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ServiceBusTemplate.class)
@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.enabled", havingValue = "true", matchIfMissing = true)
-@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = { "connection-string", "namespace" })
@ConditionalOnBean(AzureServiceBusProperties.class)
@AutoConfigureAfter(AzureServiceBusAutoConfiguration.class)
@Import({
+ AzureServiceBusPropertiesConfiguration.class,
AzureServiceBusMessagingAutoConfiguration.ServiceBusTemplateConfiguration.class,
AzureServiceBusMessagingAutoConfiguration.ProcessorContainerConfiguration.class
})
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusConnectionDetails.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusConnectionDetails.java
new file mode 100644
index 000000000000..e9a4dfd3dadb
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusConnectionDetails.java
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
+
+import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
+
+public interface AzureServiceBusConnectionDetails extends ConnectionDetails {
+
+ String getConnectionString();
+
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesConfiguration.java
new file mode 100644
index 000000000000..9fe7dc8c4860
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/AzureServiceBusPropertiesConfiguration.java
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
+
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Import;
+
+@Import({
+ ConfigurationWithConnectionDetailsBean.class,
+ ConfigurationWithoutConnectionDetailsBean.class,
+})
+@EnableConfigurationProperties
+public class AzureServiceBusPropertiesConfiguration {
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/ConfigurationWithConnectionDetailsBean.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/ConfigurationWithConnectionDetailsBean.java
new file mode 100644
index 000000000000..a3bd96e3d034
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/ConfigurationWithConnectionDetailsBean.java
@@ -0,0 +1,47 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
+
+import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.properties.utils.AzureGlobalPropertiesUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
+import org.springframework.boot.context.properties.bind.BindResult;
+import org.springframework.boot.context.properties.bind.Bindable;
+import org.springframework.boot.context.properties.bind.Binder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.env.Environment;
+
+@ConditionalOnClass(ConnectionDetails.class)
+@ConditionalOnBean(AzureServiceBusConnectionDetails.class)
+class ConfigurationWithConnectionDetailsBean {
+
+ private final Environment environment;
+ private final AzureGlobalProperties globalProperties;
+ private final AzureServiceBusConnectionDetails connectionDetails;
+
+ ConfigurationWithConnectionDetailsBean(
+ Environment environment,
+ AzureGlobalProperties globalProperties,
+ AzureServiceBusConnectionDetails connectionDetails) {
+ this.environment = environment;
+ this.globalProperties = globalProperties;
+ this.connectionDetails = connectionDetails;
+ }
+
+ @Bean
+ AzureServiceBusProperties azureServiceBusProperties() {
+ AzureServiceBusProperties propertiesLoadFromGlobalProperties =
+ AzureGlobalPropertiesUtils.loadProperties(globalProperties, new AzureServiceBusProperties());
+ BindResult bindResult = Binder.get(environment)
+ .bind(AzureServiceBusProperties.PREFIX, Bindable.ofInstance(propertiesLoadFromGlobalProperties));
+ AzureServiceBusProperties properties = bindResult.isBound() ? bindResult.get()
+ : propertiesLoadFromGlobalProperties;
+ properties.setConnectionString(connectionDetails.getConnectionString());
+ properties.setNamespace(null);
+ return properties;
+ }
+
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/ConfigurationWithoutConnectionDetailsBean.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/ConfigurationWithoutConnectionDetailsBean.java
new file mode 100644
index 000000000000..238dcde601e5
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/properties/ConfigurationWithoutConnectionDetailsBean.java
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties;
+
+import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty;
+import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.properties.utils.AzureGlobalPropertiesUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+@ConditionalOnMissingBean(type = "com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails")
+@ConditionalOnProperty(value = "spring.cloud.azure.servicebus.enabled", havingValue = "true", matchIfMissing = true)
+@ConditionalOnAnyProperty(prefix = "spring.cloud.azure.servicebus", name = {"connection-string", "namespace"})
+class ConfigurationWithoutConnectionDetailsBean {
+
+ private final AzureGlobalProperties azureGlobalProperties;
+
+ ConfigurationWithoutConnectionDetailsBean(AzureGlobalProperties azureGlobalProperties) {
+ this.azureGlobalProperties = azureGlobalProperties;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConfigurationProperties(AzureServiceBusProperties.PREFIX)
+ AzureServiceBusProperties azureServiceBusProperties() {
+ return AzureGlobalPropertiesUtils.loadProperties(azureGlobalProperties, new AzureServiceBusProperties());
+ }
+
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/properties/ConfigurationWithConnectionDetailsBean.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/properties/ConfigurationWithConnectionDetailsBean.java
index 9abbebf32c61..6ce1cfce4ccf 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/properties/ConfigurationWithConnectionDetailsBean.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/properties/ConfigurationWithConnectionDetailsBean.java
@@ -38,6 +38,8 @@ AzureStorageBlobProperties azureStorageBlobProperties(
AzureStorageBlobProperties properties = bindResult.isBound() ? bindResult.get()
: propertiesLoadFromServiceCommonProperties;
properties.setConnectionString(connectionDetails.getConnectionString());
+ properties.setAccountName(null);
+ properties.setEndpoint(null);
return properties;
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/properties/ConfigurationWithConnectionDetailsBean.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/properties/ConfigurationWithConnectionDetailsBean.java
index 94aa271710ce..e0852aa363d7 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/properties/ConfigurationWithConnectionDetailsBean.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/properties/ConfigurationWithConnectionDetailsBean.java
@@ -39,6 +39,7 @@ AzureStorageQueueProperties azureStorageQueueProperties(
: propertiesLoadFromServiceCommonProperties;
properties.setConnectionString(connectionDetails.getConnectionString());
properties.setEndpoint(connectionDetails.getEndpoint());
+ properties.setAccountName(null);
return properties;
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java
index bfef43814749..656557e67ce2 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java
@@ -75,7 +75,7 @@ void configureWithEventHubDisabled() {
void configureWithoutConnectionStringAndNamespace() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.eventhubs.enabled=true")
- .run(context -> assertThat(context).doesNotHaveBean(AzureEventHubsAutoConfiguration.class));
+ .run(context -> assertThat(context).doesNotHaveBean(AzureEventHubsProperties.class));
}
@Test
@@ -277,4 +277,20 @@ void configurationPropertiesShouldBind() {
});
}
+ @Test
+ void connectionDetailsOverridesPropertyConnectionString() {
+ String connectionString = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
+ this.contextRunner
+ .withPropertyValues(
+ "spring.cloud.azure.eventhubs.connection-string=" + connectionString
+ )
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
+ .withBean(com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails.class, CustomAzureEventHubsConnectionDetails::new)
+ .run(context -> {
+ assertThat(context).hasSingleBean(AzureEventHubsProperties.class);
+ AzureEventHubsProperties properties = context.getBean(AzureEventHubsProperties.class);
+ assertEquals(CustomAzureEventHubsConnectionDetails.CONNECTION_STRING, properties.getConnectionString());
+ });
+ }
+
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfigurationTests.java
index d4b92480a714..62d554eb6741 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsClientBuilderConfigurationTests.java
@@ -6,6 +6,9 @@
import com.azure.data.appconfiguration.ConfigurationClientBuilder;
import com.azure.messaging.eventhubs.EventHubClientBuilder;
import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer;
+import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
+import com.azure.spring.cloud.core.provider.connectionstring.StaticConnectionStringProvider;
import com.azure.spring.cloud.service.implementation.eventhubs.factory.EventHubClientBuilderFactory;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -17,7 +20,7 @@
class AzureEventHubsClientBuilderConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(AzureEventHubsClientBuilderConfiguration.class));
+ .withConfiguration(AutoConfigurations.of(AzureEventHubsAutoConfiguration.class));
@Test
void noConnectionInfoProvidedShouldNotConfigure() {
@@ -30,7 +33,7 @@ void connectionStringProvidedShouldConfigure() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.run(context -> {
assertThat(context).hasSingleBean(AzureEventHubsClientBuilderConfiguration.class);
assertThat(context).hasSingleBean(EventHubClientBuilderFactory.class);
@@ -44,7 +47,7 @@ void namespaceProvidedShouldConfigure() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.namespace=test-namespace"
)
- .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.run(context -> {
assertThat(context).hasSingleBean(AzureEventHubsClientBuilderConfiguration.class);
assertThat(context).hasSingleBean(EventHubClientBuilderFactory.class);
@@ -59,7 +62,7 @@ void customizerShouldBeCalled() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.withBean("customizer1", EventHubBuilderCustomizer.class, () -> customizer)
.withBean("customizer2", EventHubBuilderCustomizer.class, () -> customizer)
.run(context -> assertThat(customizer.getCustomizedTimes()).isEqualTo(2));
@@ -73,7 +76,7 @@ void otherCustomizerShouldNotBeCalled() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.withBean("customizer1", EventHubBuilderCustomizer.class, () -> customizer)
.withBean("customizer2", EventHubBuilderCustomizer.class, () -> customizer)
.withBean("customizer3", OtherBuilderCustomizer.class, () -> otherBuilderCustomizer)
@@ -89,7 +92,7 @@ void userDefinedEventHubsClientBuilderProvidedShouldNotAutoconfigure() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.withBean("user-defined-builder", EventHubClientBuilder.class, EventHubClientBuilder::new)
.run(context -> {
assertThat(context).hasSingleBean(EventHubClientBuilder.class);
@@ -97,6 +100,44 @@ void userDefinedEventHubsClientBuilderProvidedShouldNotAutoconfigure() {
});
}
+ @Test
+ void connectionStringPropertyRegistersStaticProvider() {
+ String connectionString = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
+ this.contextRunner
+ .withPropertyValues(
+ "spring.cloud.azure.eventhubs.connection-string=" + connectionString
+ )
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
+ .run(context -> {
+ assertThat(context).hasSingleBean(StaticConnectionStringProvider.class);
+ assertThat(context.getBean(StaticConnectionStringProvider.class).getConnectionString())
+ .isEqualTo(connectionString);
+ });
+ }
+
+ @Test
+ void connectionDetailsRegistersStaticProvider() {
+ String connectionString = String.format(CONNECTION_STRING_FORMAT, "details-namespace");
+ this.contextRunner
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
+ .withBean(AzureEventHubsConnectionDetails.class, () -> new TestConnectionDetails(connectionString))
+ .run(context -> {
+ assertThat(context).hasSingleBean(StaticConnectionStringProvider.class);
+ assertThat(context.getBean(StaticConnectionStringProvider.class).getConnectionString())
+ .isEqualTo(connectionString);
+ });
+ }
+
+ @Test
+ void namespaceOnlyDoesNotRegisterStaticProvider() {
+ this.contextRunner
+ .withPropertyValues(
+ "spring.cloud.azure.eventhubs.namespace=test-namespace"
+ )
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
+ .run(context -> assertThat(context).doesNotHaveBean(StaticConnectionStringProvider.class));
+ }
+
private static class EventHubBuilderCustomizer extends TestBuilderCustomizer {
}
@@ -105,4 +146,17 @@ private static class OtherBuilderCustomizer extends TestBuilderCustomizer {
assertThat(context).hasSingleBean(AzureEventHubsConsumerClientConfiguration.class);
assertThat(context).doesNotHaveBean(AzureEventHubsConsumerClientConfiguration.SharedConsumerConnectionConfiguration.class);
@@ -45,6 +46,7 @@ void eventHubNameAndConsumerGroupProvidedShouldConfigure() {
"spring.cloud.azure.eventhubs.consumer.event-hub-name=test-eventhub",
"spring.cloud.azure.eventhubs.consumer.consumer-group=test-consumer-group"
)
+ .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(AzureEventHubsConsumerClientConfiguration.class);
assertThat(context).doesNotHaveBean(AzureEventHubsConsumerClientConfiguration.SharedConsumerConnectionConfiguration.class);
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfigurationTests.java
index 87daf3997d50..6939088dba23 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsMessagingAutoConfigurationTests.java
@@ -58,7 +58,6 @@ void withoutEventHubsTemplateShouldNotConfigure() {
@Test
void withoutEventHubConnectionShouldNotConfigure() {
this.contextRunner
- .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.withBean(CheckpointStore.class, TestCheckpointStore::new)
.run(context -> assertThat(context).doesNotHaveBean(AzureEventHubsMessagingAutoConfiguration.ProcessorContainerConfiguration.class));
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfigurationTests.java
index d8c4f6147c89..db7361326694 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsProducerClientConfigurationTests.java
@@ -33,6 +33,7 @@ void eventHubNameProvidedShouldConfigure() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.event-hub-name=test-eventhub"
)
+ .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(AzureEventHubsProducerClientConfiguration.class);
assertThat(context).doesNotHaveBean(AzureEventHubsProducerClientConfiguration.SharedProducerConnectionConfiguration.class);
@@ -43,6 +44,7 @@ void eventHubNameProvidedShouldConfigure() {
.withPropertyValues(
"spring.cloud.azure.eventhubs.producer.event-hub-name=test-eventhub"
)
+ .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(AzureEventHubsProducerClientConfiguration.class);
assertThat(context).doesNotHaveBean(AzureEventHubsProducerClientConfiguration.SharedProducerConnectionConfiguration.class);
@@ -65,6 +67,7 @@ void withGlobalEventHubConnectionSetShouldConfigureShared() {
"spring.cloud.azure.eventhubs.namespace=" + namespace,
"spring.cloud.azure.eventhubs.event-hub-name=" + eventHubName
)
+ .withUserConfiguration(AzureEventHubsPropertiesTestConfiguration.class)
.withBean(EventHubClientBuilder.class, () -> clientBuilder)
.run(
context -> {
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/CustomAzureEventHubsConnectionDetails.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/CustomAzureEventHubsConnectionDetails.java
new file mode 100644
index 000000000000..d5faa229ef11
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/CustomAzureEventHubsConnectionDetails.java
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.eventhubs;
+
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
+
+public class CustomAzureEventHubsConnectionDetails implements AzureEventHubsConnectionDetails {
+
+ static final String CONNECTION_STRING = "Endpoint=sb://connection-detail-namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=test-key;EntityPath=test-eventhub";
+
+ @Override
+ public String getConnectionString() {
+ return CONNECTION_STRING;
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfigurationTests.java
index 8eb24d6d593e..f8e200454794 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaAutoConfigurationTests.java
@@ -5,6 +5,7 @@
import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
import com.azure.spring.cloud.core.provider.connectionstring.StaticConnectionStringProvider;
import com.azure.spring.cloud.core.service.AzureServiceType;
import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.ArmConnectionStringProvider;
@@ -26,12 +27,12 @@
import static org.apache.kafka.common.security.auth.SecurityProtocol.SASL_SSL;
import static org.assertj.core.api.Assertions.assertThat;
-
@SuppressWarnings("deprecation")
class AzureEventHubsKafkaAutoConfigurationTests {
static final String CONNECTION_STRING_FORMAT =
"Endpoint=sb://%s.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=key";
+ private static final String CONNECTION_STRING = String.format(CONNECTION_STRING_FORMAT, "test-namespace");
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(AzureEventHubsKafkaAutoConfiguration.class, KafkaAutoConfiguration.class));
@@ -223,5 +224,36 @@ public AzureServiceType.EventHubs getServiceType() {
}
}
+ @Test
+ void connectionStringRegistersProvider() {
+ this.contextRunner
+ .withPropertyValues(
+ "spring.cloud.azure.eventhubs.connection-string=" + CONNECTION_STRING
+ )
+ .run(context -> {
+ assertThat(context).hasSingleBean(StaticConnectionStringProvider.class);
+ StaticConnectionStringProvider> provider = context.getBean(StaticConnectionStringProvider.class);
+ assertThat(provider.getServiceType()).isEqualTo(AzureServiceType.EVENT_HUBS);
+ assertThat(provider.getConnectionString()).isEqualTo(CONNECTION_STRING);
+ });
+ }
+ @Test
+ void connectionDetailsRegistersProvider() {
+ this.contextRunner
+ .withBean(AzureEventHubsConnectionDetails.class, () -> () -> CONNECTION_STRING)
+ .run(context -> {
+ assertThat(context).hasSingleBean(StaticConnectionStringProvider.class);
+ StaticConnectionStringProvider> provider = context.getBean(StaticConnectionStringProvider.class);
+ assertThat(provider.getServiceType()).isEqualTo(AzureServiceType.EVENT_HUBS);
+ assertThat(provider.getConnectionString()).isEqualTo(CONNECTION_STRING);
+ });
+ }
+
+ @Test
+ void namespaceOnlyDoesNotRegisterProvider() {
+ this.contextRunner
+ .withPropertyValues("spring.cloud.azure.eventhubs.namespace=test-namespace")
+ .run(context -> assertThat(context).doesNotHaveBean(StaticConnectionStringProvider.class));
+ }
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java
index 176514dbca37..63195f6cd724 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java
@@ -8,6 +8,7 @@
import com.azure.messaging.servicebus.models.ServiceBusReceiveMode;
import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests;
import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
import com.azure.spring.cloud.core.properties.profile.AzureEnvironmentProperties;
import com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider;
@@ -81,7 +82,7 @@ void configureAzureServiceBusPropertiesWithGlobalDefaults() {
azureProperties.getCredential().setClientSecret("azure-client-secret");
azureProperties.getRetry().getExponential().setBaseDelay(Duration.ofSeconds(2));
- this.contextRunner
+ this.getMinimalContextRunner()
.withBean("azureProperties", AzureGlobalProperties.class, () -> azureProperties)
.withPropertyValues(
"spring.cloud.azure.servicebus.credential.client-id=servicebus-client-id",
@@ -104,7 +105,7 @@ void configureServiceBusDomainNameOverrideGlobalDefault() {
AzureGlobalProperties azureProperties = new AzureGlobalProperties();
azureProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT);
- this.contextRunner
+ this.getMinimalContextRunner()
.withBean("azureProperties", AzureGlobalProperties.class, () -> azureProperties)
.withPropertyValues(
"spring.cloud.azure.servicebus.domain-name=servicebus.chinacloudapi.cn"
@@ -120,7 +121,7 @@ void configureServiceBusDomainNameOverrideGlobalDefault() {
@Test
void configureAmqpTransportTypeShouldApply() {
- this.contextRunner
+ this.getMinimalContextRunner()
.withBean("azureProperties", AzureGlobalProperties.class, AzureGlobalProperties::new)
.withPropertyValues("spring.cloud.azure.servicebus.client.transport-type=AmqpWebSockets")
.run(context -> {
@@ -132,7 +133,7 @@ void configureAmqpTransportTypeShouldApply() {
@Test
void configureRetryShouldApply() {
- this.contextRunner
+ this.getMinimalContextRunner()
.withBean("azureProperties", AzureGlobalProperties.class, AzureGlobalProperties::new)
.withPropertyValues(
"spring.cloud.azure.servicebus.retry.mode=fixed",
@@ -297,4 +298,20 @@ void consumerSubscriptionNameShouldConfigureConsumerClient() {
assertThat(context).hasSingleBean(AzureServiceBusConsumerClientConfiguration.class);
});
}
+
+ @Test
+ void connectionDetailsHasHigherPriority() {
+ String connectionString = String.format(CONNECTION_STRING_FORMAT, "property-namespace");
+ this.contextRunner
+ .withPropertyValues(
+ "spring.cloud.azure.servicebus.connection-string=" + connectionString
+ )
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
+ .withBean(AzureServiceBusConnectionDetails.class, CustomAzureServiceBusConnectionDetails::new)
+ .run(context -> {
+ assertThat(context).hasSingleBean(AzureServiceBusProperties.class);
+ AzureServiceBusProperties properties = context.getBean(AzureServiceBusProperties.class);
+ assertEquals(CustomAzureServiceBusConnectionDetails.CONNECTION_STRING, properties.getConnectionString());
+ });
+ }
}
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfigurationTests.java
index 060bf8a1029b..cde00bb3389c 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusClientBuilderConfigurationTests.java
@@ -7,6 +7,7 @@
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer;
import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
import com.azure.spring.cloud.core.provider.connectionstring.StaticConnectionStringProvider;
import com.azure.spring.cloud.core.service.AzureServiceType;
@@ -22,7 +23,8 @@
class AzureServiceBusClientBuilderConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(AzureServiceBusClientBuilderConfiguration.class));
+ .withConfiguration(AutoConfigurations.of(AzureServiceBusAutoConfiguration.class))
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new);
@Test
void noConnectionInfoProvidedShouldNotConfigure() {
@@ -30,13 +32,12 @@ void noConnectionInfoProvidedShouldNotConfigure() {
}
@Test
- @SuppressWarnings("rawtypes")
+ @SuppressWarnings({"rawtypes", "unchecked"})
void connectionStringProvidedShouldConfigure() {
contextRunner
.withPropertyValues(
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(AzureServiceBusClientBuilderConfiguration.class);
assertThat(context).hasSingleBean(ServiceBusClientBuilderFactory.class);
@@ -55,7 +56,6 @@ void customizerShouldBeCalled() {
.withPropertyValues(
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.withBean("customizer1", ServiceBusBuilderCustomizer.class, () -> customizer)
.withBean("customizer2", ServiceBusBuilderCustomizer.class, () -> customizer)
.run(context -> assertThat(customizer.getCustomizedTimes()).isEqualTo(2));
@@ -69,7 +69,6 @@ void otherCustomizerShouldNotBeCalled() {
.withPropertyValues(
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.withBean("customizer1", ServiceBusBuilderCustomizer.class, () -> customizer)
.withBean("customizer2", ServiceBusBuilderCustomizer.class, () -> customizer)
.withBean("customizer3", OtherBuilderCustomizer.class, () -> otherBuilderCustomizer)
@@ -81,17 +80,30 @@ void otherCustomizerShouldNotBeCalled() {
@Test
void configureWithNamespaceAndEmptyConnectionString() {
- this.contextRunner.withConfiguration(AutoConfigurations.of(AzureServiceBusAutoConfiguration.class))
+ this.contextRunner
.withPropertyValues(
"spring.cloud.azure.servicebus.connection-string=",
"spring.cloud.azure.servicebus.namespace=test-servicebus-namespace")
- .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new)
.run(context -> {
assertThat(context).hasSingleBean(AzureServiceBusProperties.class);
assertThat(context).doesNotHaveBean(StaticConnectionStringProvider.class);
});
}
+ @Test
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ void connectionDetailsRegistersStaticProvider() {
+ String connectionString = String.format(CONNECTION_STRING_FORMAT, "details-namespace");
+ this.contextRunner
+ .withBean(AzureServiceBusConnectionDetails.class, () -> new TestConnectionDetails(connectionString))
+ .run(context -> {
+ assertThat(context).hasSingleBean(StaticConnectionStringProvider.class);
+ StaticConnectionStringProvider provider = context.getBean(StaticConnectionStringProvider.class);
+ assertThat(provider.getConnectionString()).isEqualTo(connectionString);
+ assertThat(provider.getServiceType()).isEqualTo(AzureServiceType.SERVICE_BUS);
+ });
+ }
+
private static class ServiceBusBuilderCustomizer extends TestBuilderCustomizer {
}
@@ -100,4 +112,17 @@ private static class OtherBuilderCustomizer extends TestBuilderCustomizer {
assertThat(context).doesNotHaveBean(AzureServiceBusMessagingAutoConfiguration.ProcessorContainerConfiguration.class);
assertThat(context).doesNotHaveBean(AzureServiceBusMessagingAutoConfiguration.ConsumerContainerConfiguration.class);
@@ -75,7 +76,6 @@ void connectionInfoProvidedShouldConfigure() {
.withPropertyValues(
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(ServiceBusProcessorFactory.class);
assertThat(context).hasSingleBean(AzureServiceBusMessagingAutoConfiguration.ProcessorContainerConfiguration.class);
@@ -91,7 +91,6 @@ void withoutObjectMapperShouldNotConfigure() {
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.run(context -> assertThatIllegalStateException());
}
@@ -99,7 +98,6 @@ void withoutObjectMapperShouldNotConfigure() {
void withIsolatedObjectMapper() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"))
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
.run(context -> {
assertThat(context).hasBean("defaultServiceBusMessageConverter");
@@ -113,7 +111,6 @@ void withNonIsolatedObjectMapper() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.message-converter.isolated-object-mapper=false")
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
.run(context -> {
assertThat(context).hasBean("serviceBusMessageConverter");
@@ -127,7 +124,6 @@ void withUserProvidedObjectMapper() {
this.contextRunner
.withPropertyValues("spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.message-converter.isolated-object-mapper=false")
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.withBean("userObjectMapper", ObjectMapper.class, ObjectMapper::new)
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
.run(context -> {
@@ -148,7 +144,6 @@ void testCustomTokenCredentialConfiguration() {
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.servicebus.credential.token-credential-bean-name=customTokenCredential"
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.run(context -> {
// Verify that the properties contain the correct credential bean name
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusTemplateConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusTemplateConfigurationTests.java
index 075d5a6e873c..709969993a33 100644
--- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusTemplateConfigurationTests.java
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusTemplateConfigurationTests.java
@@ -3,6 +3,7 @@
package com.azure.spring.cloud.autoconfigure.implementation.servicebus;
+import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties;
import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties;
import com.azure.spring.cloud.service.servicebus.properties.ServiceBusEntityType;
import com.azure.spring.messaging.servicebus.core.ServiceBusTemplate;
@@ -23,7 +24,8 @@
class AzureServiceBusTemplateConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(AzureServiceBusMessagingAutoConfiguration.class));
+ .withConfiguration(AutoConfigurations.of(AzureServiceBusAutoConfiguration.class, AzureServiceBusMessagingAutoConfiguration.class))
+ .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new);
@Test
void testAzureServiceBusDisabled() {
@@ -55,7 +57,6 @@ void testMessageConverterProvided() {
.withPropertyValues(
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace")
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.run(context -> {
assertThat(context).hasSingleBean(ServiceBusMessageConverter.class);
assertThat(context).hasSingleBean(ServiceBusTemplate.class);
@@ -74,7 +75,6 @@ void testMessageEntityTypeProvided() {
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.servicebus.entity-type=QUEUE"
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.run(context -> {
assertServiceBusTemplate(context, ServiceBusEntityType.QUEUE);
});
@@ -88,7 +88,6 @@ void testMessageProducerEntityTypeProvided() {
"spring.cloud.azure.servicebus.connection-string=" + String.format(CONNECTION_STRING_FORMAT, "test-namespace"),
"spring.cloud.azure.servicebus.producer.entity-type=topic"
)
- .withUserConfiguration(AzureServiceBusPropertiesTestConfiguration.class)
.run(context -> {
assertServiceBusTemplate(context, ServiceBusEntityType.TOPIC);
});
diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/CustomAzureServiceBusConnectionDetails.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/CustomAzureServiceBusConnectionDetails.java
new file mode 100644
index 000000000000..8a267548ec62
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/CustomAzureServiceBusConnectionDetails.java
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.autoconfigure.implementation.servicebus;
+
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
+
+import static com.azure.spring.cloud.autoconfigure.implementation.util.TestServiceBusUtils.CONNECTION_STRING_FORMAT;
+
+public class CustomAzureServiceBusConnectionDetails implements AzureServiceBusConnectionDetails {
+
+ static final String CONNECTION_STRING = String.format(CONNECTION_STRING_FORMAT, "connection-detail-namespace");
+
+ @Override
+ public String getConnectionString() {
+ return CONNECTION_STRING;
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/pom.xml b/sdk/spring/spring-cloud-azure-docker-compose/pom.xml
index 3c7ab3ee05ca..fe468c9da775 100644
--- a/sdk/spring/spring-cloud-azure-docker-compose/pom.xml
+++ b/sdk/spring/spring-cloud-azure-docker-compose/pom.xml
@@ -93,6 +93,24 @@
provided
+
+ com.azure
+ azure-messaging-servicebus
+ 7.17.13
+ test
+
+
+ com.azure
+ azure-messaging-eventhubs
+ 5.20.5
+ test
+
+
+ com.azure.spring
+ spring-messaging-azure-servicebus
+ 5.24.1
+ test
+
org.springframework.boot
spring-boot-test
@@ -117,6 +135,12 @@
3.27.3
test
+
+ org.awaitility
+ awaitility
+ 4.3.0
+ test
+
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/main/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/ServiceBusDockerComposeConnectionDetailsFactory.java b/sdk/spring/spring-cloud-azure-docker-compose/src/main/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/ServiceBusDockerComposeConnectionDetailsFactory.java
new file mode 100644
index 000000000000..408e03ff0e85
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/main/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/ServiceBusDockerComposeConnectionDetailsFactory.java
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.docker.compose.implementation.service.connection.bus;
+
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
+import org.springframework.boot.docker.compose.core.RunningService;
+import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
+import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
+
+class ServiceBusDockerComposeConnectionDetailsFactory
+ extends DockerComposeConnectionDetailsFactory {
+
+ private static final int SERVICE_BUS_PORT = 5672;
+
+ protected ServiceBusDockerComposeConnectionDetailsFactory() {
+ super("azure-messaging/servicebus-emulator");
+ }
+
+ @Override
+ protected AzureServiceBusConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
+ return new ServiceBusContainerConnectionDetails(source.getRunningService());
+ }
+
+ /**
+ * {@link AzureServiceBusConnectionDetails} backed by a {@code Service Bus}
+ * {@link RunningService}.
+ */
+ private static class ServiceBusContainerConnectionDetails extends DockerComposeConnectionDetails
+ implements AzureServiceBusConnectionDetails {
+
+ private final String host;
+
+ private final int port;
+
+ ServiceBusContainerConnectionDetails(RunningService service) {
+ super(service);
+ this.host = service.host();
+ this.port = service.ports().get(SERVICE_BUS_PORT);
+ }
+
+ @Override
+ public String getConnectionString() {
+ return "Endpoint=sb://%s:%d;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"
+ .formatted(this.host, this.port);
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/main/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/EventHubsDockerComposeConnectionDetailsFactory.java b/sdk/spring/spring-cloud-azure-docker-compose/src/main/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/EventHubsDockerComposeConnectionDetailsFactory.java
new file mode 100644
index 000000000000..e34128b855f5
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/main/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/EventHubsDockerComposeConnectionDetailsFactory.java
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.docker.compose.implementation.service.connection.hubs;
+
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
+import org.springframework.boot.docker.compose.core.RunningService;
+import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
+import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
+
+class EventHubsDockerComposeConnectionDetailsFactory
+ extends DockerComposeConnectionDetailsFactory {
+
+ private static final int EVENT_HUBS_PORT = 5672;
+
+ protected EventHubsDockerComposeConnectionDetailsFactory() {
+ super("azure-messaging/eventhubs-emulator");
+ }
+
+ @Override
+ protected AzureEventHubsConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
+ return new EventHubsContainerConnectionDetails(source.getRunningService());
+ }
+
+ /**
+ * {@link AzureEventHubsConnectionDetails} backed by an {@code Event Hubs}
+ * {@link RunningService}.
+ */
+ private static class EventHubsContainerConnectionDetails extends DockerComposeConnectionDetails
+ implements AzureEventHubsConnectionDetails {
+
+ private final String host;
+
+ private final int port;
+
+ EventHubsContainerConnectionDetails(RunningService service) {
+ super(service);
+ this.host = service.host();
+ this.port = service.ports().get(EVENT_HUBS_PORT);
+ }
+
+ @Override
+ public String getConnectionString() {
+ return "Endpoint=sb://%s:%d;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"
+ .formatted(this.host, this.port);
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/main/resources/META-INF/spring.factories b/sdk/spring/spring-cloud-azure-docker-compose/src/main/resources/META-INF/spring.factories
index 17b7623a3151..591a4d528944 100644
--- a/sdk/spring/spring-cloud-azure-docker-compose/src/main/resources/META-INF/spring.factories
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/main/resources/META-INF/spring.factories
@@ -1,3 +1,5 @@
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\
+com.azure.spring.cloud.docker.compose.implementation.service.connection.bus.ServiceBusDockerComposeConnectionDetailsFactory,\
com.azure.spring.cloud.docker.compose.implementation.service.connection.storage.StorageBlobDockerComposeConnectionDetailsFactory,\
-com.azure.spring.cloud.docker.compose.implementation.service.connection.storage.StorageQueueDockerComposeConnectionDetailsFactory
+com.azure.spring.cloud.docker.compose.implementation.service.connection.storage.StorageQueueDockerComposeConnectionDetailsFactory,\
+com.azure.spring.cloud.docker.compose.implementation.service.connection.hubs.EventHubsDockerComposeConnectionDetailsFactory
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/test/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/ServiceBusDockerComposeConnectionDetailsFactoryTests.java b/sdk/spring/spring-cloud-azure-docker-compose/src/test/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/ServiceBusDockerComposeConnectionDetailsFactoryTests.java
new file mode 100644
index 000000000000..3f1d51308a7d
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/test/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/ServiceBusDockerComposeConnectionDetailsFactoryTests.java
@@ -0,0 +1,114 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.docker.compose.implementation.service.connection.bus;
+
+import com.azure.messaging.servicebus.ServiceBusMessage;
+import com.azure.messaging.servicebus.ServiceBusSenderClient;
+import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.AzureServiceBusAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.AzureServiceBusMessagingAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
+import com.azure.spring.cloud.service.servicebus.consumer.ServiceBusErrorHandler;
+import com.azure.spring.cloud.service.servicebus.consumer.ServiceBusRecordMessageListener;
+import com.azure.spring.messaging.servicebus.core.ServiceBusTemplate;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.messaging.support.MessageBuilder;
+
+import java.time.Duration;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.waitAtMost;
+
+@SpringBootTest(properties = {
+ "spring.docker.compose.skip.in-tests=false",
+ "spring.docker.compose.file=classpath:com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/servicebus-compose.yaml",
+ "spring.docker.compose.stop.command=down",
+ "spring.docker.compose.readiness.timeout=PT5M",
+ "spring.cloud.azure.servicebus.namespace=sbemulatorns",
+ "spring.cloud.azure.servicebus.entity-name=queue.1",
+ "spring.cloud.azure.servicebus.entity-type=queue",
+ "spring.cloud.azure.servicebus.producer.entity-name=queue.1",
+ "spring.cloud.azure.servicebus.producer.entity-type=queue",
+ "spring.cloud.azure.servicebus.processor.entity-name=queue.1",
+ "spring.cloud.azure.servicebus.processor.entity-type=queue"
+})
+@EnabledOnOs(OS.LINUX)
+class ServiceBusDockerComposeConnectionDetailsFactoryTests {
+
+ @Autowired
+ private AzureServiceBusConnectionDetails connectionDetails;
+
+ @Autowired
+ private ServiceBusSenderClient senderClient;
+
+ @Autowired
+ private ServiceBusTemplate serviceBusTemplate;
+
+ @Test
+ void connectionDetailsShouldBeProvidedByFactory() {
+ assertThat(connectionDetails).isNotNull();
+ assertThat(connectionDetails.getConnectionString())
+ .isNotBlank()
+ .startsWith("Endpoint=sb://");
+ }
+
+ @Test
+ void senderClientCanSendMessage() {
+ // Wait for Service Bus emulator to be fully ready and queue entity to be available
+ // The emulator depends on SQL Edge and needs time to initialize the messaging entities
+ waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
+ this.senderClient.sendMessage(new ServiceBusMessage("Hello World!"));
+ });
+
+ waitAtMost(Duration.ofSeconds(30)).pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+ assertThat(Config.MESSAGES).contains("Hello World!");
+ });
+ }
+
+ @Test
+ void serviceBusTemplateCanSendMessage() {
+ // Wait for Service Bus emulator to be fully ready and queue entity to be available
+ // The emulator depends on SQL Edge and needs time to initialize the messaging entities
+ waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
+ this.serviceBusTemplate.sendAsync("queue.1", MessageBuilder.withPayload("Hello from ServiceBusTemplate!").build()).block();
+ });
+
+ waitAtMost(Duration.ofSeconds(30)).pollDelay(Duration.ofSeconds(5)).untilAsserted(() -> {
+ assertThat(Config.MESSAGES).contains("Hello from ServiceBusTemplate!");
+ });
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ImportAutoConfiguration(classes = {
+ AzureGlobalPropertiesAutoConfiguration.class,
+ AzureServiceBusAutoConfiguration.class,
+ AzureServiceBusMessagingAutoConfiguration.class})
+ static class Config {
+
+ private static final Set MESSAGES = ConcurrentHashMap.newKeySet();
+
+ @Bean
+ ServiceBusRecordMessageListener processMessage() {
+ return context -> {
+ MESSAGES.add(context.getMessage().getBody().toString());
+ };
+ }
+
+ @Bean
+ ServiceBusErrorHandler errorHandler() {
+ // No-op error handler for tests: acknowledge errors without affecting test execution.
+ return (context) -> {
+ };
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/test/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/EventHubsDockerComposeConnectionDetailsFactoryTests.java b/sdk/spring/spring-cloud-azure-docker-compose/src/test/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/EventHubsDockerComposeConnectionDetailsFactoryTests.java
new file mode 100644
index 000000000000..1369301024c1
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/test/java/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/EventHubsDockerComposeConnectionDetailsFactoryTests.java
@@ -0,0 +1,65 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.docker.compose.implementation.service.connection.hubs;
+
+import com.azure.messaging.eventhubs.EventData;
+import com.azure.messaging.eventhubs.EventHubProducerClient;
+import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.Duration;
+import java.util.Collections;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.waitAtMost;
+
+@SpringBootTest(properties = {
+ "spring.docker.compose.skip.in-tests=false",
+ "spring.docker.compose.file=classpath:com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/eventhubs-compose.yaml",
+ "spring.docker.compose.stop.command=down",
+ "spring.docker.compose.readiness.timeout=PT5M",
+ "spring.cloud.azure.eventhubs.event-hub-name=eh1",
+ "spring.cloud.azure.eventhubs.producer.event-hub-name=eh1"
+})
+@EnabledOnOs(OS.LINUX)
+class EventHubsDockerComposeConnectionDetailsFactoryTests {
+
+ @Autowired
+ private AzureEventHubsConnectionDetails connectionDetails;
+
+ @Autowired
+ private EventHubProducerClient producerClient;
+
+ @Test
+ void connectionDetailsShouldBeProvidedByFactory() {
+ assertThat(connectionDetails).isNotNull();
+ assertThat(connectionDetails.getConnectionString())
+ .isNotBlank()
+ .startsWith("Endpoint=sb://");
+ }
+
+ @Test
+ void producerClientCanSendMessage() {
+ // Wait for Event Hubs emulator to be fully ready and event hub entity to be available
+ waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
+ EventData event = new EventData("Hello World!");
+ this.producerClient.send(Collections.singletonList(event));
+ });
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ImportAutoConfiguration(classes = {
+ AzureGlobalPropertiesAutoConfiguration.class,
+ AzureEventHubsAutoConfiguration.class})
+ static class Config {
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/Config.json b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/Config.json
new file mode 100644
index 000000000000..256f4fbc40c4
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/Config.json
@@ -0,0 +1,108 @@
+{
+ "UserConfig": {
+ "Namespaces": [
+ {
+ "Name": "sbemulatorns",
+ "Queues": [
+ {
+ "Name": "queue.1",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "DuplicateDetectionHistoryTimeWindow": "PT20S",
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "RequiresDuplicateDetection": false,
+ "RequiresSession": false
+ }
+ }
+ ],
+
+ "Topics": [
+ {
+ "Name": "topic.1",
+ "Properties": {
+ "DefaultMessageTimeToLive": "PT1H",
+ "DuplicateDetectionHistoryTimeWindow": "PT20S",
+ "RequiresDuplicateDetection": false
+ },
+ "Subscriptions": [
+ {
+ "Name": "subscription.1",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "RequiresSession": false
+ },
+ "Rules": [
+ {
+ "Name": "app-prop-filter-1",
+ "Properties": {
+ "FilterType": "Correlation",
+ "CorrelationFilter": {
+ "ContentType": "application/text",
+ "CorrelationId": "id1",
+ "Label": "subject1",
+ "MessageId": "msgid1",
+ "ReplyTo": "someQueue",
+ "ReplyToSessionId": "sessionId",
+ "SessionId": "session1",
+ "To": "xyz"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "Name": "subscription.2",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "RequiresSession": false
+ },
+ "Rules": [
+ {
+ "Name": "user-prop-filter-1",
+ "Properties": {
+ "FilterType": "Correlation",
+ "CorrelationFilter": {
+ "Properties": {
+ "prop3": "value3"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "Name": "subscription.3",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "RequiresSession": false
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "Logging": {
+ "Type": "File"
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/servicebus-compose.yaml b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/servicebus-compose.yaml
new file mode 100644
index 000000000000..87bfa50479b0
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/bus/servicebus-compose.yaml
@@ -0,0 +1,30 @@
+services:
+ servicebus:
+ image: mcr.microsoft.com/azure-messaging/servicebus-emulator:latest
+ pull_policy: always
+ volumes:
+ - "./Config.json:/ServiceBus_Emulator/ConfigFiles/Config.json"
+ ports:
+ - "5672"
+ environment:
+ SQL_SERVER: sqledge
+ MSSQL_SA_PASSWORD: A_Str0ng_Required_Password
+ ACCEPT_EULA: Y
+ depends_on:
+ - sqledge
+ networks:
+ sb-emulator:
+ aliases:
+ - "sb-emulator"
+ sqledge:
+ image: "mcr.microsoft.com/azure-sql-edge:latest"
+ networks:
+ sb-emulator:
+ aliases:
+ - "sqledge"
+ environment:
+ ACCEPT_EULA: Y
+ MSSQL_SA_PASSWORD: A_Str0ng_Required_Password
+
+networks:
+ sb-emulator:
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/Config.json b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/Config.json
new file mode 100644
index 000000000000..0749990d11d4
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/Config.json
@@ -0,0 +1,20 @@
+{
+ "UserConfig": {
+ "NamespaceConfig": [
+ {
+ "Type": "EventHub",
+ "Name": "emulatorns1",
+ "Entities": [
+ {
+ "Name": "eh1",
+ "PartitionCount": "2",
+ "ConsumerGroups": []
+ }
+ ]
+ }
+ ],
+ "LoggingConfig": {
+ "Type": "File"
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/eventhubs-compose.yaml b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/eventhubs-compose.yaml
new file mode 100644
index 000000000000..6aa1d2d7a0f9
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-docker-compose/src/test/resources/com/azure/spring/cloud/docker/compose/implementation/service/connection/hubs/eventhubs-compose.yaml
@@ -0,0 +1,34 @@
+services:
+ eventhubs:
+ image: mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest
+ pull_policy: always
+ volumes:
+ # Mount the emulator configuration to the path expected by the emulator image
+ - "./Config.json:/Eventhubs_Emulator/ConfigFiles/Config.json"
+ ports:
+ - "5672"
+ environment:
+ # Event Hubs emulator requires external blob/metadata storage provided by azurite
+ BLOB_SERVER: azurite
+ METADATA_SERVER: azurite
+ ACCEPT_EULA: Y
+ depends_on:
+ - azurite
+ networks:
+ eh-emulator:
+ aliases:
+ - "eh-emulator"
+
+ azurite:
+ image: "mcr.microsoft.com/azure-storage/azurite:latest"
+ ports:
+ - "10000"
+ - "10001"
+ - "10002"
+ networks:
+ eh-emulator:
+ aliases:
+ - "azurite"
+
+networks:
+ eh-emulator:
diff --git a/sdk/spring/spring-cloud-azure-starter-appconfiguration-config/README.md b/sdk/spring/spring-cloud-azure-starter-appconfiguration-config/README.md
index b23adc9fce07..568483f89e7b 100644
--- a/sdk/spring/spring-cloud-azure-starter-appconfiguration-config/README.md
+++ b/sdk/spring/spring-cloud-azure-starter-appconfiguration-config/README.md
@@ -404,9 +404,9 @@ Please follow [instructions here][contributing_md] to build from source or contr
[package]: https://mvnrepository.com/artifact/com.microsoft.azure/spring-cloud-azure-appconfiguration-config
-[app_configuration_sample]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_v4.3.0/appconfiguration/azure-spring-cloud-appconfiguration-config/azure-spring-cloud-appconfiguration-config-sample
-[app_configuration_conversation_complete_sample]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_v4.3.0/appconfiguration/azure-spring-cloud-appconfiguration-config/azure-spring-cloud-appconfiguration-config-convert-sample/azure-spring-cloud-appconfiguration-config-convert-sample-complete
-[app_configuration_conversation_initail_sample]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_v4.3.0/appconfiguration/azure-spring-cloud-appconfiguration-config/azure-spring-cloud-appconfiguration-config-convert-sample/azure-spring-cloud-appconfiguration-config-convert-sample-initial
+[app_configuration_sample]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-boot-3.x/appconfiguration/spring-cloud-azure-appconfiguration-config/spring-cloud-azure-appconfiguration-config-sample
+[app_configuration_conversation_complete_sample]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-boot-3.x/appconfiguration/spring-cloud-azure-appconfiguration-config/spring-cloud-azure-appconfiguration-config-convert-sample/spring-cloud-azure-appconfiguration-config-convert-sample-complete
+[app_configuration_conversation_initail_sample]: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-boot-3.x/appconfiguration/spring-cloud-azure-appconfiguration-config/spring-cloud-azure-appconfiguration-config-convert-sample/spring-cloud-azure-appconfiguration-config-convert-sample-initial
[azure_subscription]: https://azure.microsoft.com/free
[spring logging document]: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#boot-features-logging
[contributing_md]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/spring/CONTRIBUTING.md
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/pom.xml b/sdk/spring/spring-cloud-azure-testcontainers/pom.xml
index a5cce841390c..9b078e99a396 100644
--- a/sdk/spring/spring-cloud-azure-testcontainers/pom.xml
+++ b/sdk/spring/spring-cloud-azure-testcontainers/pom.xml
@@ -78,17 +78,32 @@
12.26.1
true
+
+ com.azure.spring
+ spring-messaging-azure-servicebus
+ 5.24.1
+ test
+
org.springframework.boot
spring-boot-testcontainers
3.5.4
+
+ org.apache.commons
+ commons-lang3
+ 3.17.0
+
org.testcontainers
- azure
- 1.21.3
- true
+ testcontainers
+ 2.0.3
+
+
+ org.testcontainers
+ testcontainers-azure
+ 2.0.3
+ test
+
+
+ com.azure
+ azure-messaging-eventhubs
+ 5.20.5
+ test
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ 13.2.1.jre11
+ test
+
org.springframework
spring-test
@@ -120,8 +153,14 @@
org.testcontainers
- junit-jupiter
- 1.21.3
+ testcontainers-junit-jupiter
+ 2.0.3
+ test
+
+
+ org.awaitility
+ awaitility
+ 4.3.0
test
@@ -167,8 +206,11 @@
+ org.apache.commons:commons-lang3:[3.17.0]
org.springframework.boot:spring-boot-testcontainers:[3.5.4]
- org.testcontainers:azure:[1.21.3]
+ org.testcontainers:testcontainers-azure:[2.0.3]
+ org.testcontainers:testcontainers:[2.0.3]
+ com.microsoft.sqlserver:mssql-jdbc:[13.2.1.jre11]
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/main/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/bus/ServiceBusContainerConnectionDetailsFactory.java b/sdk/spring/spring-cloud-azure-testcontainers/src/main/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/bus/ServiceBusContainerConnectionDetailsFactory.java
new file mode 100644
index 000000000000..d378bcf5fa64
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/main/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/bus/ServiceBusContainerConnectionDetailsFactory.java
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.testcontainers.implementation.service.connection.bus;
+
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
+import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
+import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
+import org.testcontainers.azure.ServiceBusEmulatorContainer;
+
+class ServiceBusContainerConnectionDetailsFactory
+ extends ContainerConnectionDetailsFactory {
+
+ @Override
+ protected AzureServiceBusConnectionDetails getContainerConnectionDetails(ContainerConnectionSource source) {
+ return new ServiceBusContainerConnectionDetails(source);
+ }
+
+ /**
+ * {@link AzureServiceBusConnectionDetails} backed by a {@link ContainerConnectionSource}.
+ */
+ private static class ServiceBusContainerConnectionDetails extends ContainerConnectionDetails
+ implements AzureServiceBusConnectionDetails {
+
+ ServiceBusContainerConnectionDetails(ContainerConnectionSource source) {
+ super(source);
+ }
+
+ @Override
+ public String getConnectionString() {
+ return getContainer().getConnectionString();
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/main/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/hubs/EventHubsContainerConnectionDetailsFactory.java b/sdk/spring/spring-cloud-azure-testcontainers/src/main/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/hubs/EventHubsContainerConnectionDetailsFactory.java
new file mode 100644
index 000000000000..a3b5460446ef
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/main/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/hubs/EventHubsContainerConnectionDetailsFactory.java
@@ -0,0 +1,34 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.testcontainers.implementation.service.connection.hubs;
+
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
+import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
+import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
+import org.testcontainers.azure.EventHubsEmulatorContainer;
+
+class EventHubsContainerConnectionDetailsFactory
+ extends ContainerConnectionDetailsFactory {
+
+ @Override
+ protected AzureEventHubsConnectionDetails getContainerConnectionDetails(ContainerConnectionSource source) {
+ return new EventHubsContainerConnectionDetails(source);
+ }
+
+ /**
+ * {@link AzureEventHubsConnectionDetails} backed by a {@link ContainerConnectionSource}.
+ */
+ private static class EventHubsContainerConnectionDetails extends ContainerConnectionDetails
+ implements AzureEventHubsConnectionDetails {
+
+ EventHubsContainerConnectionDetails(ContainerConnectionSource source) {
+ super(source);
+ }
+
+ @Override
+ public String getConnectionString() {
+ return getContainer().getConnectionString();
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/main/resources/META-INF/spring.factories b/sdk/spring/spring-cloud-azure-testcontainers/src/main/resources/META-INF/spring.factories
index 6543d8914a45..a590e8a7e19f 100644
--- a/sdk/spring/spring-cloud-azure-testcontainers/src/main/resources/META-INF/spring.factories
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,6 @@
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\
com.azure.spring.cloud.testcontainers.implementation.service.connection.cosmos.CosmosContainerConnectionDetailsFactory,\
+com.azure.spring.cloud.testcontainers.implementation.service.connection.bus.ServiceBusContainerConnectionDetailsFactory,\
com.azure.spring.cloud.testcontainers.implementation.service.connection.storage.StorageBlobContainerConnectionDetailsFactory,\
-com.azure.spring.cloud.testcontainers.implementation.service.connection.storage.StorageQueueContainerConnectionDetailsFactory
+com.azure.spring.cloud.testcontainers.implementation.service.connection.storage.StorageQueueContainerConnectionDetailsFactory,\
+com.azure.spring.cloud.testcontainers.implementation.service.connection.hubs.EventHubsContainerConnectionDetailsFactory
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/test/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/bus/ServiceBusContainerConnectionDetailsFactoryTests.java b/sdk/spring/spring-cloud-azure-testcontainers/src/test/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/bus/ServiceBusContainerConnectionDetailsFactoryTests.java
new file mode 100644
index 000000000000..c77ce4c646eb
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/test/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/bus/ServiceBusContainerConnectionDetailsFactoryTests.java
@@ -0,0 +1,131 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.testcontainers.implementation.service.connection.bus;
+
+import com.azure.messaging.servicebus.ServiceBusMessage;
+import com.azure.messaging.servicebus.ServiceBusSenderClient;
+import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.AzureServiceBusAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.AzureServiceBusMessagingAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusConnectionDetails;
+import com.azure.spring.cloud.service.servicebus.consumer.ServiceBusErrorHandler;
+import com.azure.spring.cloud.service.servicebus.consumer.ServiceBusRecordMessageListener;
+import com.azure.spring.messaging.servicebus.core.ServiceBusTemplate;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.azure.ServiceBusEmulatorContainer;
+import org.testcontainers.containers.MSSQLServerContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.MountableFile;
+
+import java.time.Duration;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.waitAtMost;
+
+@SpringJUnitConfig
+@TestPropertySource(properties = { "spring.cloud.azure.servicebus.entity-name=queue.1",
+ "spring.cloud.azure.servicebus.entity-type=queue" })
+@Testcontainers
+@EnabledOnOs(OS.LINUX)
+@SuppressWarnings("deprecation") // Link to related issue: https://github.com/testcontainers/testcontainers-java/issues/11554
+class ServiceBusContainerConnectionDetailsFactoryTests {
+
+ private static final Network NETWORK = Network.newNetwork();
+
+ private static final MSSQLServerContainer> SQLSERVER = new MSSQLServerContainer<>(
+ "mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04")
+ .acceptLicense()
+ .withNetwork(NETWORK)
+ .withNetworkAliases("sqlserver");
+
+ @Container
+ @ServiceConnection
+ private static final ServiceBusEmulatorContainer SERVICE_BUS = new ServiceBusEmulatorContainer(
+ "mcr.microsoft.com/azure-messaging/servicebus-emulator:latest")
+ .acceptLicense()
+ .withCopyFileToContainer(MountableFile.forClasspathResource("servicebus/Config.json"),
+ "/ServiceBus_Emulator/ConfigFiles/Config.json")
+ .withNetwork(NETWORK)
+ .withMsSqlServerContainer(SQLSERVER);
+
+ @Autowired
+ private AzureServiceBusConnectionDetails connectionDetails;
+
+ @Autowired
+ private ServiceBusSenderClient senderClient;
+
+ @Autowired
+ private ServiceBusTemplate serviceBusTemplate;
+
+ @Test
+ void connectionDetailsShouldBeProvidedByFactory() {
+ assertThat(connectionDetails).isNotNull();
+ assertThat(connectionDetails.getConnectionString())
+ .isNotBlank()
+ .startsWith("Endpoint=sb://");
+ }
+
+ @Test
+ void senderClientCanSendMessage() {
+ // Wait for Service Bus emulator to be fully ready and queue entity to be available
+ waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
+ this.senderClient.sendMessage(new ServiceBusMessage("Hello World!"));
+ });
+
+ waitAtMost(Duration.ofSeconds(30)).untilAsserted(() -> {
+ assertThat(Config.MESSAGES).contains("Hello World!");
+ });
+ }
+
+ @Test
+ void serviceBusTemplateCanSendMessage() {
+ // Wait for Service Bus emulator to be fully ready and queue entity to be available
+ waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
+ this.serviceBusTemplate.sendAsync("queue.1", MessageBuilder.withPayload("Hello from ServiceBusTemplate!").build()).block();
+ });
+
+ waitAtMost(Duration.ofSeconds(30)).untilAsserted(() -> {
+ assertThat(Config.MESSAGES).contains("Hello from ServiceBusTemplate!");
+ });
+ }
+
+
+ @Configuration(proxyBeanMethods = false)
+ @ImportAutoConfiguration(classes = {AzureGlobalPropertiesAutoConfiguration.class,
+ AzureServiceBusAutoConfiguration.class,
+ AzureServiceBusMessagingAutoConfiguration.class})
+ static class Config {
+
+ private static final Set MESSAGES = ConcurrentHashMap.newKeySet();
+
+ @Bean
+ ServiceBusRecordMessageListener processMessage() {
+ return context -> {
+ MESSAGES.add(context.getMessage().getBody().toString());
+ };
+ }
+
+ @Bean
+ ServiceBusErrorHandler errorHandler() {
+ // No-op error handler for tests: acknowledge errors without affecting test execution.
+ return (context) -> {
+ };
+ }
+
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/test/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/hubs/EventHubsContainerConnectionDetailsFactoryTests.java b/sdk/spring/spring-cloud-azure-testcontainers/src/test/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/hubs/EventHubsContainerConnectionDetailsFactoryTests.java
new file mode 100644
index 000000000000..84c05c2bc6a2
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/test/java/com/azure/spring/cloud/testcontainers/implementation/service/connection/hubs/EventHubsContainerConnectionDetailsFactoryTests.java
@@ -0,0 +1,86 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.spring.cloud.testcontainers.implementation.service.connection.hubs;
+
+import com.azure.messaging.eventhubs.EventData;
+import com.azure.messaging.eventhubs.EventHubProducerClient;
+import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration;
+import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsConnectionDetails;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.azure.EventHubsEmulatorContainer;
+import org.testcontainers.azure.AzuriteContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.MountableFile;
+
+import java.time.Duration;
+import java.util.Collections;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.waitAtMost;
+
+@SpringJUnitConfig
+@TestPropertySource(properties = {
+ "spring.cloud.azure.eventhubs.event-hub-name=eh1"
+})
+@Testcontainers
+@EnabledOnOs(OS.LINUX)
+class EventHubsContainerConnectionDetailsFactoryTests {
+
+ private static final Network NETWORK = Network.newNetwork();
+
+ @Container
+ private static final AzuriteContainer AZURITE = new AzuriteContainer("mcr.microsoft.com/azure-storage/azurite:latest")
+ .withNetwork(NETWORK)
+ .withNetworkAliases("azurite");
+
+ @Container
+ @ServiceConnection
+ private static final EventHubsEmulatorContainer EVENT_HUBS = new EventHubsEmulatorContainer(
+ "mcr.microsoft.com/azure-messaging/eventhubs-emulator:latest")
+ .acceptLicense()
+ .withCopyFileToContainer(MountableFile.forClasspathResource("eventhubs/Config.json"),
+ "/Eventhubs_Emulator/ConfigFiles/Config.json")
+ .withNetwork(NETWORK)
+ .withAzuriteContainer(AZURITE);
+
+ @Autowired
+ private AzureEventHubsConnectionDetails connectionDetails;
+
+ @Autowired
+ private EventHubProducerClient producerClient;
+
+ @Test
+ void connectionDetailsShouldBeProvidedByFactory() {
+ assertThat(connectionDetails).isNotNull();
+ assertThat(connectionDetails.getConnectionString())
+ .isNotBlank()
+ .startsWith("Endpoint=sb://");
+ }
+
+ @Test
+ void producerClientCanSendMessage() {
+ // Wait for Event Hubs emulator to be fully ready and event hub entity to be available
+ waitAtMost(Duration.ofSeconds(120)).pollInterval(Duration.ofSeconds(2)).untilAsserted(() -> {
+ EventData event = new EventData("Hello World!");
+ this.producerClient.send(Collections.singletonList(event));
+ });
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @ImportAutoConfiguration(classes = {AzureGlobalPropertiesAutoConfiguration.class,
+ AzureEventHubsAutoConfiguration.class})
+ static class Config {
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/eventhubs/Config.json b/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/eventhubs/Config.json
new file mode 100644
index 000000000000..0749990d11d4
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/eventhubs/Config.json
@@ -0,0 +1,20 @@
+{
+ "UserConfig": {
+ "NamespaceConfig": [
+ {
+ "Type": "EventHub",
+ "Name": "emulatorns1",
+ "Entities": [
+ {
+ "Name": "eh1",
+ "PartitionCount": "2",
+ "ConsumerGroups": []
+ }
+ ]
+ }
+ ],
+ "LoggingConfig": {
+ "Type": "File"
+ }
+ }
+}
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/logback-test.xml b/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/logback-test.xml
new file mode 100644
index 000000000000..f760dc6205b3
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/logback-test.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ %d{HH:mm:ss.SSS} %-5level %logger - %msg%n
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/servicebus/Config.json b/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/servicebus/Config.json
new file mode 100644
index 000000000000..256f4fbc40c4
--- /dev/null
+++ b/sdk/spring/spring-cloud-azure-testcontainers/src/test/resources/servicebus/Config.json
@@ -0,0 +1,108 @@
+{
+ "UserConfig": {
+ "Namespaces": [
+ {
+ "Name": "sbemulatorns",
+ "Queues": [
+ {
+ "Name": "queue.1",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "DuplicateDetectionHistoryTimeWindow": "PT20S",
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "RequiresDuplicateDetection": false,
+ "RequiresSession": false
+ }
+ }
+ ],
+
+ "Topics": [
+ {
+ "Name": "topic.1",
+ "Properties": {
+ "DefaultMessageTimeToLive": "PT1H",
+ "DuplicateDetectionHistoryTimeWindow": "PT20S",
+ "RequiresDuplicateDetection": false
+ },
+ "Subscriptions": [
+ {
+ "Name": "subscription.1",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "RequiresSession": false
+ },
+ "Rules": [
+ {
+ "Name": "app-prop-filter-1",
+ "Properties": {
+ "FilterType": "Correlation",
+ "CorrelationFilter": {
+ "ContentType": "application/text",
+ "CorrelationId": "id1",
+ "Label": "subject1",
+ "MessageId": "msgid1",
+ "ReplyTo": "someQueue",
+ "ReplyToSessionId": "sessionId",
+ "SessionId": "session1",
+ "To": "xyz"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "Name": "subscription.2",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "RequiresSession": false
+ },
+ "Rules": [
+ {
+ "Name": "user-prop-filter-1",
+ "Properties": {
+ "FilterType": "Correlation",
+ "CorrelationFilter": {
+ "Properties": {
+ "prop3": "value3"
+ }
+ }
+ }
+ }
+ ]
+ },
+ {
+ "Name": "subscription.3",
+ "Properties": {
+ "DeadLetteringOnMessageExpiration": false,
+ "DefaultMessageTimeToLive": "PT1H",
+ "LockDuration": "PT1M",
+ "MaxDeliveryCount": 10,
+ "ForwardDeadLetteredMessagesTo": "",
+ "ForwardTo": "",
+ "RequiresSession": false
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "Logging": {
+ "Type": "File"
+ }
+ }
+}