Convert hibernate-4.0 groovy tests - part 1 (#9211)

This commit is contained in:
Jay DeLuca 2023-08-17 07:02:40 -04:00 committed by GitHub
parent c640169388
commit 4bdfbc95d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 913 additions and 615 deletions

View File

@ -32,6 +32,8 @@ dependencies {
testImplementation("org.hibernate:hibernate-core:4.0.0.Final")
testImplementation("org.hibernate:hibernate-entitymanager:4.0.0.Final")
testImplementation("org.javassist:javassist:3.28.0-GA")
}
val latestDepTest = findProperty("testLatestDeps") as Boolean

View File

@ -4,6 +4,7 @@
*/
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

View File

@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.javaagent.instrumentation.hibernate.v4_0.Value
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import org.hibernate.Criteria
import org.hibernate.Session
@ -39,7 +40,7 @@ class CriteriaTest extends AbstractHibernateTest {
}
}
span(1) {
name "Criteria.$methodName Value"
name "Criteria.$methodName $Value.name"
kind INTERNAL
childOf span(0)
attributes {

View File

@ -3,6 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.javaagent.instrumentation.hibernate.v4_0.Value
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import spock.lang.Shared
import spock.lang.Unroll
@ -143,23 +144,23 @@ class EntityManagerTest extends AbstractHibernateTest {
where:
testName | methodName | resource | attach | flushOnCommit | sessionMethodTest
"lock" | "lock" | "Value" | true | false | { em, val ->
"lock" | "lock" | Value.name | true | false | { em, val ->
em.lock(val, LockModeType.PESSIMISTIC_READ)
}
"refresh" | "refresh" | "Value" | true | false | { em, val ->
"refresh" | "refresh" | Value.name | true | false | { em, val ->
em.refresh(val)
}
"find" | "(get|find)" | "Value" | false | false | { em, val ->
"find" | "(get|find)" | Value.name | false | false | { em, val ->
em.find(Value, val.getId())
}
"persist" | "persist" | "Value" | false | true | { em, val ->
"persist" | "persist" | Value.name | false | true | { em, val ->
em.persist(new Value("insert me"))
}
"merge" | "merge" | "Value" | true | true | { em, val ->
"merge" | "merge" | Value.name | true | true | { em, val ->
val.setName("New name")
em.merge(val)
}
"remove" | "delete" | "Value" | true | true | { em, val ->
"remove" | "delete" | Value.name | true | true | { em, val ->
em.remove(val)
}
}

View File

@ -1,605 +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.MappingException
import org.hibernate.Query
import org.hibernate.ReplicationMode
import org.hibernate.Session
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(MappingException, "Unknown entity: 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()
Query 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") }
"createSQLQuery" | "SELECT Value" | { sess -> sess.createSQLQuery("SELECT * 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
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.hibernate.v4_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;
abstract class AbstractHibernateTest {
@RegisterExtension
protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
protected static SessionFactory sessionFactory;
protected static List<Value> prepopulated;
@BeforeAll
@SuppressWarnings("deprecation") // buildSessionFactory
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.save(prepopulated.get(i));
}
writer.getTransaction().commit();
writer.close();
}
@AfterAll
static void cleanUp() {
if (sessionFactory != null) {
sessionFactory.close();
}
}
}

View File

@ -0,0 +1,846 @@
/*
* 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.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.ThrowableAssert.catchThrowable;
import static org.junit.jupiter.api.Named.named;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
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") // 'lock' is a deprecated method in the Session class
class SessionTest extends AbstractHibernateTest {
@ParameterizedTest
@MethodSource("provideArgumentsHibernateAction")
void testHibernateAction(Parameter parameter) {
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
session.beginTransaction();
parameter.sessionMethodTest.accept(session, prepopulated.get(0));
session.getTransaction().commit();
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
span ->
span.hasName("Session." + parameter.methodName + " " + Value.class.getName())
.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"))))));
}
private static Stream<Arguments> provideArgumentsHibernateAction() {
return Stream.of(
Arguments.of(
named(
"lock",
new Parameter(
"lock",
(Session session, Value val) -> session.lock(val, LockMode.READ),
null))),
Arguments.of(
named(
"lock with entity name",
new Parameter(
"lock",
(Session session, Value val) ->
session.lock(Value.class.getName(), val, LockMode.READ),
null))),
Arguments.of(
named(
"lock with null name",
new Parameter(
"lock",
(Session session, Value val) -> session.lock(null, val, LockMode.READ),
null))),
Arguments.of(
named(
"buildLockRequest",
new Parameter(
"lock",
(Session session, Value val) ->
session.buildLockRequest(LockOptions.READ).lock(val),
null))),
Arguments.of(named("refresh", new Parameter("refresh", Session::refresh, null))),
Arguments.of(
named(
"refresh with entity name",
new Parameter(
"refresh",
(Session session, Value val) -> session.refresh(Value.class.getName(), val),
null))),
Arguments.of(
named(
"get with entity name",
new Parameter(
"get",
(Session session, Value val) -> session.get(Value.class.getName(), val.getId()),
null))),
Arguments.of(
named(
"get with entity class",
new Parameter(
"get",
(Session session, Value val) -> session.get(Value.class, val.getId()),
null))));
}
@ParameterizedTest
@MethodSource("provideArgumentsHibernateActionStateless")
void testHibernateActionStateless(Parameter parameter) {
testing.runWithSpan(
"parent",
() -> {
StatelessSession session = sessionFactory.openStatelessSession();
session.beginTransaction();
parameter.statelessSessionMethodTest.accept(session, prepopulated.get(0));
session.getTransaction().commit();
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
span ->
span.hasName("Session." + parameter.methodName + " " + Value.class.getName())
.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"))))));
}
private static Stream<Arguments> provideArgumentsHibernateActionStateless() {
return Stream.of(
Arguments.of(named("refresh", new Parameter("refresh", null, StatelessSession::refresh))),
Arguments.of(
named(
"refresh with entity name",
new Parameter(
"refresh",
null,
(StatelessSession session, Value val) ->
session.refresh(Value.class.getName(), val)))),
Arguments.of(
named(
"get with entity name",
new Parameter(
"get",
null,
(StatelessSession session, Value val) ->
session.get(Value.class.getName(), val.getId())))),
Arguments.of(
named(
"get with entity class",
new Parameter(
"get",
null,
(StatelessSession session, Value val) ->
session.get(Value.class, val.getId())))),
Arguments.of(
named(
"insert",
new Parameter(
"insert",
null,
(StatelessSession session, Value val) ->
session.insert(new Value("insert me"))))),
Arguments.of(
named(
"insert with entity name",
new Parameter(
"insert",
null,
(StatelessSession session, Value val) ->
session.insert(Value.class.getName(), new Value("insert me"))))),
Arguments.of(
named(
"insert with null entity name",
new Parameter(
"insert",
null,
(StatelessSession session, Value val) ->
session.insert(null, new Value("insert me"))))),
Arguments.of(
named(
"update (StatelessSession)",
new Parameter(
"update",
null,
(StatelessSession session, Value val) -> {
val.setName("New name");
session.update(val);
}))),
Arguments.of(
named(
"update with entity name (StatelessSession)",
new Parameter(
"update",
null,
(StatelessSession session, Value val) -> {
val.setName("New name");
session.update(Value.class.getName(), val);
}))),
Arguments.of(
named(
"delete (Session)",
new Parameter(
"delete",
null,
(StatelessSession session, Value val) -> {
session.delete(val);
prepopulated.remove(val);
}))),
Arguments.of(
named(
"delete with entity name (Session)",
new Parameter(
"delete",
null,
(StatelessSession session, Value val) -> {
session.delete(Value.class.getName(), val);
prepopulated.remove(val);
}))));
}
@ParameterizedTest
@MethodSource("provideArgumentsHibernateReplicate")
void testHibernateReplicate(Parameter parameter) {
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
session.beginTransaction();
parameter.sessionMethodTest.accept(session, prepopulated.get(0));
session.getTransaction().commit();
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
span ->
span.hasName("Session." + parameter.methodName + " " + Value.class.getName())
.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")))),
span ->
span.hasKind(CLIENT)
.hasParent(trace.getSpan(3))
.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 Stream<Arguments> provideArgumentsHibernateReplicate() {
return Stream.of(
Arguments.of(
named(
"replicate",
new Parameter(
"replicate",
(Session session, Value val) -> {
Value replicated = new Value(val.getName() + " replicated");
replicated.setId(val.getId());
session.replicate(replicated, ReplicationMode.OVERWRITE);
},
null))),
Arguments.of(
named(
"replicate by entity name",
new Parameter(
"replicate",
(Session session, Value val) -> {
Value replicated = new Value(val.getName() + " replicated");
replicated.setId(val.getId());
session.replicate(
Value.class.getName(), replicated, ReplicationMode.OVERWRITE);
},
null))));
}
@Test
void testHibernateFailedReplicate() {
Throwable mappingException =
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
session.beginTransaction();
Throwable exception =
catchThrowable(
() -> {
session.replicate(123L /* Not a valid entity */, ReplicationMode.OVERWRITE);
});
session.getTransaction().commit();
session.close();
return exception;
});
assertThat(mappingException.getClass()).isEqualTo(MappingException.class);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
span ->
span.hasName("Session.replicate java.lang.Long")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasStatus(StatusData.error())
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id"))))
.hasException(mappingException),
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("provideArgumentsHibernateCommitAction")
void testHibernateCommitAction(Parameter parameter) {
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
session.beginTransaction();
parameter.sessionMethodTest.accept(session, prepopulated.get(0));
session.getTransaction().commit();
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
span ->
span.hasName("Session." + parameter.methodName + " " + Value.class.getName())
.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(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id")))),
span ->
span.hasKind(CLIENT)
.hasParent(trace.getSpan(2))
.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 Stream<Arguments> provideArgumentsHibernateCommitAction() {
return Stream.of(
Arguments.of(
named(
"save",
new Parameter(
"save",
(Session session, Value val) -> {
session.save(new Value("Another value"));
},
null))),
Arguments.of(
named(
"save with entity name",
new Parameter(
"save",
(Session session, Value val) -> {
session.save(Value.class.getName(), new Value("Another value"));
},
null))),
Arguments.of(
named(
"saveOrUpdate save",
new Parameter(
"saveOrUpdate",
(Session session, Value val) -> {
session.saveOrUpdate(new Value("Value"));
},
null))),
Arguments.of(
named(
"saveOrUpdate save with entity name",
new Parameter(
"saveOrUpdate",
(Session session, Value val) -> {
session.saveOrUpdate(Value.class.getName(), new Value("Value"));
},
null))),
Arguments.of(
named(
"saveOrUpdate update with entity name",
new Parameter(
"saveOrUpdate",
(Session session, Value val) -> {
val.setName("New name");
session.saveOrUpdate(Value.class.getName(), val);
},
null))),
Arguments.of(
named(
"merge",
new Parameter(
"merge",
(Session session, Value val) -> {
session.merge(new Value("merge me in"));
},
null))),
Arguments.of(
named(
"merge with entity name",
new Parameter(
"merge",
(Session session, Value val) -> {
session.merge(Value.class.getName(), new Value("merge me in"));
},
null))),
Arguments.of(
named(
"persist",
new Parameter(
"persist",
(Session session, Value val) -> {
session.persist(new Value("merge me in"));
},
null))),
Arguments.of(
named(
"persist with entity name",
new Parameter(
"persist",
(Session session, Value val) -> {
session.persist(Value.class.getName(), new Value("merge me in"));
},
null))),
Arguments.of(
named(
"persist with null entity name",
new Parameter(
"persist",
(Session session, Value val) -> {
session.persist(null, new Value("merge me in"));
},
null))),
Arguments.of(
named(
"update (Session)",
new Parameter(
"update",
(Session session, Value val) -> {
val.setName("New name");
session.update(val);
},
null))),
Arguments.of(
named(
"update by entityName (Session)",
new Parameter(
"update",
(Session session, Value val) -> {
val.setName("New name");
session.update(Value.class.getName(), val);
},
null))),
Arguments.of(
named(
"delete (Session)",
new Parameter(
"delete",
(Session session, Value val) -> {
session.delete(val);
prepopulated.remove(val);
},
null))),
Arguments.of(
named(
"delete by entityName (Session)",
new Parameter(
"delete",
(Session session, Value val) -> {
session.delete(Value.class.getName(), val);
prepopulated.remove(val);
},
null))));
}
@ParameterizedTest
@MethodSource("provideArgumentsStateQuery")
void testAttachesStateToQueryCreated(Consumer<Session> queryBuilder) {
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
session.beginTransaction();
queryBuilder.accept(session);
session.getTransaction().commit();
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
span ->
span.hasName("SELECT 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"))))));
}
private static Stream<Arguments> provideArgumentsStateQuery() {
return Stream.of(
Arguments.of(
named(
"createQuery",
((Consumer<Session>) session -> session.createQuery("from Value").list())),
Arguments.of(
named(
"getNamedQuery",
((Consumer<Session>)
session -> session.getNamedQuery("TestNamedQuery").list())),
Arguments.of(
named(
"createSQLQuery",
(Consumer<Session>)
session -> session.createSQLQuery("SELECT * FROM Value").list())))));
}
@Test
void testHibernateOverlappingSessions() {
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();
});
AtomicReference<String> sessionId1 = new AtomicReference<>();
AtomicReference<String> sessionId2 = new AtomicReference<>();
AtomicReference<String> sessionId3 = new AtomicReference<>();
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span -> span.hasName("overlapping Sessions"),
span -> {
span.hasName("Session.save " + Value.class.getName())
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class)));
sessionId1.set(
trace.getSpan(1).getAttributes().get(stringKey("hibernate.session_id")));
},
span -> {
span.hasName("Session.insert " + Value.class.getName())
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class)));
sessionId2.set(
trace.getSpan(2).getAttributes().get(stringKey("hibernate.session_id")));
},
span ->
span.hasName("INSERT db1.Value")
.hasKind(CLIENT)
.hasParent(trace.getSpan(2))
.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("insert")),
equalTo(SemanticAttributes.DB_OPERATION, "INSERT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")),
span -> {
span.hasName("Session.save " + Value.class.getName())
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class)));
sessionId3.set(
trace.getSpan(4).getAttributes().get(stringKey("hibernate.session_id")));
},
span ->
span.hasName("Session.delete " + Value.class.getName())
.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(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id")))),
span ->
span.hasName("INSERT db1.Value")
.hasKind(CLIENT)
.hasParent(trace.getSpan(6))
.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("insert")),
equalTo(SemanticAttributes.DB_OPERATION, "INSERT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")),
span ->
span.hasName("DELETE db1.Value")
.hasKind(CLIENT)
.hasParent(trace.getSpan(6))
.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("delete")),
equalTo(SemanticAttributes.DB_OPERATION, "DELETE"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Value"))));
assertThat(sessionId1.get()).isNotEqualTo(sessionId2.get());
assertThat(sessionId1.get()).isNotEqualTo(sessionId3.get());
assertThat(sessionId2.get()).isNotEqualTo(sessionId3.get());
}
private static class Parameter {
public final String methodName;
public final BiConsumer<Session, Value> sessionMethodTest;
public final BiConsumer<StatelessSession, Value> statelessSessionMethodTest;
public Parameter(
String methodName,
BiConsumer<Session, Value> sessionMethodTest,
BiConsumer<StatelessSession, Value> statelessSessionMethodTest) {
this.methodName = methodName;
this.sessionMethodTest = sessionMethodTest;
this.statelessSessionMethodTest = statelessSessionMethodTest;
}
}
}

View File

@ -3,6 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.hibernate.v4_0;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

View File

@ -4,7 +4,7 @@
version="2.0">
<persistence-unit name="test-pu">
<class>Value</class>
<class>io.opentelemetry.javaagent.instrumentation.hibernate.v4_0.Value</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>

View File

@ -22,7 +22,7 @@
<property name="hbm2ddl.auto">create</property>
<!-- Objects -->
<mapping class="Value"/>
<mapping class="io.opentelemetry.javaagent.instrumentation.hibernate.v4_0.Value"/>
</session-factory>