perf enhancements finally working

This commit is contained in:
James 2017-04-17 16:56:53 -04:00
parent fbbe792726
commit 5adc09ad56
19 changed files with 209 additions and 72 deletions

View File

@ -63,6 +63,7 @@ public abstract class RequestDetails {
private IRestfulResponse myResponse;
private RestOperationTypeEnum myRestOperationType;
private String mySecondaryOperation;
private boolean mySubRequest;
private Map<String, List<String>> myUnqualifiedToQualifiedNames;
private Map<Object, Object> myUserData;
protected abstract byte[] getByteStreamRequestContents();
@ -71,6 +72,7 @@ public abstract class RequestDetails {
* Return the charset as defined by the header contenttype. Return null if it is not set.
*/
public abstract Charset getCharset();
public String getCompartmentName() {
return myCompartmentName;
}
@ -78,7 +80,6 @@ public abstract class RequestDetails {
public String getCompleteUrl() {
return myCompleteUrl;
}
/**
* Returns the <b>conditional URL</b> if this request has one, or <code>null</code> otherwise. For an
* update or delete method, this is the part of the URL after the <code>?</code>. For a create, this
@ -248,6 +249,19 @@ public abstract class RequestDetails {
return myRespondGzip;
}
/**
* Is this request a sub-request (i.e. a request within a batch or transaction)? This
* flag is used internally by hapi-fhir-jpaserver-base, but not used in the plain server
* library. You may use it in your client code as a hint when implementing transaction logic in the plain
* server.
* <p>
* Defaults to {@literal false}
* </p>
*/
public boolean isSubRequest() {
return mySubRequest;
}
public final byte[] loadRequestContents() {
if (myRequestContents == null) {
myRequestContents = getByteStreamRequestContents();
@ -327,10 +341,23 @@ public abstract class RequestDetails {
public void setRestOperationType(RestOperationTypeEnum theRestOperationType) {
myRestOperationType = theRestOperationType;
}
public void setSecondaryOperation(String theSecondaryOperation) {
mySecondaryOperation = theSecondaryOperation;
}
/**
* Is this request a sub-request (i.e. a request within a batch or transaction)? This
* flag is used internally by hapi-fhir-jpaserver-base, but not used in the plain server
* library. You may use it in your client code as a hint when implementing transaction logic in the plain
* server.
* <p>
* Defaults to {@literal false}
* </p>
*/
public void setSubRequest(boolean theSubRequest) {
mySubRequest = theSubRequest;
}
private class RequestOperationCallback implements IRequestOperationCallback {

View File

@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.server.servlet;
* 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
* 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,
@ -94,7 +94,7 @@ public class ServletRequestDetails extends RequestDetails {
try {
InputStream inputStream = reader.getInputStream(this);
requestContents = IOUtils.toByteArray(inputStream);
if (myServer.isUncompressIncomingContents()) {
String contentEncoding = myServletRequest.getHeader(Constants.HEADER_CONTENT_ENCODING);
if ("gzip".equals(contentEncoding)) {
@ -105,7 +105,7 @@ public class ServletRequestDetails extends RequestDetails {
}
}
}
//FIXME resource leak
// FIXME resource leak
return requestContents;
} catch (IOException e) {
ourLog.error("Could not load request resource", e);
@ -164,7 +164,6 @@ public class ServletRequestDetails extends RequestDetails {
this.myServletResponse = myServletResponse;
}
@Override
public Charset getCharset() {
String ct = getHeader(Constants.HEADER_CONTENT_TYPE);

View File

@ -871,6 +871,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
if (theRequestDetails != null) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), getResourceName(), null);
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
if (theRequestDetails.isSubRequest()) {
theParams.setLoadSynchronous(true);
theParams.setLoadSynchronousUpTo(myDaoConfig.getMaximumSearchResultCountInTransaction());
}
}
return mySearchCoordinatorSvc.registerSearch(this, theParams, getResourceName());

View File

@ -48,6 +48,13 @@ public class DaoConfig {
"http://hl7.org/fhir/codesystem-*",
"http://hl7.org/fhir/StructureDefinition/*")));
/**
* Default value for {@link #setMaximumSearchResultCountInTransaction(int)}
*
* @see #setMaximumSearchResultCountInTransaction(int)
*/
private static final int DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION = 500;
// ***
// update setter javadoc if default changes
// ***
@ -86,12 +93,14 @@ public class DaoConfig {
// update setter javadoc if default changes
// ***
private int myMaximumExpansionSize = 5000;
private int myMaximumSearchResultCountInTransaction = DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private boolean mySchedulingDisabled;
private boolean mySubscriptionEnabled;
private long mySubscriptionPollDelay = 1000;
private Long mySubscriptionPurgeInactiveAfterMillis;
private Set<String> myTreatBaseUrlsAsLocal = new HashSet<String>();
private Set<String> myTreatReferencesAsLogical = new HashSet<String>(DEFAULT_LOGICAL_BASE_URLS);
/**
@ -173,6 +182,18 @@ public class DaoConfig {
return myMaximumExpansionSize;
}
/**
* Provides the maximum number of results which may be returned by a search within a FHIR <code>transaction</code>
* operation. For example, if this value is set to <code>100</code> and a FHIR transaction is processed with a sub-request
* for <code>Patient?gender=male</code>, the server will throw an error (and the transaction will fail) if there are more than
* 100 resources on the server which match this query.
*
* @see #DEFAULT_LOGICAL_BASE_URLS The default value for this setting
*/
public int getMaximumSearchResultCountInTransaction() {
return myMaximumSearchResultCountInTransaction;
}
public ResourceEncodingEnum getResourceEncoding() {
return myResourceEncoding;
}
@ -499,6 +520,18 @@ public class DaoConfig {
myMaximumExpansionSize = theMaximumExpansionSize;
}
/**
* Provides the maximum number of results which may be returned by a search within a FHIR <code>transaction</code>
* operation. For example, if this value is set to <code>100</code> and a FHIR transaction is processed with a sub-request
* for <code>Patient?gender=male</code>, the server will throw an error (and the transaction will fail) if there are more than
* 100 resources on the server which match this query.
*
* @see #DEFAULT_LOGICAL_BASE_URLS The default value for this setting
*/
public void setMaximumSearchResultCountInTransaction(int theMaximumSearchResultCountInTransaction) {
myMaximumSearchResultCountInTransaction = theMaximumSearchResultCountInTransaction;
}
public void setResourceEncoding(ResourceEncodingEnum theResourceEncoding) {
myResourceEncoding = theResourceEncoding;
}

View File

@ -1264,19 +1264,23 @@ public class SearchBuilder implements ISearchBuilder {
List<Long> pids = myFulltextSearchSvc.everything(myResourceName, myParams);
if (pids.isEmpty()) {
// Will never match
pids = Collections.singletonList((Long) null);
pids = Collections.singletonList(-1L);
}
myPredicates.add(myResourceTableRoot.get("myId").as(Long.class).in(pids));
}
myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates)));
/*
* Now perform the search
*/
final TypedQuery<Long> query = myEntityManager.createQuery(outerQuery);
// FIXME: remove
query.getResultList();
return new Iterator<Long>() {
private Long myNext;

View File

@ -28,6 +28,11 @@ import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.dstu3.model.SearchParameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.jpa.dao.BaseSearchParamExtractor;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSearchParameter;
@ -51,9 +56,18 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
protected void markAffectedResources(SearchParameter theResource) {
if (theResource != null) {
String expression = theResource.getExpression();
String resourceType = expression.substring(0, expression.indexOf('.'));
final String resourceType = expression.substring(0, expression.indexOf('.'));
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", expression);
int updatedCount = myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
int updatedCount = txTemplate.execute(new TransactionCallback<Integer>() {
@Override
public Integer doInTransaction(TransactionStatus theStatus) {
return myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
}
});
ourLog.info("Marked {} resources for reindexing", updatedCount);
}

View File

@ -100,7 +100,10 @@ public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry {
}
}
IBundleProvider allSearchParamsBp = mySpDao.search(new SearchParameterMap());
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronous(true);
IBundleProvider allSearchParamsBp = mySpDao.search(params);
int size = allSearchParamsBp.size();
// Just in case..

View File

@ -54,6 +54,9 @@ public class Search implements Serializable {
@Column(name="CREATED", nullable=false, updatable=false)
private Date myCreated;
@Column(name="FAILURE_CODE", nullable=true)
private Integer myFailureCode;
@Column(name="FAILURE_MESSAGE", length=FAILURE_MESSAGE_LENGTH, nullable=true)
private String myFailureMessage;
@ -65,7 +68,7 @@ public class Search implements Serializable {
@OneToMany(mappedBy="mySearch")
private Collection<SearchInclude> myIncludes;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="LAST_UPDATED_HIGH", nullable=true, insertable=true, updatable=false)
private Date myLastUpdatedHigh;
@ -73,7 +76,7 @@ public class Search implements Serializable {
@Temporal(TemporalType.TIMESTAMP)
@Column(name="LAST_UPDATED_LOW", nullable=true, insertable=true, updatable=false)
private Date myLastUpdatedLow;
@Column(name="NUM_FOUND", nullable=false)
private int myNumFound;
@ -88,18 +91,18 @@ public class Search implements Serializable {
@OneToMany(mappedBy="mySearch")
private Collection<SearchResult> myResults;
@Column(name="SEARCH_STRING", length=1000, nullable=true)
private String mySearchString;
@Enumerated(EnumType.ORDINAL)
@Column(name="SEARCH_TYPE", nullable=false)
private SearchTypeEnum mySearchType;
@Enumerated(EnumType.STRING)
@Column(name="SEARCH_STATUS", nullable=false, length=10)
private SearchStatusEnum myStatus;
@Column(name="TOTAL_COUNT", nullable=true)
private Integer myTotalCount;
@ -110,6 +113,10 @@ public class Search implements Serializable {
return myCreated;
}
public Integer getFailureCode() {
return myFailureCode;
}
public String getFailureMessage() {
return myFailureMessage;
}
@ -152,11 +159,11 @@ public class Search implements Serializable {
public Long getResourceId() {
return myResourceId;
}
public String getResourceType() {
return myResourceType;
}
public SearchTypeEnum getSearchType() {
return mySearchType;
}
@ -177,6 +184,10 @@ public class Search implements Serializable {
myCreated = theCreated;
}
public void setFailureCode(Integer theFailureCode) {
myFailureCode = theFailureCode;
}
public void setFailureMessage(String theFailureMessage) {
myFailureMessage = left(theFailureMessage, FAILURE_MESSAGE_LENGTH);

View File

@ -30,6 +30,16 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class ServletSubRequestDetails extends ServletRequestDetails {
private Map<String, ArrayList<String>> myHeaders = new HashMap<String, ArrayList<String>>();
public void addHeader(String theName, String theValue) {
String lowerCase = theName.toLowerCase();
ArrayList<String> list = myHeaders.get(lowerCase);
if (list == null) {
list = new ArrayList<String>();
myHeaders.put(lowerCase, list);
}
list.add(theValue);
}
@Override
public String getHeader(String theName) {
@ -49,14 +59,9 @@ public class ServletSubRequestDetails extends ServletRequestDetails {
return list;
}
public void addHeader(String theName, String theValue) {
String lowerCase = theName.toLowerCase();
ArrayList<String> list = myHeaders.get(lowerCase);
if (list == null) {
list = new ArrayList<String>();
myHeaders.put(lowerCase, list);
}
list.add(theValue);
@Override
public boolean isSubRequest() {
return true;
}
}

View File

@ -33,7 +33,7 @@ public class PersistedJpaSearchFirstPageBundleProvider extends PersistedJpaBundl
@Override
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
checkForFailedSearch();
SearchCoordinatorSvcImpl.verifySearchHasntFailedOrThrowInternalErrorException(mySearch);
final List<Long> pids = mySearchTask.getResourcePids(theFromIndex, theToIndex);
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
@ -48,15 +48,8 @@ public class PersistedJpaSearchFirstPageBundleProvider extends PersistedJpaBundl
@Override
public Integer size() {
mySearchTask.awaitInitialSync();
checkForFailedSearch();
SearchCoordinatorSvcImpl.verifySearchHasntFailedOrThrowInternalErrorException(mySearch);
return super.size();
}
private void checkForFailedSearch() {
if (mySearch.getStatus() == SearchStatusEnum.FAILED) {
throw new InternalErrorException("Failure while loading search results");
}
}
}

View File

@ -7,6 +7,7 @@ import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -14,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
@ -37,8 +39,10 @@ import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.method.PageMethodBinding;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.util.ObjectUtil;
public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
static final int DEFAULT_SYNC_SIZE = 250;
@ -143,12 +147,13 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
ISearchBuilder sb = theCallingDao.newSearchBuilder();
sb.setType(resourceTypeClass, theResourceType);
Iterator<Long> resultIter = sb.createQuery(theParams);
if (theParams.isLoadSynchronous()) {
// Load the results synchronously
List<Long> pids = new ArrayList<Long>();
Iterator<Long> resultIter = sb.createQuery(theParams);
while (resultIter.hasNext()) {
pids.add(resultIter.next());
if (theParams.getLoadSynchronousUpTo() != null && pids.size() >= theParams.getLoadSynchronousUpTo()) {
@ -246,7 +251,11 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
static void verifySearchHasntFailedOrThrowInternalErrorException(Search theSearch) {
if (theSearch.getStatus() == SearchStatusEnum.FAILED) {
throw new InternalErrorException(theSearch.getFailureMessage());
Integer status = theSearch.getFailureCode();
status = ObjectUtils.defaultIfNull(status, 500);
String message = theSearch.getFailureMessage();
throw BaseServerResponseException.newInstance(status, message);
}
}
@ -318,9 +327,20 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
ourLog.error("Failed during search loading after {}ms", sw.getMillis(), t);
myUnsyncedPids.clear();
mySearch.setStatus(SearchStatusEnum.FAILED);
String failureMessage = ExceptionUtils.getRootCauseMessage(t);
Throwable rootCause = ExceptionUtils.getRootCause(t);
rootCause = ObjectUtils.defaultIfNull(rootCause, t);
String failureMessage = rootCause.getMessage();
int failureCode = InternalErrorException.STATUS_CODE;
if (t instanceof BaseServerResponseException) {
failureCode = ((BaseServerResponseException) t).getStatusCode();
}
mySearch.setFailureMessage(failureMessage);
mySearch.setFailureCode(failureCode);
mySearch.setStatus(SearchStatusEnum.FAILED);
saveSearch();
}

View File

@ -16,6 +16,9 @@ import javax.servlet.http.HttpServletRequest;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.Test;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
@ -150,13 +153,18 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test {
@Test
public void testSearchAndReindex() {
Patient patient;
SearchParameterMap map;
patient = new Patient();
patient.getText().setDiv("<div>DIVAAA</div>");
patient.addName().addGiven("NAMEAAA");
IIdType pId1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
final IIdType pId1= newTxTemplate().execute(new TransactionCallback<IIdType>() {
@Override
public IIdType doInTransaction(TransactionStatus theStatus) {
// TODO Auto-generated method stub
Patient patient = new Patient();
patient.getText().setDiv("<div>DIVAAA</div>");
patient.addName().addGiven("NAMEAAA");
return myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
}
});
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
@ -169,12 +177,21 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test {
/*
* Reindex
*/
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
Patient patient = new Patient();
patient.setId(pId1);
patient.getText().setDiv("<div>DIVBBB</div>");
patient.addName().addGiven("NAMEBBB");
myPatientDao.update(patient, mySrd);
}
});
patient = new Patient();
patient.setId(pId1);
patient.getText().setDiv("<div>DIVBBB</div>");
patient.addName().addGiven("NAMEBBB");
myPatientDao.update(patient, mySrd);
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("NAMEAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty());
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));

View File

@ -230,7 +230,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
Observation o2 = new Observation();
o2.getCode().addCoding().setSystem("foo").setCode("testChoiceParamDateAlt02");
o2.setEffective(new DateTimeDt("2015-03-08T11:11:11"));
IIdType id2 = myObservationDao.create(o2, mySrd).getId();
IIdType id2 = myObservationDao.create(o2, mySrd).getId().toUnqualifiedVersionless();
{
IBundleProvider found = myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_DATE, new DateParam(">2001-01-02")));
@ -2225,7 +2225,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
SearchParameterMap pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_CODE_VALUE_CONCEPT));
try {
myObservationDao.search(pm);
myObservationDao.search(pm).size();
fail();
} catch (InvalidRequestException e) {
assertEquals("This server does not support _sort specifications of type COMPOSITE - Can't serve _sort=code-value-concept", e.getMessage());

View File

@ -244,7 +244,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
map = new SearchParameterMap();
map.add("foo", new TokenParam(null, "male"));
try {
myPatientDao.search(map);
myPatientDao.search(map).size();
fail();
} catch (InvalidRequestException e) {
assertEquals("Unknown search parameter foo for resource type Patient", e.getMessage());
@ -282,7 +282,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
map = new SearchParameterMap();
map.add("foo", new TokenParam(null, "male"));
try {
myPatientDao.search(map);
myPatientDao.search(map).size();
fail();
} catch (InvalidRequestException e) {
assertEquals("Unknown search parameter foo for resource type Patient", e.getMessage());

View File

@ -191,7 +191,7 @@ public class FhirResourceDaoDstu3SearchWithLuceneDisabledTest extends BaseJpaTes
SearchParameterMap map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam(methodName));
try {
myOrganizationDao.search(map);
myOrganizationDao.search(map).size();
fail();
} catch (InvalidRequestException e) {
assertEquals("Fulltext search is not enabled on this service, can not process parameter: _content", e.getMessage());
@ -209,7 +209,7 @@ public class FhirResourceDaoDstu3SearchWithLuceneDisabledTest extends BaseJpaTes
SearchParameterMap map = new SearchParameterMap();
map.add(Constants.PARAM_TEXT, new StringParam(methodName));
try {
myOrganizationDao.search(map);
myOrganizationDao.search(map).size();
fail();
} catch (InvalidRequestException e) {
assertEquals("Fulltext search is not enabled on this service, can not process parameter: _text", e.getMessage());

View File

@ -722,7 +722,7 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
SearchParameterMap params = new SearchParameterMap();
params.add(Observation.SP_CODE, new TokenParam(URL_MY_CODE_SYSTEM, "AAA").setModifier(TokenParamModifier.ABOVE));
try {
myObservationDao.search(params);
myObservationDao.search(params).size();
fail();
} catch (InvalidRequestException e) {
assertEquals("Expansion of ValueSet produced too many codes (maximum 1) - Operation aborted!", e.getMessage());

View File

@ -2679,7 +2679,7 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
SearchParameterMap pm = new SearchParameterMap();
pm.setSort(new SortSpec(Observation.SP_CODE_VALUE_CONCEPT));
try {
myObservationDao.search(pm);
myObservationDao.search(pm).size();
fail();
} catch (InvalidRequestException e) {
assertEquals("This server does not support _sort specifications of type COMPOSITE - Can't serve _sort=code-value-concept", e.getMessage());

View File

@ -64,7 +64,7 @@ public class SearchCoordinatorSvcImplTest {
private IDao myCallingDao;
@Mock
private EntityManager myEntityManager;
private int myExpectedNumberOfSearchBuildersCreated = 1;
private int myExpectedNumberOfSearchBuildersCreated = 2;
@Mock
private ISearchBuilder mySearchBuider;
@Mock
@ -156,7 +156,7 @@ public class SearchCoordinatorSvcImplTest {
try {
result.getResources(0, 100000);
} catch (InternalErrorException e) {
assertEquals("NullPointerException: FAILED", e.getMessage());
assertEquals("FAILED", e.getMessage());
}
}
@ -272,7 +272,7 @@ public class SearchCoordinatorSvcImplTest {
assertEquals("30", resources.get(0).getIdElement().getValueAsString());
assertEquals("799", resources.get(769).getIdElement().getValueAsString());
myExpectedNumberOfSearchBuildersCreated = 3;
myExpectedNumberOfSearchBuildersCreated = 4;
}
@Test

View File

@ -20,17 +20,6 @@
<version>${project.version}</version>
</dependency>
<!--
The JPA project uses a newer API but we'll try to hold to this version
as much as possible. See #283.
-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- Testing -->
<dependency>
<groupId>xmlunit</groupId>
@ -150,6 +139,22 @@
<artifactId>guava</artifactId>
<scope>test</scope>
</dependency>
<!--
The JPA project uses a newer API but we'll try to hold to this version
as much as possible. See #283.
This dependency comes last so that the newer version brought in by
Jetty for unit tests comes first on the classpath (since jetty
needs that newer version. The unit tests are slooooow otherwise.
-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>