Convert Hibernate-4.0 groovy tests - part 3 (#9282)

This commit is contained in:
Jay DeLuca 2023-08-24 09:18:04 -04:00 committed by GitHub
parent 39244a6bc4
commit 27c8d00243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 678 additions and 634 deletions

View File

@ -42,9 +42,6 @@ testing {
val version5Test by registering(JvmTestSuite::class) { val version5Test by registering(JvmTestSuite::class) {
dependencies { dependencies {
sources { sources {
groovy {
setSrcDirs(listOf("src/test/groovy"))
}
java { java {
setSrcDirs(listOf("src/test/java")) setSrcDirs(listOf("src/test/java"))
} }

View File

@ -1,40 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.javaagent.instrumentation.hibernate.v4_0.Value
import org.hibernate.Session
import org.hibernate.SessionFactory
import org.hibernate.cfg.Configuration
import spock.lang.Shared
abstract class AbstractHibernateTest extends AgentInstrumentationSpecification {
@Shared
protected SessionFactory sessionFactory
@Shared
protected List<Value> 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()
}
}
}

View File

@ -1,206 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import org.hibernate.Query
import org.hibernate.Session
import static io.opentelemetry.api.trace.SpanKind.CLIENT
import static io.opentelemetry.api.trace.SpanKind.INTERNAL
class QueryTest extends AbstractHibernateTest {
def "test hibernate query.#queryMethodName single call"() {
setup:
// With Transaction
runWithSpan("parent") {
Session session = sessionFactory.openSession()
session.beginTransaction()
queryInteraction(session)
session.getTransaction().commit()
session.close()
}
// Without Transaction
if (!requiresTransaction) {
runWithSpan("parent2") {
Session session = sessionFactory.openSession()
queryInteraction(session)
session.close()
}
}
expect:
def sessionId
assertTraces(requiresTransaction ? 1 : 2) {
// With Transaction
trace(0, 4) {
span(0) {
name "parent"
kind INTERNAL
hasNoParent()
attributes {
}
}
span(1) {
name expectedSpanName
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" {
sessionId = it
it instanceof String
}
}
}
span(2) {
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "h2"
"$SemanticAttributes.DB_NAME" "db1"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:"
"$SemanticAttributes.DB_STATEMENT" String
"$SemanticAttributes.DB_OPERATION" String
"$SemanticAttributes.DB_SQL_TABLE" "Value"
}
}
span(3) {
name "Transaction.commit"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" sessionId
}
}
}
if (!requiresTransaction) {
// Without Transaction
trace(1, 3) {
span(0) {
name "parent2"
kind INTERNAL
hasNoParent()
attributes {
}
}
span(1) {
name expectedSpanName
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" String
}
}
span(2) {
name "SELECT db1.Value"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "h2"
"$SemanticAttributes.DB_NAME" "db1"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/^select /
"$SemanticAttributes.DB_OPERATION" "SELECT"
"$SemanticAttributes.DB_SQL_TABLE" "Value"
}
}
}
}
}
where:
queryMethodName | expectedSpanName | requiresTransaction | queryInteraction
"query/list" | "SELECT Value" | false | { sess ->
Query q = sess.createQuery("from Value")
q.list()
}
"query/executeUpdate" | "UPDATE Value" | true | { sess ->
Query q = sess.createQuery("update Value set name = :name")
q.setParameter("name", "alyx")
q.executeUpdate()
}
"query/uniqueResult" | "SELECT Value" | false | { sess ->
Query q = sess.createQuery("from Value where id = :id")
q.setParameter("id", 1L)
q.uniqueResult()
}
"iterate" | "SELECT Value" | false | { sess ->
Query q = sess.createQuery("from Value")
q.iterate()
}
"query/scroll" | "SELECT Value" | false | { sess ->
Query q = sess.createQuery("from Value")
q.scroll()
}
}
def "test hibernate query.iterate"() {
setup:
runWithSpan("parent") {
Session session = sessionFactory.openSession()
session.beginTransaction()
Query q = session.createQuery("from Value")
Iterator iterator = q.iterate()
while (iterator.hasNext()) {
iterator.next()
}
session.getTransaction().commit()
session.close()
}
expect:
def sessionId
assertTraces(1) {
trace(0, 4) {
span(0) {
name "parent"
kind INTERNAL
hasNoParent()
attributes {
}
}
span(1) {
name "SELECT Value"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" {
sessionId = it
it instanceof String
}
}
}
span(2) {
name "SELECT db1.Value"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "h2"
"$SemanticAttributes.DB_NAME" "db1"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "h2:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/^select /
"$SemanticAttributes.DB_OPERATION" "SELECT"
"$SemanticAttributes.DB_SQL_TABLE" "Value"
}
}
span(3) {
name "Transaction.commit"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" sessionId
}
}
}
}
}
}

