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 bbe10ba1e7 Add Qdrant exception and auth tests
bbe10ba1e7 is described below
commit bbe10ba1e78203bd6c7e0cac7bcb06efcfabf34c
Author: Lukas Lowinger <[email protected]>
AuthorDate: Tue Mar 3 08:05:37 2026 +0100
Add Qdrant exception and auth tests
---
.../component/qdrant/it/QdrantResource.java | 121 +++++++++++++++++++++
...source.java => AbstractQdrantTestResource.java} | 24 +++-
.../quarkus/component/qdrant/it/QdrantAuthIT.java | 24 ++++
.../component/qdrant/it/QdrantAuthTest.java | 48 ++++++++
.../component/qdrant/it/QdrantAuthTestProfile.java | 29 +++++
.../qdrant/it/QdrantAuthTestResource.java | 26 +++++
.../quarkus/component/qdrant/it/QdrantTest.java | 31 ++++++
.../component/qdrant/it/QdrantTestResource.java | 50 +--------
8 files changed, 303 insertions(+), 50 deletions(-)
diff --git
a/integration-tests/qdrant/src/main/java/org/apache/camel/quarkus/component/qdrant/it/QdrantResource.java
b/integration-tests/qdrant/src/main/java/org/apache/camel/quarkus/component/qdrant/it/QdrantResource.java
index ad8f1f9a29..e7199878a9 100644
---
a/integration-tests/qdrant/src/main/java/org/apache/camel/quarkus/component/qdrant/it/QdrantResource.java
+++
b/integration-tests/qdrant/src/main/java/org/apache/camel/quarkus/component/qdrant/it/QdrantResource.java
@@ -185,4 +185,125 @@ public class QdrantResource {
return Response.ok(operationId + "/" + opeartionStatus + "/" +
operationValue).build();
}
+
+ @Path("/exception/nonExistentCollection")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response retrieveFromNonExistentCollection() {
+ // Try to retrieve from a collection that doesn't exist
+ // This should trigger QdrantException
+ Exchange exchange = producer.to("qdrant:nonExistentCollection")
+ .withHeader(QdrantHeaders.ACTION, QdrantAction.RETRIEVE)
+ .withBody(PointIdFactory.id(1))
+ .request(Exchange.class);
+
+ if (exchange.isFailed() && exchange.getException() != null) {
+ Exception exception = exchange.getException();
+ return Response.status(500)
+ .entity("QdrantException: " + exception.getMessage())
+ .build();
+ }
+ return Response.ok("Should not reach here").build();
+ }
+
+ @Path("/exception/invalidOperation")
+ @PUT
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response invalidCollectionOperation() {
+ // Try to create collection with invalid parameters
+ // This should trigger QdrantException
+ Exchange exchange = producer.to("qdrant:testCollection")
+ .withHeader(QdrantHeaders.ACTION,
QdrantAction.CREATE_COLLECTION)
+ .withBody(
+ Collections.VectorParams.newBuilder()
+ .setSize(0) // Invalid size
+
.setDistance(Collections.Distance.Cosine).build())
+ .request(Exchange.class);
+
+ if (exchange.isFailed() && exchange.getException() != null) {
+ Exception exception = exchange.getException();
+ return Response.status(500)
+ .entity("QdrantException: " + exception.getMessage())
+ .build();
+ }
+ return Response.ok("Should not reach here").build();
+ }
+
+ @Path("/exception/withMessage")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response exceptionWithMessage() {
+ // Verify that exception messages are properly preserved
+ Exchange exchange = producer.to("qdrant:nonExistentTestCollection")
+ .withHeader(QdrantHeaders.ACTION, QdrantAction.DELETE)
+ .withBody(Common.Filter.newBuilder()
+ .addMust(matchKeyword("test", "value"))
+ .build())
+ .request(Exchange.class);
+
+ if (exchange.isFailed() && exchange.getException() != null) {
+ Exception exception = exchange.getException();
+ return Response.status(500)
+ .entity("QdrantException: Test exception message - " +
exception.getMessage())
+ .build();
+ }
+ return Response.ok("Should not reach here").build();
+ }
+
+ @Path("/apiKey/valid")
+ @PUT
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response testWithValidApiKey() {
+ // The component is already configured with correct API key in
QdrantAuthTestResource
+ producer.to("qdrant:authTestCollection")
+ .withHeader(QdrantHeaders.ACTION,
QdrantAction.CREATE_COLLECTION)
+ .withBody(
+ Collections.VectorParams.newBuilder()
+ .setSize(2)
+
.setDistance(Collections.Distance.Cosine).build())
+ .request();
+
+ return Response.ok("ApiKeyCredentials reflection works: authentication
successful").build();
+ }
+
+ @Path("/apiKey/invalid")
+ @PUT
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response testWithInvalidApiKey() {
+ // Test that wrong API key is rejected
+ // Use endpoint URI with explicit wrong API key to override component
configuration
+ try {
+ producer.to("qdrant:authTestCollection2?apiKey=wrong-api-key")
+ .withHeader(QdrantHeaders.ACTION,
QdrantAction.CREATE_COLLECTION)
+ .withBody(
+ Collections.VectorParams.newBuilder()
+ .setSize(2)
+
.setDistance(Collections.Distance.Cosine).build())
+ .request();
+
+ return Response.status(500)
+ .entity("Authentication should have failed but succeeded!")
+ .build();
+ } catch (Exception e) {
+ // Expected to fail on authentication
+ if (exceptionChainContains(e, "UNAUTHENTICATED") ||
exceptionChainContains(e, "PERMISSION_DENIED")) {
+ return Response.status(403).entity("Authentication correctly
failed").build();
+ }
+ return Response.status(500)
+ .entity("Unexpected error: " + e.getMessage())
+ .build();
+ }
+ }
+
+ private boolean exceptionChainContains(Throwable e, String searchTerm) {
+ Throwable current = e;
+ while (current != null) {
+ String message = current.getMessage();
+ if (message != null &&
message.toLowerCase().contains(searchTerm.toLowerCase())) {
+ return true;
+ }
+ current = current.getCause();
+ }
+ return false;
+ }
}
diff --git
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTestResource.java
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/AbstractQdrantTestResource.java
similarity index 74%
copy from
integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTestResource.java
copy to
integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/AbstractQdrantTestResource.java
index a01d8115bd..24e4e0e916 100644
---
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTestResource.java
+++
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/AbstractQdrantTestResource.java
@@ -28,21 +28,34 @@ import
org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.qdrant.QdrantContainer;
import org.testcontainers.utility.DockerImageName;
-public class QdrantTestResource implements QuarkusTestResourceLifecycleManager
{
+abstract class AbstractQdrantTestResource implements
QuarkusTestResourceLifecycleManager {
- private static final Logger LOG =
LoggerFactory.getLogger(QdrantTestResource.class);
+ private static final Logger LOG =
LoggerFactory.getLogger(AbstractQdrantTestResource.class);
private static final String QDRANT_IMAGE =
ConfigProvider.getConfig().getValue("qdrant.container.image", String.class);
private static final int QDRANT_GRPC_PORT = 6334;
+ protected static final String QDRANT_API_KEY = "test-secret-api-key";
private GenericContainer<?> qdrantContainer;
+ /**
+ * Override this method to enable API key authentication
+ */
+ protected abstract boolean isAuthEnabled();
+
@Override
public Map<String, String> start() {
Map<String, String> properties = new HashMap<>();
DockerImageName qdrantImageName =
DockerImageName.parse(QDRANT_IMAGE).asCompatibleSubstituteFor("qdrant/qdrant");
- qdrantContainer = new QdrantContainer(qdrantImageName)
+ QdrantContainer container = new QdrantContainer(qdrantImageName)
.withLogConsumer(new Slf4jLogConsumer(LOG));
+
+ // Configure authentication if enabled
+ if (isAuthEnabled()) {
+ container.withEnv("QDRANT__SERVICE__API_KEY", QDRANT_API_KEY);
+ }
+
+ qdrantContainer = container;
qdrantContainer.start();
String grpcHost = qdrantContainer.getHost();
@@ -51,6 +64,11 @@ public class QdrantTestResource implements
QuarkusTestResourceLifecycleManager {
properties.put("camel.component.qdrant.host", grpcHost);
properties.put("camel.component.qdrant.port", grpcPort.toString());
+ // Add API key property if authentication is enabled
+ if (isAuthEnabled()) {
+ properties.put("camel.component.qdrant.api-key", QDRANT_API_KEY);
+ }
+
LOG.info("Properties: {}", properties);
return properties;
diff --git
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthIT.java
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthIT.java
new file mode 100644
index 0000000000..e9898b659e
--- /dev/null
+++
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthIT.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.qdrant.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class QdrantAuthIT extends QdrantAuthTest {
+
+}
diff --git
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTest.java
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTest.java
new file mode 100644
index 0000000000..389c12013d
--- /dev/null
+++
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.qdrant.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.containsString;
+
+@QuarkusTest
+@TestProfile(QdrantAuthTestProfile.class)
+class QdrantAuthTest {
+
+ @Test
+ void apiKeyAuthenticationShouldWork() {
+ // This test runs with QdrantAuthTestProfile which configures the
component with API key
+ RestAssured.put("/qdrant/apiKey/valid")
+ .then()
+ .statusCode(200)
+ .body(containsString("ApiKeyCredentials reflection works"));
+ }
+
+ @Test
+ void invalidApiKeyShouldBeRejected() {
+ // Verify that authentication is actually enforced with wrong API key
+ RestAssured.put("/qdrant/apiKey/invalid")
+ .then()
+ .statusCode(403)
+ .body(containsString("Authentication correctly failed"));
+ }
+
+}
diff --git
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTestProfile.java
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTestProfile.java
new file mode 100644
index 0000000000..8c1cf4dd15
--- /dev/null
+++
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTestProfile.java
@@ -0,0 +1,29 @@
+/*
+ * 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.qdrant.it;
+
+import java.util.List;
+
+import io.quarkus.test.junit.QuarkusTestProfile;
+
+public class QdrantAuthTestProfile implements QuarkusTestProfile {
+
+ @Override
+ public List<TestResourceEntry> testResources() {
+ return List.of(new TestResourceEntry(QdrantAuthTestResource.class));
+ }
+}
diff --git
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTestResource.java
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTestResource.java
new file mode 100644
index 0000000000..d1199df8cd
--- /dev/null
+++
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantAuthTestResource.java
@@ -0,0 +1,26 @@
+/*
+ * 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.qdrant.it;
+
+public class QdrantAuthTestResource extends AbstractQdrantTestResource {
+
+ @Override
+ protected boolean isAuthEnabled() {
+ return true;
+ }
+
+}
diff --git
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTest.java
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTest.java
index 6862bf28e4..6c106293d4 100644
---
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTest.java
+++
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTest.java
@@ -21,6 +21,7 @@ import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
+import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
@QuarkusTestResource(QdrantTestResource.class)
@@ -63,4 +64,34 @@ class QdrantTest {
.body(is("0/"));
}
+ @Test
+ void operationOnNonExistentCollectionShouldThrowException() {
+ // Try to retrieve from a collection that doesn't exist
+ // This should trigger QdrantException from the qdrant client
+ RestAssured.get("/qdrant/exception/nonExistentCollection")
+ .then()
+ .statusCode(500)
+ .body(containsString("QdrantException"));
+ }
+
+ @Test
+ void invalidCollectionOperationShouldThrowException() {
+ // Try to perform an invalid operation
+ // This should trigger QdrantException with a descriptive message
+ RestAssured.put("/qdrant/exception/invalidOperation")
+ .then()
+ .statusCode(500)
+ .body(containsString("QdrantException"));
+ }
+
+ @Test
+ void exceptionMessageShouldBePreserved() {
+ // Verify that exception messages are properly preserved
+ // This is important for native reflection support
+ RestAssured.get("/qdrant/exception/withMessage")
+ .then()
+ .statusCode(500)
+ .body(containsString("Test exception message"));
+ }
+
}
diff --git
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTestResource.java
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTestResource.java
index a01d8115bd..fb7e6a0407 100644
---
a/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTestResource.java
+++
b/integration-tests/qdrant/src/test/java/org/apache/camel/quarkus/component/qdrant/it/QdrantTestResource.java
@@ -16,55 +16,11 @@
*/
package org.apache.camel.quarkus.component.qdrant.it;
-import java.util.HashMap;
-import java.util.Map;
-
-import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
-import org.eclipse.microprofile.config.ConfigProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testcontainers.containers.GenericContainer;
-import org.testcontainers.containers.output.Slf4jLogConsumer;
-import org.testcontainers.qdrant.QdrantContainer;
-import org.testcontainers.utility.DockerImageName;
-
-public class QdrantTestResource implements QuarkusTestResourceLifecycleManager
{
-
- private static final Logger LOG =
LoggerFactory.getLogger(QdrantTestResource.class);
- private static final String QDRANT_IMAGE =
ConfigProvider.getConfig().getValue("qdrant.container.image", String.class);
- private static final int QDRANT_GRPC_PORT = 6334;
-
- private GenericContainer<?> qdrantContainer;
-
- @Override
- public Map<String, String> start() {
- Map<String, String> properties = new HashMap<>();
-
- DockerImageName qdrantImageName =
DockerImageName.parse(QDRANT_IMAGE).asCompatibleSubstituteFor("qdrant/qdrant");
- qdrantContainer = new QdrantContainer(qdrantImageName)
- .withLogConsumer(new Slf4jLogConsumer(LOG));
- qdrantContainer.start();
-
- String grpcHost = qdrantContainer.getHost();
- Integer grpcPort = qdrantContainer.getMappedPort(QDRANT_GRPC_PORT);
-
- properties.put("camel.component.qdrant.host", grpcHost);
- properties.put("camel.component.qdrant.port", grpcPort.toString());
-
- LOG.info("Properties: {}", properties);
-
- return properties;
- }
+public class QdrantTestResource extends AbstractQdrantTestResource {
@Override
- public void stop() {
- try {
- if (qdrantContainer != null) {
- qdrantContainer.stop();
- }
- } catch (Exception ex) {
- LOG.error("An issue occurred while stopping Qdrant container", ex);
- }
+ protected boolean isAuthEnabled() {
+ return false;
}
}