Fix tests for expiring search results

This commit is contained in:
James 2017-04-22 08:50:51 -04:00
parent dd5580ed2d
commit fa2950dacb
4 changed files with 247 additions and 181 deletions

View File

@ -99,7 +99,7 @@ public class DaoConfig {
private int myMaximumExpansionSize = 5000;
private int myMaximumSearchResultCountInTransaction = DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private Long myReuseCachedSearchResultsForMillis;
private Long myReuseCachedSearchResultsForMillis = DEFAULT_REUSE_CACHED_SEARCH_RESULTS_FOR_MILLIS;
private boolean mySchedulingDisabled;
private boolean mySubscriptionEnabled;
private long mySubscriptionPollDelay = 1000;

View File

@ -334,117 +334,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
@Test
public void testSearchReusesResultsEnabled() throws Exception {
List<IBaseResource> resources = new ArrayList<IBaseResource>();
for (int i = 0; i < 50; i++) {
Organization org = new Organization();
org.setName("HELLO");
resources.add(org);
}
ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute();
myDaoConfig.setReuseCachedSearchResultsForMillis(1000L);
Bundle result1 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid1 = toSearchUuidFromLinkNext(result1);
Search search1 = newTxTemplate().execute(new TransactionCallback<Search>() {
@Override
public Search doInTransaction(TransactionStatus theStatus) {
return mySearchEntityDao.findByUuid(uuid1);
}
});
Date lastReturned1 = search1.getSearchLastReturned();
Bundle result2 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid2 = toSearchUuidFromLinkNext(result2);
Search search2 = newTxTemplate().execute(new TransactionCallback<Search>() {
@Override
public Search doInTransaction(TransactionStatus theStatus) {
return mySearchEntityDao.findByUuid(uuid2);
}
});
Date lastReturned2 = search2.getSearchLastReturned();
assertTrue(lastReturned2.getTime() > lastReturned1.getTime());
Thread.sleep(1500);
Bundle result3 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
String uuid3 = toSearchUuidFromLinkNext(result3);
assertEquals(uuid1, uuid2);
assertNotEquals(uuid1, uuid3);
}
@Test
public void testSearchReusesResultsDisabled() throws Exception {
List<IBaseResource> resources = new ArrayList<IBaseResource>();
for (int i = 0; i < 50; i++) {
Organization org = new Organization();
org.setName("HELLO");
resources.add(org);
}
ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute();
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
Bundle result1 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid1 = toSearchUuidFromLinkNext(result1);
Bundle result2 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid2 = toSearchUuidFromLinkNext(result2);
Bundle result3 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
String uuid3 = toSearchUuidFromLinkNext(result3);
assertNotEquals(uuid1, uuid2);
assertNotEquals(uuid1, uuid3);
}
/**
* See #438
*/
@ -517,6 +406,24 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
Validate.notNull(input);
ourClient.create().resource(input).execute().getResource();
}
@Test
public void testCreateConditional() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
MethodOutcome output1 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
MethodOutcome output2 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
}
@Test
public void testCreateIncludesRequestValidatorInterceptorOutcome() throws IOException {
@ -548,23 +455,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
}
}
@Test
public void testCreateConditional() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
MethodOutcome output1 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
patient = new Patient();
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
patient.addName().setFamily("Tester").addGiven("Raghad");
MethodOutcome output2 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
}
@Test
@Ignore
public void testCreateQuestionnaireResponseWithValidation() throws IOException {
@ -888,17 +778,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
}
}
@Test
public void testDeleteReturnsOperationOutcome() {
Patient p = new Patient();
p.addName().setFamily("FAM");
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
IBaseOperationOutcome resp = ourClient.delete().resourceById(id).execute();
OperationOutcome oo = (OperationOutcome) resp;
assertThat(oo.getIssueFirstRep().getDiagnostics(), startsWith("Successfully deleted 1 resource(s) in "));
}
@Test
public void testDeleteResourceConditional1() throws IOException {
String methodName = "testDeleteResourceConditional1";
@ -1027,24 +906,15 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
}
/**
* See issue #52
*/
@Test
public void testProcedureRequestResources() throws Exception {
IGenericClient client = ourClient;
int initialSize = client.search().forResource(ProcedureRequest.class).returnBundle(Bundle.class).execute().getEntry().size();
ProcedureRequest res = new ProcedureRequest();
res.addIdentifier().setSystem("urn:foo").setValue("123");
client.create().resource(res).execute();
int newSize = client.search().forResource(ProcedureRequest.class).returnBundle(Bundle.class).execute().getEntry().size();
assertEquals(1, newSize - initialSize);
public void testDeleteReturnsOperationOutcome() {
Patient p = new Patient();
p.addName().setFamily("FAM");
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
IBaseOperationOutcome resp = ourClient.delete().resourceById(id).execute();
OperationOutcome oo = (OperationOutcome) resp;
assertThat(oo.getIssueFirstRep().getDiagnostics(), startsWith("Successfully deleted 1 resource(s) in "));
}
/**
@ -1285,31 +1155,6 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
}
// private void delete(String theResourceType, String theParamName, String theParamValue) {
// Bundle resources;
// do {
// IQuery<Bundle> forResource = ourClient.search().forResource(theResourceType);
// if (theParamName != null) {
// forResource = forResource.where(new StringClientParam(theParamName).matches().value(theParamValue));
// }
// resources = forResource.execute();
// for (IResource next : resources.toListOfResources()) {
// ourLog.info("Deleting resource: {}", next.getId());
// ourClient.delete().resource(next).execute();
// }
// } while (resources.size() > 0);
// }
//
// private void deleteToken(String theResourceType, String theParamName, String theParamSystem, String theParamValue)
// {
// Bundle resources = ourClient.search().forResource(theResourceType).where(new
// TokenClientParam(theParamName).exactly().systemAndCode(theParamSystem, theParamValue)).execute();
// for (IResource next : resources.toListOfResources()) {
// ourLog.info("Deleting resource: {}", next.getId());
// ourClient.delete().resource(next).execute();
// }
// }
/**
* See #147"Patient"
*/
@ -1432,6 +1277,31 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
}
// private void delete(String theResourceType, String theParamName, String theParamValue) {
// Bundle resources;
// do {
// IQuery<Bundle> forResource = ourClient.search().forResource(theResourceType);
// if (theParamName != null) {
// forResource = forResource.where(new StringClientParam(theParamName).matches().value(theParamValue));
// }
// resources = forResource.execute();
// for (IResource next : resources.toListOfResources()) {
// ourLog.info("Deleting resource: {}", next.getId());
// ourClient.delete().resource(next).execute();
// }
// } while (resources.size() > 0);
// }
//
// private void deleteToken(String theResourceType, String theParamName, String theParamSystem, String theParamValue)
// {
// Bundle resources = ourClient.search().forResource(theResourceType).where(new
// TokenClientParam(theParamName).exactly().systemAndCode(theParamSystem, theParamValue)).execute();
// for (IResource next : resources.toListOfResources()) {
// ourLog.info("Deleting resource: {}", next.getId());
// ourClient.delete().resource(next).execute();
// }
// }
@Test
public void testEverythingPatientOperation() throws Exception {
String methodName = "testEverythingOperation";
@ -2271,6 +2141,26 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
}
/**
* See issue #52
*/
@Test
public void testProcedureRequestResources() throws Exception {
IGenericClient client = ourClient;
int initialSize = client.search().forResource(ProcedureRequest.class).returnBundle(Bundle.class).execute().getEntry().size();
ProcedureRequest res = new ProcedureRequest();
res.addIdentifier().setSystem("urn:foo").setValue("123");
client.create().resource(res).execute();
int newSize = client.search().forResource(ProcedureRequest.class).returnBundle(Bundle.class).execute().getEntry().size();
assertEquals(1, newSize - initialSize);
}
/**
* Test for issue #60
*/
@ -2813,6 +2703,147 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
assertTrue(new InstantDt(value) + " should be before " + new InstantDt(after), value.before(after));
}
@Test
public void testSearchReusesNoParams() throws Exception {
List<IBaseResource> resources = new ArrayList<IBaseResource>();
for (int i = 0; i < 50; i++) {
Organization org = new Organization();
org.setName("HELLO");
resources.add(org);
}
ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute();
myDaoConfig.setReuseCachedSearchResultsForMillis(1000L);
Bundle result1 = ourClient
.search()
.forResource("Organization")
.returnBundle(Bundle.class)
.execute();
final String uuid1 = toSearchUuidFromLinkNext(result1);
Bundle result2 = ourClient
.search()
.forResource("Organization")
.returnBundle(Bundle.class)
.execute();
final String uuid2 = toSearchUuidFromLinkNext(result2);
assertEquals(uuid1, uuid2);
}
@Test
public void testSearchReusesResultsDisabled() throws Exception {
List<IBaseResource> resources = new ArrayList<IBaseResource>();
for (int i = 0; i < 50; i++) {
Organization org = new Organization();
org.setName("HELLO");
resources.add(org);
}
ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute();
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
Bundle result1 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid1 = toSearchUuidFromLinkNext(result1);
Bundle result2 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid2 = toSearchUuidFromLinkNext(result2);
Bundle result3 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
String uuid3 = toSearchUuidFromLinkNext(result3);
assertNotEquals(uuid1, uuid2);
assertNotEquals(uuid1, uuid3);
}
@Test
public void testSearchReusesResultsEnabled() throws Exception {
List<IBaseResource> resources = new ArrayList<IBaseResource>();
for (int i = 0; i < 50; i++) {
Organization org = new Organization();
org.setName("HELLO");
resources.add(org);
}
ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute();
myDaoConfig.setReuseCachedSearchResultsForMillis(1000L);
Bundle result1 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid1 = toSearchUuidFromLinkNext(result1);
Search search1 = newTxTemplate().execute(new TransactionCallback<Search>() {
@Override
public Search doInTransaction(TransactionStatus theStatus) {
return mySearchEntityDao.findByUuid(uuid1);
}
});
Date lastReturned1 = search1.getSearchLastReturned();
Bundle result2 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
final String uuid2 = toSearchUuidFromLinkNext(result2);
Search search2 = newTxTemplate().execute(new TransactionCallback<Search>() {
@Override
public Search doInTransaction(TransactionStatus theStatus) {
return mySearchEntityDao.findByUuid(uuid2);
}
});
Date lastReturned2 = search2.getSearchLastReturned();
assertTrue(lastReturned2.getTime() > lastReturned1.getTime());
Thread.sleep(1500);
Bundle result3 = ourClient
.search()
.forResource("Organization")
.where(Organization.NAME.matches().value("HELLO"))
.count(5)
.returnBundle(Bundle.class)
.execute();
String uuid3 = toSearchUuidFromLinkNext(result3);
assertEquals(uuid1, uuid2);
assertNotEquals(uuid1, uuid3);
}
/**
* See #316
*/

