From a4acdce2fad1e05317543b4b6fce21728b9b9836 Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Wed, 24 May 2023 16:41:01 +0200 Subject: [PATCH] HHH-16617 Add test for issue --- .../test/cache/QueryCacheWithFilterTest.java | 148 ------------------ .../querycache/QueryCacheWithFilterTest.java | 140 +++++++++++++++++ .../test/jcache/QueryCacheWithFilterTest.java | 147 ++++++++--------- 3 files changed, 216 insertions(+), 219 deletions(-) delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/cache/QueryCacheWithFilterTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryCacheWithFilterTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/QueryCacheWithFilterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cache/QueryCacheWithFilterTest.java deleted file mode 100644 index fed8075e85..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cache/QueryCacheWithFilterTest.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.hibernate.orm.test.cache; - -import java.util.List; - -import org.hibernate.annotations.Filter; -import org.hibernate.annotations.FilterDef; -import org.hibernate.annotations.ParamDef; -import org.hibernate.cache.spi.RegionFactory; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.query.Query; -import org.hibernate.stat.CacheRegionStatistics; -import org.hibernate.stat.spi.StatisticsImplementor; - -import org.hibernate.testing.orm.junit.DomainModel; -import org.hibernate.testing.orm.junit.ServiceRegistry; -import org.hibernate.testing.orm.junit.SessionFactory; -import org.hibernate.testing.orm.junit.SessionFactoryScope; -import org.hibernate.testing.orm.junit.Setting; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; - -import static org.assertj.core.api.Assertions.assertThat; - -@DomainModel(annotatedClasses = { - QueryCacheWithFilterTest.Person.class, -}) -@SessionFactory(generateStatistics = true) -@ServiceRegistry( - settings = { - @Setting(name = AvailableSettings.USE_QUERY_CACHE, value = "true"), - @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true") - } -) -public class QueryCacheWithFilterTest { - - @BeforeEach - public void setUp(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - Person p = new Person(); - p.setName( "John" ); - session.persist( p ); - } - ); - } - - @Test - public void testQueryKeyIsImmutable(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - session.enableFilter( "personName" ) - .setParameter( "name", "John" ); - Query query = session.createQuery( - "from Person p", - Person.class - ); - query.setCacheable( true ); - - List resultList = query.getResultList(); - assertThat( resultList ).hasSize( 1 ); - - //cache query should not be affected by the additional filter - session.enableFilter( "personName2" ) - .setParameter( "name", "John" ); - } - ); - scope.inTransaction( - session -> { - session.enableFilter( "personName" ) - .setParameter( "name", "John" ); - Query query = session.createQuery( - "from Person p", - Person.class - ); - query.setCacheable( true ); - - List resultList = query.getResultList(); - assertThat( resultList ).hasSize( 1 ); - - assertThat( getQueryCacheRegionStatistics( session ).getHitCount() ).isEqualTo( 1 ); - } - ); - } - - private static CacheRegionStatistics getQueryCacheRegionStatistics(SessionImplementor session) { - StatisticsImplementor statistics = session.getSessionFactory().getStatistics(); - return statistics.getQueryRegionStatistics( RegionFactory.DEFAULT_QUERY_RESULTS_REGION_UNQUALIFIED_NAME ); - } - - - @Entity(name = "Person") - @FilterDef( - name = "personName", - parameters = @ParamDef( - name = "name", - type = String.class - ) - ) - @Filter( - name = "personName", - condition = "name = :name" - ) - @FilterDef( - name = "personName2", - parameters = @ParamDef( - name = "name", - type = String.class - ) - ) - @Filter( - name = "personName2", - condition = "name = :name" - ) - public static class Person { - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - private String name; - - public Person() { - } - - public Person(String name) { - this.name = name; - } - - public Long getId() { - return id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryCacheWithFilterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryCacheWithFilterTest.java new file mode 100644 index 0000000000..c1550a6b0e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/querycache/QueryCacheWithFilterTest.java @@ -0,0 +1,140 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.querycache; + +import java.util.List; + +import org.hibernate.annotations.Filter; +import org.hibernate.annotations.FilterDef; +import org.hibernate.annotations.ParamDef; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.stat.spi.StatisticsImplementor; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Jira; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +import static org.assertj.core.api.Assertions.assertThat; + +@DomainModel( annotatedClasses = QueryCacheWithFilterTest.Person.class ) +@SessionFactory( generateStatistics = true ) +@ServiceRegistry( settings = { + @Setting( name = AvailableSettings.USE_QUERY_CACHE, value = "true" ), + @Setting( name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true" ) +} ) +public class QueryCacheWithFilterTest { + @BeforeAll + public void setUp(SessionFactoryScope scope) { + scope.inTransaction( session -> session.persist( new Person( "John" ) ) ); + } + + @AfterAll + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( session -> session.createMutationQuery( "delete from Person" ).executeUpdate() ); + } + + @Test + @Jira( "https://hibernate.atlassian.net/browse/HHH-16385" ) + public void testQueryCacheKeyIsImmutable(SessionFactoryScope scope) { + scope.getSessionFactory().getCache().evictQueryRegions(); + final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); + statistics.clear(); + + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "John" ); + executeQuery( session, 1 ); + // cache query key should not be affected by changing enabled filters + session.enableFilter( "personName2" ).setParameter( "name", "John2" ); + } ); + + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 0 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 1 ); + + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "John" ); + executeQuery( session, 1 ); + } ); + + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 1 ); + } + + @Test + @Jira( "https://hibernate.atlassian.net/browse/HHH-16617" ) + public void testQueryCacheDifferentFilterParams(SessionFactoryScope scope) { + scope.getSessionFactory().getCache().evictQueryRegions(); + final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); + statistics.clear(); + + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "John" ); + executeQuery( session, 1 ); + } ); + + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 0 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 1 ); + + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "Jack" ); + executeQuery( session, 0 ); + } ); + + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 0 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 2 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 2 ); + } + + private void executeQuery(SessionImplementor session, int expectedResults) { + final List resultList = session.createQuery( + "from Person p", + Person.class + ).setCacheable( true ).getResultList(); + assertThat( resultList ).hasSize( expectedResults ); + } + + @Entity( name = "Person" ) + @FilterDef( name = "personName", parameters = @ParamDef( name = "name", type = String.class ) ) + @Filter( name = "personName", condition = "name = :name" ) + @FilterDef( name = "personName2", parameters = @ParamDef( name = "name", type = String.class ) ) + @Filter( name = "personName2", condition = "name = :name" ) + public static class Person { + @Id + @GeneratedValue + private Long id; + + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + } +} diff --git a/hibernate-jcache/src/test/java/org/hibernate/orm/test/jcache/QueryCacheWithFilterTest.java b/hibernate-jcache/src/test/java/org/hibernate/orm/test/jcache/QueryCacheWithFilterTest.java index e5b032cbc9..ec4361ec30 100644 --- a/hibernate-jcache/src/test/java/org/hibernate/orm/test/jcache/QueryCacheWithFilterTest.java +++ b/hibernate-jcache/src/test/java/org/hibernate/orm/test/jcache/QueryCacheWithFilterTest.java @@ -13,10 +13,13 @@ import org.hibernate.stat.CacheRegionStatistics; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Jira; import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,87 +30,94 @@ import jakarta.persistence.Id; import static org.assertj.core.api.Assertions.assertThat; -@DomainModel(annotatedClasses = { - QueryCacheWithFilterTest.Person.class, -}) -@SessionFactory(generateStatistics = true) -@ServiceRegistry( - settings = { - @Setting(name = AvailableSettings.USE_QUERY_CACHE, value = "true"), - @Setting(name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true"), - @Setting(name = AvailableSettings.CACHE_REGION_FACTORY, value = "jcache") - } -) +@DomainModel( annotatedClasses = QueryCacheWithFilterTest.Person.class ) +@SessionFactory( generateStatistics = true ) +@ServiceRegistry( settings = { + @Setting( name = AvailableSettings.USE_QUERY_CACHE, value = "true" ), + @Setting( name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true" ), + @Setting( name = AvailableSettings.CACHE_REGION_FACTORY, value = "jcache" ) +} ) public class QueryCacheWithFilterTest { - - @BeforeEach + @BeforeAll public void setUp(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - Person p = new Person(); - p.setName( "John" ); - session.persist( p ); - } - ); + scope.inTransaction( session -> session.persist( new Person( "John" ) ) ); + } + + @AfterAll + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( session -> session.createMutationQuery( "delete from Person" ).executeUpdate() ); } @Test - public void testQueryKeyIsSerializable(SessionFactoryScope scope) { - scope.inTransaction( - session -> { - session.enableFilter( "personName" ) - .setParameter( "name", "John" ); - Query query = session.createQuery( - "from Person p", - Person.class - ); - query.setCacheable( true ); + @Jira( "https://hibernate.atlassian.net/browse/HHH-16385" ) + public void testQueryCacheKeyIsImmutable(SessionFactoryScope scope) { + scope.getSessionFactory().getCache().evictQueryRegions(); + final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); + statistics.clear(); - List resultList1 = query.getResultList(); - assertThat( resultList1 ).hasSize( 1 ); + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "John" ); + executeQuery( session, 1 ); + // cache query key should not be affected by changing enabled filters + session.enableFilter( "personName2" ).setParameter( "name", "John2" ); + } ); - //if QueryKey is not serializable, EHCache will silently fail the cache store operation - } - ); - scope.inTransaction( - session -> { - session.enableFilter( "personName" ) - .setParameter( "name", "John" ); - Query query = session.createQuery( - "from Person p", - Person.class - ); - query.setCacheable( true ); + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 0 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 1 ); - List resultList = query.getResultList(); - assertThat( resultList ).hasSize( 1 ); + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "John" ); + executeQuery( session, 1 ); + } ); - assertThat( getQueryCacheRegionStatistics( session ).getHitCount() ).isEqualTo( 1 ); - } - ); + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 1 ); } - private static CacheRegionStatistics getQueryCacheRegionStatistics(SessionImplementor session) { - StatisticsImplementor statistics = session.getSessionFactory().getStatistics(); - return statistics.getQueryRegionStatistics( RegionFactory.DEFAULT_QUERY_RESULTS_REGION_UNQUALIFIED_NAME ); + @Test + @Jira( "https://hibernate.atlassian.net/browse/HHH-16617" ) + public void testQueryCacheDifferentFilterParams(SessionFactoryScope scope) { + scope.getSessionFactory().getCache().evictQueryRegions(); + final StatisticsImplementor statistics = scope.getSessionFactory().getStatistics(); + statistics.clear(); + + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "John" ); + executeQuery( session, 1 ); + } ); + + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 0 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 1 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 1 ); + + scope.inTransaction( session -> { + session.enableFilter( "personName" ).setParameter( "name", "Jack" ); + executeQuery( session, 0 ); + } ); + + assertThat( statistics.getQueryCacheHitCount() ).isEqualTo( 0 ); + assertThat( statistics.getQueryCacheMissCount() ).isEqualTo( 2 ); + assertThat( statistics.getQueryCachePutCount() ).isEqualTo( 2 ); } - @Entity(name = "Person") - @FilterDef( - name = "personName", - parameters = @ParamDef( - name = "name", - type = String.class - ) - ) - @Filter( - name = "personName", - condition = "name = :name" - ) + private void executeQuery(SessionImplementor session, int expectedResults) { + final List resultList = session.createQuery( + "from Person p", + Person.class + ).setCacheable( true ).getResultList(); + assertThat( resultList ).hasSize( expectedResults ); + } + + @Entity( name = "Person" ) + @FilterDef( name = "personName", parameters = @ParamDef( name = "name", type = String.class ) ) + @Filter( name = "personName", condition = "name = :name" ) + @FilterDef( name = "personName2", parameters = @ParamDef( name = "name", type = String.class ) ) + @Filter( name = "personName2", condition = "name = :name" ) public static class Person { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue private Long id; private String name; @@ -126,10 +136,5 @@ public class QueryCacheWithFilterTest { public String getName() { return name; } - - public void setName(String name) { - this.name = name; - } } - }