From f7c7004250d9963f872171c985152b04864bfe50 Mon Sep 17 00:00:00 2001 From: Nitesh S <36809515+niteshs7@users.noreply.github.com> Date: Fri, 5 May 2023 19:40:50 +0530 Subject: [PATCH] convert hibernate 6 tests from groovy to java (#8304) --- .../test/groovy/AbstractHibernateTest.groovy | 39 - .../src/test/groovy/CriteriaTest.groovy | 87 -- .../src/test/groovy/EntityManagerTest.groovy | 233 ----- .../src/test/groovy/ProcedureCallTest.groovy | 175 ---- .../src/test/groovy/SessionTest.groovy | 603 ------------- .../hibernate/v6_0/AbstractHibernateTest.java | 47 + .../hibernate/v6_0/CriteriaTest.java | 101 +++ .../hibernate/v6_0/EntityManagerTest.java | 339 +++++++ .../hibernate/v6_0/ProcedureCallTest.java | 188 ++++ .../hibernate/v6_0/SessionTest.java | 845 ++++++++++++++++++ .../hibernate/v6_0}/Value.java | 2 + .../test/resources/META-INF/persistence.xml | 4 +- .../src/test/resources/hibernate.cfg.xml | 2 +- .../procedure-call-hibernate.cfg.xml | 2 +- 14 files changed, 1526 insertions(+), 1141 deletions(-) delete mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/AbstractHibernateTest.groovy delete mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/CriteriaTest.groovy delete mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/EntityManagerTest.groovy delete mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/ProcedureCallTest.groovy delete mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/SessionTest.groovy create mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/AbstractHibernateTest.java create mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/CriteriaTest.java create mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/EntityManagerTest.java create mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/ProcedureCallTest.java create mode 100644 instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/SessionTest.java rename instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/{ => io/opentelemetry/javaagent/instrumentation/hibernate/v6_0}/Value.java (92%) diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/AbstractHibernateTest.groovy b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/AbstractHibernateTest.groovy deleted file mode 100644 index 79c3b8ddf2..0000000000 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/AbstractHibernateTest.groovy +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification -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-6.0/javaagent/src/test/groovy/CriteriaTest.groovy b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/CriteriaTest.groovy deleted file mode 100644 index 3b7fe642b4..0000000000 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/CriteriaTest.groovy +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes -import jakarta.persistence.criteria.CriteriaBuilder -import jakarta.persistence.criteria.CriteriaQuery -import jakarta.persistence.criteria.Root -import org.hibernate.Session - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.INTERNAL - -class CriteriaTest extends AbstractHibernateTest { - - def "test criteria query.#methodName"() { - setup: - runWithSpan("parent") { - Session session = sessionFactory.openSession() - session.beginTransaction() - CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder() - CriteriaQuery createQuery = criteriaBuilder.createQuery(Value) - Root root = createQuery.from(Value) - createQuery.select(root) - .where(criteriaBuilder.like(root.get("name"), "Hello")) - .orderBy(criteriaBuilder.desc(root.get("name"))) - def query= session.createQuery(createQuery) - interaction.call(query) - 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 - } - } - } - } - - where: - methodName | interaction - "getResultList" | { c -> c.getResultList() } - "uniqueResult" | { c -> c.uniqueResult() } - "getSingleResultOrNull" | { c -> c.getSingleResultOrNull() } - } -} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/EntityManagerTest.groovy b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/EntityManagerTest.groovy deleted file mode 100644 index 0f0daac398..0000000000 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/EntityManagerTest.groovy +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes -import jakarta.persistence.EntityManager -import jakarta.persistence.EntityManagerFactory -import jakarta.persistence.EntityTransaction -import jakarta.persistence.LockModeType -import jakarta.persistence.Persistence -import jakarta.persistence.Query -import spock.lang.Shared -import spock.lang.Unroll - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.INTERNAL - -class EntityManagerTest extends AbstractHibernateTest { - - @Shared - EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("test-pu") - - @Unroll - def "test hibernate action #testName"() { - setup: - EntityManager entityManager = entityManagerFactory.createEntityManager() - EntityTransaction entityTransaction = entityManager.getTransaction() - entityTransaction.begin() - - def entity = prepopulated.get(0) - if (attach) { - entity = runWithSpan("setup") { - entityManager.merge(prepopulated.get(0)) - } - ignoreTracesAndClear(1) - } - - when: - runWithSpan("parent") { - try { - sessionMethodTest.call(entityManager, entity) - } catch (Exception e) { - // We expected this, we should see the error field set on the span. - } - - entityTransaction.commit() - entityManager.close() - } - - then: - boolean isPersistTest = "persist" == testName - def sessionId - assertTraces(1) { - trace(0, 4 + (isPersistTest ? 1 : 0)) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name ~/Session.$methodName $resource/ - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - - def offset = 0 - if (isPersistTest) { - // persist test has an extra query for getting id of inserted element - offset = 1 - span(2) { - name "SELECT db1.Value" - childOf span(1) - kind CLIENT - 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" - } - } - } - - if (!flushOnCommit) { - span(2 + offset) { - childOf span(1) - kind CLIENT - 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 + offset) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } else { - span(2 + offset) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - span(3 + offset) { - childOf span(2 + offset) - kind CLIENT - 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" - } - } - } - } - } - - where: - testName | methodName | resource | attach | flushOnCommit | sessionMethodTest - "lock" | "lock" | "Value" | true | false | { em, val -> - em.lock(val, LockModeType.PESSIMISTIC_READ) - } - "refresh" | "refresh" | "Value" | true | false | { em, val -> - em.refresh(val) - } - "find" | "(get|find)" | "Value" | false | false | { em, val -> - em.find(Value, val.getId()) - } - "persist" | "persist" | "Value" | false | true | { em, val -> - em.persist(new Value("insert me")) - } - "merge" | "merge" | "Value" | true | true | { em, val -> - val.setName("New name") - em.merge(val) - } - "remove" | "delete" | "Value" | true | true | { em, val -> - em.remove(val) - } - } - - @Unroll - def "test attaches State to query created via #queryMethodName"() { - setup: - runWithSpan("parent") { - EntityManager entityManager = entityManagerFactory.createEntityManager() - EntityTransaction entityTransaction = entityManager.getTransaction() - entityTransaction.begin() - Query query = queryBuildMethod(entityManager) - query.getResultList() - entityTransaction.commit() - entityManager.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name resource - 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" String - "$SemanticAttributes.DB_OPERATION" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - } - - where: - queryMethodName | resource | queryBuildMethod - "createQuery" | "SELECT Value" | { em -> em.createQuery("from Value") } - "getNamedQuery" | "SELECT Value" | { em -> em.createNamedQuery("TestNamedQuery") } - "createSQLQuery" | "SELECT Value" | { em -> em.createNativeQuery("SELECT * FROM Value") } - } - -} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/ProcedureCallTest.groovy b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/ProcedureCallTest.groovy deleted file mode 100644 index f7827670d2..0000000000 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/ProcedureCallTest.groovy +++ /dev/null @@ -1,175 +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 jakarta.persistence.ParameterMode -import org.hibernate.Session -import org.hibernate.SessionFactory -import org.hibernate.cfg.Configuration -import org.hibernate.exception.SQLGrammarException -import org.hibernate.procedure.ProcedureCall -import spock.lang.Shared - -import java.sql.Connection -import java.sql.DriverManager -import java.sql.Statement - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.INTERNAL -import static io.opentelemetry.api.trace.StatusCode.ERROR - -class ProcedureCallTest extends AgentInstrumentationSpecification { - - @Shared - protected SessionFactory sessionFactory - - @Shared - protected List prepopulated - - def setupSpec() { - sessionFactory = new Configuration().configure("procedure-call-hibernate.cfg.xml").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 < 2; i++) { - prepopulated.add(new Value("Hello :) " + i)) - writer.save(prepopulated.get(i)) - } - writer.getTransaction().commit() - writer.close() - - // Create a stored procedure. - Connection conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", "1") - Statement stmt = conn.createStatement() - stmt.execute("CREATE PROCEDURE TEST_PROC() MODIFIES SQL DATA BEGIN ATOMIC INSERT INTO Value VALUES (420, 'fred'); END") - stmt.close() - conn.close() - } - - def cleanupSpec() { - if (sessionFactory != null) { - sessionFactory.close() - } - } - - def "test ProcedureCall"() { - setup: - - runWithSpan("parent") { - Session session = sessionFactory.openSession() - session.beginTransaction() - - ProcedureCall call = session.createStoredProcedureCall("TEST_PROC") - call.getOutputs() - - session.getTransaction().commit() - session.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "ProcedureCall.getOutputs TEST_PROC" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - name "CALL test.TEST_PROC" - kind CLIENT - childOf span(1) - attributes { - "$SemanticAttributes.DB_SYSTEM" "hsqldb" - "$SemanticAttributes.DB_NAME" "test" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_STATEMENT" "{call TEST_PROC()}" - "$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:" - "$SemanticAttributes.DB_OPERATION" "CALL" - } - } - span(3) { - kind INTERNAL - name "Transaction.commit" - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - } - } - - def "test failing ProcedureCall"() { - setup: - - runWithSpan("parent") { - Session session = sessionFactory.openSession() - session.beginTransaction() - - ProcedureCall call = session.createStoredProcedureCall("TEST_PROC") - def parameterRegistration = call.registerParameter("nonexistent", Long, ParameterMode.IN) - call.setParameter(parameterRegistration, 420L) - try { - call.getOutputs() - } catch (Exception e) { - // We expected this. - } - - session.getTransaction().commit() - session.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 3) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "ProcedureCall.getOutputs TEST_PROC" - kind INTERNAL - childOf span(0) - status ERROR - errorEvent(SQLGrammarException, ~/could not prepare statement/) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - } - } -} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/SessionTest.groovy b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/SessionTest.groovy deleted file mode 100644 index fffbbbf682..0000000000 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/groovy/SessionTest.groovy +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes -import org.hibernate.LockMode -import org.hibernate.LockOptions -import org.hibernate.ReplicationMode -import org.hibernate.Session -import org.hibernate.UnknownEntityTypeException -import spock.lang.Shared - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.INTERNAL -import static io.opentelemetry.api.trace.StatusCode.ERROR - -class SessionTest extends AbstractHibernateTest { - - @Shared - private Closure sessionBuilder = { return sessionFactory.openSession() } - @Shared - private Closure statelessSessionBuilder = { return sessionFactory.openStatelessSession() } - - - def "test hibernate action #testName"() { - setup: - - // Test for each implementation of Session. - for (def buildSession : sessionImplementations) { - runWithSpan("parent") { - def session = buildSession() - session.beginTransaction() - - try { - sessionMethodTest.call(session, prepopulated.get(0)) - } catch (Exception e) { - // We expected this, we should see the error field set on the span. - } - - session.getTransaction().commit() - session.close() - } - } - - expect: - def sessionId - assertTraces(sessionImplementations.size()) { - for (int i = 0; i < sessionImplementations.size(); i++) { - trace(i, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "Session.$methodName $resource" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - childOf span(1) - kind CLIENT - 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 - } - } - } - } - } - - where: - testName | methodName | resource | sessionImplementations | sessionMethodTest - "lock" | "lock" | "Value" | [sessionBuilder] | { sesh, val -> - sesh.lock(val, LockMode.READ) - } - "lock with entity name" | "lock" | "Value" | [sessionBuilder] | { sesh, val -> - sesh.lock("Value", val, LockMode.READ) - } - "lock with null name" | "lock" | "Value" | [sessionBuilder] | { sesh, val -> - sesh.lock(null, val, LockMode.READ) - } - "buildLockRequest" | "lock" | "Value" | [sessionBuilder] | { sesh, val -> - sesh.buildLockRequest(LockOptions.READ) - .lock(val) - } - "refresh" | "refresh" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val -> - sesh.refresh(val) - } - "refresh with entity name" | "refresh" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val -> - sesh.refresh("Value", val) - } - "get with entity name" | "get" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val -> - sesh.get("Value", val.getId()) - } - "get with entity class" | "get" | "Value" | [sessionBuilder, statelessSessionBuilder] | { sesh, val -> - sesh.get(Value, val.getId()) - } - "insert" | "insert" | "Value" | [statelessSessionBuilder] | { sesh, val -> - sesh.insert(new Value("insert me")) - } - "insert with entity name" | "insert" | "Value" | [statelessSessionBuilder] | { sesh, val -> - sesh.insert("Value", new Value("insert me")) - } - "insert with null entity name" | "insert" | "Value" | [statelessSessionBuilder] | { sesh, val -> - sesh.insert(null, new Value("insert me")) - } - "update (StatelessSession)" | "update" | "Value" | [statelessSessionBuilder] | { sesh, val -> - val.setName("New name") - sesh.update(val) - } - "update with entity name (StatelessSession)" | "update" | "Value" | [statelessSessionBuilder] | { sesh, val -> - val.setName("New name") - sesh.update("Value", val) - } - "delete (Session)" | "delete" | "Value" | [statelessSessionBuilder] | { sesh, val -> - sesh.delete(val) - prepopulated.remove(val) - } - "delete with entity name (Session)" | "delete" | "Value" | [statelessSessionBuilder] | { sesh, val -> - sesh.delete("Value", val) - prepopulated.remove(val) - } - } - - def "test hibernate replicate: #testName"() { - setup: - - // Test for each implementation of Session. - runWithSpan("parent") { - def session = sessionFactory.openSession() - session.beginTransaction() - - try { - sessionMethodTest.call(session, prepopulated.get(0)) - } catch (Exception e) { - // We expected this, we should see the error field set on the span. - } - - session.getTransaction().commit() - session.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 5) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "Session.$methodName $resource" - 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 - } - } - span(4) { - kind CLIENT - childOf span(3) - 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" - } - } - } - - } - - where: - testName | methodName | resource | sessionMethodTest - "replicate" | "replicate" | "Value" | { sesh, val -> - Value replicated = new Value(val.getName() + " replicated") - replicated.setId(val.getId()) - sesh.replicate(replicated, ReplicationMode.OVERWRITE) - } - "replicate by entityName" | "replicate" | "Value" | { sesh, val -> - Value replicated = new Value(val.getName() + " replicated") - replicated.setId(val.getId()) - sesh.replicate("Value", replicated, ReplicationMode.OVERWRITE) - } - } - - def "test hibernate failed replicate"() { - setup: - - // Test for each implementation of Session. - runWithSpan("parent") { - def session = sessionFactory.openSession() - session.beginTransaction() - - try { - session.replicate(new Long(123) /* Not a valid entity */, ReplicationMode.OVERWRITE) - } catch (Exception e) { - // We expected this, we should see the error field set on the span. - } - - session.getTransaction().commit() - session.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 3) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "Session.replicate java.lang.Long" - kind INTERNAL - childOf span(0) - status ERROR - errorEvent(UnknownEntityTypeException, "Unable to locate persister: java.lang.Long") - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - - } - } - - - def "test hibernate commit action #testName"() { - setup: - - runWithSpan("parent") { - def session = sessionBuilder() - session.beginTransaction() - - try { - sessionMethodTest.call(session, prepopulated.get(0)) - } catch (Exception e) { - // We expected this, we should see the error field set on the span. - } - - session.getTransaction().commit() - session.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name "Session.$methodName $resource" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId = it - it instanceof String - } - } - } - span(2) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - span(3) { - kind CLIENT - childOf span(2) - 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" - } - } - } - } - - where: - testName | methodName | resource | sessionMethodTest - "save" | "save" | "Value" | { sesh, val -> - sesh.save(new Value("Another value")) - } - "save with entity name" | "save" | "Value" | { sesh, val -> - sesh.save("Value", new Value("Another value")) - } - "saveOrUpdate save" | "saveOrUpdate" | "Value" | { sesh, val -> - sesh.saveOrUpdate(new Value("Value")) - } - "saveOrUpdate save with entity name" | "saveOrUpdate" | "Value" | { sesh, val -> - sesh.saveOrUpdate("Value", new Value("Value")) - } - "saveOrUpdate update with entity name" | "saveOrUpdate" | "Value" | { sesh, val -> - val.setName("New name") - sesh.saveOrUpdate("Value", val) - } - "merge" | "merge" | "Value" | { sesh, val -> - sesh.merge(new Value("merge me in")) - } - "merge with entity name" | "merge" | "Value" | { sesh, val -> - sesh.merge("Value", new Value("merge me in")) - } - "persist" | "persist" | "Value" | { sesh, val -> - sesh.persist(new Value("merge me in")) - } - "persist with entity name" | "persist" | "Value" | { sesh, val -> - sesh.persist("Value", new Value("merge me in")) - } - "persist with null entity name" | "persist" | "Value" | { sesh, val -> - sesh.persist(null, new Value("merge me in")) - } - "update (Session)" | "update" | "Value" | { sesh, val -> - val.setName("New name") - sesh.update(val) - } - "update by entityName (Session)" | "update" | "Value" | { sesh, val -> - val.setName("New name") - sesh.update("Value", val) - } - "delete (Session)" | "delete" | "Value" | { sesh, val -> - sesh.delete(val) - prepopulated.remove(val) - } - "delete by entityName (Session)" | "delete" | "Value" | { sesh, val -> - sesh.delete("Value", val) - prepopulated.remove(val) - } - } - - def "test attaches State to query created via #queryMethodName"() { - setup: - runWithSpan("parent") { - Session session = sessionFactory.openSession() - session.beginTransaction() - def query = queryBuildMethod(session) - query.list() - session.getTransaction().commit() - session.close() - } - - expect: - def sessionId - assertTraces(1) { - trace(0, 4) { - span(0) { - name "parent" - kind INTERNAL - hasNoParent() - attributes { - } - } - span(1) { - name resource - 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" "SELECT" - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - span(3) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId - } - } - } - } - - where: - queryMethodName | resource | queryBuildMethod - "createQuery" | "SELECT Value" | { sess -> sess.createQuery("from Value") } - "getNamedQuery" | "SELECT Value" | { sess -> sess.getNamedQuery("TestNamedQuery") } - "createNativeQuery" | "SELECT Value" | { sess -> sess.createNativeQuery("SELECT * FROM Value") } - "createSelectionQuery" | "SELECT Value" | { sess -> sess.createSelectionQuery("from Value") } - } - - def "test hibernate overlapping Sessions"() { - setup: - - runWithSpan("overlapping Sessions") { - def session1 = sessionFactory.openSession() - session1.beginTransaction() - def session2 = sessionFactory.openStatelessSession() - def session3 = sessionFactory.openSession() - - def value1 = new Value("Value 1") - session1.save(value1) - session2.insert(new Value("Value 2")) - session3.save(new Value("Value 3")) - session1.delete(value1) - - session2.close() - session1.getTransaction().commit() - session1.close() - session3.close() - } - - expect: - def sessionId1 - def sessionId2 - def sessionId3 - assertTraces(1) { - trace(0, 9) { - span(0) { - name "overlapping Sessions" - attributes { - } - } - span(1) { - name "Session.save Value" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId1 = it - it instanceof String - } - } - } - span(2) { - name "Session.insert Value" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId2 = it - it instanceof String - } - } - } - span(3) { - name "INSERT db1.Value" - kind CLIENT - childOf span(2) - attributes { - "$SemanticAttributes.DB_SYSTEM" "h2" - "$SemanticAttributes.DB_NAME" "db1" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/^insert / - "$SemanticAttributes.DB_OPERATION" "INSERT" - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - span(4) { - name "Session.save Value" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" { - sessionId3 = it - it instanceof String - } - } - } - span(5) { - name "Session.delete Value" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId1 - } - } - span(6) { - name "Transaction.commit" - kind INTERNAL - childOf span(0) - attributes { - "hibernate.session_id" sessionId1 - } - } - span(7) { - name "INSERT db1.Value" - kind CLIENT - childOf span(6) - attributes { - "$SemanticAttributes.DB_SYSTEM" "h2" - "$SemanticAttributes.DB_NAME" "db1" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/^insert / - "$SemanticAttributes.DB_OPERATION" "INSERT" - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - span(8) { - name "DELETE db1.Value" - kind CLIENT - childOf span(6) - attributes { - "$SemanticAttributes.DB_SYSTEM" "h2" - "$SemanticAttributes.DB_NAME" "db1" - "$SemanticAttributes.DB_USER" "sa" - "$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:" - "$SemanticAttributes.DB_STATEMENT" ~/^delete / - "$SemanticAttributes.DB_OPERATION" "DELETE" - "$SemanticAttributes.DB_SQL_TABLE" "Value" - } - } - } - } - sessionId1 != sessionId2 != sessionId3 - } -} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/AbstractHibernateTest.java b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/AbstractHibernateTest.java new file mode 100644 index 0000000000..3d7e1c677c --- /dev/null +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/AbstractHibernateTest.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hibernate.v6_0; + +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import java.util.ArrayList; +import java.util.List; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.RegisterExtension; + +public abstract class AbstractHibernateTest { + protected static SessionFactory sessionFactory; + protected static List prepopulated; + + @RegisterExtension + protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @BeforeAll + protected static void setup() { + 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.persist(prepopulated.get(i)); + } + writer.getTransaction().commit(); + writer.close(); + } + + @AfterAll + protected static void cleanup() { + if (sessionFactory != null) { + sessionFactory.close(); + } + } +} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/CriteriaTest.java b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/CriteriaTest.java new file mode 100644 index 0000000000..ef52b232b0 --- /dev/null +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/CriteriaTest.java @@ -0,0 +1,101 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hibernate.v6_0; + +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.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.hibernate.Session; +import org.hibernate.query.Query; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class CriteriaTest extends AbstractHibernateTest { + private static Stream provideParameters() { + List>> interactions = + Arrays.asList(Query::getResultList, Query::uniqueResult, Query::getSingleResultOrNull); + + return Stream.of( + Arguments.of(named("getResultList", interactions.get(0))), + Arguments.of(named("uniqueResult", interactions.get(1))), + Arguments.of(named("getSingleResultOrNull", interactions.get(2)))); + } + + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideParameters") + void testCriteriaQuery(Consumer> interaction) { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); + CriteriaQuery createQuery = criteriaBuilder.createQuery(Value.class); + Root root = createQuery.from(Value.class); + createQuery + .select(root) + .where(criteriaBuilder.like(root.get("name"), "Hello")) + .orderBy(criteriaBuilder.desc(root.get("name"))); + Query query = session.createQuery(createQuery); + interaction.accept(query); + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(4) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + span.hasName( + "SELECT io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + AttributeKey.stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("SELECT db1.Value") + .hasKind(SpanKind.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, + stringAssert -> stringAssert.startsWith("select")), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")), + span -> + span.hasName("Transaction.commit") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + AttributeKey.stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id")))))); + } +} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/EntityManagerTest.java b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/EntityManagerTest.java new file mode 100644 index 0000000000..30e07a07fa --- /dev/null +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/EntityManagerTest.java @@ -0,0 +1,339 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hibernate.v6_0; + +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.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import jakarta.persistence.LockModeType; +import jakarta.persistence.Persistence; +import jakarta.persistence.Query; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class EntityManagerTest extends AbstractHibernateTest { + static final EntityManagerFactory entityManagerFactory = + Persistence.createEntityManagerFactory("test-pu"); + + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideHibernateActionParameters") + void testHibernateAction(Parameter parameter) { + EntityManager entityManager = entityManagerFactory.createEntityManager(); + EntityTransaction entityTransaction = entityManager.getTransaction(); + entityTransaction.begin(); + + Value entity; + if (parameter.attach) { + entity = + testing.runWithSpan( + "setup", + () -> { + return entityManager.merge(prepopulated.get(0)); + }); + testing.clearData(); + } else { + entity = prepopulated.get(0); + } + + testing.runWithSpan( + "parent", + () -> { + try { + parameter.sessionMethodTest.accept(entityManager, entity); + } catch (RuntimeException e) { + // We expected this, we should see the error field set on the span. + } + entityTransaction.commit(); + entityManager.close(); + }); + + boolean isPersistTest = "persist".equals(parameter.methodName); + + testing.waitAndAssertTraces( + trace -> { + if (isPersistTest) { + trace.hasSpansSatisfyingExactlyInAnyOrder( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + assertSessionSpan( + span, + trace.getSpan(0), + "Session." + parameter.methodName + " " + parameter.resource), + span -> assertClientSpan(span, trace.getSpan(1), "SELECT db1.Value"), + span -> + assertClientSpan( + span, !parameter.flushOnCommit ? trace.getSpan(1) : trace.getSpan(3)), + span -> + assertTransactionCommitSpan( + span, + trace.getSpan(0), + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id")))); + } else { + trace.hasSpansSatisfyingExactlyInAnyOrder( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + assertSessionSpan( + span, + trace.getSpan(0), + "Session." + parameter.methodName + " " + parameter.resource), + span -> + assertClientSpan( + span, !parameter.flushOnCommit ? trace.getSpan(1) : trace.getSpan(2)), + span -> + assertTransactionCommitSpan( + span, + trace.getSpan(0), + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id")))); + } + }); + } + + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideAttachesStateParameters") + void testAttachesStateToQuery(Parameter parameter) { + testing.runWithSpan( + "parent", + () -> { + EntityManager entityManager = entityManagerFactory.createEntityManager(); + EntityTransaction entityTransaction = entityManager.getTransaction(); + entityTransaction.begin(); + Query query = parameter.queryBuildMethod.apply(entityManager); + query.getResultList(); + entityTransaction.commit(); + entityManager.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(4) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> assertSessionSpan(span, trace.getSpan(0), parameter.resource), + span -> + span.hasName("SELECT db1.Value") + .hasKind(SpanKind.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)), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")), + span -> + assertTransactionCommitSpan( + span, + trace.getSpan(0), + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))))); + } + + private static Stream provideHibernateActionParameters() { + List> sessionMethodTests = + Arrays.asList( + (em, val) -> em.lock(val, LockModeType.PESSIMISTIC_READ), + (em, val) -> em.refresh(val), + (em, val) -> em.find(Value.class, val.getId()), + (em, val) -> em.persist(new Value("insert me")), + (em, val) -> { + val.setName("New name"); + em.merge(val); + }, + (em, val) -> em.remove(val)); + + return Stream.of( + Arguments.of( + named( + "lock", + new Parameter( + "lock", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + true, + false, + sessionMethodTests.get(0)))), + Arguments.of( + named( + "refresh", + new Parameter( + "refresh", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + true, + false, + sessionMethodTests.get(1)))), + Arguments.of( + named( + "find", + new Parameter( + "find", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + false, + false, + sessionMethodTests.get(2)))), + Arguments.of( + named( + "persist", + new Parameter( + "persist", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + false, + true, + sessionMethodTests.get(3)))), + Arguments.of( + named( + "merge", + new Parameter( + "merge", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + true, + true, + sessionMethodTests.get(4)))), + Arguments.of( + named( + "remove", + new Parameter( + "delete", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + true, + true, + sessionMethodTests.get(5))))); + } + + private static Stream provideAttachesStateParameters() { + List> queryBuildMethods = + Arrays.asList( + em -> em.createQuery("from Value"), + em -> em.createNamedQuery("TestNamedQuery"), + em -> em.createNativeQuery("SELECT * FROM Value")); + + return Stream.of( + Arguments.of( + named( + "createQuery", + new Parameter( + "createQuery", + "SELECT io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + queryBuildMethods.get(0)))), + Arguments.of( + named( + "getNamedQuery", + new Parameter( + "getNamedQuery", + "SELECT io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + queryBuildMethods.get(1)))), + Arguments.of( + named( + "createSQLQuery", + new Parameter("createSQLQuery", "SELECT Value", queryBuildMethods.get(2))))); + } + + private static class Parameter { + + Parameter(String methodName, String resource, Function queryBuildMethod) { + this.methodName = methodName; + this.resource = resource; + this.attach = false; + this.flushOnCommit = false; + this.sessionMethodTest = null; + this.queryBuildMethod = queryBuildMethod; + } + + Parameter( + String methodName, + String resource, + boolean attach, + boolean flushOnCommit, + BiConsumer sessionMethodTest) { + this.methodName = methodName; + this.resource = resource; + this.attach = attach; + this.flushOnCommit = flushOnCommit; + this.sessionMethodTest = sessionMethodTest; + this.queryBuildMethod = null; + } + + public final String methodName; + public final String resource; + public final boolean attach; + public final boolean flushOnCommit; + public final BiConsumer sessionMethodTest; + public final Function queryBuildMethod; + } + + private static SpanDataAssert assertClientSpan(SpanDataAssert span, SpanData parent) { + return span.hasKind(SpanKind.CLIENT) + .hasParent(parent) + .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")); + } + + private static SpanDataAssert assertClientSpan( + SpanDataAssert span, SpanData parent, String spanName) { + return span.hasName(spanName) + .hasKind(SpanKind.CLIENT) + .hasParent(parent) + .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")); + } + + private static SpanDataAssert assertSessionSpan( + SpanDataAssert span, SpanData parent, String spanName) { + return span.hasName(spanName) + .hasKind(SpanKind.INTERNAL) + .hasParent(parent) + .hasAttributesSatisfyingExactly( + satisfies( + AttributeKey.stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))); + } + + private static SpanDataAssert assertTransactionCommitSpan( + SpanDataAssert span, SpanData parent, String sessionId) { + return span.hasName("Transaction.commit") + .hasKind(SpanKind.INTERNAL) + .hasParent(parent) + .hasAttributesSatisfyingExactly( + equalTo(AttributeKey.stringKey("hibernate.session_id"), sessionId)); + } +} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/ProcedureCallTest.java b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/ProcedureCallTest.java new file mode 100644 index 0000000000..7ea9a34683 --- /dev/null +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/ProcedureCallTest.java @@ -0,0 +1,188 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hibernate.v6_0; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import jakarta.persistence.ParameterMode; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; +import org.hibernate.procedure.ProcedureCall; +import org.hibernate.query.procedure.ProcedureParameter; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class ProcedureCallTest { + protected static SessionFactory sessionFactory; + protected static List prepopulated; + + @RegisterExtension + protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @BeforeAll + static void setup() throws SQLException { + sessionFactory = + new Configuration().configure("procedure-call-hibernate.cfg.xml").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 < 2; i++) { + prepopulated.add(new Value("Hello :) " + i)); + writer.persist(prepopulated.get(i)); + } + writer.getTransaction().commit(); + writer.close(); + + // Create a stored procedure. + Connection conn = DriverManager.getConnection("jdbc:hsqldb:mem:test", "sa", "1"); + Statement stmt = conn.createStatement(); + stmt.execute( + "CREATE PROCEDURE TEST_PROC() MODIFIES SQL DATA BEGIN ATOMIC INSERT INTO Value VALUES (420, 'fred'); END"); + stmt.close(); + conn.close(); + } + + @AfterAll + static void cleanup() { + if (sessionFactory != null) { + sessionFactory.close(); + } + } + + @Test + void testProcedureCall() { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + + ProcedureCall call = session.createStoredProcedureCall("TEST_PROC"); + call.getOutputs(); + + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(4) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + span.hasName("ProcedureCall.getOutputs TEST_PROC") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + satisfies( + AttributeKey.stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("CALL test.TEST_PROC") + .hasKind(SpanKind.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:"), + equalTo(SemanticAttributes.DB_STATEMENT, "{call TEST_PROC()}"), + equalTo(SemanticAttributes.DB_OPERATION, "CALL")), + span -> + span.hasName("Transaction.commit") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + AttributeKey.stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id")))))); + } + + @Test + void testFailingProcedureCall() { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + + ProcedureCall call = session.createStoredProcedureCall("TEST_PROC"); + ProcedureParameter parameterRegistration = + call.registerParameter("nonexistent", Long.class, ParameterMode.IN); + call.setParameter(parameterRegistration, 420L); + try { + call.getOutputs(); + } catch (RuntimeException e) { + // We expected this. + } + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(3) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + span.hasName("ProcedureCall.getOutputs TEST_PROC") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)) + .hasStatus(StatusData.error()) + .hasEventsSatisfyingExactly( + event -> + event + .hasName("exception") + .hasAttributesSatisfyingExactly( + equalTo( + AttributeKey.stringKey("exception.type"), + "org.hibernate.exception.SQLGrammarException"), + satisfies( + AttributeKey.stringKey("exception.message"), + val -> + val.startsWith("could not prepare statement")), + satisfies( + AttributeKey.stringKey("exception.stacktrace"), + val -> val.isNotNull()))) + .hasAttributesSatisfyingExactly( + satisfies( + AttributeKey.stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + span.hasName("Transaction.commit") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)) + .hasAttributesSatisfyingExactly( + equalTo( + AttributeKey.stringKey("hibernate.session_id"), + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id")))))); + } +} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/SessionTest.java b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/SessionTest.java new file mode 100644 index 0000000000..dd10fceced --- /dev/null +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/SessionTest.java @@ -0,0 +1,845 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hibernate.v6_0; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Named.named; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.stream.Stream; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.ReplicationMode; +import org.hibernate.Session; +import org.hibernate.StatelessSession; +import org.hibernate.UnknownEntityTypeException; +import org.hibernate.query.SelectionQuery; +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; + +@SuppressWarnings("deprecation") // testing instrumentation of deprecated class +public class SessionTest extends AbstractHibernateTest { + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideHibernateActionParameters") + void testHibernateAction(Parameter parameter) { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + try { + parameter.sessionMethodTest.accept(session, prepopulated.get(0)); + } catch (RuntimeException e) { + // We expected this, we should see the error field set on the span. + } + session.getTransaction().commit(); + session.close(); + }); + assertTraces(parameter); + } + + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideHibernateActionWithStatelessSessionParameters") + void testHibernateActionStatelessSession(Parameter parameter) { + testing.runWithSpan( + "parent", + () -> { + StatelessSession session = sessionFactory.openStatelessSession(); + session.beginTransaction(); + try { + parameter.statelessSessionMethodTest.accept(session, prepopulated.get(0)); + + } catch (RuntimeException e) { + // We expected this, we should see the error field set on the span. + } + session.getTransaction().commit(); + session.close(); + }); + assertTraces(parameter); + } + + private static void assertTraces(Parameter parameter) { + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(4) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + assertSessionSpan( + span, + trace.getSpan(0), + "Session." + parameter.methodName + " " + parameter.resource), + span -> assertClientSpan(span, trace.getSpan(1)), + span -> + assertSpanWithSessionId( + span, + trace.getSpan(0), + "Transaction.commit", + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))))); + } + + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideHibernateReplicateParameters") + void testHibernateReplicate(Parameter parameter) { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + try { + parameter.sessionMethodTest.accept(session, prepopulated.get(0)); + } catch (RuntimeException e) { + // We expected this, we should see the error field set on the span. + } + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(5) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + assertSessionSpan( + span, + trace.getSpan(0), + "Session." + parameter.methodName + " " + parameter.resource), + span -> assertClientSpan(span, trace.getSpan(1), "SELECT"), + span -> + assertSpanWithSessionId( + span, + trace.getSpan(0), + "Transaction.commit", + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))), + span -> assertClientSpan(span, trace.getSpan(3)))); + } + + @Test + void testHibernateFailedReplicate() { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + try { + session.replicate( + Long.valueOf(123) /* Not a valid entity */, ReplicationMode.OVERWRITE); + } catch (RuntimeException e) { + // We expected this, we should see the error field set on the span. + } + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(3) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + span.hasName("Session.replicate java.lang.Long") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)) + .hasStatus(StatusData.error()) + .hasException( + new UnknownEntityTypeException( + "Unable to locate persister: java.lang.Long")) + .hasAttributesSatisfyingExactly( + satisfies( + AttributeKey.stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))), + span -> + assertSpanWithSessionId( + span, + trace.getSpan(0), + "Transaction.commit", + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))))); + } + + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideHibernateCommitActionParameters") + void testHibernateCommitAction(Parameter parameter) { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + try { + parameter.sessionMethodTest.accept(session, prepopulated.get(0)); + } catch (RuntimeException e) { + // We expected this, we should see the error field set on the span. + } + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(4) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> + assertSessionSpan( + span, + trace.getSpan(0), + "Session." + parameter.methodName + " " + parameter.resource), + span -> + assertSpanWithSessionId( + span, + trace.getSpan(0), + "Transaction.commit", + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))), + span -> assertClientSpan(span, trace.getSpan(2)))); + } + + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("provideAttachesStateToQueryParameters") + void testAttachesStateToQuery(Parameter parameter) { + testing.runWithSpan( + "parent", + () -> { + Session session = sessionFactory.openSession(); + session.beginTransaction(); + SelectionQuery query = parameter.queryBuildMethod.apply(session); + query.list(); + session.getTransaction().commit(); + session.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(4) + .hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasKind(SpanKind.INTERNAL).hasNoParent(), + span -> assertSessionSpan(span, trace.getSpan(0), parameter.resource), + span -> + span.hasKind(SpanKind.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)), + equalTo(SemanticAttributes.DB_OPERATION, "SELECT"), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")), + span -> + assertSpanWithSessionId( + span, + trace.getSpan(0), + "Transaction.commit", + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))))); + } + + @Test + void testHibernateOverlappingSessions() { + AtomicReference sessionId1 = new AtomicReference<>(); + AtomicReference sessionId2 = new AtomicReference<>(); + AtomicReference sessionId3 = new AtomicReference<>(); + + testing.runWithSpan( + "overlapping Sessions", + () -> { + Session session1 = sessionFactory.openSession(); + session1.beginTransaction(); + StatelessSession session2 = sessionFactory.openStatelessSession(); + Session session3 = sessionFactory.openSession(); + + Value value1 = new Value("Value 1"); + session1.save(value1); + session2.insert(new Value("Value 2")); + session3.save(new Value("Value 3")); + session1.delete(value1); + + session2.close(); + session1.getTransaction().commit(); + session1.close(); + session3.close(); + }); + + testing.waitAndAssertTraces( + trace -> + trace + .hasSize(9) + .hasSpansSatisfyingExactly( + span -> span.hasName("overlapping Sessions"), + span -> { + assertSessionSpan( + span, + trace.getSpan(0), + "Session.save io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value"); + sessionId1.set( + trace + .getSpan(1) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))); + }, + span -> { + assertSessionSpan( + span, + trace.getSpan(0), + "Session.insert io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value"); + sessionId2.set( + trace + .getSpan(2) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))); + }, + span -> assertClientSpan(span, trace.getSpan(2), "INSERT"), + span -> { + assertSessionSpan( + span, + trace.getSpan(0), + "Session.save io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value"); + sessionId3.set( + trace + .getSpan(4) + .getAttributes() + .get(AttributeKey.stringKey("hibernate.session_id"))); + }, + span -> + assertSpanWithSessionId( + span, + trace.getSpan(0), + "Session.delete io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + sessionId1.get()), + span -> + assertSpanWithSessionId( + span, trace.getSpan(0), "Transaction.commit", sessionId1.get()), + span -> assertClientSpan(span, trace.getSpan(6), "INSERT"), + span -> assertClientSpan(span, trace.getSpan(6), "DELETE"))); + + assertNotEquals(sessionId1.get(), sessionId2.get()); + assertNotEquals(sessionId2.get(), sessionId3.get()); + assertNotEquals(sessionId1.get(), sessionId3.get()); + } + + private static Stream provideHibernateActionParameters() { + List> sessionMethodTests = + Arrays.asList( + (session, val) -> session.lock(val, LockMode.READ), + (session, val) -> session.lock("Value", val, LockMode.READ), + (session, val) -> session.lock(null, val, LockMode.READ), + (session, val) -> session.buildLockRequest(LockOptions.READ).lock(val), + (session, val) -> session.refresh(val), + (session, val) -> session.refresh("Value", val), + (session, val) -> + session.get( + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", val.getId()), + (session, val) -> session.get(Value.class, val.getId())); + + return Stream.of( + Arguments.of( + named( + "lock", + new Parameter( + "lock", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(0), + null))), + Arguments.of( + named( + "lock with entity name", + new Parameter("lock", "Value", null, sessionMethodTests.get(1), null))), + Arguments.of( + named( + "lock with null name", + new Parameter( + "lock", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(2), + null))), + Arguments.of( + named( + "buildLockRequest", + new Parameter( + "lock", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(3), + null))), + Arguments.of( + named( + "refresh", + new Parameter( + "refresh", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(4), + null))), + Arguments.of( + named( + "refresh with entity name", + new Parameter("refresh", "Value", null, sessionMethodTests.get(5), null))), + Arguments.of( + named( + "get with entity name", + new Parameter( + "get", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(6), + null))), + Arguments.of( + named( + "get with entity class", + new Parameter( + "get", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(7), + null)))); + } + + private static Stream provideHibernateActionWithStatelessSessionParameters() { + + List> statelessSessionMethodTests = + Arrays.asList( + (statelessSession, val) -> statelessSession.refresh(val), + (statelessSession, val) -> + statelessSession.refresh( + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", val), + (statelessSession, val) -> + statelessSession.get( + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", val.getId()), + (statelessSession, val) -> statelessSession.get(Value.class, val.getId()), + (statelessSession, val) -> statelessSession.insert(new Value("insert me")), + (statelessSession, val) -> + statelessSession.insert( + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + new Value("insert me")), + (statelessSession, val) -> statelessSession.insert(null, new Value("insert me")), + (statelessSession, val) -> { + val.setName("New name"); + statelessSession.update(val); + }, + (statelessSession, val) -> { + val.setName("New name"); + statelessSession.update( + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", val); + }, + (statelessSession, val) -> { + statelessSession.delete(val); + prepopulated.remove(val); + }, + (statelessSession, val) -> { + statelessSession.delete( + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", val); + prepopulated.remove(val); + }); + + return Stream.of( + Arguments.of( + named( + "refresh", + new Parameter( + "refresh", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(0)))), + Arguments.of( + named( + "refresh with entity name", + new Parameter( + "refresh", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(1)))), + Arguments.of( + named( + "get with entity name", + new Parameter( + "get", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(2)))), + Arguments.of( + named( + "get with entity class", + new Parameter( + "get", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(3)))), + Arguments.of( + named( + "insert", + new Parameter( + "insert", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(4)))), + Arguments.of( + named( + "insert with entity name", + new Parameter( + "insert", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(5)))), + Arguments.of( + named( + "insert with null entity name", + new Parameter( + "insert", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(6)))), + Arguments.of( + named( + "update (StatelessSession)", + new Parameter( + "update", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(7)))), + Arguments.of( + named( + "update with entity name (StatelessSession)", + new Parameter( + "update", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(8)))), + Arguments.of( + named( + "delete (Session)", + new Parameter( + "delete", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(9)))), + Arguments.of( + named( + "delete with entity name (Session)", + new Parameter( + "delete", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + null, + statelessSessionMethodTests.get(10))))); + } + + private static Stream provideHibernateReplicateParameters() { + List> sessionMethodTests = + Arrays.asList( + (session, val) -> { + Value replicated = new Value(val.getName() + " replicated"); + replicated.setId(val.getId()); + session.replicate(replicated, ReplicationMode.OVERWRITE); + }, + (session, val) -> { + Value replicated = new Value(val.getName() + " replicated"); + replicated.setId(val.getId()); + session.replicate("Value", replicated, ReplicationMode.OVERWRITE); + }); + + return Stream.of( + Arguments.of( + named( + "replicate", + new Parameter( + "replicate", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(0), + null))), + Arguments.of( + named( + "replicate by entityName", + new Parameter("replicate", "Value", null, sessionMethodTests.get(1), null)))); + } + + private static Stream provideHibernateCommitActionParameters() { + List> sessionMethodTests = + Arrays.asList( + (session, val) -> session.save(new Value("Another value")), + (session, val) -> session.save("Value", new Value("Another value")), + (session, val) -> session.saveOrUpdate(new Value("Value")), + (session, val) -> session.saveOrUpdate("Value", new Value("Value")), + (session, val) -> { + val.setName("New name"); + session.saveOrUpdate("Value", val); + }, + (session, val) -> session.merge(new Value("merge me in")), + (session, val) -> session.merge("Value", new Value("merge me in")), + (session, val) -> session.persist(new Value("merge me in")), + (session, val) -> session.persist("Value", new Value("merge me in")), + (session, val) -> session.persist(null, new Value("merge me in")), + (session, val) -> { + val.setName("New name"); + session.update(val); + }, + (session, val) -> { + val.setName("New name"); + session.update("Value", val); + }, + (session, val) -> { + session.delete(val); + prepopulated.remove(val); + }, + (session, val) -> { + session.delete("Value", val); + prepopulated.remove(val); + }); + + return Stream.of( + Arguments.of( + named( + "save", + new Parameter( + "save", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(0), + null))), + Arguments.of( + named( + "save with entity name", + new Parameter("save", "Value", null, sessionMethodTests.get(1), null))), + Arguments.of( + named( + "saveOrUpdate save", + new Parameter( + "saveOrUpdate", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(2), + null))), + Arguments.of( + named( + "saveOrUpdate save with entity name", + new Parameter("saveOrUpdate", "Value", null, sessionMethodTests.get(3), null))), + Arguments.of( + named( + "saveOrUpdate update with entity name", + new Parameter("saveOrUpdate", "Value", null, sessionMethodTests.get(4), null))), + Arguments.of( + named( + "merge", + new Parameter( + "merge", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(5), + null))), + Arguments.of( + named( + "merge with entity name", + new Parameter("merge", "Value", null, sessionMethodTests.get(6), null))), + Arguments.of( + named( + "persist", + new Parameter( + "persist", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(7), + null))), + Arguments.of( + named( + "persist with entity name", + new Parameter("persist", "Value", null, sessionMethodTests.get(8), null))), + Arguments.of( + named( + "persist with null entity name", + new Parameter( + "persist", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(9), + null))), + Arguments.of( + named( + "update (Session)", + new Parameter( + "update", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(10), + null))), + Arguments.of( + named( + "update by entityName (Session)", + new Parameter("update", "Value", null, sessionMethodTests.get(11), null))), + Arguments.of( + named( + "delete (Session)", + new Parameter( + "delete", + "io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + null, + sessionMethodTests.get(12), + null))), + Arguments.of( + named( + "delete by entityName (Session)", + new Parameter("delete", "Value", null, sessionMethodTests.get(13), null)))); + } + + private static Stream provideAttachesStateToQueryParameters() { + List>> queryBuildMethods = + Arrays.asList( + session -> session.createQuery("from Value"), + session -> session.getNamedQuery("TestNamedQuery"), + session -> session.createNativeQuery("SELECT * FROM Value"), + session -> session.createSelectionQuery("from Value")); + + return Stream.of( + Arguments.of( + named( + "createQuery", + new Parameter( + "createQuery", + "SELECT io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + queryBuildMethods.get(0), + null, + null))), + Arguments.of( + named( + "getNamedQuery", + new Parameter( + "getNamedQuery", + "SELECT io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + queryBuildMethods.get(1), + null, + null))), + Arguments.of( + named( + "createNativeQuery", + new Parameter( + "createNativeQuery", "SELECT Value", queryBuildMethods.get(2), null, null))), + Arguments.of( + named( + "createSelectionQuery", + new Parameter( + "createSelectionQuery", + "SELECT io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value", + queryBuildMethods.get(3), + null, + null)))); + } + + private static class Parameter { + Parameter( + String methodName, + String resource, + Function> queryBuildMethod, + BiConsumer sessionMethodTest, + BiConsumer statelessSessionMethodTest) { + this.methodName = methodName; + this.resource = resource; + this.sessionMethodTest = sessionMethodTest; + this.queryBuildMethod = queryBuildMethod; + this.statelessSessionMethodTest = statelessSessionMethodTest; + } + + public final String methodName; + public final String resource; + public final Function> queryBuildMethod; + public final BiConsumer sessionMethodTest; + public final BiConsumer statelessSessionMethodTest; + } + + private static SpanDataAssert assertSessionSpan( + SpanDataAssert span, SpanData parent, String spanName) { + return span.hasName(spanName) + .hasKind(SpanKind.INTERNAL) + .hasParent(parent) + .hasAttributesSatisfyingExactly( + satisfies( + AttributeKey.stringKey("hibernate.session_id"), + val -> val.isInstanceOf(String.class))); + } + + private static SpanDataAssert assertSpanWithSessionId( + SpanDataAssert span, SpanData parent, String spanName, String sessionId) { + return span.hasName(spanName) + .hasKind(SpanKind.INTERNAL) + .hasParent(parent) + .hasAttributesSatisfyingExactly( + equalTo(AttributeKey.stringKey("hibernate.session_id"), sessionId)); + } + + private static SpanDataAssert assertClientSpan(SpanDataAssert span, SpanData parent) { + return span.hasKind(SpanKind.CLIENT) + .hasParent(parent) + .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")); + } + + private static SpanDataAssert assertClientSpan( + SpanDataAssert span, SpanData parent, String verb) { + return span.hasName(verb.concat(" db1.Value")) + .hasKind(SpanKind.CLIENT) + .hasParent(parent) + .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, + stringAssert -> stringAssert.startsWith(verb.toLowerCase())), + equalTo(SemanticAttributes.DB_OPERATION, verb), + equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")); + } +} diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/Value.java b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/Value.java similarity index 92% rename from instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/Value.java rename to instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/Value.java index aeeccb474a..2e33a22d0f 100644 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/Value.java +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hibernate/v6_0/Value.java @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +package io.opentelemetry.javaagent.instrumentation.hibernate.v6_0; + import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/META-INF/persistence.xml b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/META-INF/persistence.xml index 3cb3eed07e..8a76a2ce2d 100644 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/META-INF/persistence.xml +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/META-INF/persistence.xml @@ -4,7 +4,7 @@ version="2.0"> - Value + io.opentelemetry.javaagent.instrumentation.hibernate.v6_0.Value true @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/hibernate.cfg.xml b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/hibernate.cfg.xml index fe5e5de6b1..a57f93094a 100644 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/hibernate.cfg.xml +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/hibernate.cfg.xml @@ -22,7 +22,7 @@ create - + diff --git a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/procedure-call-hibernate.cfg.xml b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/procedure-call-hibernate.cfg.xml index bbc3827dda..0c9752bb18 100644 --- a/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/procedure-call-hibernate.cfg.xml +++ b/instrumentation/hibernate/hibernate-6.0/javaagent/src/test/resources/procedure-call-hibernate.cfg.xml @@ -17,7 +17,7 @@ create - +