content: /*
   * 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.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv;
  import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
  import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
  import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies;
  import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING;
  import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAME;
  import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
  import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SQL_TABLE;
  import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT;
  import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
  import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER;
  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 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);
  
    @SuppressWarnings("deprecation") // TODO DB_CONNECTION_STRING deprecation
    @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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              satisfies(
                                  maybeStable(DB_STATEMENT),
                                  val ->
                                      val.matches(
                                          Pattern.compile(
                                              "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName(.*)from Customer(.*)"))),
                              equalTo(maybeStable(DB_OPERATION), "SELECT"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              satisfies(
                                  maybeStable(DB_STATEMENT),
                                  val ->
                                      val.matches(
                                          Pattern.compile(
                                              "insert into Customer (.*) values \\(.*, \\?, \\?\\)"))),
                              equalTo(maybeStable(DB_OPERATION), "INSERT"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  maybeStable(DB_STATEMENT),
                                  "call next value for hibernate_sequence"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              satisfies(
                                  maybeStable(DB_STATEMENT),
                                  val ->
                                      val.matches(
                                          Pattern.compile(
                                              "insert into Customer (.*) values \\(.* \\?, \\?\\)"))),
                              equalTo(maybeStable(DB_OPERATION), "INSERT"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              satisfies(
                                  maybeStable(DB_STATEMENT),
                                  val ->
                                      val.matches(
                                          Pattern.compile(
                                              "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))),
                              equalTo(maybeStable(DB_OPERATION), "SELECT"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              equalTo(
                                  maybeStable(DB_STATEMENT),
                                  "update Customer set firstName=?, lastName=? where id=?"),
                              equalTo(maybeStable(DB_OPERATION), "UPDATE"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              satisfies(
                                  maybeStable(DB_STATEMENT),
                                  val ->
                                      val.matches(
                                          Pattern.compile(
                                              "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)(where ([^.]+).lastName=\\?)"))),
                              equalTo(maybeStable(DB_OPERATION), "SELECT"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              satisfies(
                                  maybeStable(DB_STATEMENT),
                                  val ->
                                      val.matches(
                                          Pattern.compile(
                                              "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))),
                              equalTo(maybeStable(DB_OPERATION), "SELECT"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              equalTo(maybeStable(DB_STATEMENT), "delete from Customer where id=?"),
                              equalTo(maybeStable(DB_OPERATION), "DELETE"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              satisfies(
                                  maybeStable(DB_STATEMENT),
                                  val ->
                                      val.matches(
                                          Pattern.compile(
                                              "select ([^.]+).id([^,]*), ([^.]+).firstName([^,]*), ([^.]+).lastName (.*)from Customer (.*)where ([^.]+).id=\\?"))),
                              equalTo(maybeStable(DB_OPERATION), "SELECT"),
                              equalTo(maybeStable(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(maybeStable(DB_SYSTEM), "hsqldb"),
                              equalTo(maybeStable(DB_NAME), "test"),
                              equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"),
                              equalTo(
                                  DB_CONNECTION_STRING,
                                  emitStableDatabaseSemconv() ? null : "hsqldb:mem:"),
                              equalTo(maybeStable(DB_STATEMENT), "delete from Customer where id=?"),
                              equalTo(maybeStable(DB_OPERATION), "DELETE"),
                              equalTo(maybeStable(DB_SQL_TABLE), "Customer")));
            }
          });
    }
  }
  