From dcdd1f8a44b58711b8f749c187431d91224aae57 Mon Sep 17 00:00:00 2001 From: i10320 Date: Wed, 5 Feb 2025 17:10:28 +0200 Subject: [PATCH 1/2] Add IT for Hibernate reactive with oracle reactive client --- .github/native-tests.json | 4 +- .../hibernate-reactive-oracle/pom.xml | 253 ++++++++++++++++++ .../reactive/oracle/model/FriesianCow.java | 18 ++ .../reactive/oracle/model/GuineaPig.java | 64 +++++ .../reactive/oracle/model/lazy/Author.java | 73 +++++ .../reactive/oracle/model/lazy/Book.java | 87 ++++++ .../HibernateReactiveTestEndpoint.java | 137 ++++++++++ ...ibernateReactiveTestEndpointFetchLazy.java | 71 +++++ ...ateReactiveTestEndpointJoinedSubclass.java | 121 +++++++++ .../src/main/resources/application.properties | 17 ++ .../HibernateReactiveFetchLazyInGraalIT.java | 7 + .../HibernateReactiveFetchLazyTest.java | 54 ++++ .../oracle/HibernateReactiveInGraalIT.java | 7 + ...ernateReactiveJoinedSubclassInGraalIT.java | 7 + .../HibernateReactiveJoinedSubclassTest.java | 29 ++ .../oracle/HibernateReactiveTest.java | 85 ++++++ integration-tests/pom.xml | 1 + 17 files changed, 1033 insertions(+), 2 deletions(-) create mode 100644 integration-tests/hibernate-reactive-oracle/pom.xml create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/FriesianCow.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/GuineaPig.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Author.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Book.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpoint.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointFetchLazy.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointJoinedSubclass.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties create mode 100644 integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyInGraalIT.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyTest.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveInGraalIT.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassInGraalIT.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassTest.java create mode 100644 integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveTest.java diff --git a/.github/native-tests.json b/.github/native-tests.json index b0a0f2d8d85b6..2e877cdfba4c0 100644 --- a/.github/native-tests.json +++ b/.github/native-tests.json @@ -44,8 +44,8 @@ }, { "category": "Data7", - "timeout": 90, - "test-modules": "reactive-oracle-client, reactive-mysql-client, reactive-db2-client, hibernate-reactive-db2, hibernate-reactive-mariadb, hibernate-reactive-mssql, hibernate-reactive-mysql, hibernate-reactive-mysql-agroal-flyway, hibernate-reactive-panache, hibernate-reactive-panache-kotlin", + "timeout": 95, + "test-modules": "reactive-oracle-client, reactive-mysql-client, reactive-db2-client, hibernate-reactive-db2, hibernate-reactive-mariadb, hibernate-reactive-mssql, hibernate-reactive-mysql, hibernate-reactive-mysql-agroal-flyway, hibernate-reactive-panache, hibernate-reactive-panache-kotlin, hibernate-reactive-oracle", "os-name": "ubuntu-latest" }, { diff --git a/integration-tests/hibernate-reactive-oracle/pom.xml b/integration-tests/hibernate-reactive-oracle/pom.xml new file mode 100644 index 0000000000000..80d549e5f7421 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/pom.xml @@ -0,0 +1,253 @@ + + + + quarkus-integration-tests-parent + io.quarkus + 999-SNAPSHOT + + 4.0.0 + + quarkus-integration-test-hibernate-reactive-oracle + Quarkus - Integration Tests - Hibernate Reactive - Oracle + Hibernate Reactive related tests running with the Oracle database + + + vertx-reactive:oracle:thin:@localhost:1520/hibernate_orm_test + + + + + io.quarkus + quarkus-hibernate-reactive + + + io.quarkus + quarkus-reactive-oracle-client + + + io.quarkus + quarkus-rest-jsonb + + + io.quarkus + quarkus-elytron-security-properties-file + + + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + io.quarkus + quarkus-hibernate-reactive-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-reactive-oracle-client-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-rest-jsonb-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-elytron-security-properties-file-deployment + ${project.version} + pom + test + + + * + * + + + + + + + + + src/main/resources + true + + + + + maven-surefire-plugin + + true + + true + + + + + + maven-failsafe-plugin + + true + + true + + + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + + + test-oracle + + + test-containers + + + + + + maven-surefire-plugin + + false + + + + maven-failsafe-plugin + + false + + + + + + + + docker-oracle + + + start-containers + + + + + + io.fabric8 + docker-maven-plugin + + + + ${oracle.image} + oracle + + + hibernate_orm_test + hibernate_orm_test + hibernate_orm_test + hibernate_orm_test + + + 1520:1521 + + + ORACLE: + default + cyan + + + + + + true + + + + docker-start + pre-integration-test + + stop + build + start + + + + docker-stop + post-integration-test + + stop + + + + + + org.codehaus.mojo + exec-maven-plugin + + + docker-prune + generate-resources + + exec + + + ${docker-prune.location} + + + + + + + + + + + diff --git a/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/FriesianCow.java b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/FriesianCow.java new file mode 100644 index 0000000000000..43cae6b8d1fe3 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/FriesianCow.java @@ -0,0 +1,18 @@ +package io.quarkus.it.hibernate.reactive.oracle.model; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "Cow") +public class FriesianCow { + + @Id + @GeneratedValue + public Long id; + + public String name; + +} diff --git a/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/GuineaPig.java b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/GuineaPig.java new file mode 100644 index 0000000000000..7f27f631735bd --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/GuineaPig.java @@ -0,0 +1,64 @@ +package io.quarkus.it.hibernate.reactive.oracle.model; + +import java.util.Objects; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedNativeQuery; +import jakarta.persistence.Table; + +@Entity +@Table(name = "Pig") +@NamedNativeQuery(name = "pig.all", query = "select * from Pig", resultClass = GuineaPig.class) +public class GuineaPig { + + @Id + private Integer id; + private String name; + + public GuineaPig() { + } + + public GuineaPig(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return id + ": " + name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + GuineaPig guineaPig = (GuineaPig) o; + return Objects.equals(name, guineaPig.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Author.java b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Author.java new file mode 100644 index 0000000000000..133318174e40e --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Author.java @@ -0,0 +1,73 @@ +package io.quarkus.it.hibernate.reactive.oracle.model.lazy; + +import static jakarta.persistence.CascadeType.PERSIST; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Objects; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +@Entity +@Table +public class Author { + @Id + private Integer id; + + private String name; + + @OneToMany(mappedBy = "author", cascade = PERSIST) + private Collection books = new ArrayList<>(); + + public Author() { + } + + public Author(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Collection getBooks() { + return books; + } + + public void setBooks(Collection books) { + this.books = books; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Author author = (Author) o; + return Objects.equals(name, author.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Book.java b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Book.java new file mode 100644 index 0000000000000..368b36400c827 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/model/lazy/Book.java @@ -0,0 +1,87 @@ +package io.quarkus.it.hibernate.reactive.oracle.model.lazy; + +import static jakarta.persistence.FetchType.LAZY; + +import java.util.Objects; + +import jakarta.json.bind.annotation.JsonbTransient; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; + +@Entity +@Table +public class Book { + @Id + @GeneratedValue + private Integer id; + + private String isbn; + + private String title; + + @JsonbTransient + @ManyToOne(fetch = LAZY) + private Author author; + + public Book(String isbn, String title, Author author) { + this.title = title; + this.isbn = isbn; + this.author = author; + } + + public Book() { + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Author getAuthor() { + return author; + } + + public void setAuthor(Author author) { + this.author = author; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Book book = (Book) o; + return Objects.equals(isbn, book.isbn) + && Objects.equals(title, book.title); + } + + @Override + public int hashCode() { + return Objects.hash(isbn, title); + } +} diff --git a/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpoint.java b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpoint.java new file mode 100644 index 0000000000000..0347cc13e0580 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpoint.java @@ -0,0 +1,137 @@ +package io.quarkus.it.hibernate.reactive.oracle.resources; + +import java.util.List; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import org.hibernate.reactive.mutiny.Mutiny; + +import io.quarkus.it.hibernate.reactive.oracle.model.FriesianCow; +import io.quarkus.it.hibernate.reactive.oracle.model.GuineaPig; +import io.quarkus.security.Authenticated; +import io.smallrye.mutiny.Uni; +import io.vertx.mutiny.oracleclient.OraclePool; +import io.vertx.mutiny.sqlclient.Row; +import io.vertx.mutiny.sqlclient.RowSet; +import io.vertx.mutiny.sqlclient.Tuple; + +@Path("/tests") +@Authenticated +public class HibernateReactiveTestEndpoint { + + @Inject + Mutiny.SessionFactory sessionFactory; + + // Injecting a Vert.x Pool is not required, it's only used to + // independently validate the contents of the database for the test + @Inject + OraclePool oraclePool; + + @GET + @Path("/reactiveFindNativeQuery") + public Uni> reactiveFindNativeQuery() { + return populateDB() + .chain(() -> sessionFactory.withSession(s -> s.createNamedQuery("pig.all", GuineaPig.class).getResultList())); + } + + @GET + @Path("/reactiveFindMutiny") + public Uni reactiveFindMutiny() { + final GuineaPig expectedPig = new GuineaPig(5, "Aloi"); + return populateDB().chain(() -> sessionFactory.withSession(s -> s.find(GuineaPig.class, expectedPig.getId()))); + } + + @GET + @Path("/reactivePersist") + public Uni reactivePersist() { + final GuineaPig pig = new GuineaPig(10, "Tulip"); + return sessionFactory.withTransaction(s -> s.persist(pig)) + .chain(() -> selectNameFromId(10)); + } + + @GET + @Path("/reactiveCowPersist") + public Uni reactiveCowPersist() { + final FriesianCow cow = new FriesianCow(); + cow.name = "Carolina"; + return sessionFactory.withTransaction(s -> s.persist(cow)) + .chain(() -> sessionFactory + .withSession(s -> s.createQuery("from FriesianCow f where f.name = :name", FriesianCow.class) + .setParameter("name", cow.name).getSingleResult())); + } + + @GET + @Path("/reactiveRemoveTransientEntity") + public Uni reactiveRemoveTransientEntity() { + return populateDB() + .chain(() -> selectNameFromId(5)) + .invoke(name -> { + if (name == null) + throw new AssertionError("Database was not populated properly"); + }) + .chain(() -> sessionFactory + .withTransaction(s -> s.merge(new GuineaPig(5, "Aloi")).chain(s::remove))) + .chain(() -> selectNameFromId(5)) + .map(result -> { + if (result == null) + return "OK"; + else + return result; + }); + } + + @GET + @Path("/reactiveRemoveManagedEntity") + public Uni reactiveRemoveManagedEntity() { + return populateDB() + .chain(() -> selectNameFromId(5)) + .invoke(name -> { + if (name == null) + throw new AssertionError("Database was not populated properly"); + }) + .chain(() -> sessionFactory.withTransaction(s -> s.find(GuineaPig.class, 5).chain(s::remove))) + .chain(() -> selectNameFromId(5)) + .map(result -> { + if (result == null) + return "OK"; + else + return result; + }); + } + + @GET + @Path("/reactiveUpdate") + public Uni reactiveUpdate() { + final String NEW_NAME = "Tina"; + return populateDB() + .chain(() -> sessionFactory.withTransaction(s -> s.find(GuineaPig.class, 5).invoke(pig -> { + if (NEW_NAME.equals(pig.getName())) + throw new AssertionError("Pig already had name " + NEW_NAME); + pig.setName(NEW_NAME); + }))) + .chain(() -> selectNameFromId(5)); + } + + private Uni> populateDB() { + return Uni.combine().all().unis( + oraclePool.query("DELETE FROM Pig").execute(), + oraclePool.query("DELETE FROM Cow").execute()) + .asTuple() + .chain(() -> oraclePool.preparedQuery("INSERT INTO Pig (id, name) VALUES (5, 'Aloi')").execute()); + } + + private Uni selectNameFromId(Integer id) { + return oraclePool.preparedQuery("SELECT name FROM Pig WHERE id = ?").execute(Tuple.of(id)).map(rowSet -> { + if (rowSet.size() == 1) { + return rowSet.iterator().next().getString(0); + } else if (rowSet.size() > 1) { + throw new AssertionError("More than one result returned: " + rowSet.size()); + } else { + return null; // Size 0 + } + }); + } + +} diff --git a/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointFetchLazy.java b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointFetchLazy.java new file mode 100644 index 0000000000000..a24a6c62d5f3a --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointFetchLazy.java @@ -0,0 +1,71 @@ +package io.quarkus.it.hibernate.reactive.oracle.resources; + +import java.util.Collection; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + +import org.hibernate.reactive.mutiny.Mutiny; + +import io.quarkus.it.hibernate.reactive.oracle.model.lazy.Author; +import io.quarkus.it.hibernate.reactive.oracle.model.lazy.Book; +import io.smallrye.mutiny.Uni; +import io.vertx.mutiny.oracleclient.OraclePool; +import io.vertx.mutiny.sqlclient.Tuple; + +@Path("/hr-fetch") +public class HibernateReactiveTestEndpointFetchLazy { + + @Inject + Mutiny.SessionFactory sessionFactory; + + // Injecting a Vert.x Pool is not required, It's used to + // independently validate the contents of the database for the test + @Inject + OraclePool oraclePool; + + @GET + @Path("/findBooksWithMutiny/{authorId}") + public Uni> findBooksWithMutiny(@PathParam("authorId") Integer authorId) { + return sessionFactory.withSession(s -> s.find(Author.class, authorId) + .chain(author -> Mutiny.fetch(author.getBooks()))); + } + + @GET + @Path("/getReferenceBooksWithMutiny/{authorId}") + public Uni> getReferenceBooksWithMutiny(@PathParam("authorId") Integer authorId) { + return sessionFactory.withSession(s -> s.fetch(s.getReference(Author.class, authorId)) + .chain(author -> Mutiny.fetch(author.getBooks()))); + } + + @POST + @Path("/prepareDb") + public Uni prepareDb() { + final Author author = new Author(567, "Neal Stephenson"); + final Book book1 = new Book("0-380-97346-4", "Cryptonomicon", author); + final Book book2 = new Book("0-553-08853-X", "Snow Crash", author); + author.getBooks().add(book1); + author.getBooks().add(book2); + + return sessionFactory.withTransaction(s -> s.createQuery(" delete from Book").executeUpdate() + .call(() -> s.createQuery("delete from Author").executeUpdate()) + .call(() -> s.persist(author)) + .chain(s::flush)) + .chain(() -> selectNameFromId(author.getId())); + } + + private Uni selectNameFromId(Integer id) { + return oraclePool.preparedQuery("SELECT name FROM Author WHERE id = ?").execute(Tuple.of(id)).map(rowSet -> { + if (rowSet.size() == 1) { + return rowSet.iterator().next().getString(0); + } else if (rowSet.size() > 1) { + throw new AssertionError("More than one result returned: " + rowSet.size()); + } else { + return null; // Size 0 + } + }); + } +} diff --git a/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointJoinedSubclass.java b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointJoinedSubclass.java new file mode 100644 index 0000000000000..95e54d30382f9 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/java/io/quarkus/it/hibernate/reactive/oracle/resources/HibernateReactiveTestEndpointJoinedSubclass.java @@ -0,0 +1,121 @@ +package io.quarkus.it.hibernate.reactive.oracle.resources; + +import java.util.Objects; + +import jakarta.inject.Inject; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.Table; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; + +import org.hibernate.reactive.mutiny.Mutiny; + +import io.smallrye.mutiny.Uni; + +/** + * We want to check that the right {@link org.hibernate.hql.spi.id.MultiTableBulkIdStrategy} + * is set when using Hibernate Reactive. + * + * @see io.quarkus.hibernate.reactive.runtime.boot.FastBootReactiveEntityManagerFactoryBuilder + * @see org.hibernate.reactive.bulk.impl.ReactiveBulkIdStrategy + */ +@Path("/hr-joinedsubclass") +public class HibernateReactiveTestEndpointJoinedSubclass { + + @Inject + Mutiny.SessionFactory sessionFactory; + + @DELETE + @Path("/deleteBook/{bookId}") + public Uni deleteBook(@PathParam("bookId") Integer bookId) { + return sessionFactory.withTransaction(s -> s + .createQuery("delete BookJS where id=:id") + .setParameter("id", bookId) + .executeUpdate()) + .chain(() -> sessionFactory.withSession(s -> s.find(SpellBook.class, bookId))); + } + + @POST + @Path("/prepareDb") + public Uni prepareDb() { + final SpellBook spells = new SpellBook(6, "Necronomicon", true); + return sessionFactory.withTransaction(s -> s.persist(spells)); + } + + @Entity(name = "SpellBookJS") + @Table(name = "SpellBookJS") + @DiscriminatorValue("S") + public static class SpellBook extends Book { + + private boolean forbidden; + + public SpellBook(Integer id, String title, boolean forbidden) { + super(id, title); + this.forbidden = forbidden; + } + + SpellBook() { + } + + public boolean getForbidden() { + return forbidden; + } + } + + @Entity(name = "BookJS") + @Table(name = "BookJS") + @Inheritance(strategy = InheritanceType.JOINED) + public static class Book { + + @Id + private Integer id; + private String title; + + public Book() { + } + + public Book(Integer id, String title) { + this.id = id; + this.title = title; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Book book = (Book) o; + return Objects.equals(title, book.title); + } + + @Override + public int hashCode() { + return Objects.hash(title); + } + } +} diff --git a/integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties b/integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties new file mode 100644 index 0000000000000..9499103bd18f9 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties @@ -0,0 +1,17 @@ +quarkus.datasource.db-kind=oracle +quarkus.datasource.username=hibernate_orm_test +quarkus.datasource.password=hibernate_orm_test + +# Hibernate config +#quarkus.hibernate-orm.log.sql=true +quarkus.hibernate-orm.database.generation=drop-and-create + +# Reactive config +quarkus.datasource.reactive=true +quarkus.datasource.reactive.url=${reactive-oracle.url} + + +quarkus.security.users.embedded.enabled=true +quarkus.security.users.embedded.users.scott=jb0ss +quarkus.security.users.embedded.plain-text=true +quarkus.security.users.embedded.roles.scott=Admin,admin,Tester,user diff --git a/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyInGraalIT.java b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyInGraalIT.java new file mode 100644 index 0000000000000..777a940ceaa4a --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyInGraalIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.hibernate.reactive.oracle; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class HibernateReactiveFetchLazyInGraalIT extends HibernateReactiveFetchLazyTest { +} diff --git a/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyTest.java b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyTest.java new file mode 100644 index 0000000000000..0b65e07044ea5 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveFetchLazyTest.java @@ -0,0 +1,54 @@ +package io.quarkus.it.hibernate.reactive.oracle; + +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toList; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import io.quarkus.it.hibernate.reactive.oracle.resources.HibernateReactiveTestEndpointFetchLazy; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import io.restassured.response.Response; + +@QuarkusTest +@TestHTTPEndpoint(HibernateReactiveTestEndpointFetchLazy.class) +public class HibernateReactiveFetchLazyTest { + + @Test + public void fetchAfterGetReferenceWithMutiny() { + RestAssured.when() + .post("/prepareDb") + .then() + .body(is("Neal Stephenson")); + + Response response = RestAssured.when() + .get("/getReferenceBooksWithMutiny/567") + .then() + .extract().response(); + assertTitles(response, "Cryptonomicon", "Snow Crash"); + } + + @Test + public void fetchAfterFindWithMutiny() { + RestAssured.when() + .post("/prepareDb") + .then() + .body(is("Neal Stephenson")); + + Response response = RestAssured.when() + .get("/findBooksWithMutiny/567") + .then() + .extract().response(); + assertTitles(response, "Cryptonomicon", "Snow Crash"); + } + + private void assertTitles(Response response, String... expectedTitles) { + List titles = response.jsonPath().getList("title").stream().sorted().collect(toList()); + assertIterableEquals(asList(expectedTitles), titles); + } +} diff --git a/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveInGraalIT.java b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveInGraalIT.java new file mode 100644 index 0000000000000..423d0ce249042 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveInGraalIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.hibernate.reactive.oracle; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class HibernateReactiveInGraalIT extends HibernateReactiveTest { +} diff --git a/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassInGraalIT.java b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassInGraalIT.java new file mode 100644 index 0000000000000..63747467ab07f --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassInGraalIT.java @@ -0,0 +1,7 @@ +package io.quarkus.it.hibernate.reactive.oracle; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class HibernateReactiveJoinedSubclassInGraalIT extends HibernateReactiveJoinedSubclassTest { +} diff --git a/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassTest.java b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassTest.java new file mode 100644 index 0000000000000..39cd734a69539 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveJoinedSubclassTest.java @@ -0,0 +1,29 @@ +package io.quarkus.it.hibernate.reactive.oracle; + +import static org.hamcrest.Matchers.emptyOrNullString; + +import org.junit.jupiter.api.Test; + +import io.quarkus.it.hibernate.reactive.oracle.resources.HibernateReactiveTestEndpointJoinedSubclass; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +@QuarkusTest +@TestHTTPEndpoint(HibernateReactiveTestEndpointJoinedSubclass.class) +public class HibernateReactiveJoinedSubclassTest { + + @Test + public void deleteBookQuery() { + RestAssured.when() + .post("/prepareDb") + .then() + .statusCode(204); + + RestAssured.when() + .delete("/deleteBook/6") + .then() + .statusCode(204) + .body(emptyOrNullString()); + } +} diff --git a/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveTest.java b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveTest.java new file mode 100644 index 0000000000000..b165ce49485e7 --- /dev/null +++ b/integration-tests/hibernate-reactive-oracle/src/test/java/io/quarkus/it/hibernate/reactive/oracle/HibernateReactiveTest.java @@ -0,0 +1,85 @@ +package io.quarkus.it.hibernate.reactive.oracle; + +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.it.hibernate.reactive.oracle.resources.HibernateReactiveTestEndpoint; +import io.quarkus.test.common.http.TestHTTPEndpoint; +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; + +/** + * Test various JPA operations running in Quarkus + * + * Also makes sure that these work with a blocking security implementation + */ +@QuarkusTest +@TestHTTPEndpoint(HibernateReactiveTestEndpoint.class) +public class HibernateReactiveTest { + + @Test + public void reactiveFindNativeQuery() { + RestAssured.given().when() + .auth().preemptive().basic("scott", "jb0ss") + .get("/reactiveFindNativeQuery") + .then() + .statusCode(anyOf(is(200), is(204))); + } + + @Test + public void reactiveCowPersist() { + RestAssured.given().when() + .auth().preemptive().basic("scott", "jb0ss") + .get("/reactiveCowPersist") + .then() + .body(containsString("\"name\":\"Carolina\"}")); //Use containsString as we don't know the Id this object will have + } + + @Test + public void reactiveFindMutiny() { + RestAssured.given().when() + .auth().preemptive().basic("scott", "jb0ss") + .get("/reactiveFindMutiny") + .then() + .body(is("{\"id\":5,\"name\":\"Aloi\"}")); + } + + @Test + public void reactivePersist() { + RestAssured.given().when() + .auth().preemptive().basic("scott", "jb0ss") + .get("/reactivePersist") + .then() + .body(is("Tulip")); + } + + @Test + public void reactiveRemoveTransientEntity() { + RestAssured.given().when() + .auth().preemptive().basic("scott", "jb0ss") + .get("/reactiveRemoveTransientEntity") + .then() + .body(is("OK")); + } + + @Test + public void reactiveRemoveManagedEntity() { + RestAssured.given().when() + .auth().preemptive().basic("scott", "jb0ss") + .get("/reactiveRemoveManagedEntity") + .then() + .body(is("OK")); + } + + @Test + public void reactiveUpdate() { + RestAssured.given().when() + .auth().preemptive().basic("scott", "jb0ss") + .get("/reactiveUpdate") + .then() + .body(is("Tina")); + } +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 5d297a6148331..0418df77c89ab 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -216,6 +216,7 @@ hibernate-reactive-mssql hibernate-reactive-mysql hibernate-reactive-mysql-agroal-flyway + hibernate-reactive-oracle hibernate-reactive-postgresql hibernate-reactive-panache hibernate-reactive-panache-kotlin From a6dadc5f3ebb65143b7f0bfdab10a58e1dd684f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 19 Feb 2025 08:39:56 +0100 Subject: [PATCH 2/2] Align Oracle DB setup in quarkus-it-hibernate-reactive-oracle on other ITs E.g. on quarkus-reactive-oracle-client-deployment, quarkus-it-jpa-oracle. Because the current setup doesn't seem to work. --- .../hibernate-reactive-oracle/pom.xml | 85 ++++++++++++++++--- .../src/main/resources/application.properties | 2 +- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/integration-tests/hibernate-reactive-oracle/pom.xml b/integration-tests/hibernate-reactive-oracle/pom.xml index 80d549e5f7421..a2f1c2bbb7111 100644 --- a/integration-tests/hibernate-reactive-oracle/pom.xml +++ b/integration-tests/hibernate-reactive-oracle/pom.xml @@ -14,7 +14,7 @@ Hibernate Reactive related tests running with the Oracle database - vertx-reactive:oracle:thin:@localhost:1520/hibernate_orm_test + vertx-reactive:oracle:thin:@localhost:1521/FREEPDB1 @@ -186,36 +186,40 @@ ${oracle.image} - oracle + + 1521:1521 + - hibernate_orm_test hibernate_orm_test - hibernate_orm_test - hibernate_orm_test - - 1520:1521 - - ORACLE: + Oracle Database: default - cyan + red + + + + + + yes + + + - true docker-start - pre-integration-test + compile stop - build start @@ -247,6 +251,61 @@ + + + + mac-m1 + + + aarch64 + + + + + + maven-surefire-plugin + + true + + + + io.fabric8 + docker-maven-plugin + + + + ${oracle.image} + + true + + + + + + + + + + + podman + + + env.IS_PODMAN + true + + + + + + maven-surefire-plugin + + true + + + + + diff --git a/integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties b/integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties index 9499103bd18f9..2f2533752ae0f 100644 --- a/integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties +++ b/integration-tests/hibernate-reactive-oracle/src/main/resources/application.properties @@ -1,5 +1,5 @@ quarkus.datasource.db-kind=oracle -quarkus.datasource.username=hibernate_orm_test +quarkus.datasource.username=SYSTEM quarkus.datasource.password=hibernate_orm_test # Hibernate config