This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push:
new 3a76807c1f Added azure-servicebus local testing
3a76807c1f is described below
commit 3a76807c1f706b9d94a6d6f607861cbd49c8c053
Author: Jiri Ondrusek <[email protected]>
AuthorDate: Tue Mar 4 09:38:46 2025 +0100
Added azure-servicebus local testing
---
.../azure/azure-servicebus/pom.xml | 5 +
.../src/main/resources/application.properties | 3 +
.../azure/servicebus/it/AzureServiceBusIT.java | 3 -
.../azure/servicebus/it/AzureServiceBusTest.java | 26 +++--
.../support/azure/AzureServiceBusTestResource.java | 120 +++++++++++++++++++++
.../src/main/resources/servicebus-config.json | 90 ++++++++++++++++
.../main/resources/servicebus-docker-compose.yaml | 46 ++++++++
pom.xml | 2 +
8 files changed, 286 insertions(+), 9 deletions(-)
diff --git a/integration-test-groups/azure/azure-servicebus/pom.xml
b/integration-test-groups/azure/azure-servicebus/pom.xml
index e589fa42bd..71258e692d 100644
--- a/integration-test-groups/azure/azure-servicebus/pom.xml
+++ b/integration-test-groups/azure/azure-servicebus/pom.xml
@@ -72,6 +72,11 @@
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-azure</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<profiles>
diff --git
a/integration-test-groups/azure/azure-servicebus/src/main/resources/application.properties
b/integration-test-groups/azure/azure-servicebus/src/main/resources/application.properties
index 03acdfc389..76053671f1 100644
---
a/integration-test-groups/azure/azure-servicebus/src/main/resources/application.properties
+++
b/integration-test-groups/azure/azure-servicebus/src/main/resources/application.properties
@@ -21,3 +21,6 @@
azure.servicebus.topic.subscription.name=${AZURE_SERVICEBUS_TOPIC_SUBSCRIPTION_N
# Avoid autowiring custom ServiceBus clients. They are set explicitly via
endpoint options
camel.component.azure-servicebus.autowired-enabled=false
+
+# Uncomment to reduce log noise from com.azure internals
+# quarkus.log.category."com.azure".level = OFF
\ No newline at end of file
diff --git
a/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusIT.java
b/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusIT.java
index 2bc9aaa435..fc907b1a12 100644
---
a/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusIT.java
+++
b/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusIT.java
@@ -17,10 +17,7 @@
package org.apache.camel.quarkus.component.azure.servicebus.it;
import io.quarkus.test.junit.QuarkusIntegrationTest;
-import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
-@EnabledIfEnvironmentVariable(named = "AZURE_SERVICEBUS_CONNECTION_STRING",
matches = ".+")
-@EnabledIfEnvironmentVariable(named = "AZURE_SERVICEBUS_QUEUE_NAME", matches =
".+")
@QuarkusIntegrationTest
class AzureServiceBusIT extends AzureServiceBusTest {
}
diff --git
a/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java
b/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java
index 8592476e0f..1634c3deb3 100644
---
a/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java
+++
b/integration-test-groups/azure/azure-servicebus/src/test/java/org/apache/camel/quarkus/component/azure/servicebus/it/AzureServiceBusTest.java
@@ -29,15 +29,18 @@ import com.azure.core.amqp.AmqpTransportType;
import com.azure.core.util.BinaryData;
import com.azure.messaging.servicebus.ServiceBusClientBuilder;
import com.azure.messaging.servicebus.ServiceBusProcessorClient;
+import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
+import org.apache.camel.quarkus.test.EnabledIf;
+import org.apache.camel.quarkus.test.mock.backend.MockBackendDisabled;
+import org.apache.camel.quarkus.test.support.azure.AzureServiceBusTestResource;
import org.awaitility.Awaitility;
import org.jboss.logging.Logger;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@@ -45,9 +48,8 @@ import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
-@EnabledIfEnvironmentVariable(named = "AZURE_SERVICEBUS_CONNECTION_STRING",
matches = ".+")
-@EnabledIfEnvironmentVariable(named = "AZURE_SERVICEBUS_QUEUE_NAME", matches =
".+")
@QuarkusTest
+@QuarkusTestResource(AzureServiceBusTestResource.class)
class AzureServiceBusTest {
// NOTE: Consumer endpoints are started / stopped manually to prevent them
from inferring with each other
@@ -55,6 +57,11 @@ class AzureServiceBusTest {
@BeforeAll
public static void beforeAll() {
+ //this is not necessary for mocked testing
+ if (AzureServiceBusHelper.isMockBackEnd()) {
+ return;
+ }
+
// Drain the test queue in case there are messages lingering from
previous failed runs
ServiceBusProcessorClient client = new ServiceBusClientBuilder()
.connectionString(AzureServiceBusHelper.getConnectionString())
@@ -135,9 +142,8 @@ class AzureServiceBusTest {
final List<String> messages = new ArrayList<>();
for (int i = 0; i < 3; i++) {
- messages.add(UUID.randomUUID().toString());
+ messages.add("cq-azure-servicebus-test-" +
UUID.randomUUID().toString());
}
-
try {
RestAssured.given()
.post("/azure-servicebus/route/" + consumerRouteId +
"/start")
@@ -213,6 +219,7 @@ class AzureServiceBusTest {
}
@Test
+ @EnabledIf({ MockBackendDisabled.class }) //only connection string is
enabled on emulator, see
https://github.com/Azure/azure-service-bus-emulator-installer/issues/30#issuecomment-2500163047
void tokenCredentialAuthentication() {
final String messageBody = UUID.randomUUID().toString();
try {
@@ -306,6 +313,7 @@ class AzureServiceBusTest {
}
}
+ @EnabledIf({ MockBackendDisabled.class }) //only connection string is
enabled on emulator, see
https://github.com/Azure/azure-service-bus-emulator-installer/issues/30#issuecomment-2500163047
@Test
void azureIdentityCredentials() {
Assumptions.assumeTrue(AzureServiceBusHelper.isAzureIdentityCredentialsAvailable());
@@ -357,7 +365,13 @@ class AzureServiceBusTest {
String[] payloadTypes = { String.class.getSimpleName(),
byte[].class.getSimpleName(),
BinaryData.class.getSimpleName() };
- AmqpTransportType[] transportTypes = AmqpTransportType.values();
+ //in mocked backend, the AMQP_WEB_SOCKET is not supported, see
https://github.com/Azure/azure-service-bus-emulator-installer/issues/51
+ AmqpTransportType[] transportTypes;
+ if (AzureServiceBusHelper.isMockBackEnd()) {
+ transportTypes = new AmqpTransportType[] { AmqpTransportType.AMQP
};
+ } else {
+ transportTypes = AmqpTransportType.values();
+ }
return Stream.of(destinationTypes.split(","))
.flatMap(s1 -> Stream.of(transportTypes)
.flatMap(s2 -> Stream.of(payloadTypes)
diff --git
a/integration-tests-support/azure/src/main/java/org/apache/camel/quarkus/test/support/azure/AzureServiceBusTestResource.java
b/integration-tests-support/azure/src/main/java/org/apache/camel/quarkus/test/support/azure/AzureServiceBusTestResource.java
new file mode 100644
index 0000000000..68577d6e02
--- /dev/null
+++
b/integration-tests-support/azure/src/main/java/org/apache/camel/quarkus/test/support/azure/AzureServiceBusTestResource.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.quarkus.test.support.azure;
+
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import io.quarkus.runtime.LaunchMode;
+import io.quarkus.runtime.configuration.ConfigUtils;
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import io.smallrye.config.SmallRyeConfig;
+import org.apache.camel.quarkus.test.mock.backend.MockBackendUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.ComposeContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+
+public class AzureServiceBusTestResource implements
QuarkusTestResourceLifecycleManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(AzureServiceBusTestResource.class);
+ private static final int SERVICEBUS_INNER_PORT = 5672;
+ private Map<String, String> initArgs = new LinkedHashMap<>();
+ private ComposeContainer container;
+
+ @Override
+ public void init(Map<String, String> initArgs) {
+ this.initArgs = initArgs;
+ }
+
+ @Override
+ public Map<String, String> start() {
+ final SmallRyeConfig config = ConfigUtils.configBuilder(true,
LaunchMode.NORMAL).build();
+
+ final boolean realCredentialsProvided =
System.getenv("AZURE_SERVICEBUS_CONNECTION_STRING") != null
+ && System.getenv("AZURE_SERVICEBUS_QUEUE_NAME") != null;
+
+ final boolean startMockBackend =
MockBackendUtils.startMockBackend(false);
+ final Map<String, String> result = new LinkedHashMap<>();
+ if (startMockBackend && !realCredentialsProvided) {
+ MockBackendUtils.logMockBackendUsed();
+
+ try {
+ //copy docker-compose to tmp location
+ File dockerComposeFile, configFile;
+ try (InputStream inYaml =
getClass().getClassLoader().getResourceAsStream("servicebus-docker-compose.yaml");
+ InputStream inJson =
getClass().getClassLoader().getResourceAsStream("servicebus-config.json")) {
+ dockerComposeFile =
File.createTempFile("servicebus-docker-compose-", ".yaml");
+ configFile = File.createTempFile("servicebus-config-",
".json");
+ Files.copy(inYaml, dockerComposeFile.toPath(),
StandardCopyOption.REPLACE_EXISTING);
+ Files.copy(inJson, configFile.toPath(),
StandardCopyOption.REPLACE_EXISTING);
+ }
+
+ container = new ComposeContainer(dockerComposeFile)
+ .withEnv("ACCEPT_EULA", "Y")
+ .withEnv("SERVICEBUS_EMULATOR_IMAGE",
+
config.getValue("servicebus-emulator.container.image", String.class))
+ .withEnv("SQL_EDGE_IMAGE",
config.getValue("azure-sql-edge.container.image", String.class))
+ .withEnv("CONFIG_FILE", configFile.getAbsolutePath())
+ .withEnv("MSSQL_SA_PASSWORD", "12345678923456y!43")
+ .withExposedService("emulator", SERVICEBUS_INNER_PORT)
+ .withLocalCompose(true)
+ .withLogConsumer("emulator", new
Slf4jLogConsumer(LOGGER))
+ .waitingFor("emulator", Wait.forLogMessage(".*Emulator
Service is Successfully Up!.*", 1));
+
+ container.start();
+
+ String connectionString =
"Endpoint=sb://%s:%d;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;"
+ .formatted(container.getServiceHost("emulator",
SERVICEBUS_INNER_PORT),
+ container.getServicePort("emulator",
SERVICEBUS_INNER_PORT));
+ result.put("azure.servicebus.connection.string",
connectionString);
+ result.put("azure.servicebus.queue.name", "queue.1");
+ result.put("azure.servicebus.topic.name", "topic.1");
+ result.put("azure.servicebus.topic.subscription.name",
"subscription.1");
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ if (!startMockBackend && !realCredentialsProvided) {
+ throw new IllegalStateException(
+ "Set AZURE_SERVICEBUS_CONNECTION_STRING and
AZURE_SERVICEBUS_QUEUE_NAME env vars if you set
CAMEL_QUARKUS_START_MOCK_BACKEND=false");
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void stop() {
+ try {
+
+ if (container != null) {
+ container.stop();
+ }
+
+ } catch (Exception e) {
+ // ignored
+ }
+ }
+
+}
diff --git
a/integration-tests-support/azure/src/main/resources/servicebus-config.json
b/integration-tests-support/azure/src/main/resources/servicebus-config.json
new file mode 100644
index 0000000000..bdc25570d0
--- /dev/null
+++ b/integration-tests-support/azure/src/main/resources/servicebus-config.json
@@ -0,0 +1,90 @@
+{
+ "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
+ }
+ },
+ {
+ "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"
+ }
+ }
+}
\ No newline at end of file
diff --git
a/integration-tests-support/azure/src/main/resources/servicebus-docker-compose.yaml
b/integration-tests-support/azure/src/main/resources/servicebus-docker-compose.yaml
new file mode 100644
index 0000000000..4df541a4f7
--- /dev/null
+++
b/integration-tests-support/azure/src/main/resources/servicebus-docker-compose.yaml
@@ -0,0 +1,46 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+name: microsoft-azure-servicebus-emulator
+services:
+ emulator:
+ image: "${SERVICEBUS_EMULATOR_IMAGE}"
+ volumes:
+ - "${CONFIG_FILE}:/ServiceBus_Emulator/ConfigFiles/Config.json"
+ ports:
+ - 0:5672
+ environment:
+ SQL_SERVER: sqledge
+ MSSQL_SA_PASSWORD: ${MSSQL_SA_PASSWORD}
+ ACCEPT_EULA: ${ACCEPT_EULA}
+ depends_on:
+ - sqledge
+ networks:
+ sb-emulator:
+ aliases:
+ - "sb-emulator"
+ sqledge:
+ image: "${SQL_EDGE_IMAGE}"
+ networks:
+ sb-emulator:
+ aliases:
+ - "sqledge"
+ environment:
+ ACCEPT_EULA: ${ACCEPT_EULA}
+ MSSQL_SA_PASSWORD: ${MSSQL_SA_PASSWORD}
+networks:
+ sb-emulator:
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 913ac69878..d97274793a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -221,6 +221,7 @@
<!-- Test container image properties -->
<activemq.container.image>mirror.gcr.io/rmohr/activemq:5.15.9-alpine</activemq.container.image>
<arangodb.container.image>mirror.gcr.io/arangodb:3.12.0</arangodb.container.image>
+
<azure-sql-edge.container.image>mcr.microsoft.com/azure-sql-edge:latest</azure-sql-edge.container.image>
<azurite.container.image>mcr.microsoft.com/azure-storage/azurite:3.33.0</azurite.container.image>
<calculator-ws.container.image>quay.io/l2x6/calculator-ws:1.2</calculator-ws.container.image>
<cassandra.container.image>mirror.gcr.io/cassandra:5.0.2</cassandra.container.image>
@@ -254,6 +255,7 @@
<qdrant.container.image>mirror.gcr.io/qdrant/qdrant:v1.9.7-unprivileged</qdrant.container.image>
<rabbitmq.container.image>mirror.gcr.io/rabbitmq:3.13.7-management-alpine</rabbitmq.container.image>
<redis.container.image>mirror.gcr.io/redis:6.2.14-alpine</redis.container.image>
+
<servicebus-emulator.container.image>mcr.microsoft.com/azure-messaging/servicebus-emulator:latest</servicebus-emulator.container.image>
<smb.container.image>quay.io/jamesnetherton/camel-smb-test-server:1.0.0</smb.container.image>
<solr.container.image>mirror.gcr.io/solr:9.8.0-slim</solr.container.image>
<splunk.container.image>mirror.gcr.io/splunk/splunk:9.3.1</splunk.container.image>