View File

@ -1,385 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import org.hibernate.Version
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import spock.lang.Shared
import spring.jpa.Customer
import spring.jpa.CustomerRepository
import spring.jpa.PersistenceConfig
import static io.opentelemetry.api.trace.SpanKind.CLIENT
import static io.opentelemetry.api.trace.SpanKind.INTERNAL
class SpringJpaTest extends AgentInstrumentationSpecification {
@Shared
def context = new AnnotationConfigApplicationContext(PersistenceConfig)
@Shared
def repo = context.getBean(CustomerRepository)
def "test CRUD"() {
setup:
def isHibernate4 = Version.getVersionString().startsWith("4.")
def customer = new Customer("Bob", "Anonymous")
expect:
customer.id == null
!runWithSpan("parent") {
repo.findAll().iterator().hasNext()
}
def sessionId
assertTraces(1) {
trace(0, 4) {
span(0) {
name "parent"
kind INTERNAL
hasNoParent()
attributes {
}
}
span(1) {
name "SELECT Customer"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" {
sessionId = it
it instanceof String
}
}
}
span(2) {
name "SELECT test.Customer"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName(.*)from Customer(.*)/
"$SemanticAttributes.DB_OPERATION" "SELECT"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
span(3) {
name "Transaction.commit"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" sessionId
}
}
}
}
clearExportedData()
when:
runWithSpan("parent") {
repo.save(customer)
}
def savedId = customer.id
then:
customer.id != null
def sessionId2
assertTraces(1) {
trace(0, 4 + (isHibernate4 ? 0 : 1)) {
span(0) {
name "parent"
kind INTERNAL
hasNoParent()
attributes {
}
}
span(1) {
name "Session.persist spring.jpa.Customer"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" {
sessionId2 = it
it instanceof String
}
}
}
if (!isHibernate4) {
span(2) {
name "CALL test"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_STATEMENT" "call next value for hibernate_sequence"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_OPERATION" "CALL"
}
}
span(3) {
name "Transaction.commit"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" sessionId2
}
}
span(4) {
name "INSERT test.Customer"
kind CLIENT
childOf span(3)
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/insert into Customer \(.*\) values \(.*, \?, \?\)/
"$SemanticAttributes.DB_OPERATION" "INSERT"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
} else {
span(2) {
name "INSERT test.Customer"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/insert into Customer \(.*\) values \(.*, \?, \?\)/
"$SemanticAttributes.DB_OPERATION" "INSERT"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
span(3) {
name "Transaction.commit"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" sessionId2
}
}
}
}
}
clearExportedData()
when:
customer.firstName = "Bill"
runWithSpan("parent") {
repo.save(customer)
}
then:
customer.id == savedId
def sessionId3
assertTraces(1) {
trace(0, 5) {
span(0) {
name "parent"
kind INTERNAL
hasNoParent()
attributes {
}
}
span(1) {
name "Session.merge spring.jpa.Customer"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" {
sessionId3 = it
it instanceof String
}
}
}
span(2) {
name "SELECT test.Customer"
kind CLIENT
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)where ([^.]+)\.id( ?)=( ?)\?/
"$SemanticAttributes.DB_OPERATION" "SELECT"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
span(3) {
name "Transaction.commit"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" sessionId3
}
}
span(4) {
name "UPDATE test.Customer"
kind CLIENT
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" "update Customer set firstName=?, lastName=? where id=?"
"$SemanticAttributes.DB_OPERATION" "UPDATE"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
}
}
clearExportedData()
when:
customer = runWithSpan("parent") {
repo.findByLastName("Anonymous")[0]
}
then:
customer.id == savedId
customer.firstName == "Bill"
assertTraces(1) {
trace(0, 3) {
span(0) {
name "parent"
kind INTERNAL
hasNoParent()
attributes {
}
}
span(1) {
name "SELECT Customer"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" String
}
}
span(2) {
name "SELECT test.Customer"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)(where ([^.]+)\.lastName( ?)=( ?)\?|)/
"$SemanticAttributes.DB_OPERATION" "SELECT"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
}
}
clearExportedData()
when:
runWithSpan("parent") {
repo.delete(customer)
}
then:
assertTraces(1) {
trace(0, 6 + (isHibernate4 ? 0 : 1)) {
span(0) {
name "parent"
kind INTERNAL
hasNoParent()
attributes {
}
}
def offset = 0
if (!isHibernate4) {
offset = 2
span(1) {
name ~/Session.(get|find) spring.jpa.Customer/
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" String
}
}
span(2) {
name "SELECT test.Customer"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)where ([^.]+)\.id( ?)=( ?)\?/
"$SemanticAttributes.DB_OPERATION" "SELECT"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
}
span(1 + offset) {
name "Session.merge spring.jpa.Customer"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" String
}
}
if (isHibernate4) {
offset = 1
span(2) {
name "SELECT test.Customer"
kind CLIENT
childOf span(1)
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" ~/select ([^.]+)\.id([^,]*), ([^.]+)\.firstName([^,]*), ([^.]+)\.lastName (.*)from Customer (.*)where ([^.]+)\.id( ?)=( ?)\?/
"$SemanticAttributes.DB_OPERATION" "SELECT"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
}
span(2 + offset) {
name "Session.delete spring.jpa.Customer"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" String
}
}
span(3 + offset) {
name "Transaction.commit"
kind INTERNAL
childOf span(0)
attributes {
"hibernate.session_id" String
}
}
span(4 + offset) {
name "DELETE test.Customer"
kind CLIENT
attributes {
"$SemanticAttributes.DB_SYSTEM" "hsqldb"
"$SemanticAttributes.DB_NAME" "test"
"$SemanticAttributes.DB_USER" "sa"
"$SemanticAttributes.DB_CONNECTION_STRING" "hsqldb:mem:"
"$SemanticAttributes.DB_STATEMENT" "delete from Customer where id=?"
"$SemanticAttributes.DB_OPERATION" "DELETE"
"$SemanticAttributes.DB_SQL_TABLE" "Customer"
}
}
}
}
}
}

