From 36bb87a4990bceb7df208f3ef7f872884ef64cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 4 Dec 2023 13:59:56 +0100 Subject: [PATCH] Add test specifically for using Hibernate ORM in a non-quarkus way --- .../jpa/nonquarkus/NonQuarkusApiResource.java | 130 ++++++++++++++++++ .../io/quarkus/it/jpa/nonquarkus/Person.java | 71 ++++++++++ .../it/jpa/nonquarkus/SequencedAddress.java | 42 ++++++ .../io/quarkus/it/jpa/nonquarkus/Status.java | 6 + .../NonQuarkusApiInGraalITCase.java | 7 + .../it/jpa/nonquarkus/NonQuarkusApiTest.java | 29 ++++ 6 files changed, 285 insertions(+) create mode 100644 integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiResource.java create mode 100644 integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Person.java create mode 100644 integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/SequencedAddress.java create mode 100644 integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Status.java create mode 100644 integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiInGraalITCase.java create mode 100644 integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiTest.java diff --git a/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiResource.java b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiResource.java new file mode 100644 index 0000000000000..1c61195643a59 --- /dev/null +++ b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiResource.java @@ -0,0 +1,130 @@ +package io.quarkus.it.jpa.nonquarkus; + +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityTransaction; +import jakarta.persistence.PersistenceUnit; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/non-quarkus") +@ApplicationScoped +public class NonQuarkusApiResource { + + @PersistenceUnit + EntityManagerFactory entityManagerFactory; + + @GET + @Path("test") + public String test() throws IOException { + //Cleanup any existing data: + deleteAllPerson(entityManagerFactory); + + //Store some well known Person instances we can then test on: + storeTestPersons(entityManagerFactory); + + //Load all persons and run some checks on the query results: + verifyListOfExistingPersons(entityManagerFactory); + + //Try a JPA named query: + verifyJPANamedQuery(entityManagerFactory); + + deleteAllPerson(entityManagerFactory); + + return "OK"; + } + + private static void verifyJPANamedQuery(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + TypedQuery typedQuery = em.createNamedQuery( + "get_person_by_name", Person.class); + typedQuery.setParameter("name", "Quarkus"); + final Person singleResult = typedQuery.getSingleResult(); + + if (!singleResult.getName().equals("Quarkus")) { + throw new RuntimeException("Wrong result from named JPA query"); + } + + transaction.commit(); + em.close(); + } + + private static void verifyListOfExistingPersons(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + listExistingPersons(em); + transaction.commit(); + em.close(); + } + + private static void storeTestPersons(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + persistNewPerson(em, "Gizmo"); + persistNewPerson(em, "Quarkus"); + persistNewPerson(em, "Hibernate ORM"); + transaction.commit(); + em.close(); + } + + private static void deleteAllPerson(final EntityManagerFactory emf) { + EntityManager em = emf.createEntityManager(); + EntityTransaction transaction = em.getTransaction(); + transaction.begin(); + em.createNativeQuery("Delete from Person").executeUpdate(); + transaction.commit(); + em.close(); + } + + private static void listExistingPersons(EntityManager em) { + CriteriaBuilder cb = em.getCriteriaBuilder(); + + CriteriaQuery cq = cb.createQuery(Person.class); + Root from = cq.from(Person.class); + cq.select(from).orderBy(cb.asc(from.get("name"))); + TypedQuery q = em.createQuery(cq); + List allpersons = q.getResultList(); + if (allpersons.size() != 3) { + throw new RuntimeException("Incorrect number of results"); + } + if (!allpersons.get(0).getName().equals("Gizmo")) { + throw new RuntimeException("Incorrect order of results"); + } + StringBuilder sb = new StringBuilder("list of stored Person names:\n\t"); + for (Person p : allpersons) { + p.describeFully(sb); + sb.append("\n\t"); + if (p.getStatus() != Status.LIVING) { + throw new RuntimeException("Incorrect status " + p); + } + } + sb.append("\nList complete.\n"); + System.out.print(sb); + } + + private static void persistNewPerson(EntityManager entityManager, String name) { + Person person = new Person(); + person.setName(name); + person.setStatus(Status.LIVING); + person.setAddress(new SequencedAddress("Street " + randomName())); + entityManager.persist(person); + } + + private static String randomName() { + return UUID.randomUUID().toString(); + } + +} diff --git a/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Person.java b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Person.java new file mode 100644 index 0000000000000..2a00014b5854c --- /dev/null +++ b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Person.java @@ -0,0 +1,71 @@ +package io.quarkus.it.jpa.nonquarkus; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQuery; + +@Entity +@NamedQuery(name = "get_person_by_name", query = "select p from Person p where name = :name") +public class Person { + + private long id; + private String name; + private SequencedAddress address; + private Status status; + + public Person() { + } + + public Person(long id, String name, SequencedAddress address) { + this.id = id; + this.name = name; + this.address = address; + } + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "personSeq") + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + public SequencedAddress getAddress() { + return address; + } + + public void setAddress(SequencedAddress address) { + this.address = address; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public void describeFully(StringBuilder sb) { + sb.append("Person with id=").append(id).append(", name='").append(name).append("', status='").append(status) + .append("', address { "); + getAddress().describeFully(sb); + sb.append(" }"); + } +} diff --git a/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/SequencedAddress.java b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/SequencedAddress.java new file mode 100644 index 0000000000000..bc469e79ed786 --- /dev/null +++ b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/SequencedAddress.java @@ -0,0 +1,42 @@ +package io.quarkus.it.jpa.nonquarkus; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity +public class SequencedAddress { + + private long id; + private String street; + + public SequencedAddress() { + } + + public SequencedAddress(String street) { + this.street = street; + } + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "addressSeq") + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getStreet() { + return street; + } + + public void setStreet(String name) { + this.street = name; + } + + public void describeFully(StringBuilder sb) { + sb.append("Address with id=").append(id).append(", street='").append(street).append("'"); + } +} diff --git a/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Status.java b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Status.java new file mode 100644 index 0000000000000..9cdcc0e0445fb --- /dev/null +++ b/integration-tests/jpa/src/main/java/io/quarkus/it/jpa/nonquarkus/Status.java @@ -0,0 +1,6 @@ +package io.quarkus.it.jpa.nonquarkus; + +public enum Status { + LIVING, + DECEASED +} diff --git a/integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiInGraalITCase.java b/integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiInGraalITCase.java new file mode 100644 index 0000000000000..1fa655987df8a --- /dev/null +++ b/integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiInGraalITCase.java @@ -0,0 +1,7 @@ +package io.quarkus.it.jpa.nonquarkus; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class NonQuarkusApiInGraalITCase extends NonQuarkusApiTest { +} diff --git a/integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiTest.java b/integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiTest.java new file mode 100644 index 0000000000000..490af87e39f48 --- /dev/null +++ b/integration-tests/jpa/src/test/java/io/quarkus/it/jpa/nonquarkus/NonQuarkusApiTest.java @@ -0,0 +1,29 @@ +package io.quarkus.it.jpa.nonquarkus; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.core.Is.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +/** + * Test usage of JPA in a way that is not recommended with Quarkus: + * creating the entity manager manually, using `em.getTransaction()`, ... + *

+ * This is mainly tested to ensure migration is relatively easy, like we test `persistence.xml` support: + * we expect developers to move to `@Inject EntityManager em;` + * and `QuarkusTransaction`/`UserTransaction` for best results. + */ +@QuarkusTest +public class NonQuarkusApiTest { + + @Test + public void test() { + given().queryParam("expectedSchema", "SCHEMA1") + .when().get("/jpa-test/non-quarkus/test").then() + .body(is("OK")) + .statusCode(200); + } + +}