From aeb1da83f297fe089f7a4d5948902febd51b95c8 Mon Sep 17 00:00:00 2001 From: Jens Schauder Date: Tue, 13 Nov 2018 16:15:36 +0100 Subject: [PATCH] #146 - Added tests and simplified condition. Added tests to verify behaviour. In order to improve testability querying was extracted into package private method. The condition avoiding the IN-queries with empty parameter lists was simplified and made less lenient. Original pull request: #147. --- .../support/EnversRevisionRepositoryImpl.java | 13 ++- ...EnversRevisionRepositoryImplUnitTests.java | 101 ++++++++++++++++++ .../support/RepositoryIntegrationTests.java | 21 ++++ 3 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 src/test/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImplUnitTests.java diff --git a/src/main/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImpl.java b/src/main/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImpl.java index 8fa5efc..a404585 100755 --- a/src/main/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImpl.java +++ b/src/main/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImpl.java @@ -90,7 +90,7 @@ public class EnversRevisionRepositoryImpl type = entityInformation.getJavaType(); AuditReader reader = AuditReaderFactory.get(entityManager); - List revisions = reader.getRevisions(type, id); + List revisions = getRevisions(id, type, reader); if (revisions.isEmpty()) { return Optional.empty(); @@ -129,7 +129,7 @@ public class EnversRevisionRepositoryImpl type = entityInformation.getJavaType(); AuditReader reader = AuditReaderFactory.get(entityManager); - List revisionNumbers = reader.getRevisions(type, id); + List revisionNumbers = getRevisions(id, type, reader); return revisionNumbers.isEmpty() ? Revisions.none() : getEntitiesForRevisions((List) revisionNumbers, id, reader); @@ -144,14 +144,15 @@ public class EnversRevisionRepositoryImpl type = entityInformation.getJavaType(); AuditReader reader = AuditReaderFactory.get(entityManager); - List revisionNumbers = reader.getRevisions(type, id); + List revisionNumbers = getRevisions((ID) id, (Class) type, reader); boolean isDescending = RevisionSort.getRevisionDirection(pageable.getSort()).isDescending(); if (isDescending) { Collections.reverse(revisionNumbers); } - if (revisionNumbers.isEmpty() || pageable.getOffset() > revisionNumbers.size()) { + if ( + pageable.getOffset() >= revisionNumbers.size()) { return Page.empty(pageable); } @@ -166,6 +167,10 @@ public class EnversRevisionRepositoryImpl>(revisions.getContent(), pageable, revisionNumbers.size()); } + List getRevisions(ID id, Class type, AuditReader reader) { + return reader.getRevisions(type, id); + } + /** * Returns the entities in the given revisions for the entitiy with the given id. * diff --git a/src/test/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImplUnitTests.java b/src/test/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImplUnitTests.java new file mode 100644 index 0000000..9bb1713 --- /dev/null +++ b/src/test/java/org/springframework/data/envers/repository/support/EnversRevisionRepositoryImplUnitTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.envers.repository.support; + +import static org.mockito.Mockito.*; + +import javax.persistence.EntityManager; + +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.envers.AuditReader; +import org.hibernate.envers.boot.internal.EnversService; +import org.junit.Before; +import org.junit.Test; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.jpa.repository.support.JpaEntityInformation; +import org.springframework.data.repository.history.support.RevisionEntityInformation; + +import java.util.Collections; +import java.util.List; + +/** + * Unit tests for EversRevisionRepositoryImpl. + * + * @author Jens Schauder + */ +public class EnversRevisionRepositoryImplUnitTests { + + private static final int NON_EXISTING_ID = -999; + + JpaEntityInformation entityInformation = mock(JpaEntityInformation.class); + RevisionEntityInformation revisionEntityInformation = mock(RevisionEntityInformation.class); + SessionImplementor session = mock(SessionImplementor.class, RETURNS_DEEP_STUBS); + EnversService enversService = mock(EnversService.class, RETURNS_DEEP_STUBS); + EntityManager entityManager = mock(EntityManager.class); + + + @Before + public void mockHibernateInfrastructure() { + + when(entityInformation.getJavaType()).thenReturn((Class) DummyEntity.class); + + when(enversService.getEntitiesConfigurations().isVersioned(any(String.class))).thenReturn(true); + + when(session.isOpen()).thenReturn(true); + when(session.getFactory().getServiceRegistry().getService(EnversService.class)).thenReturn(enversService); + + when(entityManager.getDelegate()).thenReturn(session); + } + + @Test // #146 + public void findRevisionShortCircuitsOnEmptyRevisionList() { + + failOnEmptyRevisions(); + + EnversRevisionRepositoryImplUnderTest repository = new EnversRevisionRepositoryImplUnderTest<>(entityInformation, revisionEntityInformation, entityManager); + + repository.findRevisions(-999, PageRequest.of(0, 5)); + } + + private void failOnEmptyRevisions() { + + // simulate failure to query with empty revisions list as Postgres does. + when(enversService.getRevisionInfoQueryCreator().getRevisionsQuery(any(Session.class), eq(Collections.emptySet())) + .getResultList()).thenThrow(HibernateException.class); + } + + /** + * An extension for the {@link EnversRevisionRepositoryImpl} that skips accessing the AuditReader and always returns an empty List. + */ + private class EnversRevisionRepositoryImplUnderTest> + extends EnversRevisionRepositoryImpl { + + EnversRevisionRepositoryImplUnderTest(JpaEntityInformation entityInformation, + RevisionEntityInformation revisionEntityInformation, EntityManager entityManager) { + super(entityInformation, revisionEntityInformation, entityManager); + } + + @Override + List getRevisions(ID id, Class type, AuditReader reader) { + return Collections.emptyList(); + } + } + + private static class DummyEntity { + } +} \ No newline at end of file diff --git a/src/test/java/org/springframework/data/envers/repository/support/RepositoryIntegrationTests.java b/src/test/java/org/springframework/data/envers/repository/support/RepositoryIntegrationTests.java index a68aa4d..f747465 100755 --- a/src/test/java/org/springframework/data/envers/repository/support/RepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/envers/repository/support/RepositoryIntegrationTests.java @@ -183,4 +183,25 @@ public class RepositoryIntegrationTests { .extracting(c -> c.name, c -> c.code) // .containsExactly(null, null); } + + @Test // #146 + public void shortCurcuitingWhenOffsetIsToLarge() { + Country de = new Country(); + de.code = "de"; + de.name = "Deutschland"; + + countryRepository.save(de); + + countryRepository.delete(de); + + check(de, 0, 1); + check(de, 1, 1); + check(de, 2, 0); + } + + void check(Country de, int page, int expectedSize) { + + Page> revisions = countryRepository.findRevisions(de.id, PageRequest.of(page,1)); + assertThat(revisions).hasSize(expectedSize); + } }