View File

@ -0,0 +1,222 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.instrumentation.hibernate.v4_0;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.api.trace.SpanKind.CLIENT;
import static io.opentelemetry.api.trace.SpanKind.INTERNAL;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static org.junit.jupiter.api.Named.named;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.hibernate.Session;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class QueryTest extends AbstractHibernateTest {
@Test
void testHibernateQueryExecuteUpdateWithTransaction() {
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
session.beginTransaction();
session
.createQuery("update Value set name = :name")
.setParameter("name", "alyx")
.executeUpdate();
session.getTransaction().commit();
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("UPDATE Value")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "h2"),
equalTo(SemanticAttributes.DB_NAME, "db1"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "h2:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val -> val.isInstanceOf(String.class)),
satisfies(
SemanticAttributes.DB_OPERATION,
val -> val.isInstanceOf(String.class)),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id"))))));
}
@ParameterizedTest
@MethodSource("providesArgumentsSingleCall")
void testHibernateQuerySingleCall(Parameter parameter) {
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
parameter.queryInteraction.accept(session);
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName(parameter.expectedSpanName)
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("SELECT db1.Value")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "h2"),
equalTo(SemanticAttributes.DB_NAME, "db1"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "h2:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT, val -> val.startsWith("select ")),
equalTo(SemanticAttributes.DB_OPERATION, "SELECT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Value"))));
}
private static Stream<Arguments> providesArgumentsSingleCall() {
return Stream.of(
Arguments.of(
named(
"query/list",
new Parameter("SELECT Value", sess -> sess.createQuery("from Value").list()))),
Arguments.of(
named(
"query/uniqueResult",
new Parameter(
"SELECT Value",
sess ->
sess.createQuery("from Value where id = :id")
.setParameter("id", 1L)
.uniqueResult()))),
Arguments.of(
named(
"iterate",
new Parameter("SELECT Value", sess -> sess.createQuery("from Value").iterate()))),
Arguments.of(
named(
"query/scroll",
new Parameter("SELECT Value", sess -> sess.createQuery("from Value").scroll()))));
}
@Test
void testHibernateQueryIterate() {
testing.runWithSpan(
"parent",
() -> {
Session session = sessionFactory.openSession();
session.beginTransaction();
@SuppressWarnings("unchecked")
Iterator<Value> iterator = session.createQuery("from Value").iterate();
while (iterator.hasNext()) {
iterator.next();
}
session.getTransaction().commit();
session.close();
});
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("SELECT Value")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("SELECT db1.Value")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "h2"),
equalTo(SemanticAttributes.DB_NAME, "db1"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "h2:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT, val -> val.startsWith("select ")),
equalTo(SemanticAttributes.DB_OPERATION, "SELECT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Value")),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id"))))));
}
private static class Parameter {
public final String expectedSpanName;
public final Consumer<Session> queryInteraction;
public Parameter(String expectedSpanName, Consumer<Session> queryInteraction) {
this.expectedSpanName = expectedSpanName;
this.queryInteraction = queryInteraction;
}
}
}

