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 2023/04/18 15:26:24 UTC

[camel-quarkus] 02/04: Test OpenTelemetry extension integration with opentelemetry-jdbc

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch 2.13.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 2c8425d87254c4fd211426dbdfba8e0820767f93
Author: James Netherton <ja...@gmail.com>
AuthorDate: Tue Apr 18 09:57:28 2023 +0100

    Test OpenTelemetry extension integration with opentelemetry-jdbc
    
    Fixes #4789
---
 integration-tests/opentelemetry/pom.xml            | 44 +++++++++++++++++
 ...enTelemetryResource.java => JdbcQueryBean.java} | 50 +++++++++----------
 .../opentelemetry/it/OpenTelemetryResource.java    |  7 +++
 .../it/OpenTelemetryRouteBuilder.java              |  3 ++
 .../src/main/resources/application.properties      |  7 +++
 .../opentelemetry/it/OpenTelemetryTest.java        | 43 +++++++++++++++++
 .../it/OpenTelemetryTestResource.java              | 56 ++++++++++++++++++++++
 7 files changed, 186 insertions(+), 24 deletions(-)

diff --git a/integration-tests/opentelemetry/pom.xml b/integration-tests/opentelemetry/pom.xml
index 81cdab23d9..5ab121b65f 100644
--- a/integration-tests/opentelemetry/pom.xml
+++ b/integration-tests/opentelemetry/pom.xml
@@ -59,10 +59,22 @@
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-resteasy-jsonb</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-agroal</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-jdbc-postgresql</artifactId>
+        </dependency>
         <dependency>
             <groupId>io.opentelemetry</groupId>
             <artifactId>opentelemetry-sdk-testing</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.opentelemetry.instrumentation</groupId>
+            <artifactId>opentelemetry-jdbc</artifactId>
+        </dependency>
 
         <!-- test dependencies -->
         <dependency>
@@ -75,6 +87,27 @@
             <artifactId>rest-assured</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>testcontainers</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit4-mock</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <profiles>
@@ -181,6 +214,17 @@
                 </dependency>
             </dependencies>
         </profile>
+        <profile>
+            <id>skip-testcontainers-tests</id>
+            <activation>
+                <property>
+                    <name>skip-testcontainers-tests</name>
+                </property>
+            </activation>
+            <properties>
+                <skipTests>true</skipTests>
+            </properties>
+        </profile>
     </profiles>
 
 </project>
diff --git a/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryResource.java b/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/JdbcQueryBean.java
similarity index 50%
copy from integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryResource.java
copy to integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/JdbcQueryBean.java
index 23e1395ff5..2f25504af8 100644
--- a/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryResource.java
+++ b/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/JdbcQueryBean.java
@@ -16,34 +16,36 @@
  */
 package org.apache.camel.quarkus.component.opentelemetry.it;
 
-import javax.enterprise.context.ApplicationScoped;
-import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
 
