This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 3bec2839cdb9 CAMEL-26620: camel-azure-eventgrid - add integration
tests on Floci AZ (#29239)
3bec2839cdb9 is described below
commit 3bec2839cdb9c2081a25419a07267dac03450513
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Nov 6 10:29:45 2026 +0100
CAMEL-26620: camel-azure-eventgrid - add integration tests on Floci AZ
(#29239)
camel-azure-eventgrid had no integration tests. Add a
camel-test-infra-azure-eventgrid module: a local service on Floci AZ that
creates a topic in the CloudEvents 1.0 schema through its Azure Resource
Manager API and gives its endpoint, access key and resource id, and a
remote one for a real topic.
EventGridProducerIT publishes through the component, configured with the
topic endpoint and access key, to a webhook subscriber of the test that
the Floci AZ container reaches through Testcontainers.exposeHostPorts, and
checks a single event and a list published as one event per element. The
Event Grid SDK sends an access key only over HTTPS, so Floci AZ runs with
TLS and the test trusts its certificate authority through the JVM trust
store, set before the first HTTPS call. The integration tests are skipped
on ppc64le and s390x.
Signed-off-by: Andrea Cosentino <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
---
.../apache/camel/catalog/test-infra/metadata.json | 11 ++
.../camel-azure/camel-azure-eventgrid/pom.xml | 15 ++
.../eventgrid/integration/EventGridProducerIT.java | 151 ++++++++++++++++++++
.../eventgrid/integration/EventGridSubscriber.java | 122 ++++++++++++++++
.../src/test/resources/log4j2.properties | 27 ++++
test-infra/camel-test-infra-all/pom.xml | 11 ++
.../src/generated/resources/META-INF/metadata.json | 11 ++
.../camel-test-infra-azure-eventgrid/pom.xml | 58 ++++++++
.../clients/AzureEventGridManagementClient.java | 157 +++++++++++++++++++++
.../eventgrid/common/AzureEventGridProperties.java | 33 +++++
.../services/AzureEventGridInfraService.java | 59 ++++++++
.../AzureEventGridLocalContainerInfraService.java | 155 ++++++++++++++++++++
.../services/AzureEventGridRemoteInfraService.java | 72 ++++++++++
.../eventgrid/services/AzureEventGridService.java | 27 ++++
.../services/AzureEventGridServiceFactory.java | 101 +++++++++++++
.../src/main/resources/META-INF/MANIFEST.MF | 0
test-infra/pom.xml | 1 +
17 files changed, 1011 insertions(+)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
index e1f97d5309cd..7512bf9a444a 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
@@ -702,6 +702,17 @@
"version" : "4.24.0-SNAPSHOT",
"serviceVersion" : "2.22.0",
"uiSupported" : true
+}, {
+ "service" :
"org.apache.camel.test.infra.azure.eventgrid.services.AzureEventGridInfraService",
+ "description" : "Local Azure Event Grid service with Floci AZ",
+ "implementation" :
"org.apache.camel.test.infra.azure.eventgrid.services.AzureEventGridLocalContainerInfraService",
+ "alias" : [ "azure" ],
+ "aliasImplementation" : [ "event-grid" ],
+ "groupId" : "org.apache.camel",
+ "artifactId" : "camel-test-infra-azure-eventgrid",
+ "version" : "4.24.0-SNAPSHOT",
+ "serviceVersion" : "0.16.0",
+ "uiSupported" : false
}, {
"service" :
"org.apache.camel.test.infra.infinispan.services.InfinispanInfraService",
"description" : "Infinispan is a distributed in-memory key/value data store",
diff --git a/components/camel-azure/camel-azure-eventgrid/pom.xml
b/components/camel-azure/camel-azure-eventgrid/pom.xml
index 74203ab8aaa0..a343c61099fd 100644
--- a/components/camel-azure/camel-azure-eventgrid/pom.xml
+++ b/components/camel-azure/camel-azure-eventgrid/pom.xml
@@ -33,6 +33,9 @@
<description>Camel Azure Event Grid Component</description>
<properties>
+ <!-- Floci AZ is not available on these platforms -->
+ <skipITs.ppc64le>true</skipITs.ppc64le>
+ <skipITs.s390x>true</skipITs.s390x>
</properties>
<dependencies>
@@ -72,5 +75,17 @@
<artifactId>commons-lang3</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <version>${awaitility-version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-infra-azure-eventgrid</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git
a/components/camel-azure/camel-azure-eventgrid/src/test/java/org/apache/camel/component/azure/eventgrid/integration/EventGridProducerIT.java
b/components/camel-azure/camel-azure-eventgrid/src/test/java/org/apache/camel/component/azure/eventgrid/integration/EventGridProducerIT.java
new file mode 100644
index 000000000000..5f388e34f2c6
--- /dev/null
+++
b/components/camel-azure/camel-azure-eventgrid/src/test/java/org/apache/camel/component/azure/eventgrid/integration/EventGridProducerIT.java
@@ -0,0 +1,151 @@
+/*
+ * 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.component.azure.eventgrid.integration;
+
+import java.time.OffsetDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.azure.eventgrid.EventGridConstants;
+import
org.apache.camel.test.infra.azure.eventgrid.clients.AzureEventGridManagementClient;
+import
org.apache.camel.test.infra.azure.eventgrid.services.AzureEventGridService;
+import
org.apache.camel.test.infra.azure.eventgrid.services.AzureEventGridServiceFactory;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Publishes events to a topic of Floci AZ, which delivers them to a webhook
subscriber of the test.
+ */
+@DisabledIfSystemProperty(named = "azure.instance.type", matches = "remote",
+ disabledReason = "A remote topic cannot deliver its
events to the subscriber of the test")
+class EventGridProducerIT extends CamelTestSupport {
+ private static final String TRUST_STORE = "javax.net.ssl.trustStore";
+ private static final String TRUST_STORE_PASSWORD =
"javax.net.ssl.trustStorePassword";
+ private static final String TRUST_STORE_TYPE =
"javax.net.ssl.trustStoreType";
+ private static final Map<String, String> SAVED_PROPERTIES = new
HashMap<>();
+
+ @Order(1)
+ @RegisterExtension
+ static EventGridSubscriber subscriber = new EventGridSubscriber();
+
+ @Order(2)
+ @RegisterExtension
+ static AzureEventGridService service =
AzureEventGridServiceFactory.createService();
+
+ @BeforeAll
+ static void subscribe() {
+ // the Event Grid SDK sends the access key only over HTTPS: trust the
certificate authority of Floci AZ
+ setProperty(TRUST_STORE, service.trustStore());
+ setProperty(TRUST_STORE_PASSWORD, service.trustStorePassword());
+ setProperty(TRUST_STORE_TYPE, "PKCS12");
+
+ new AzureEventGridManagementClient(service.resourceManagerEndpoint())
+ .createWebhookSubscription(service.topicId(), "camel-it",
subscriber.endpointUrl());
+ }
+
+ @AfterAll
+ static void restoreProperties() {
+ SAVED_PROPERTIES.forEach((name, value) -> {
+ if (value != null) {
+ System.setProperty(name, value);
+ } else {
+ System.clearProperty(name);
+ }
+ });
+ }
+
+ @Override
+ protected RoutesBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:publish")
+ .to("azure-eventgrid:" + service.topicEndpoint() +
"?accessKey=RAW(" + service.topicAccessKey() + ")");
+ }
+ };
+ }
+
+ @Test
+ void eventIsDelivered() {
+ String subject = "/orders/" + UUID.randomUUID();
+ OffsetDateTime time = OffsetDateTime.parse("2026-11-05T10:15:30Z");
+
+ Exchange result = template.send("direct:publish", exchange -> {
+ exchange.getIn().setBody(Map.of("item", "Camel", "quantity", 3));
+ exchange.getIn().setHeader(EventGridConstants.EVENT_TYPE,
"Camel.Order.Created");
+ exchange.getIn().setHeader(EventGridConstants.SUBJECT, subject);
+ exchange.getIn().setHeader(EventGridConstants.ID, "order-1");
+ exchange.getIn().setHeader(EventGridConstants.EVENT_TIME, time);
+ });
+
+ assertNull(result.getException());
+ Map<String, Object> event = receivedEvents(subject, 1).get(0);
+ assertEquals("order-1", event.get("id"));
+ assertEquals("Camel.Order.Created", event.get("type"));
+ assertEquals("1.0", event.get("specversion"));
+ assertTrue(time.isEqual(OffsetDateTime.parse((String)
event.get("time"))));
+ assertEquals(Map.of("item", "Camel", "quantity", 3),
event.get("data"));
+ }
+
+ @Test
+ void listIsDeliveredAsOneEventPerElement() {
+ String subject = "/batches/" + UUID.randomUUID();
+ String text = "he said \"hi\"\n\tC:\\camel Grüße";
+
+ Exchange result = template.send("direct:publish", exchange -> {
+ exchange.getIn().setBody(List.of(Map.of("name", "Camel"), text,
42));
+ exchange.getIn().setHeader(EventGridConstants.SUBJECT, subject);
+ });
+
+ assertNull(result.getException());
+ // Event Grid delivers the events of a batch one by one, in no given
order
+ List<Map<String, Object>> events = receivedEvents(subject, 3);
+ assertEquals(Set.of(Map.of("name", "Camel"), text, 42),
+ events.stream().map(event ->
event.get("data")).collect(Collectors.toSet()));
+ assertEquals(3, events.stream().map(event ->
event.get("id")).distinct().count());
+ assertEquals(Set.of("Camel.Event"), events.stream().map(event ->
event.get("type")).collect(Collectors.toSet()));
+ }
+
+ private static List<Map<String, Object>> receivedEvents(String subject,
int count) {
+ await().atMost(30, TimeUnit.SECONDS)
+ .untilAsserted(() -> assertEquals(count,
subscriber.events(subject).size()));
+ return subscriber.events(subject);
+ }
+
+ private static void setProperty(String name, String value) {
+ SAVED_PROPERTIES.put(name, System.getProperty(name));
+ System.setProperty(name, value);
+ }
+}
diff --git
a/components/camel-azure/camel-azure-eventgrid/src/test/java/org/apache/camel/component/azure/eventgrid/integration/EventGridSubscriber.java
b/components/camel-azure/camel-azure-eventgrid/src/test/java/org/apache/camel/component/azure/eventgrid/integration/EventGridSubscriber.java
new file mode 100644
index 000000000000..a13115a9d608
--- /dev/null
+++
b/components/camel-azure/camel-azure-eventgrid/src/test/java/org/apache/camel/component/azure/eventgrid/integration/EventGridSubscriber.java
@@ -0,0 +1,122 @@
+/*
+ * 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.component.azure.eventgrid.integration;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import com.azure.json.JsonProviders;
+import com.azure.json.JsonReader;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpServer;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.Testcontainers;
+import org.testcontainers.containers.GenericContainer;
+
+/**
+ * A webhook subscriber of an Event Grid topic of Floci AZ: an HTTP server of
the test, which the container of Floci AZ
+ * reaches at {@code host.testcontainers.internal}. It answers the validation
handshake of the CloudEvents schema and
+ * keeps the events delivered to it.
+ * <p>
+ * Register it before the service of Floci AZ: a container has the {@code
host.testcontainers.internal} host only when a
+ * port of the host was exposed before it started.
+ */
+class EventGridSubscriber implements BeforeAllCallback, AfterAllCallback {
+ private static final Logger LOG =
LoggerFactory.getLogger(EventGridSubscriber.class);
+ private static final String PATH = "/events";
+
+ private final List<Map<String, Object>> events = new
CopyOnWriteArrayList<>();
+ private HttpServer server;
+
+ @Override
+ public void beforeAll(ExtensionContext context) throws IOException {
+ server = HttpServer.create(new
InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
+ server.createContext(PATH, this::handle);
+ server.start();
+
+ Testcontainers.exposeHostPorts(server.getAddress().getPort());
+ }
+
+ @Override
+ public void afterAll(ExtensionContext context) {
+ if (server != null) {
+ server.stop(0);
+ }
+ }
+
+ /**
+ * The URL of the webhook for the container of Floci AZ
+ */
+ String endpointUrl() {
+ return "http://" + GenericContainer.INTERNAL_HOST_HOSTNAME + ":" +
server.getAddress().getPort() + PATH;
+ }
+
+ /**
+ * The events received with a subject, as their JSON
+ */
+ List<Map<String, Object>> events(String subject) {
+ return events.stream().filter(event ->
subject.equals(event.get("subject"))).toList();
+ }
+
+ private void handle(HttpExchange exchange) throws IOException {
+ try {
+ switch (exchange.getRequestMethod()) {
+ case "OPTIONS" -> allowOrigin(exchange);
+ case "POST" -> receive(exchange);
+ default -> exchange.sendResponseHeaders(405, -1);
+ }
+ } finally {
+ exchange.close();
+ }
+ }
+
+ /**
+ * The validation handshake of the CloudEvents schema (abuse protection):
Event Grid delivers to a webhook that
+ * allows the origin of the request
+ */
+ private static void allowOrigin(HttpExchange exchange) throws IOException {
+ String origin =
exchange.getRequestHeaders().getFirst("WebHook-Request-Origin");
+ if (origin == null) {
+ exchange.sendResponseHeaders(400, -1);
+ return;
+ }
+ LOG.info("Allowing the origin {} of the validation handshake", origin);
+ exchange.getResponseHeaders().set("WebHook-Allowed-Origin", origin);
+ exchange.sendResponseHeaders(200, -1);
+ }
+
+ /**
+ * A delivery: a JSON array of events in the CloudEvents schema
+ */
+ @SuppressWarnings("unchecked")
+ private void receive(HttpExchange exchange) throws IOException {
+ try (JsonReader reader =
JsonProviders.createReader(exchange.getRequestBody().readAllBytes())) {
+ List<Map<String, Object>> delivered = (List<Map<String, Object>>)
reader.readUntyped();
+ LOG.info("Received {}", delivered);
+ events.addAll(delivered);
+ }
+ exchange.sendResponseHeaders(200, -1);
+ }
+}
diff --git
a/components/camel-azure/camel-azure-eventgrid/src/test/resources/log4j2.properties
b/components/camel-azure/camel-azure-eventgrid/src/test/resources/log4j2.properties
new file mode 100644
index 000000000000..2d7e1d65b15c
--- /dev/null
+++
b/components/camel-azure/camel-azure-eventgrid/src/test/resources/log4j2.properties
@@ -0,0 +1,27 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-azure-eventgrid-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/test-infra/camel-test-infra-all/pom.xml
b/test-infra/camel-test-infra-all/pom.xml
index 950bfdf0a4ef..80d96e5addda 100644
--- a/test-infra/camel-test-infra-all/pom.xml
+++ b/test-infra/camel-test-infra-all/pom.xml
@@ -71,6 +71,11 @@
<artifactId>camel-test-infra-rabbitmq</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-infra-azure-eventgrid</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-infra-azure-key-vault</artifactId>
@@ -423,6 +428,12 @@
<artifactId>camel-test-infra-rabbitmq</artifactId>
</dependency>
</fileSet>
+ <fileSet>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+
<artifactId>camel-test-infra-azure-eventgrid</artifactId>
+ </dependency>
+ </fileSet>
<fileSet>
<dependency>
<groupId>org.apache.camel</groupId>
diff --git
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
index e1f97d5309cd..7512bf9a444a 100644
---
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
+++
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
@@ -702,6 +702,17 @@
"version" : "4.24.0-SNAPSHOT",
"serviceVersion" : "2.22.0",
"uiSupported" : true
+}, {
+ "service" :
"org.apache.camel.test.infra.azure.eventgrid.services.AzureEventGridInfraService",
+ "description" : "Local Azure Event Grid service with Floci AZ",
+ "implementation" :
"org.apache.camel.test.infra.azure.eventgrid.services.AzureEventGridLocalContainerInfraService",
+ "alias" : [ "azure" ],
+ "aliasImplementation" : [ "event-grid" ],
+ "groupId" : "org.apache.camel",
+ "artifactId" : "camel-test-infra-azure-eventgrid",
+ "version" : "4.24.0-SNAPSHOT",
+ "serviceVersion" : "0.16.0",
+ "uiSupported" : false
}, {
"service" :
"org.apache.camel.test.infra.infinispan.services.InfinispanInfraService",
"description" : "Infinispan is a distributed in-memory key/value data store",
diff --git a/test-infra/camel-test-infra-azure-eventgrid/pom.xml
b/test-infra/camel-test-infra-azure-eventgrid/pom.xml
new file mode 100644
index 000000000000..1d63332239e1
--- /dev/null
+++ b/test-infra/camel-test-infra-azure-eventgrid/pom.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>camel-test-infra-parent</artifactId>
+ <groupId>org.apache.camel</groupId>
+ <relativePath>../camel-test-infra-parent/pom.xml</relativePath>
+ <version>4.24.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <name>Camel :: Test Infra :: Azure Event Grid</name>
+ <artifactId>camel-test-infra-azure-eventgrid</artifactId>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>com.azure</groupId>
+ <artifactId>azure-sdk-bom</artifactId>
+ <version>${azure-sdk-bom-version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-infra-azure-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- azure sdk: the JSON of the management API -->
+ <dependency>
+ <groupId>com.azure</groupId>
+ <artifactId>azure-json</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/clients/AzureEventGridManagementClient.java
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/clients/AzureEventGridManagementClient.java
new file mode 100644
index 000000000000..47ceff9ba813
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/clients/AzureEventGridManagementClient.java
@@ -0,0 +1,157 @@
+/*
+ * 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.test.infra.azure.eventgrid.clients;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.Map;
+
+import com.azure.json.JsonProviders;
+import com.azure.json.JsonReader;
+import com.azure.json.JsonWriter;
+
+/**
+ * A client of the Event Grid management (Azure Resource Manager) API of Floci
AZ, which needs no authentication: it
+ * creates custom topics, reads their access keys and subscribes webhooks to
them.
+ */
+public class AzureEventGridManagementClient {
+ private static final String API_VERSION = "2025-02-15";
+ private static final String CLOUD_EVENT_SCHEMA = "CloudEventSchemaV1_0";
+ private static final Duration TIMEOUT = Duration.ofSeconds(30);
+
+ private final HttpClient client =
HttpClient.newBuilder().connectTimeout(TIMEOUT).build();
+ private final String endpoint;
+
+ /**
+ * @param endpoint the address of Floci AZ, for example {@code
http://localhost:4577}
+ */
+ public AzureEventGridManagementClient(String endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ /**
+ * Creates a custom topic that takes events in the CloudEvents 1.0 schema
+ *
+ * @param topicId the resource id of the topic:
+ * {@code
/subscriptions/<id>/resourceGroups/<group>/providers/Microsoft.EventGrid/topics/<name>}
+ */
+ public void createCloudEventTopic(String topicId) {
+ send("PUT", topicId, Map.of(
+ "location", "eastus",
+ "properties", Map.of("inputSchema", CLOUD_EVENT_SCHEMA)));
+ }
+
+ /**
+ * The first access key of a topic
+ */
+ public String topicAccessKey(String topicId) {
+ Map<String, Object> keys = send("POST", topicId + "/listKeys", null);
+ Object key = keys.get("key1");
+ if (!(key instanceof String)) {
+ throw new IllegalStateException("No key1 in the keys of the topic
" + topicId + ": " + keys.keySet());
+ }
+ return (String) key;
+ }
+
+ /**
+ * Subscribes a webhook to a topic. Event Grid delivers the events to it
in the CloudEvents 1.0 schema, after the
+ * validation handshake: an {@code OPTIONS} request with the {@code
WebHook-Request-Origin} header, to which the
+ * webhook answers with the {@code WebHook-Allowed-Origin} header.
+ *
+ * @param topicId the resource id of the topic
+ * @param name the name of the event subscription
+ * @param endpointUrl the URL of the webhook, which the container of Floci
AZ must reach
+ */
+ public void createWebhookSubscription(String topicId, String name, String
endpointUrl) {
+ send("PUT", topicId +
"/providers/Microsoft.EventGrid/eventSubscriptions/" + name, Map.of(
+ "properties", Map.of(
+ "destination", Map.of(
+ "endpointType", "WebHook",
+ "properties", Map.of("endpointUrl",
endpointUrl)),
+ "eventDeliverySchema", CLOUD_EVENT_SCHEMA)));
+ }
+
+ /**
+ * The certificate authority, in PEM, that signs the certificate of Floci
AZ when it serves HTTPS
+ * ({@code FLOCI_AZ_TLS_ENABLED=true})
+ */
+ public String tlsCertificate() {
+ HttpRequest request = HttpRequest.newBuilder(URI.create(endpoint +
"/_floci/tls-cert"))
+ .timeout(TIMEOUT)
+ .GET()
+ .build();
+ return execute(request);
+ }
+
+ private Map<String, Object> send(String method, String resourceId,
Map<String, Object> body) {
+ HttpRequest request = HttpRequest.newBuilder(URI.create(endpoint +
resourceId + "?api-version=" + API_VERSION))
+ .timeout(TIMEOUT)
+ .header("Content-Type", "application/json")
+ .method(method, body != null
+ ? HttpRequest.BodyPublishers.ofString(toJson(body))
+ : HttpRequest.BodyPublishers.noBody())
+ .build();
+ return fromJson(execute(request));
+ }
+
+ private String execute(HttpRequest request) {
+ try {
+ HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
+ if (response.statusCode() / 100 != 2) {
+ throw new IllegalStateException(
+ request.method() + " " + request.uri() + " failed with
" + response.statusCode() + ": "
+ + response.body());
+ }
+ return response.body();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException("Interrupted while calling " +
request.uri(), e);
+ }
+ }
+
+ private static String toJson(Map<String, Object> body) {
+ StringWriter json = new StringWriter();
+ try (JsonWriter writer = JsonProviders.createWriter(json)) {
+ writer.writeUntyped(body);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ return json.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Map<String, Object> fromJson(String json) {
+ try (JsonReader reader = JsonProviders.createReader(json)) {
+ Object value = reader.readUntyped();
+ if (!(value instanceof Map)) {
+ throw new IllegalStateException("Not a JSON object: " + json);
+ }
+ return (Map<String, Object>) value;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/common/AzureEventGridProperties.java
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/common/AzureEventGridProperties.java
new file mode 100644
index 000000000000..6e1cca722312
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/common/AzureEventGridProperties.java
@@ -0,0 +1,33 @@
+/*
+ * 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.test.infra.azure.eventgrid.common;
+
+public final class AzureEventGridProperties {
+ /**
+ * The endpoint the events of the topic are published to: set by the local
service, read by the remote one
+ */
+ public static final String TOPIC_ENDPOINT =
"azure.eventgrid.topic.endpoint";
+ /**
+ * An access key of the topic: set by the local service, read by the
remote one
+ */
+ public static final String ACCESS_KEY = "azure.eventgrid.access.key";
+
+ private AzureEventGridProperties() {
+
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridInfraService.java
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridInfraService.java
new file mode 100644
index 000000000000..18016e31b591
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridInfraService.java
@@ -0,0 +1,59 @@
+/*
+ * 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.test.infra.azure.eventgrid.services;
+
+import org.apache.camel.test.infra.common.services.InfrastructureService;
+
+/**
+ * An Event Grid custom topic that takes events in the CloudEvents 1.0 schema.
+ */
+public interface AzureEventGridInfraService extends InfrastructureService {
+
+ /**
+ * The endpoint the events of the topic are published to, for example
+ * {@code https://localhost:4577/camel-topic-eventgrid/api/events}
+ */
+ String topicEndpoint();
+
+ /**
+ * An access key of the topic
+ */
+ String topicAccessKey();
+
+ /**
+ * The resource id of the topic, under which the management API keeps its
event subscriptions, or null when it is
+ * not known
+ */
+ String topicId();
+
+ /**
+ * The address of the management (Azure Resource Manager) API of the
topic, or null when it is not known
+ */
+ String resourceManagerEndpoint();
+
+ /**
+ * A PKCS12 trust store with the certificate authority of the topic
endpoint, to give to the JVM of a client with
+ * {@code javax.net.ssl.trustStore}, or null when the JVM trusts that
endpoint already
+ */
+ String trustStore();
+
+ /**
+ * The password of the trust store, or null when there is no trust store
+ */
+ String trustStorePassword();
+}
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridLocalContainerInfraService.java
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridLocalContainerInfraService.java
new file mode 100644
index 000000000000..203db969b401
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridLocalContainerInfraService.java
@@ -0,0 +1,155 @@
+/*
+ * 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.test.infra.azure.eventgrid.services;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.util.UUID;
+
+import org.apache.camel.spi.annotations.InfraService;
+import org.apache.camel.test.infra.azure.common.services.FlociAzContainer;
+import org.apache.camel.test.infra.azure.common.services.FlociAzInfraService;
+import
org.apache.camel.test.infra.azure.eventgrid.clients.AzureEventGridManagementClient;
+import
org.apache.camel.test.infra.azure.eventgrid.common.AzureEventGridProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A local Event Grid service: a custom topic of Floci AZ that takes events in
the CloudEvents 1.0 schema. The Event
+ * Grid SDK sends an access key only over HTTPS, so Floci AZ serves HTTPS too,
on the same port, with a certificate
+ * signed by a certificate authority of its own: {@link #trustStore()} holds
that authority.
+ */
+@InfraService(service = AzureEventGridInfraService.class,
+ description = "Local Azure Event Grid service with Floci AZ",
+ serviceAlias = "azure", serviceImplementationAlias =
"event-grid")
+public class AzureEventGridLocalContainerInfraService extends
FlociAzInfraService implements AzureEventGridInfraService {
+ private static final Logger LOG =
LoggerFactory.getLogger(AzureEventGridLocalContainerInfraService.class);
+ private static final String TOPIC_NAME = "camel-topic";
+ private static final String TOPIC_ID =
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/camel"
+ +
"/providers/Microsoft.EventGrid/topics/" + TOPIC_NAME;
+
+ private final String trustStorePassword = UUID.randomUUID().toString();
+ private String topicAccessKey;
+ private Path trustStore;
+
+ @Override
+ protected FlociAzContainer initContainer(String imageName) {
+ return super.initContainer(imageName).withEnv("FLOCI_AZ_TLS_ENABLED",
"true");
+ }
+
+ @Override
+ public void initialize() {
+ getContainer().start();
+
+ AzureEventGridManagementClient client = new
AzureEventGridManagementClient(resourceManagerEndpoint());
+ client.createCloudEventTopic(TOPIC_ID);
+ topicAccessKey = client.topicAccessKey(TOPIC_ID);
+ trustStore = createTrustStore(client.tlsCertificate());
+
+ LOG.info("Floci AZ Event Grid topic {} running at {}", TOPIC_NAME,
topicEndpoint());
+
+ registerProperties();
+ }
+
+ /**
+ * Registers the properties of the topic, and not those of the storage
account of Floci AZ, which Event Grid does
+ * not use
+ */
+ @Override
+ public void registerProperties() {
+ System.setProperty(AzureEventGridProperties.TOPIC_ENDPOINT,
topicEndpoint());
+ System.setProperty(AzureEventGridProperties.ACCESS_KEY,
topicAccessKey());
+ }
+
+ @Override
+ public void shutdown() {
+ super.shutdown();
+
+ if (trustStore != null) {
+ try {
+ Files.deleteIfExists(trustStore);
+ } catch (IOException e) {
+ LOG.warn("Cannot delete the trust store {}: {}", trustStore,
e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * The endpoint of the topic at the address of the container: the endpoint
Floci AZ gives for the topic is built
+ * from its own base URL ({@code http://localhost:4577}), which is not the
mapped port of the container.
+ */
+ @Override
+ public String topicEndpoint() {
+ return String.format("https://%s:%d/%s-eventgrid/api/events", host(),
port(), TOPIC_NAME);
+ }
+
+ @Override
+ public String topicAccessKey() {
+ return topicAccessKey;
+ }
+
+ @Override
+ public String topicId() {
+ return TOPIC_ID;
+ }
+
+ @Override
+ public String resourceManagerEndpoint() {
+ return getContainer().serviceAddress();
+ }
+
+ @Override
+ public String trustStore() {
+ return trustStore != null ? trustStore.toString() : null;
+ }
+
+ @Override
+ public String trustStorePassword() {
+ return trustStore != null ? trustStorePassword : null;
+ }
+
+ private Path createTrustStore(String certificateAuthority) {
+ try {
+ Certificate certificate = CertificateFactory.getInstance("X.509")
+ .generateCertificate(new
ByteArrayInputStream(certificateAuthority.getBytes(StandardCharsets.US_ASCII)));
+
+ KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ keyStore.load(null, null);
+ keyStore.setCertificateEntry("floci-az", certificate);
+
+ Path file = Files.createTempFile("floci-az-", ".p12");
+ try (OutputStream out = Files.newOutputStream(file)) {
+ keyStore.store(out, trustStorePassword.toCharArray());
+ }
+ return file;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException("Cannot create a trust store with
the certificate authority of Floci AZ", e);
+ }
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridRemoteInfraService.java
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridRemoteInfraService.java
new file mode 100644
index 000000000000..27fb837fcc17
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridRemoteInfraService.java
@@ -0,0 +1,72 @@
+/*
+ * 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.test.infra.azure.eventgrid.services;
+
+import
org.apache.camel.test.infra.azure.eventgrid.common.AzureEventGridProperties;
+
+/**
+ * A topic of Azure Event Grid, given with the {@code
azure.eventgrid.topic.endpoint} and
+ * {@code azure.eventgrid.access.key} system properties
+ */
+public class AzureEventGridRemoteInfraService implements
AzureEventGridInfraService {
+
+ @Override
+ public void registerProperties() {
+ // NO-OP
+ }
+
+ @Override
+ public void initialize() {
+ registerProperties();
+ }
+
+ @Override
+ public void shutdown() {
+ // NO-OP
+ }
+
+ @Override
+ public String topicEndpoint() {
+ return System.getProperty(AzureEventGridProperties.TOPIC_ENDPOINT);
+ }
+
+ @Override
+ public String topicAccessKey() {
+ return System.getProperty(AzureEventGridProperties.ACCESS_KEY);
+ }
+
+ @Override
+ public String topicId() {
+ return null;
+ }
+
+ @Override
+ public String resourceManagerEndpoint() {
+ return null;
+ }
+
+ @Override
+ public String trustStore() {
+ return null;
+ }
+
+ @Override
+ public String trustStorePassword() {
+ return null;
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridService.java
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridService.java
new file mode 100644
index 000000000000..a7f7c03414df
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridService.java
@@ -0,0 +1,27 @@
+/*
+ * 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.test.infra.azure.eventgrid.services;
+
+import org.apache.camel.test.infra.common.services.ContainerTestService;
+import org.apache.camel.test.infra.common.services.TestService;
+
+/**
+ * Test infra service for Azure Event Grid
+ */
+public interface AzureEventGridService extends AzureEventGridInfraService,
TestService, ContainerTestService {
+}
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridServiceFactory.java
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridServiceFactory.java
new file mode 100644
index 000000000000..8cd76aaffbb6
--- /dev/null
+++
b/test-infra/camel-test-infra-azure-eventgrid/src/main/java/org/apache/camel/test/infra/azure/eventgrid/services/AzureEventGridServiceFactory.java
@@ -0,0 +1,101 @@
+/*
+ * 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.test.infra.azure.eventgrid.services;
+
+import org.apache.camel.test.infra.common.services.SimpleTestServiceBuilder;
+import org.apache.camel.test.infra.common.services.SingletonService;
+
+/**
+ * Creates the Event Grid service: a local one by default, a remote one with
{@code azure.instance.type=remote}
+ */
+public final class AzureEventGridServiceFactory {
+
+ private static class SingletonAzureEventGridService extends
SingletonService<AzureEventGridService>
+ implements AzureEventGridService {
+ public SingletonAzureEventGridService(AzureEventGridService service,
String name) {
+ super(service, name);
+ }
+
+ @Override
+ public String topicEndpoint() {
+ return getService().topicEndpoint();
+ }
+
+ @Override
+ public String topicAccessKey() {
+ return getService().topicAccessKey();
+ }
+
+ @Override
+ public String topicId() {
+ return getService().topicId();
+ }
+
+ @Override
+ public String resourceManagerEndpoint() {
+ return getService().resourceManagerEndpoint();
+ }
+
+ @Override
+ public String trustStore() {
+ return getService().trustStore();
+ }
+
+ @Override
+ public String trustStorePassword() {
+ return getService().trustStorePassword();
+ }
+ }
+
+ private AzureEventGridServiceFactory() {
+
+ }
+
+ public static SimpleTestServiceBuilder<AzureEventGridService> builder() {
+ return new SimpleTestServiceBuilder<>("azure");
+ }
+
+ public static AzureEventGridService createService() {
+ return builder()
+ .addLocalMapping(AzureEventGridLocalContainerService::new)
+ .addRemoteMapping(AzureEventGridRemoteService::new)
+ .build();
+ }
+
+ public static AzureEventGridService createSingletonService() {
+ return SingletonServiceHolder.INSTANCE;
+ }
+
+ private static class SingletonServiceHolder {
+ static final AzureEventGridService INSTANCE;
+ static {
+ SimpleTestServiceBuilder<AzureEventGridService> instance =
builder();
+ instance.addLocalMapping(
+ () -> new SingletonAzureEventGridService(new
AzureEventGridLocalContainerService(), "azure-eventgrid"))
+ .addRemoteMapping(AzureEventGridRemoteService::new);
+ INSTANCE = instance.build();
+ }
+ }
+
+ static class AzureEventGridLocalContainerService extends
AzureEventGridLocalContainerInfraService
+ implements AzureEventGridService {
+ }
+
+ static class AzureEventGridRemoteService extends
AzureEventGridRemoteInfraService implements AzureEventGridService {
+ }
+}
diff --git
a/test-infra/camel-test-infra-azure-eventgrid/src/main/resources/META-INF/MANIFEST.MF
b/test-infra/camel-test-infra-azure-eventgrid/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/test-infra/pom.xml b/test-infra/pom.xml
index d2f2f875c104..01e1a1b91335 100644
--- a/test-infra/pom.xml
+++ b/test-infra/pom.xml
@@ -51,6 +51,7 @@
<module>camel-test-infra-mongodb</module>
<module>camel-test-infra-rabbitmq</module>
<module>camel-test-infra-azure-common</module>
+ <module>camel-test-infra-azure-eventgrid</module>
<module>camel-test-infra-azure-key-vault</module>
<module>camel-test-infra-azure-storage-blob</module>
<module>camel-test-infra-azure-storage-datalake</module>