Merge pull request #1263 from jamesagnew/expunge-testing

Expunge testing
This commit is contained in:
James Agnew 2019-04-03 16:42:08 -04:00 committed by GitHub
commit 242e138a1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 14 deletions

View File

@ -224,6 +224,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
throw new MethodNotAllowedException("$expunge is not enabled on this server"); throw new MethodNotAllowedException("$expunge is not enabled on this server");
} }
if (theExpungeOptions.getLimit() < 1) {
throw new InvalidRequestException("Expunge limit may not be less than 1. Received expunge limit "+theExpungeOptions.getLimit() + ".");
}
AtomicInteger remainingCount = new AtomicInteger(theExpungeOptions.getLimit()); AtomicInteger remainingCount = new AtomicInteger(theExpungeOptions.getLimit());
if (theResourceName == null && theResourceId == null && theVersion == null) { if (theResourceName == null && theResourceId == null && theVersion == null) {
@ -275,12 +279,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
for (Long next : resourceIds) { for (Long next : resourceIds) {
txTemplate.execute(t -> { txTemplate.execute(t -> {
expungeHistoricalVersionsOfId(next, remainingCount); expungeHistoricalVersionsOfId(next, remainingCount);
if (remainingCount.get() <= 0) {
ourLog.debug("Expunge limit has been hit - Stopping operation");
return toExpungeOutcome(theExpungeOptions, remainingCount);
}
return null; return null;
}); });
if (remainingCount.get() <= 0) {
ourLog.debug("Expunge limit has been hit - Stopping operation");
return toExpungeOutcome(theExpungeOptions, remainingCount);
}
} }
/* /*
@ -291,6 +295,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
expungeCurrentVersionOfResource(next, remainingCount); expungeCurrentVersionOfResource(next, remainingCount);
return null; return null;
}); });
if (remainingCount.get() <= 0) {
ourLog.debug("Expunge limit has been hit - Stopping operation");
return toExpungeOutcome(theExpungeOptions, remainingCount);
}
} }
} }
@ -302,8 +310,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
*/ */
Pageable page = PageRequest.of(0, remainingCount.get()); Pageable page = PageRequest.of(0, remainingCount.get());
Slice<Long> historicalIds = txTemplate.execute(t -> { Slice<Long> historicalIds = txTemplate.execute(t -> {
if (theResourceId != null && theVersion != null) { if (theResourceId != null) {
return toSlice(myResourceHistoryTableDao.findForIdAndVersion(theResourceId, theVersion)); if (theVersion != null) {
return toSlice(myResourceHistoryTableDao.findForIdAndVersion(theResourceId, theVersion));
} else {
return myResourceHistoryTableDao.findIdsOfPreviousVersionsOfResourceId(page, theResourceId);
}
} else { } else {
if (theResourceName != null) { if (theResourceName != null) {
return myResourceHistoryTableDao.findIdsOfPreviousVersionsOfResources(page, theResourceName); return myResourceHistoryTableDao.findIdsOfPreviousVersionsOfResources(page, theResourceName);

View File

@ -1,10 +1,6 @@
package ca.uhn.fhir.jpa.dao.data; package ca.uhn.fhir.jpa.dao.data;
import java.util.Collection; import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import java.util.Date;
import javax.persistence.TemporalType;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice; import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
@ -13,7 +9,9 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.Temporal; import org.springframework.data.jpa.repository.Temporal;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable; import javax.persistence.TemporalType;
import java.util.Collection;
import java.util.Date;
/* /*
* #%L * #%L
@ -74,6 +72,13 @@ public interface IResourceHistoryTableDao extends JpaRepository<ResourceHistoryT
@Query("SELECT t.myId FROM ResourceHistoryTable t WHERE t.myResourceId = :resId AND t.myResourceVersion != :dontWantVersion") @Query("SELECT t.myId FROM ResourceHistoryTable t WHERE t.myResourceId = :resId AND t.myResourceVersion != :dontWantVersion")
Slice<Long> findForResourceId(Pageable thePage, @Param("resId") Long theId, @Param("dontWantVersion") Long theDontWantVersion); Slice<Long> findForResourceId(Pageable thePage, @Param("resId") Long theId, @Param("dontWantVersion") Long theDontWantVersion);
@Query("" +
"SELECT v.myId FROM ResourceHistoryTable v " +
"LEFT OUTER JOIN ResourceTable t ON (v.myResourceId = t.myId) " +
"WHERE v.myResourceVersion != t.myVersion AND " +
"t.myId = :resId")
Slice<Long> findIdsOfPreviousVersionsOfResourceId(Pageable thePage, @Param("resId") Long theResourceId);
@Query("" + @Query("" +
"SELECT v.myId FROM ResourceHistoryTable v " + "SELECT v.myId FROM ResourceHistoryTable v " +
"LEFT OUTER JOIN ResourceTable t ON (v.myResourceId = t.myId) " + "LEFT OUTER JOIN ResourceTable t ON (v.myResourceId = t.myId) " +

View File

@ -49,8 +49,9 @@ public class ExpungeOptions {
/** /**
* The maximum number of resource versions to expunge * The maximum number of resource versions to expunge
*/ */
public void setLimit(int theLimit) { public ExpungeOptions setLimit(int theLimit) {
myLimit = theLimit; myLimit = theLimit;
return this;
} }
public boolean isExpungeEverything() { public boolean isExpungeEverything() {

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.util.ExpungeOptions; import ca.uhn.fhir.jpa.util.ExpungeOptions;
import ca.uhn.fhir.jpa.util.JpaConstants; import ca.uhn.fhir.jpa.util.JpaConstants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -17,7 +18,8 @@ import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class ResourceProviderExpungeDstu3Test extends BaseResourceProviderDstu3Test { public class ResourceProviderExpungeDstu3Test extends BaseResourceProviderDstu3Test {
@ -290,6 +292,61 @@ public class ResourceProviderExpungeDstu3Test extends BaseResourceProviderDstu3T
assertGone(myDeletedObservationId); assertGone(myDeletedObservationId);
} }
@Test
public void testExpungeLimitZero() {
try {
myPatientDao.expunge(new ExpungeOptions()
.setExpungeDeletedResources(true)
.setExpungeOldVersions(true)
.setLimit(0));
fail();
} catch (InvalidRequestException e) {
assertEquals("Expunge limit may not be less than 1. Received expunge limit 0.", e.getMessage());
}
}
@Test
public void testExpungeInstanceOldVersionsAndDeletedBoundaryLimit() {
myPatientDao.delete(myTwoVersionPatientId);
myPatientDao.expunge(myTwoVersionPatientId.toUnqualifiedVersionless(), new ExpungeOptions()
.setExpungeDeletedResources(true)
.setExpungeOldVersions(true)
.setLimit(2));
// Patients
assertStillThere(myOneVersionPatientId);
assertExpunged(myTwoVersionPatientId.withVersion("1"));
assertExpunged(myTwoVersionPatientId.withVersion("2"));
assertGone(myDeletedPatientId);
// No observations deleted
assertStillThere(myOneVersionObservationId);
assertStillThere(myTwoVersionObservationId.withVersion("1"));
assertStillThere(myTwoVersionObservationId.withVersion("2"));
assertGone(myDeletedObservationId);
}
@Test
public void testExpungeNothing() {
myPatientDao.expunge(myOneVersionPatientId.toUnqualifiedVersionless(), new ExpungeOptions()
.setExpungeDeletedResources(true)
.setExpungeOldVersions(true));
// Patients
assertStillThere(myOneVersionPatientId);
assertStillThere(myTwoVersionPatientId.withVersion("1"));
assertStillThere(myTwoVersionPatientId.withVersion("2"));
assertGone(myDeletedPatientId);
// No observations deleted
assertStillThere(myOneVersionObservationId);
assertStillThere(myTwoVersionObservationId.withVersion("1"));
assertStillThere(myTwoVersionObservationId.withVersion("2"));
assertGone(myDeletedObservationId);
}
@Test @Test
public void testParameters() { public void testParameters() {
Parameters p = new Parameters(); Parameters p = new Parameters();

View File

@ -125,6 +125,13 @@
in the built WAR, in order to prevent duplicates and conflicts in implementing in the built WAR, in order to prevent duplicates and conflicts in implementing
projects. projects.
</action> </action>
<action type="fix">
Two expunge bug fixes:
The first bug is that the expunge operation wasn't bailing once it hit its limit. This resulted in a
"Page size must not be less than one!" error.
The second bug is that one case wasn't properly handled: when a resourceId with no version is provided.
This executed the case where only resource type is provided.
</action>
</release> </release>
<release version="3.7.0" date="2019-02-06" description="Gale"> <release version="3.7.0" date="2019-02-06" description="Gale">
<action type="add"> <action type="add">