You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2022/03/25 07:07:53 UTC
[camel-quarkus] branch main updated: Improve Infinispan extension test coverage
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 62c14ec Improve Infinispan extension test coverage
62c14ec is described below
commit 62c14ec4760a327b606b876f5780dc518692c5d1
Author: James Netherton <ja...@gmail.com>
AuthorDate: Thu Mar 24 15:20:44 2022 +0000
Improve Infinispan extension test coverage
Fixes #3658
---
.../pages/reference/extensions/infinispan.adoc | 13 +
.../runtime/src/main/doc/configuration.adoc | 2 +
.../runtime/src/main/doc/limitations.adoc | 3 +
integration-tests/infinispan/pom.xml | 33 ++
.../component/infinispan/InfinispanResources.java | 303 ++++++++++++-
.../component/infinispan/InfinispanRoutes.java | 275 +++++++++++-
.../quarkus/component/infinispan/model/Person.java | 44 ++
.../component/infinispan/model/PersonSchema.java | 24 ++
.../infinispan/InfinispanServerTestResource.java | 4 +-
.../component/infinispan/InfinispanTest.java | 479 ++++++++++++++++++++-
.../infinispan/src/test/resources/infinispan.xml | 82 ++++
pom.xml | 1 +
poms/bom/pom.xml | 9 +
13 files changed, 1241 insertions(+), 31 deletions(-)
diff --git a/docs/modules/ROOT/pages/reference/extensions/infinispan.adoc b/docs/modules/ROOT/pages/reference/extensions/infinispan.adoc
index fec768d..951cf43 100644
--- a/docs/modules/ROOT/pages/reference/extensions/infinispan.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/infinispan.adoc
@@ -38,3 +38,16 @@ Or add the coordinates to your existing project:
----
Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
+
+== Camel Quarkus limitations
+
+=== InfinispanRemoteAggregationRepository in native mode
+
+At present the `InfinispanRemoteAggregationRepository` is not supported in native mode.
+
+
+== Additional Camel Quarkus configuration
+
+You can either configure the Infinispan client via the relevant Camel Infinispan component & endpoint options, or you
+may use the https://quarkus.io/guides/infinispan-client#configuration-reference[Quarkus Infinispan extension configuration properties].
+
diff --git a/extensions/infinispan/runtime/src/main/doc/configuration.adoc b/extensions/infinispan/runtime/src/main/doc/configuration.adoc
new file mode 100644
index 0000000..000b2d0
--- /dev/null
+++ b/extensions/infinispan/runtime/src/main/doc/configuration.adoc
@@ -0,0 +1,2 @@
+You can either configure the Infinispan client via the relevant Camel Infinispan component & endpoint options, or you
+may use the https://quarkus.io/guides/infinispan-client#configuration-reference[Quarkus Infinispan extension configuration properties].
diff --git a/extensions/infinispan/runtime/src/main/doc/limitations.adoc b/extensions/infinispan/runtime/src/main/doc/limitations.adoc
new file mode 100644
index 0000000..007d7b3
--- /dev/null
+++ b/extensions/infinispan/runtime/src/main/doc/limitations.adoc
@@ -0,0 +1,3 @@
+=== InfinispanRemoteAggregationRepository in native mode
+
+At present the `InfinispanRemoteAggregationRepository` is not supported in native mode.
diff --git a/integration-tests/infinispan/pom.xml b/integration-tests/infinispan/pom.xml
index e5df665..eaaa533 100644
--- a/integration-tests/infinispan/pom.xml
+++ b/integration-tests/infinispan/pom.xml
@@ -44,6 +44,10 @@
<artifactId>camel-quarkus-direct</artifactId>
</dependency>
<dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mock</artifactId>
+ </dependency>
+ <dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
@@ -147,6 +151,19 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mock-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
</profile>
<profile>
@@ -160,6 +177,22 @@
<skipTests>true</skipTests>
</properties>
</profile>
+ <profile>
+ <id>jdk17-build</id>
+ <activation>
+ <jdk>[17,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <argLine>--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED</argLine>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
</profiles>
</project>
diff --git a/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanResources.java b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanResources.java
index 9bdd07f..d852091 100644
--- a/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanResources.java
+++ b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanResources.java
@@ -17,30 +17,48 @@
package org.apache.camel.quarkus.component.infinispan;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
-import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.infinispan.InfinispanConstants;
+import org.apache.camel.component.infinispan.InfinispanQueryBuilder;
import org.apache.camel.component.infinispan.remote.InfinispanRemoteComponent;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.quarkus.component.infinispan.model.Person;
+import org.apache.camel.util.CollectionHelper;
import org.infinispan.client.hotrod.RemoteCacheManager;
+import org.infinispan.client.hotrod.ServerStatistics;
-@Path("/test")
+import static org.apache.camel.quarkus.component.infinispan.InfinispanRoutes.CORRELATOR_HEADER;
+
+@Path("/infinispan")
@ApplicationScoped
public class InfinispanResources {
- public static final String CACHE_NAME = "camel";
+ public static final String CACHE_NAME_CAMEL = "camel";
+ public static final String CACHE_NAME_QUARKUS = "quarkus";
@Inject
RemoteCacheManager cacheManager;
@@ -51,11 +69,6 @@ public class InfinispanResources {
@Inject
CamelContext camelContext;
- @PostConstruct
- public void setUp() {
- cacheManager.administration().getOrCreateCache(CACHE_NAME, (String) null);
- }
-
@Path("/inspect")
@GET
@Produces(MediaType.APPLICATION_JSON)
@@ -68,26 +81,294 @@ public class InfinispanResources {
.build();
}
+ @Path("/aggregate")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public void aggregate(@QueryParam("component") String component, String content) {
+ String uri = component.equals("infinispan") ? "direct:camelAggregation" : "direct:quarkusAggregation";
+ Map<String, Object> headers = getCommonHeaders(component);
+ headers.put(CORRELATOR_HEADER, CORRELATOR_HEADER);
+ template.sendBodyAndHeaders(uri, content, headers);
+ }
+
+ @Path("/clear")
+ @DELETE
+ public void clear(@QueryParam("component") String component) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ template.sendBodyAndHeaders("direct:clear", null, headers);
+ }
+
+ @Path("/clearAsync")
+ @DELETE
+ public void clearAsync(@QueryParam("component") String component)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ Map<String, Object> headers = getCommonHeaders(component);
+ CompletableFuture<?> future = template.requestBodyAndHeaders("direct:clearAsync", null, headers,
+ CompletableFuture.class);
+ future.get(5, TimeUnit.SECONDS);
+ }
+
+ @Path("/compute")
+ @POST
+ public void compute(@QueryParam("component") String component) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ template.sendBodyAndHeaders("direct:compute", null, headers);
+ }
+
+ @Path("/computeAsync")
+ @POST
+ public void computeAsync(@QueryParam("component") String component)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ Map<String, Object> headers = getCommonHeaders(component);
+ CompletableFuture<?> future = template.requestBodyAndHeaders("direct:computeAsync", null, headers,
+ CompletableFuture.class);
+ future.get(5, TimeUnit.SECONDS);
+ }
+
+ @Path("/containsKey")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Boolean containsKey(@QueryParam("component") String component) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ return template.requestBodyAndHeaders("direct:containsKey", null, headers, Boolean.class);
+ }
+
+ @Path("/containsValue")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Boolean containsValue(@QueryParam("component") String component, @QueryParam("value") String value) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ return template.requestBodyAndHeaders("direct:containsValue", value, headers, Boolean.class);
+ }
+
@Path("/get")
@GET
@Produces(MediaType.TEXT_PLAIN)
- public String get(@QueryParam("component") String component) {
+ public String get(@QueryParam("component") String component, @QueryParam("key") String key) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ headers.put(InfinispanConstants.KEY, Objects.requireNonNullElse(key, "the-key"));
+ return template.requestBodyAndHeaders("direct:get", null, headers, String.class);
+ }
+
+ @Path("/getOrDefault")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getOrDefault(@QueryParam("component") String component) {
Map<String, Object> headers = getCommonHeaders(component);
- return template.requestBodyAndHeaders("direct:get", "", headers, String.class);
+ return template.requestBodyAndHeaders("direct:getOrDefault", null, headers, String.class);
}
@Path("/put")
@POST
+ @Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
public String put(@QueryParam("component") String component, String content) {
Map<String, Object> headers = getCommonHeaders(component);
return template.requestBodyAndHeaders("direct:put", content, headers, String.class);
}
+ @Path("/putAsync")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public void putAsync(@QueryParam("component") String component, String content)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ Map<String, Object> headers = getCommonHeaders(component);
+ CompletableFuture<?> future = template.requestBodyAndHeaders("direct:putAsync", content, headers,
+ CompletableFuture.class);
+ future.get(5, TimeUnit.SECONDS);
+ }
+
+ @Path("/putAll")
+ @POST
+ public void putAll(@QueryParam("component") String component) {
+ Map<String, String> body = CollectionHelper.mapOf("key-1", "value-1", "key-2", "value-2");
+ Map<String, Object> headers = getCommonHeaders(component);
+ template.sendBodyAndHeaders("direct:putAll", body, headers);
+ }
+
+ @Path("/putAllAsync")
+ @POST
+ public void putAllAsync(@QueryParam("component") String component)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ Map<String, String> body = CollectionHelper.mapOf("key-1", "value-1", "key-2", "value-2");
+ Map<String, Object> headers = getCommonHeaders(component);
+ CompletableFuture<?> future = template.requestBodyAndHeaders("direct:putAllAsync", body, headers,
+ CompletableFuture.class);
+ future.get(5, TimeUnit.SECONDS);
+ }
+
+ @Path("/putIdempotent")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public void putIdempotent(
+ @QueryParam("component") String component,
+ @QueryParam("messageId") String messageId,
+ String content) {
+ String uri = component.equals("infinispan") ? "direct:camelIdempotent" : "direct:quarkusIdempotent";
+ Map<String, Object> headers = getCommonHeaders(component);
+ headers.put("MessageId", messageId);
+ template.sendBodyAndHeaders(uri, content, headers);
+ }
+
+ @Path("/putIfAbsent")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.TEXT_PLAIN)
+ public String putIfAbsent(@QueryParam("component") String component, String content) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ return template.requestBodyAndHeaders("direct:putIfAbsent", content, headers, String.class);
+ }
+
+ @Path("/putIfAbsentAsync")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public void putIfAbsentAsync(@QueryParam("component") String component, String content)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ Map<String, Object> headers = getCommonHeaders(component);
+ CompletableFuture<?> future = template.requestBodyAndHeaders("direct:putIfAbsentAsync", content, headers,
+ CompletableFuture.class);
+ future.get(5, TimeUnit.SECONDS);
+ }
+
+ @Path("/query")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ @SuppressWarnings("unchecked")
+ public Response query(@QueryParam("component") String component) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ String cacheName = (String) headers.get("cacheName");
+
+ cacheManager.getCache(cacheName).put("person", new Person("Test", "Person"));
+
+ String query = "FROM person.Person WHERE firstName = 'Test'";
+ InfinispanQueryBuilder builder = InfinispanQueryBuilder.create(query);
+
+ headers.put(InfinispanConstants.QUERY_BUILDER, builder);
+
+ List<String> result = template.requestBodyAndHeaders("direct:query", null, headers, List.class);
+ if (result.isEmpty()) {
+ return Response.status(404).build();
+ }
+ return Response.ok().entity(result.get(0)).build();
+ }
+
+ @Path("/remove")
+ @DELETE
+ public void remove(@QueryParam("component") String component) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ template.requestBodyAndHeaders("direct:remove", null, headers, String.class);
+ }
+
+ @Path("/removeAsync")
+ @DELETE
+ public void removeAsync(@QueryParam("component") String component)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ Map<String, Object> headers = getCommonHeaders(component);
+ CompletableFuture<?> future = template.requestBodyAndHeaders("direct:removeAsync", null, headers,
+ CompletableFuture.class);
+ future.get(5, TimeUnit.SECONDS);
+ }
+
+ @Path("/replace")
+ @PATCH
+ @Consumes(MediaType.TEXT_PLAIN)
+ public void replace(@QueryParam("component") String component, String content) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ template.sendBodyAndHeaders("direct:replace", content, headers);
+ }
+
+ @Path("/replaceAsync")
+ @PATCH
+ @Consumes(MediaType.TEXT_PLAIN)
+ public void replaceAsync(@QueryParam("component") String component, String content)
+ throws ExecutionException, InterruptedException, TimeoutException {
+ Map<String, Object> headers = getCommonHeaders(component);
+ CompletableFuture<?> future = template.requestBodyAndHeaders("direct:replaceAsync", content, headers,
+ CompletableFuture.class);
+ future.get(5, TimeUnit.SECONDS);
+ }
+
+ @Path("/size")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Integer size(@QueryParam("component") String component) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ return template.requestBodyAndHeaders("direct:size", null, headers, Integer.class);
+ }
+
+ @Path("/stats")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Integer stats(@QueryParam("component") String component) {
+ Map<String, Object> headers = getCommonHeaders(component);
+ ServerStatistics statistics = template.requestBodyAndHeaders("direct:stats", null, headers, ServerStatistics.class);
+ return statistics.getIntStatistic(ServerStatistics.CURRENT_NR_OF_ENTRIES);
+ }
+
+ @Path("/mock/aggregation/results")
+ @GET
+ public void assertMockEndpointAggregationResults(@QueryParam("uri") String uri) throws InterruptedException {
+ MockEndpoint mockEndpoint = camelContext.getEndpoint(uri, MockEndpoint.class);
+ mockEndpoint.expectedMessageCount(2);
+ mockEndpoint.expectedBodiesReceived(1 + 3 + 4 + 5, 6 + 7 + 20 + 21);
+
+ try {
+ mockEndpoint.assertIsSatisfied(5000);
+ } finally {
+ mockEndpoint.reset();
+ }
+ }
+
+ @Path("/mock/event/results")
+ @GET
+ public void assertMockEndpointEventResults(@QueryParam("uri") String uri) throws InterruptedException {
+ MockEndpoint mockEndpoint = camelContext.getEndpoint(uri, MockEndpoint.class);
+ mockEndpoint.expectedMessageCount(1);
+ mockEndpoint.message(0).header(InfinispanConstants.EVENT_TYPE).isEqualTo("CLIENT_CACHE_ENTRY_CREATED");
+ mockEndpoint.message(0).header(InfinispanConstants.CACHE_NAME).isNotNull();
+ mockEndpoint.message(0).header(InfinispanConstants.KEY).isEqualTo("test-key");
+
+ try {
+ mockEndpoint.assertIsSatisfied(5000);
+ } finally {
+ mockEndpoint.reset();
+ }
+ }
+
+ @Path("/mock/idempotent/results")
+ @GET
+ public void assertMockEndpointIdempotentResults(@QueryParam("uri") String uri) throws InterruptedException {
+ MockEndpoint mockEndpoint = camelContext.getEndpoint(uri, MockEndpoint.class);
+ mockEndpoint.expectedMessageCount(1);
+ try {
+ mockEndpoint.assertIsSatisfied(5000);
+ } finally {
+ mockEndpoint.reset();
+ }
+ }
+
+ @POST
+ @Path("consumer/{routeId}/{enabled}")
+ public void manageRoute(
+ @PathParam("routeId") String routeId,
+ @PathParam("enabled") boolean enabled) throws Exception {
+ if (enabled) {
+ camelContext.getRouteController().startRoute(routeId);
+ } else {
+ camelContext.getRouteController().stopRoute(routeId);
+ }
+ }
+
private Map<String, Object> getCommonHeaders(String componentName) {
Map<String, Object> headers = new HashMap<>();
headers.put("component", componentName);
- headers.put("cacheName", CACHE_NAME);
+
+ if (componentName.equals("infinispan")) {
+ headers.put("cacheName", CACHE_NAME_CAMEL);
+ } else {
+ headers.put("cacheName", CACHE_NAME_QUARKUS);
+ }
+
return headers;
}
}
diff --git a/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanRoutes.java b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanRoutes.java
index c194cee..e9476d7 100644
--- a/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanRoutes.java
+++ b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/InfinispanRoutes.java
@@ -17,36 +17,194 @@
package org.apache.camel.quarkus.component.infinispan;
import java.nio.charset.StandardCharsets;
+import java.util.Set;
+import java.util.function.BiFunction;
import javax.inject.Named;
+import org.apache.camel.AggregationStrategy;
+import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.infinispan.InfinispanConstants;
import org.apache.camel.component.infinispan.InfinispanOperation;
+import org.apache.camel.component.infinispan.remote.InfinispanRemoteAggregationRepository;
import org.apache.camel.component.infinispan.remote.InfinispanRemoteComponent;
import org.apache.camel.component.infinispan.remote.InfinispanRemoteComponentConfigurer;
+import org.apache.camel.component.infinispan.remote.InfinispanRemoteConfiguration;
+import org.apache.camel.component.infinispan.remote.InfinispanRemoteCustomListener;
+import org.apache.camel.component.infinispan.remote.InfinispanRemoteIdempotentRepository;
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.infinispan.client.hotrod.RemoteCacheManager;
+import org.infinispan.client.hotrod.annotation.ClientCacheEntryCreated;
+import org.infinispan.client.hotrod.annotation.ClientListener;
+import org.infinispan.client.hotrod.configuration.Configuration;
+import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
+import org.infinispan.client.hotrod.event.ClientCacheEntryCreatedEvent;
+import org.infinispan.commons.marshall.StringMarshaller;
+
+import static org.apache.camel.quarkus.component.infinispan.InfinispanResources.CACHE_NAME_CAMEL;
+import static org.apache.camel.quarkus.component.infinispan.InfinispanResources.CACHE_NAME_QUARKUS;
public class InfinispanRoutes extends RouteBuilder {
+ public static final int COMPLETION_SIZE = 4;
+ public static final String CORRELATOR_HEADER = "CORRELATOR_HEADER";
+
@Override
public void configure() {
- // we do not need to set any information about the target infinispan server
- // as the RemoteConnectionManager is produced by the infinispan extension
- // and camel-main automatically bind it to the component
+ from("direct:clear")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.CLEAR)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}");
- from("direct:put")
- .convertBodyTo(byte[].class)
- .to("log:cache?showAll=true")
- .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUT)
- .setHeader(InfinispanConstants.KEY).constant("the-key".getBytes(StandardCharsets.UTF_8))
+ from("direct:clearAsync")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.CLEARASYNC)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:compute")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.COMPUTE)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}?remappingFunction=#customMappingFunction");
+
+ from("direct:computeAsync")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.COMPUTEASYNC)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}?remappingFunction=#customMappingFunction");
+
+ from("direct:containsKey")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.CONTAINSKEY)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:containsValue")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.CONTAINSVALUE)
.setHeader(InfinispanConstants.VALUE).body()
- .toD("${header.component}:${header.cacheName}")
- .to("log:put?showAll=true");
+ .toD("${header.component}:${header.cacheName}");
from("direct:get")
.setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GET)
- .setHeader(InfinispanConstants.KEY).constant("the-key".getBytes(StandardCharsets.UTF_8))
- .toD("${header.component}:${header.cacheName}")
- .to("log:get?showAll=true");
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:getOrDefault")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.GETORDEFAULT)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .setHeader(InfinispanConstants.DEFAULT_VALUE).constant("default-value")
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:put")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUT)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .setHeader(InfinispanConstants.VALUE).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:putAsync")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUTASYNC)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .setHeader(InfinispanConstants.VALUE).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:putAll")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUTALL)
+ .setHeader(InfinispanConstants.MAP).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:putAllAsync")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUTALLASYNC)
+ .setHeader(InfinispanConstants.MAP).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:putIfAbsent")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUTIFABSENT)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .setHeader(InfinispanConstants.VALUE).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:putIfAbsentAsync")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.PUTIFABSENTASYNC)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .setHeader(InfinispanConstants.VALUE).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:query")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.QUERY)
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:remove")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.REMOVE)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:removeAsync")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.REMOVEASYNC)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:replace")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.REPLACE)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .setHeader(InfinispanConstants.VALUE).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:replaceAsync")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.REPLACEASYNC)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .setHeader(InfinispanConstants.VALUE).body()
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:size")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.SIZE)
+ .setHeader(InfinispanConstants.KEY).constant("the-key")
+ .toD("${header.component}:${header.cacheName}");
+
+ from("direct:stats")
+ .setHeader(InfinispanConstants.OPERATION).constant(InfinispanOperation.STATS)
+ .toD("${header.component}:${header.cacheName}");
+
+ from("infinispan:camel?eventTypes=CLIENT_CACHE_ENTRY_CREATED")
+ .id("infinispan-events")
+ .autoStartup(false)
+ .to("mock:resultCreated");
+
+ // Only start aggregation repository routes in JVM mode
+ if (!"executable".equals(System.getProperty("org.graalvm.nativeimage.kind"))) {
+ from("direct:camelAggregation")
+ .aggregate(header(CORRELATOR_HEADER))
+ .aggregationRepository(createAggregationRepository("infinispan"))
+ .aggregationStrategy(createAggregationStrategy())
+ .completionSize(COMPLETION_SIZE)
+ .to("mock:aggregationResult");
+
+ from("direct:quarkusAggregation")
+ .aggregate(header(CORRELATOR_HEADER))
+ .aggregationRepository(createAggregationRepository("infinispan-quarkus"))
+ .aggregationStrategy(createAggregationStrategy())
+ .completionSize(COMPLETION_SIZE)
+ .to("mock:aggregationResult");
+ }
+
+ from("direct:camelIdempotent")
+ .idempotentConsumer(header("MessageID"), createIdempotentRepository("infinispan"))
+ .to("mock:resultIdempotent");
+
+ from("direct:quarkusIdempotent")
+ .idempotentConsumer(header("MessageID"), createIdempotentRepository("infinispan-quarkus"))
+ .to("mock:resultIdempotent");
+
+ from("infinispan-quarkus:quarkus?eventTypes=CLIENT_CACHE_ENTRY_CREATED")
+ .id("infinispan-quarkus-events")
+ .autoStartup(false)
+ .to("mock:resultCreated");
+
+ from("infinispan:camel?customListener=#customListener")
+ .id("infinispan-custom-listener")
+ .autoStartup(false)
+ .to("mock:resultCustomListener");
+
+ from("infinispan-quarkus:quarkus?customListener=#customListener")
+ .id("infinispan-quarkus-custom-listener")
+ .autoStartup(false)
+ .to("mock:resultCustomListener");
}
@Named("infinispan-quarkus")
@@ -59,4 +217,95 @@ public class InfinispanRoutes extends RouteBuilder {
public InfinispanRemoteComponentConfigurer quarkusInfinispanConfigurer() {
return new InfinispanRemoteComponentConfigurer();
}
+
+ @Named("customMappingFunction")
+ public BiFunction<String, String, String> mappingFunction() {
+ return (k, v) -> v + "-remapped";
+ }
+
+ @Named("customListener")
+ public InfinispanRemoteCustomListener customListener() {
+ return new CustomListener();
+ }
+
+ private InfinispanRemoteIdempotentRepository createIdempotentRepository(String componentName) {
+ String cacheName = componentName.equals("infinispan") ? CACHE_NAME_CAMEL : CACHE_NAME_QUARKUS;
+ InfinispanRemoteConfiguration configuration = getConfiguration(componentName);
+ InfinispanRemoteIdempotentRepository repository = new InfinispanRemoteIdempotentRepository(cacheName);
+ repository.setConfiguration(configuration);
+ return repository;
+ }
+
+ private InfinispanRemoteAggregationRepository createAggregationRepository(String componentName) {
+ String cacheName = componentName.equals("infinispan") ? CACHE_NAME_CAMEL : CACHE_NAME_QUARKUS;
+ InfinispanRemoteAggregationRepository aggregationRepository = new InfinispanRemoteAggregationRepository(cacheName);
+ InfinispanRemoteConfiguration configuration = getConfiguration(componentName);
+ aggregationRepository.setConfiguration(configuration);
+ return aggregationRepository;
+ }
+
+ private InfinispanRemoteConfiguration getConfiguration(String componentName) {
+ CamelContext camelContext = getCamelContext();
+ InfinispanRemoteComponent component = camelContext.getComponent(componentName, InfinispanRemoteComponent.class);
+ InfinispanRemoteConfiguration configuration = component.getConfiguration().clone();
+ configuration.setCacheContainerConfiguration(getConfigurationBuilder());
+ if (componentName.equals("infinispan-quarkus")) {
+ Set<RemoteCacheManager> beans = camelContext.getRegistry().findByType(RemoteCacheManager.class);
+ RemoteCacheManager cacheManager = beans.iterator().next();
+ configuration.setCacheContainer(cacheManager);
+ }
+ return configuration;
+ }
+
+ private Configuration getConfigurationBuilder() {
+ Config config = ConfigProvider.getConfig();
+ ConfigurationBuilder clientBuilder = new ConfigurationBuilder();
+ String[] hostParts = config.getValue("quarkus.infinispan-client.server-list", String.class).split(":");
+
+ clientBuilder.addServer()
+ .host(hostParts[0])
+ .port(Integer.parseInt(hostParts[1]));
+
+ clientBuilder
+ .security()
+ .authentication()
+ .username(config.getValue("quarkus.infinispan-client.auth-username", String.class))
+ .password(config.getValue("quarkus.infinispan-client.auth-password", String.class))
+ .serverName(config.getValue("quarkus.infinispan-client.auth-server-name", String.class))
+ .saslMechanism(config.getValue("quarkus.infinispan-client.sasl-mechanism", String.class))
+ .realm(config.getValue("quarkus.infinispan-client.auth-realm", String.class))
+ .marshaller(new StringMarshaller(StandardCharsets.UTF_8));
+
+ return clientBuilder.build();
+ }
+
+ private AggregationStrategy createAggregationStrategy() {
+ return (oldExchange, newExchange) -> {
+ if (oldExchange == null) {
+ return newExchange;
+ } else {
+ Integer n = newExchange.getIn().getBody(Integer.class);
+ Integer o = oldExchange.getIn().getBody(Integer.class);
+ Integer v = (o == null ? 0 : o) + (n == null ? 0 : n);
+ oldExchange.getIn().setBody(v, Integer.class);
+ return oldExchange;
+ }
+ };
+ }
+
+ @ClientListener
+ static final class CustomListener extends InfinispanRemoteCustomListener {
+
+ @ClientCacheEntryCreated
+ public void entryCreated(ClientCacheEntryCreatedEvent<?> event) {
+ if (isAccepted(event.getType())) {
+ getEventProcessor().processEvent(
+ event.getType().toString(),
+ getCacheName(),
+ event.getKey(),
+ null,
+ null);
+ }
+ }
+ }
}
diff --git a/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/model/Person.java b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/model/Person.java
new file mode 100644
index 0000000..9902d83
--- /dev/null
+++ b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/model/Person.java
@@ -0,0 +1,44 @@
+/*
+ * 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.component.infinispan.model;
+
+import java.util.Objects;
+
+import org.infinispan.protostream.annotations.ProtoFactory;
+import org.infinispan.protostream.annotations.ProtoField;
+
+public class Person {
+
+ private final String firstName;
+ private final String lastName;
+
+ @ProtoFactory
+ public Person(String firstName, String lastName) {
+ this.firstName = Objects.requireNonNull(firstName);
+ this.lastName = Objects.requireNonNull(lastName);
+ }
+
+ @ProtoField(number = 1)
+ public String getFirstName() {
+ return firstName;
+ }
+
+ @ProtoField(number = 2)
+ public String getLastName() {
+ return lastName;
+ }
+}
diff --git a/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/model/PersonSchema.java b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/model/PersonSchema.java
new file mode 100644
index 0000000..4569d61
--- /dev/null
+++ b/integration-tests/infinispan/src/main/java/org/apache/camel/quarkus/component/infinispan/model/PersonSchema.java
@@ -0,0 +1,24 @@
+/*
+ * 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.component.infinispan.model;
+
+import org.infinispan.protostream.GeneratedSchema;
+import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
+
+@AutoProtoSchemaBuilder(includeClasses = { Person.class }, schemaPackageName = "person")
+interface PersonSchema extends GeneratedSchema {
+}
diff --git a/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanServerTestResource.java b/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanServerTestResource.java
index 812828d..54ebeac 100644
--- a/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanServerTestResource.java
+++ b/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanServerTestResource.java
@@ -23,6 +23,7 @@ import org.apache.camel.util.CollectionHelper;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.BindMode;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.TestcontainersConfiguration;
@@ -45,6 +46,8 @@ public class InfinispanServerTestResource implements QuarkusTestResourceLifecycl
.withExposedPorts(HOTROD_PORT)
.withEnv("USER", USER)
.withEnv("PASS", PASS)
+ .withClasspathResourceMapping("infinispan.xml", "/user-config/infinispan.xml", BindMode.READ_ONLY)
+ .withCommand("-c", "/user-config/infinispan.xml")
.waitingFor(Wait.forListeningPort());
container.start();
@@ -58,7 +61,6 @@ public class InfinispanServerTestResource implements QuarkusTestResourceLifecycl
Map<String, String> result = CollectionHelper.mapOf(
// quarkus
"quarkus.infinispan-client.server-list", serverList,
- "quarkus.infinispan-client.near-cache-max-entries", "3",
"quarkus.infinispan-client.auth-username", USER,
"quarkus.infinispan-client.auth-password", PASS,
"quarkus.infinispan-client.auth-realm", "default",
diff --git a/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanTest.java b/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanTest.java
index abe2592..c39731c 100644
--- a/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanTest.java
+++ b/integration-tests/infinispan/src/test/java/org/apache/camel/quarkus/component/infinispan/InfinispanTest.java
@@ -16,12 +16,20 @@
*/
package org.apache.camel.quarkus.component.infinispan;
+import java.util.UUID;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.DisabledOnNativeImage;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@@ -30,30 +38,489 @@ import static org.hamcrest.Matchers.notNullValue;
@QuarkusTestResource(InfinispanServerTestResource.class)
public class InfinispanTest {
+ @AfterEach
+ public void afterEach() {
+ for (String componentName : componentNames()) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .delete("/infinispan/clear")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(204);
+ }
+ }
+
+ @DisabledOnNativeImage("https://github.com/apache/camel-quarkus/issues/3657")
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void aggregate(String componentName) {
+ // TODO: https://github.com/apache/camel-quarkus/issues/3657
+ //
+ // Enable testing InfinispanRemoteAggregationRepository with the Quarkus configured client.
+ // Technically it is possible with a custom META-INF/hotrod-client.properties and setting
+ // infinispan.client.hotrod.marshaller=org.infinispan.jboss.marshalling.core.JBossUserMarshaller
+ // However, it potentially impacts some of the Quarkus Infinispan extension functionality that relies on
+ // the default configured ProtoStreamMarshaller, thus we avoid doing it in this test suite
+ Assumptions.assumeTrue(componentName.equals("infinispan"));
+
+ Stream.of(1, 3, 4, 5, 6, 7, 20, 21)
+ .forEach(value -> {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body(value)
+ .post("/infinispan/aggregate")
+ .then()
+ .statusCode(204);
+ });
+
+ RestAssured.with()
+ .queryParam("uri", "mock:aggregationResult")
+ .get("/infinispan/mock/aggregation/results")
+ .then()
+ .statusCode(204);
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNamesWithSynchronicity")
+ public void clear(String componentName, boolean isAsync) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("Hello " + componentName));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .delete(computePath("/infinispan/clear", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(204);
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNamesWithSynchronicity")
+ public void compute(String componentName, boolean isAsync) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Initial value")
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .post(computePath("/infinispan/compute", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("Initial value-remapped"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void containsKey(String componentName) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/containsKey")
+ .then()
+ .statusCode(200)
+ .body(is("false"));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/containsKey")
+ .then()
+ .statusCode(200)
+ .body(is("true"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void containsValue(String componentName) {
+ String value = "test-value";
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .queryParam("value", value)
+ .get("/infinispan/containsValue")
+ .then()
+ .statusCode(200)
+ .body(is("false"));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body(value)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .queryParam("value", value)
+ .get("/infinispan/containsValue")
+ .then()
+ .statusCode(200)
+ .body(is("true"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void customListener(String componentName) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .post("/infinispan/consumer/" + componentName + "-custom-listener/true")
+ .then()
+ .statusCode(204);
+
+ try {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("uri", "mock:resultCustomListener")
+ .get("/infinispan/mock/event/results")
+ .then()
+ .statusCode(204);
+ } finally {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .post("/infinispan/consumer/" + componentName + "-custom-listener/false")
+ .then()
+ .statusCode(204);
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void events(String componentName) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .post("/infinispan/consumer/" + componentName + "-events/true")
+ .then()
+ .statusCode(204);
+
+ try {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("uri", "mock:resultCreated")
+ .get("/infinispan/mock/event/results")
+ .then()
+ .statusCode(204);
+ } finally {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .post("/infinispan/consumer/" + componentName + "-events/false")
+ .then()
+ .statusCode(204);
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void getOrDefault(String componentName) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/getOrDefault")
+ .then()
+ .statusCode(200)
+ .body(is("default-value"));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/getOrDefault")
+ .then()
+ .statusCode(200)
+ .body(is("Hello " + componentName));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void idempotent(String componentName) {
+ String messageId = UUID.randomUUID().toString();
+
+ IntStream.of(1, 10).forEach(value -> {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .queryParam("messageId", messageId)
+ .body("Message " + value)
+ .post("/infinispan/putIdempotent")
+ .then()
+ .statusCode(204);
+ });
+
+ RestAssured.with()
+ .queryParam("uri", "mock:resultIdempotent")
+ .get("/infinispan/mock/idempotent/results")
+ .then()
+ .statusCode(204);
+ }
+
@Test
public void inspect() {
RestAssured.when()
- .get("/test/inspect")
+ .get("/infinispan/inspect")
.then().body(
"hosts", is(notNullValue()),
"cache-manager", is("none"));
}
@ParameterizedTest
- @ValueSource(strings = { "infinispan", "infinispan-quarkus" })
- public void testInfinispan(String componentName) {
+ @MethodSource("componentNamesWithSynchronicity")
+ public void put(String componentName, boolean isAsync) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post(computePath("/infinispan/put", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("Hello " + componentName));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNamesWithSynchronicity")
+ public void putAll(String componentName, boolean isAsync) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .post(computePath("/infinispan/putAll", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .queryParam("key", "key-1")
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("value-1"));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .queryParam("key", "key-2")
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("value-2"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNamesWithSynchronicity")
+ public void putIfAbsent(String componentName, boolean isAsync) {
RestAssured.with()
.queryParam("component", componentName)
.body("Hello " + componentName)
- .post("/test/put")
+ .post(computePath("/infinispan/putIfAbsent", isAsync))
.then()
.statusCode(204);
RestAssured.with()
.queryParam("component", componentName)
- .get("/test/get")
+ .get("/infinispan/get")
.then()
.statusCode(200)
.body(is("Hello " + componentName));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("An alternative value")
+ .post(computePath("/infinispan/putIfAbsent", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("Hello " + componentName));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void query(String componentName) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/query")
+ .then()
+ .statusCode(200);
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNamesWithSynchronicity")
+ public void remove(String componentName, boolean isAsync) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post(computePath("/infinispan/put", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .delete(computePath("/infinispan/remove", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(204);
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNamesWithSynchronicity")
+ public void replace(String componentName, boolean isAsync) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post(computePath("/infinispan/put", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("Hello " + componentName));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("replaced cache value")
+ .patch(computePath("/infinispan/replace", isAsync))
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/get")
+ .then()
+ .statusCode(200)
+ .body(is("replaced cache value"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void size(String componentName) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/size")
+ .then()
+ .statusCode(200)
+ .body(is("0"));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/size")
+ .then()
+ .statusCode(200)
+ .body(is("1"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("componentNames")
+ public void stats(String componentName) {
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/stats")
+ .then()
+ .statusCode(200)
+ .body(is("0"));
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .body("Hello " + componentName)
+ .post("/infinispan/put")
+ .then()
+ .statusCode(204);
+
+ RestAssured.with()
+ .queryParam("component", componentName)
+ .get("/infinispan/stats")
+ .then()
+ .statusCode(200)
+ .body(is("1"));
+ }
+
+ private String computePath(String path, boolean isAsync) {
+ if (isAsync) {
+ path += "Async";
+ }
+ return path;
+ }
+
+ public static String[] componentNames() {
+ return new String[] {
+ "infinispan",
+ "infinispan-quarkus"
+ };
+ }
+
+ public static Stream<Arguments> componentNamesWithSynchronicity() {
+ return Stream.of(
+ Arguments.of("infinispan", false),
+ Arguments.of("infinispan-quarkus", false),
+ Arguments.of("infinispan", true),
+ Arguments.of("infinispan-quarkus", true));
}
}
diff --git a/integration-tests/infinispan/src/test/resources/infinispan.xml b/integration-tests/infinispan/src/test/resources/infinispan.xml
new file mode 100644
index 0000000..60acf47
--- /dev/null
+++ b/integration-tests/infinispan/src/test/resources/infinispan.xml
@@ -0,0 +1,82 @@
+<?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.
+
+-->
+<infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="urn:infinispan:config:13.0 https://infinispan.org/schemas/infinispan-config-13.0.xsd
+ urn:infinispan:server:13.0 https://infinispan.org/schemas/infinispan-server-13.0.xsd"
+ xmlns="urn:infinispan:config:13.0"
+ xmlns:server="urn:infinispan:server:13.0">
+
+ <cache-container name="default" statistics="true">
+ <metrics accurate-size="true"/>
+ <transport cluster="${infinispan.cluster.name:cluster}" stack="${infinispan.cluster.stack:tcp}"
+ node-name="${infinispan.node.name:}"/>
+ <security>
+ <authorization/>
+ </security>
+
+ <!-- Used by tests where camel-infinispan manages its own cache container -->
+ <local-cache name="camel">
+ </local-cache>
+
+ <!-- Used by tests where camel-infinispan uses the Quarkus managed cache container -->
+ <local-cache name="quarkus">
+ </local-cache>
+ </cache-container>
+
+
+ <server xmlns="urn:infinispan:server:13.0">
+ <interfaces>
+ <interface name="public">
+ <inet-address value="${infinispan.bind.address:127.0.0.1}"/>
+ </interface>
+ </interfaces>
+
+ <socket-bindings default-interface="public" port-offset="${infinispan.socket.binding.port-offset:0}">
+ <socket-binding name="default" port="${infinispan.bind.port:11222}"/>
+ <socket-binding name="memcached" port="11221"/>
+ </socket-bindings>
+
+ <security>
+ <credential-stores>
+ <credential-store name="credentials" path="credentials.pfx">
+ <clear-text-credential clear-text="secret"/>
+ </credential-store>
+ </credential-stores>
+ <security-realms>
+ <security-realm name="default">
+ <!-- Uncomment to enable TLS on the realm -->
+ <!-- server-identities>
+ <ssl>
+ <keystore path="application.keystore"
+ password="password" alias="server"
+ generate-self-signed-certificate-host="localhost"/>
+ </ssl>
+ </server-identities-->
+ <properties-realm groups-attribute="Roles">
+ <user-properties path="users.properties"/>
+ <group-properties path="groups.properties"/>
+ </properties-realm>
+ </security-realm>
+ </security-realms>
+ </security>
+
+ <endpoints socket-binding="default" security-realm="default"/>
+ </server>
+</infinispan>
diff --git a/pom.xml b/pom.xml
index 4f06a59..b10bb94 100644
--- a/pom.xml
+++ b/pom.xml
@@ -98,6 +98,7 @@
<hapi-fhir.version>${hapi-fhir-version}</hapi-fhir.version>
<hbase.version>${hbase-version}</hbase.version>
<htrace.version>4.2.0-incubating</htrace.version><!-- Mess in hbase transitive deps -->
+ <infinispan.version>13.0.6.Final</infinispan.version><!-- @sync io.quarkus:quarkus-bom:${quarkus.version} dep:org.infinispan:infinispan-core -->
<influxdb.version>${influx-java-driver-version}</influxdb.version>
<jackson1.version>1.9.13</jackson1.version><!-- Mess in the transitive dependencies of spark and hbase-testing-util -->
<jackson-asl.version>${jackson1.version}</jackson-asl.version><!-- Can be different from jackson1.version on some occasions -->
diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml
index 982311d..e0e9d02 100644
--- a/poms/bom/pom.xml
+++ b/poms/bom/pom.xml
@@ -1472,6 +1472,10 @@
<groupId>org.infinispan</groupId>
<artifactId>infinispan-core</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-marshaller-protostuff</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
@@ -6577,6 +6581,11 @@
<version>${graalvm.version}</version>
</dependency>
<dependency>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-jboss-marshalling</artifactId>
+ <version>${infinispan.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>${influxdb.version}</version>