diff --git a/instrumentation/hibernate/hibernate-4.0/javaagent/build.gradle.kts b/instrumentation/hibernate/hibernate-4.0/javaagent/build.gradle.kts index 8c4dd15bdf..2fed4ace6e 100644 --- a/instrumentation/hibernate/hibernate-4.0/javaagent/build.gradle.kts +++ b/instrumentation/hibernate/hibernate-4.0/javaagent/build.gradle.kts @@ -42,9 +42,6 @@ testing { val version5Test by registering(JvmTestSuite::class) { dependencies { sources { - groovy { - setSrcDirs(listOf("src/test/groovy")) - } java { setSrcDirs(listOf("src/test/java")) } diff --git a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/AbstractHibernateTest.groovy b/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/AbstractHibernateTest.groovy deleted file mode 100644 index f6e86f8d50..0000000000 --- a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/AbstractHibernateTest.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification -import io.opentelemetry.javaagent.instrumentation.hibernate.v4_0.Value -import org.hibernate.Session -import org.hibernate.SessionFactory -import org.hibernate.cfg.Configuration -import spock.lang.Shared - -abstract class AbstractHibernateTest extends AgentInstrumentationSpecification { - - @Shared - protected SessionFactory sessionFactory - - @Shared - protected List prepopulated - - def setupSpec() { - sessionFactory = new Configuration().configure().buildSessionFactory() - // Pre-populate the DB, so delete/update can be tested. - Session writer = sessionFactory.openSession() - writer.beginTransaction() - prepopulated = new ArrayList<>() - for (int i = 0; i < 5; i++) { - prepopulated.add(new Value("Hello :) " + i)) - writer.save(prepopulated.get(i)) - } - writer.getTransaction().commit() - writer.close() - } - - def cleanupSpec() { - if (sessionFactory != null) { - sessionFactory.close() - } - } -} diff --git a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/QueryTest.groovy b/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/QueryTest.groovy deleted file mode 100644 index 55bef91349..0000000000 --- a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/QueryTest.groovy +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes -import org.hibernate.Query -import org.hibernate.Session - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.INTERNAL - -class QueryTest extends AbstractHibernateTest { - - def "test hibernate query.#queryMethodName single call"() { - setup: - - // With Transaction - runWithSpan("parent") { - Session session = sessionFactory.openSession() - session.beginTransaction() - queryInteraction(session) - session.getTransaction().commit() - session.close() - } - - // Without Transaction - if (!requiresTransaction) { - runWithSpan("parent2") { - Session session = sessionFactory.openSession() - queryInteraction(session) - session.close() - } - } - - expect: - def sessionId - assertTraces(requiresTransaction ? 1 : 2) { - // With Transaction - trace(0, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name expectedSpanName - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "h2" - "$SemanticAttributes.DB_NAME" "db1" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:" - "$SemanticAttributes.DB_STATEMENT" String - "$SemanticAttributes.DB_OPERATION" String - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - if (!requiresTransaction) { - // Without Transaction - trace(1, 3) { - span(0) { - name "parent2" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name expectedSpanName - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" String - } - } - span(2) { - name "SELECT db1.Value" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "h2" - "$SemanticAttributes.DB_NAME" "db1" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/^select / - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - } - } - } - - where: - queryMethodName | expectedSpanName | requiresTransaction | queryInteraction - "query/list" | "SELECT Value" | false | { sess -> - Query q = sess.createQuery("from Value") - q.list() - } - "query/executeUpdate" | "UPDATE Value" | true | { sess -> - Query q = sess.createQuery("update Value set name = :name") - q.setParameter("name", "alyx") - q.executeUpdate() - } - "query/uniqueResult" | "SELECT Value" | false | { sess -> - Query q = sess.createQuery("from Value where id = :id") - q.setParameter("id", 1L) - q.uniqueResult() - } - "iterate" | "SELECT Value" | false | { sess -> - Query q = sess.createQuery("from Value") - q.iterate() - } - "query/scroll" | "SELECT Value" | false | { sess -> - Query q = sess.createQuery("from Value") - q.scroll() - } - } - - def "test hibernate query.iterate"() { - setup: - - runWithSpan("parent") { - Session session = sessionFactory.openSession() - session.beginTransaction() - Query q = session.createQuery("from Value") - Iterator iterator = q.iterate() - while (iterator.hasNext()) { - iterator.next() - } - session.getTransaction().commit() - session.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "SELECT Value" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - name "SELECT db1.Value" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "h2" - "$SemanticAttributes.DB_NAME" "db1" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/^select / - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - } - } - -} diff --git a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/SpringJpaTest.groovy b/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/SpringJpaTest.groovy deleted file mode 100644 index ee29738d52..0000000000 --- a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/groovy/SpringJpaTest.groovy +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes -import org.hibernate.Version -import org.springframework.context.annotation.AnnotationConfigApplicationContext -import spock.lang.Shared -import spring.jpa.Customer -import spring.jpa.CustomerRepository -import spring.jpa.PersistenceConfig - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.INTERNAL - -class SpringJpaTest extends AgentInstrumentationSpecification { - - @Shared - def context = new AnnotationConfigApplicationContext(PersistenceConfig) - - @Shared - def repo = context.getBean(CustomerRepository) - - def "test CRUD"() { - setup: - def isHibernate4 = Version.getVersionString().startsWith("4.") - def customer = new Customer("Bob", "Anonymous") - - expect: - customer.id == null - !runWithSpan("parent") { - repo.findAll().iterator().hasNext() - } - - def sessionId - assertTraces(1) { - trace(0, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "SELECT Customer" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - name "SELECT test.Customer" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName(.*)from Customer(.*)/ - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - } - clearExportedData() - - when: - runWithSpan("parent") { - repo.save(customer) - } - def savedId = customer.id - - then: - customer.id != null - def sessionId2 - assertTraces(1) { - trace(0, 4 + (isHibernate4 ? 0 : 1)) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "Session.persist spring.jpa.Customer" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId2 = it - it instanceof String - } - } - } - if (!isHibernate4) { - span(2) { - name "CALL test" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_STATEMENT" "call next value for hibernate_sequence" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_OPERATION" "CALL" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId2 - } - } - span(4) { - name "INSERT test.Customer" - kind CLIENT - childOf span(3) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/insert into Customer \(.*\) values \(.*, \?, \?\)/ - "$SemanticAttributes.DB_OPERATION" "INSERT" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - } else { - span(2) { - name "INSERT test.Customer" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/insert into Customer \(.*\) values \(.*, \?, \?\)/ - "$SemanticAttributes.DB_OPERATION" "INSERT" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId2 - } - } - } - } - } - clearExportedData() - - when: - customer.firstName = "Bill" - runWithSpan("parent") { - repo.save(customer) - } - - then: - customer.id == savedId - def sessionId3 - assertTraces(1) { - trace(0, 5) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "Session.merge spring.jpa.Customer" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId3 = it - it instanceof String - } - } - } - span(2) { - name "SELECT test.Customer" - kind CLIENT - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)where ([^.]+)\.id( ?)=( ?)\?/ - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId3 - } - } - span(4) { - name "UPDATE test.Customer" - kind CLIENT - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" "update Customer set firstName=?, lastName=? where id=?" - "$SemanticAttributes.DB_OPERATION" "UPDATE" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - } - } - clearExportedData() - - when: - customer = runWithSpan("parent") { - repo.findByLastName("Anonymous")[0] - } - - then: - customer.id == savedId - customer.firstName == "Bill" - assertTraces(1) { - trace(0, 3) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "SELECT Customer" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" String - } - } - span(2) { - name "SELECT test.Customer" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)(where ([^.]+)\.lastName( ?)=( ?)\?|)/ - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - } - } - clearExportedData() - - when: - runWithSpan("parent") { - repo.delete(customer) - } - - then: - assertTraces(1) { - trace(0, 6 + (isHibernate4 ? 0 : 1)) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - def offset = 0 - if (!isHibernate4) { - offset = 2 - span(1) { - name ~/Session.(get|find) spring.jpa.Customer/ - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" String - } - } - span(2) { - name "SELECT test.Customer" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)where ([^.]+)\.id( ?)=( ?)\?/ - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - } - span(1 + offset) { - name "Session.merge spring.jpa.Customer" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" String - } - } - if (isHibernate4) { - offset = 1 - span(2) { - name "SELECT test.Customer" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)where ([^.]+)\.id( ?)=( ?)\?/ - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - } - span(2 + offset) { - name "Session.delete spring.jpa.Customer" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" String - } - } - span(3 + offset) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" String - } - } - span(4 + offset) { - name "DELETE test.Customer" - kind CLIENT - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_STATEMENT" "delete from Customer where id=?" - "$SemanticAttributes.DB_OPERATION" "DELETE" - "$SemanticAttributes.DB_SQL_TABLE" "Customer" - } - } - } - } - } -} diff --git a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v4_0/QueryTest.java b/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v4_0/QueryTest.java new file mode 100644 index 0000000000..57f093d256 --- /dev/null +++ b/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v4_0/QueryTest.java @@ -0,0 +1,222 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hibernate.v4_0; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static io.opentelemetry.api.trace.SpanKind.CLIENT; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static org.junit.jupiter.api.Named.named; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.util.Iterator; +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.hibernate.Session; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class QueryTest extends AbstractHibernateTest { + + @Test + void testHibernateQueryExecuteUpdateWithTransaction() { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + session + .createQuery("update Value set name = :name") + .setParameter("name", "alyx") + .executeUpdate(); + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("UPDATE Value") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "h2"), + equalTo(SemanticAttributes.DB_NAME, "db1"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "h2:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> val.isInstanceOf(String.class)), + satisfies( + SemanticAttributes.DB_OPERATION, + val -> val.isInstanceOf(String.class)), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(stringKey("hibernate.session_id")))))); + } + + @ParameterizedTest + @MethodSource("providesArgumentsSingleCall") + void testHibernateQuerySingleCall(Parameter parameter) { + + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + parameter.queryInteraction.accept(session); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName(parameter.expectedSpanName) + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT db1.Value") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "h2"), + equalTo(SemanticAttributes.DB_NAME, "db1"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "h2:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, val -> val.startsWith("select ")), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")))); + } + + private static Stream providesArgumentsSingleCall() { + return Stream.of( + Arguments.of( + named( + "query/list", + new Parameter("SELECT Value", sess -> sess.createQuery("from Value").list()))), + Arguments.of( + named( + "query/uniqueResult", + new Parameter( + "SELECT Value", + sess -> + sess.createQuery("from Value where id = :id") + .setParameter("id", 1L) + .uniqueResult()))), + Arguments.of( + named( + "iterate", + new Parameter("SELECT Value", sess -> sess.createQuery("from Value").iterate()))), + Arguments.of( + named( + "query/scroll", + new Parameter("SELECT Value", sess -> sess.createQuery("from Value").scroll())))); + } + + @Test + void testHibernateQueryIterate() { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + @SuppressWarnings("unchecked") + Iterator iterator = session.createQuery("from Value").iterate(); + while (iterator.hasNext()) { + iterator.next(); + } + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("SELECT Value") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT db1.Value") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "h2"), + equalTo(SemanticAttributes.DB_NAME, "db1"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "h2:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, val -> val.startsWith("select ")), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(stringKey("hibernate.session_id")))))); + } + + private static class Parameter { + public final String expectedSpanName; + public final Consumer queryInteraction; + + public Parameter(String expectedSpanName, Consumer queryInteraction) { + this.expectedSpanName = expectedSpanName; + this.queryInteraction = queryInteraction; + } + } +} diff --git a/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/java/spring/jpa/SpringJpaTest.java b/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/java/spring/jpa/SpringJpaTest.java new file mode 100644 index 0000000000..902b467b2a --- /dev/null +++ b/instrumentation/hibernate/hibernate-4.0/javaagent/src/test/java/spring/jpa/SpringJpaTest.java @@ -0,0 +1,456 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package spring.jpa; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static io.opentelemetry.api.trace.SpanKind.CLIENT; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.util.regex.Pattern; +import org.hibernate.Version; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +class SpringJpaTest { + + @RegisterExtension + protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + AnnotationConfigApplicationContext context = + new AnnotationConfigApplicationContext(PersistenceConfig.class); + CustomerRepository repo = context.getBean(CustomerRepository.class); + + @Test + void testCrud() { + String version = Version.getVersionString(); + boolean isHibernate4 = version.startsWith("4."); + boolean isLatestDep = version.startsWith("5.0"); + + Customer customer = new Customer("Bob", "Anonymous"); + customer.setId(null); + + boolean result = testing.runWithSpan("parent", () -> repo.findAll().iterator().hasNext()); + + assertThat(result).isEqualTo(false); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("SELECT Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> + val.matches( + Pattern.compile( + "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName(.*)from Customer(.*)"))), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(stringKey("hibernate.session_id")))))); + testing.clearData(); + + testing.runWithSpan( + "parent", + () -> { + repo.save(customer); + }); + + assertThat(customer.getId()).isNotNull(); + + testing.waitAndAssertTraces( + trace -> { + if (isHibernate4) { + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("Session.persist spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("INSERT test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> + val.matches( + Pattern.compile( + "insert into Customer (.*) values \\(.*, \\?, \\?\\)"))), + equalTo(SemanticAttributes.DB_OPERATION, "INSERT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(stringKey("hibernate.session_id"))))); + } else { + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("Session.persist spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("CALL test") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo( + SemanticAttributes.DB_STATEMENT, + "call next value for hibernate_sequence"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + equalTo(SemanticAttributes.DB_OPERATION, "CALL")), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(stringKey("hibernate.session_id")))), + span -> + span.hasName("INSERT test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(3)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> + val.matches( + Pattern.compile( + "insert into Customer (.*) values \\(.* \\?, \\?\\)"))), + equalTo(SemanticAttributes.DB_OPERATION, "INSERT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer"))); + } + }); + testing.clearData(); + + customer.setFirstName("Bill"); + + testing.runWithSpan( + "parent", + () -> { + repo.save(customer); + }); + + Long savedId = customer.getId(); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("Session.merge spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> + val.matches( + Pattern.compile( + "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(stringKey("hibernate.session_id")))), + span -> + span.hasName("UPDATE test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(3)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + equalTo( + SemanticAttributes.DB_STATEMENT, + "update Customer set firstName=?, lastName=? where id=?"), + equalTo(SemanticAttributes.DB_OPERATION, "UPDATE"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")))); + testing.clearData(); + + Customer foundCustomer = + testing.runWithSpan("parent", () -> repo.findByLastName("Anonymous").get(0)); + + assertThat(foundCustomer.getId()).isEqualTo(savedId); + assertThat(foundCustomer.getFirstName()).isEqualTo("Bill"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("SELECT Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> + val.matches( + Pattern.compile( + "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)(where ([^.]+).lastName=\\?)"))), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")))); + testing.clearData(); + + testing.runWithSpan("parent", () -> repo.delete(foundCustomer)); + + testing.waitAndAssertTraces( + trace -> { + if (isHibernate4) { + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("parent") + .hasKind(INTERNAL) + .hasNoParent() + .hasAttributes(Attributes.empty()), + span -> + span.hasName("Session.merge spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> + val.matches( + Pattern.compile( + "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")), + span -> + span.hasName("Session.delete spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("DELETE test.Customer") + .hasKind(CLIENT) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + equalTo( + SemanticAttributes.DB_STATEMENT, "delete from Customer where id=?"), + equalTo(SemanticAttributes.DB_OPERATION, "DELETE"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer"))); + + } else { + String findAction; + if (isLatestDep) { + findAction = "get"; + } else { + findAction = "find"; + } + + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(), + span -> + span.hasName("Session." + findAction + " spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT test.Customer") + .hasKind(CLIENT) + .hasParent(trace.getSpan(1)) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + satisfies( + SemanticAttributes.DB_STATEMENT, + val -> + val.matches( + Pattern.compile( + "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")), + span -> + span.hasName("Session.merge spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("Session.delete spring.jpa.Customer") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("Transaction.commit") + .hasKind(INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("DELETE test.Customer") + .hasKind(CLIENT) + .hasAttributesSatisfyingExactly( + equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"), + equalTo(SemanticAttributes.DB_NAME, "test"), + equalTo(SemanticAttributes.DB_USER, "sa"), + equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"), + equalTo( + SemanticAttributes.DB_STATEMENT, "delete from Customer where id=?"), + equalTo(SemanticAttributes.DB_OPERATION, "DELETE"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer"))); + } + }); + } +}