View File

@ -31,6 +31,7 @@ public class ExampleServerIT {
@Test
public void testCreateAndRead() throws IOException {
ourLog.info("Base URL is: http://localhost:" + ourPort + "/baseDstu3");
String methodName = "testCreateResourceConditional";
Patient pt = new Patient();

View File

@ -7,6 +7,40 @@
</properties>
<body>
<release version="2.5" date="TBD">
<action type="fix">
<![CDATA[
This release includes significant performance enhancements for the
JPA server. Most importantly, the way that searches are performed
has been re-written to allow the server to perform better when
the database has a large number of results in it.
<br/><br/>
<ul>
<li>
Searches with multiple search parameters of different
datatypes (e.g. find patients by name and date of birth)
were previously joined in Java code, now the join is
performed by the database which is faster
</li>
<li>
Searches which returned lots of results previously has all
results streamed into memory before anything was returned to
the client. This is particularly slow if you do a search for
(say) "get me all patients" since potentially thousands or
even millions of patients' IDs were loaded into memory
before anything gets returned to the client. HAPI FHIR
now has a multithreaded search coordinator which returns
results to the client as soon as they are available
</li>
</ul>
<br/><br/>
Existing users should delete the
<code>HFJ_SEARCH</code>,
<code>HFJ_SEARCH_INCLUDE</code>,
and
<code>HFJ_SEARCH_RESULT</code>
tables from your database before upgrading.
]]>
</action>
<action type="fix" issue="590">
AuthorizationInterceptor did not correctly handle paging requests
(e.g. requests for the second page of results for a search operation).