View File

@ -0,0 +1,456 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package spring.jpa;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import static io.opentelemetry.api.trace.SpanKind.CLIENT;
import static io.opentelemetry.api.trace.SpanKind.INTERNAL;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.util.regex.Pattern;
import org.hibernate.Version;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
class SpringJpaTest {
@RegisterExtension
protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(PersistenceConfig.class);
CustomerRepository repo = context.getBean(CustomerRepository.class);
@Test
void testCrud() {
String version = Version.getVersionString();
boolean isHibernate4 = version.startsWith("4.");
boolean isLatestDep = version.startsWith("5.0");
Customer customer = new Customer("Bob", "Anonymous");
customer.setId(null);
boolean result = testing.runWithSpan("parent", () -> repo.findAll().iterator().hasNext());
assertThat(result).isEqualTo(false);
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("SELECT Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("SELECT test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val ->
val.matches(
Pattern.compile(
"select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName(.*)from Customer(.*)"))),
equalTo(SemanticAttributes.DB_OPERATION, "SELECT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id"))))));
testing.clearData();
testing.runWithSpan(
"parent",
() -> {
repo.save(customer);
});
assertThat(customer.getId()).isNotNull();
testing.waitAndAssertTraces(
trace -> {
if (isHibernate4) {
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("Session.persist spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("INSERT test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val ->
val.matches(
Pattern.compile(
"insert into Customer (.*) values \\(.*, \\?, \\?\\)"))),
equalTo(SemanticAttributes.DB_OPERATION, "INSERT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id")))));
} else {
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("Session.persist spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("CALL test")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(
SemanticAttributes.DB_STATEMENT,
"call next value for hibernate_sequence"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
equalTo(SemanticAttributes.DB_OPERATION, "CALL")),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id")))),
span ->
span.hasName("INSERT test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(3))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val ->
val.matches(
Pattern.compile(
"insert into Customer (.*) values \\(.* \\?, \\?\\)"))),
equalTo(SemanticAttributes.DB_OPERATION, "INSERT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")));
}
});
testing.clearData();
customer.setFirstName("Bill");
testing.runWithSpan(
"parent",
() -> {
repo.save(customer);
});
Long savedId = customer.getId();
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("Session.merge spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("SELECT test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val ->
val.matches(
Pattern.compile(
"select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))),
equalTo(SemanticAttributes.DB_OPERATION, "SELECT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
equalTo(
stringKey("hibernate.session_id"),
trace
.getSpan(1)
.getAttributes()
.get(stringKey("hibernate.session_id")))),
span ->
span.hasName("UPDATE test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(3))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
equalTo(
SemanticAttributes.DB_STATEMENT,
"update Customer set firstName=?, lastName=? where id=?"),
equalTo(SemanticAttributes.DB_OPERATION, "UPDATE"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer"))));
testing.clearData();
Customer foundCustomer =
testing.runWithSpan("parent", () -> repo.findByLastName("Anonymous").get(0));
assertThat(foundCustomer.getId()).isEqualTo(savedId);
assertThat(foundCustomer.getFirstName()).isEqualTo("Bill");
testing.waitAndAssertTraces(
trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("SELECT Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("SELECT test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val ->
val.matches(
Pattern.compile(
"select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)(where ([^.]+).lastName=\\?)"))),
equalTo(SemanticAttributes.DB_OPERATION, "SELECT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer"))));
testing.clearData();
testing.runWithSpan("parent", () -> repo.delete(foundCustomer));
testing.waitAndAssertTraces(
trace -> {
if (isHibernate4) {
trace.hasSpansSatisfyingExactly(
span ->
span.hasName("parent")
.hasKind(INTERNAL)
.hasNoParent()
.hasAttributes(Attributes.empty()),
span ->
span.hasName("Session.merge spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("SELECT test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val ->
val.matches(
Pattern.compile(
"select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))),
equalTo(SemanticAttributes.DB_OPERATION, "SELECT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")),
span ->
span.hasName("Session.delete spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("DELETE test.Customer")
.hasKind(CLIENT)
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
equalTo(
SemanticAttributes.DB_STATEMENT, "delete from Customer where id=?"),
equalTo(SemanticAttributes.DB_OPERATION, "DELETE"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")));
} else {
String findAction;
if (isLatestDep) {
findAction = "get";
} else {
findAction = "find";
}
trace.hasSpansSatisfyingExactly(
span -> span.hasName("parent").hasKind(INTERNAL).hasNoParent(),
span ->
span.hasName("Session." + findAction + " spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("SELECT test.Customer")
.hasKind(CLIENT)
.hasParent(trace.getSpan(1))
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
satisfies(
SemanticAttributes.DB_STATEMENT,
val ->
val.matches(
Pattern.compile(
"select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))),
equalTo(SemanticAttributes.DB_OPERATION, "SELECT"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")),
span ->
span.hasName("Session.merge spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("Session.delete spring.jpa.Customer")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("Transaction.commit")
.hasKind(INTERNAL)
.hasParent(trace.getSpan(0))
.hasAttributesSatisfyingExactly(
satisfies(
stringKey("hibernate.session_id"),
val -> val.isInstanceOf(String.class))),
span ->
span.hasName("DELETE test.Customer")
.hasKind(CLIENT)
.hasAttributesSatisfyingExactly(
equalTo(SemanticAttributes.DB_SYSTEM, "hsqldb"),
equalTo(SemanticAttributes.DB_NAME, "test"),
equalTo(SemanticAttributes.DB_USER, "sa"),
equalTo(SemanticAttributes.DB_CONNECTION_STRING, "hsqldb:mem:"),
equalTo(
SemanticAttributes.DB_STATEMENT, "delete from Customer where id=?"),
equalTo(SemanticAttributes.DB_OPERATION, "DELETE"),
equalTo(SemanticAttributes.DB_SQL_TABLE, "Customer")));
}
});
}
}