-import org.apache.camel.ProducerTemplate;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
-@Path("/opentelemetry")
-@ApplicationScoped
-public class OpenTelemetryResource {
+import io.agroal.api.AgroalDataSource;
+import io.quarkus.runtime.annotations.RegisterForReflection;
 
+@Singleton
+@Named("jdbcQueryBean")
+@RegisterForReflection(fields = false)
+public class JdbcQueryBean {
     @Inject
-    ProducerTemplate producerTemplate;
-
-    @Path("/trace")
-    @GET
-    @Produces(MediaType.TEXT_PLAIN)
-    public String traceRoute() {
-        return producerTemplate.requestBody("direct:start", null, String.class);
-    }
+    AgroalDataSource dataSource;
 
-    @Path("/greet/{name}")
-    @GET
-    @Produces(MediaType.TEXT_PLAIN)
-    public String traceRoute(@PathParam("name") String name) {
-        return producerTemplate.requestBody("direct:greet", name, String.class);
+    public long getNowTimestamp() {
+        try (Connection connection = dataSource.getConnection()) {
+            try (Statement statement = connection.createStatement()) {
+                ResultSet resultSet = statement.executeQuery("SELECT EXTRACT(EPOCH FROM NOW());");
+                if (resultSet.next()) {
+                    return resultSet.getLong(1);
+                }
+                return 0;
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
     }
 }
diff --git a/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryResource.java b/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryResource.java
index 23e1395ff5..bb4cd3e2b2 100644
--- a/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryResource.java
+++ b/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryResource.java
@@ -46,4 +46,11 @@ public class OpenTelemetryResource {
     public String traceRoute(@PathParam("name") String name) {
         return producerTemplate.requestBody("direct:greet", name, String.class);
     }
+
+    @Path("/jdbc/query")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public long jdbcQuery() {
+        return producerTemplate.requestBody("direct:jdbcQuery", null, Long.class);
+    }
 }
diff --git a/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryRouteBuilder.java b/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryRouteBuilder.java
index 3c3f7e662b..b414a0df31 100644
--- a/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryRouteBuilder.java
+++ b/integration-tests/opentelemetry/src/main/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryRouteBuilder.java
@@ -38,5 +38,8 @@ public class OpenTelemetryRouteBuilder extends RouteBuilder {
 
         from("timer:filtered?repeatCount=5&delay=-1")
                 .setBody().constant("Route filtered from tracing");
+
+        from("direct:jdbcQuery")
+                .to("bean:jdbcQueryBean");
     }
 }
diff --git a/integration-tests/opentelemetry/src/main/resources/application.properties b/integration-tests/opentelemetry/src/main/resources/application.properties
index e819cd6f00..abae23ff2e 100644
--- a/integration-tests/opentelemetry/src/main/resources/application.properties
+++ b/integration-tests/opentelemetry/src/main/resources/application.properties
@@ -20,3 +20,10 @@
 #quarkus.camel.opentelemetry.exclude-patterns = platform-http:/opentelemetry/test/trace/filtered
 
 quarkus.camel.opentelemetry.exclude-patterns = timer:filtered*
+
+quarkus.datasource.devservices.enabled=false
+quarkus.datasource.db-kind=postgresql
+quarkus.datasource.username=test
+quarkus.datasource.password=s3cr3t
+quarkus.datasource.jdbc.driver=io.opentelemetry.instrumentation.jdbc.OpenTelemetryDriver
+quarkus.datasource.jdbc.max-size=16
diff --git a/integration-tests/opentelemetry/src/test/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryTest.java b/integration-tests/opentelemetry/src/test/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryTest.java
index 876030f0cc..8ad60db61a 100644
--- a/integration-tests/opentelemetry/src/test/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryTest.java
+++ b/integration-tests/opentelemetry/src/test/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryTest.java
@@ -18,16 +18,20 @@ package org.apache.camel.quarkus.component.opentelemetry.it;
 
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
+import io.quarkus.test.common.QuarkusTestResource;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 
+import static org.awaitility.Awaitility.await;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+@QuarkusTestResource(OpenTelemetryTestResource.class)
 @QuarkusTest
 class OpenTelemetryTest {
 
@@ -96,6 +100,45 @@ class OpenTelemetryTest {
         assertEquals(spans.get(1).get("parentId"), spans.get(2).get("spanId"));
     }
 
+    @Test
+    public void testTracedJdbcQuery() {
+        String timestamp = RestAssured.get("/opentelemetry/jdbc/query")
+                .then()
+                .statusCode(200)
+                .extract()
+                .body()
+                .asString();
+
+        assertTrue(Long.parseLong(timestamp) > 0);
+
+        // Verify the span hierarchy is JAX-RS Service -> Direct Endpoint -> Bean Endpoint -> Bean method -> JDBC query
+        await().atMost(30, TimeUnit.SECONDS).pollDelay(50, TimeUnit.MILLISECONDS).until(() -> getSpans().size() >= 4);
+        List<Map<String, String>> spans = getSpans();
+
+        boolean asyncProcessingStartedEventPresent = false;
+        try {
+            Thread.currentThread().getContextClassLoader()
+                    .loadClass("org.apache.camel.impl.event.ExchangeAsyncProcessingStartedEvent");
+            asyncProcessingStartedEventPresent = true;
+        } catch (ClassNotFoundException e) {
+            // Ignore
+        }
+
+        String expectedDbQuerySpanParent = asyncProcessingStartedEventPresent ? spans.get(0).get("parentId")
+                : spans.get(3).get("spanId");
+        assertEquals(expectedDbQuerySpanParent, spans.get(0).get("parentId"));
+        assertEquals("SELECT", spans.get(0).get("db.operation"));
+
+        assertEquals(spans.get(2).get("spanId"), spans.get(1).get("parentId"));
+        assertEquals("bean://jdbcQueryBean", spans.get(1).get("camel.uri"));
+
+        assertEquals(spans.get(3).get("spanId"), spans.get(2).get("parentId"));
+        assertEquals("direct://jdbcQuery", spans.get(2).get("camel.uri"));
+
+        assertEquals("0000000000000000", spans.get(3).get("parentId"));
+        assertEquals("/opentelemetry/jdbc/query", spans.get(3).get("http.target"));
+    }
+
     private List<Map<String, String>> getSpans() {
         return RestAssured.given()
                 .get("/opentelemetry/exporter/spans")
diff --git a/integration-tests/opentelemetry/src/test/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryTestResource.java b/integration-tests/opentelemetry/src/test/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryTestResource.java
new file mode 100644
index 0000000000..47bc190d78
--- /dev/null
+++ b/integration-tests/opentelemetry/src/test/java/org/apache/camel/quarkus/component/opentelemetry/it/OpenTelemetryTestResource.java
@@ -0,0 +1,56 @@
+/*
+ * 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.opentelemetry.it;
+
+import java.util.Map;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+
+public class OpenTelemetryTestResource implements QuarkusTestResourceLifecycleManager {
+    private static final String POSTGRES_USER = "test";
+    private static final String POSTGRES_PASSWORD = "s3cr3t";
+    private static final String POSTGRES_DB = "otel";
+    private static final int POSTGRES_PORT = 5432;
+    private static final String POSTGRES_IMAGE = "postgres:13.0";
+
+    private GenericContainer<?> container;
+
+    @Override
+    public Map<String, String> start() {
+        container = new GenericContainer<>(POSTGRES_IMAGE)
+                .withExposedPorts(POSTGRES_PORT)
+                .withEnv("POSTGRES_USER", POSTGRES_USER)
+                .withEnv("POSTGRES_PASSWORD", POSTGRES_PASSWORD)
+                .withEnv("POSTGRES_DB", POSTGRES_DB)
+                .waitingFor(Wait.forListeningPort());
+
+        container.start();
+
+        String jdbcUrl = String.format("jdbc:otel:postgresql://localhost:%d/%s", container.getMappedPort(POSTGRES_PORT),
+                POSTGRES_DB);
+        return Map.of("quarkus.datasource.jdbc.url", jdbcUrl);
+    }
+
+    @Override
+    public void stop() {
+        if (container != null) {
+            container.stop();
+        }
+    }
+}