Work on R4 for JPA server
This commit is contained in:
parent
e7f8f8c30d
commit
40317a650d
|
@ -334,8 +334,10 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
|||
} else {
|
||||
if (serverFhirVersionString.startsWith("0.4") || serverFhirVersionString.startsWith("0.5") || serverFhirVersionString.startsWith("1.0.")) {
|
||||
serverFhirVersionEnum = FhirVersionEnum.DSTU2;
|
||||
} else if (serverFhirVersionString.startsWith("3.")) {
|
||||
} else if (serverFhirVersionString.startsWith("3.0.")) {
|
||||
serverFhirVersionEnum = FhirVersionEnum.DSTU3;
|
||||
} else if (serverFhirVersionString.startsWith("3.1.")) {
|
||||
serverFhirVersionEnum = FhirVersionEnum.R4;
|
||||
} else {
|
||||
// we'll be lenient and accept this
|
||||
ourLog.debug("Server conformance statement indicates unknown FHIR version: {}", serverFhirVersionString);
|
||||
|
|
|
@ -34,7 +34,7 @@ import ca.uhn.fhir.jpa.config.BaseConfig;
|
|||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.dao.r4.SearchParamExtractorR4;
|
||||
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
||||
import ca.uhn.fhir.jpa.interceptor.RestHookSubscriptionR4Interceptor;
|
||||
import ca.uhn.fhir.jpa.interceptor.r4.RestHookSubscriptionR4Interceptor;
|
||||
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||
import ca.uhn.fhir.jpa.term.*;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcR4;
|
||||
|
|
|
@ -23,18 +23,15 @@ package ca.uhn.fhir.jpa.config.r4;
|
|||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.*;
|
||||
import org.springframework.web.socket.handler.PerConnectionWebSocketHandler;
|
||||
|
||||
import ca.uhn.fhir.jpa.interceptor.WebSocketSubscriptionDstu3Interceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.SubscriptionWebsocketHandlerDstu3;
|
||||
import ca.uhn.fhir.jpa.interceptor.r4.WebSocketSubscriptionR4Interceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.r4.SubscriptionWebsocketHandlerR4;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
@Configuration
|
||||
|
@ -44,17 +41,17 @@ public class WebsocketR4Config implements WebSocketConfigurer {
|
|||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry theRegistry) {
|
||||
theRegistry.addHandler(subscriptionWebSocketHandler(), "/websocket/dstu3").setAllowedOrigins("*");
|
||||
theRegistry.addHandler(subscriptionWebSocketHandler(), "/websocket/r4").setAllowedOrigins("*");
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public WebSocketHandler subscriptionWebSocketHandler() {
|
||||
PerConnectionWebSocketHandler retVal = new PerConnectionWebSocketHandler(SubscriptionWebsocketHandlerDstu3.class);
|
||||
PerConnectionWebSocketHandler retVal = new PerConnectionWebSocketHandler(SubscriptionWebsocketHandlerR4.class);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(destroyMethod="destroy")
|
||||
public TaskScheduler websocketTaskSchedulerDstu3() {
|
||||
public TaskScheduler websocketTaskSchedulerR4() {
|
||||
final ThreadPoolTaskScheduler retVal = new ThreadPoolTaskScheduler() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -65,15 +62,15 @@ public class WebsocketR4Config implements WebSocketConfigurer {
|
|||
getScheduledThreadPoolExecutor().setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
|
||||
}
|
||||
};
|
||||
retVal.setThreadNamePrefix("ws-dstu3-");
|
||||
retVal.setThreadNamePrefix("ws-r4-");
|
||||
retVal.setPoolSize(5);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IServerInterceptor webSocketSubscriptionDstu3Interceptor(){
|
||||
return new WebSocketSubscriptionDstu3Interceptor();
|
||||
public IServerInterceptor webSocketSubscriptionR4Interceptor(){
|
||||
return new WebSocketSubscriptionR4Interceptor();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,14 +22,14 @@ package ca.uhn.fhir.jpa.config.r4;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.SubscriptionWebsocketHandlerDstu3;
|
||||
import ca.uhn.fhir.jpa.subscription.r4.SubscriptionWebsocketHandlerR4;
|
||||
|
||||
@Configuration
|
||||
public class WebsocketR4DispatcherConfig {
|
||||
|
@ -38,12 +38,12 @@ public class WebsocketR4DispatcherConfig {
|
|||
private FhirContext myCtx;
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDao<org.hl7.fhir.dstu3.model.Subscription> mySubscriptionDao;
|
||||
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
SubscriptionWebsocketHandlerDstu3.setCtx(myCtx);
|
||||
SubscriptionWebsocketHandlerDstu3.setSubscriptionDao((IFhirResourceDaoSubscription<Subscription>) mySubscriptionDao);
|
||||
SubscriptionWebsocketHandlerR4.setCtx(myCtx);
|
||||
SubscriptionWebsocketHandlerR4.setSubscriptionDao((IFhirResourceDaoSubscription<Subscription>) mySubscriptionDao);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ import javax.xml.stream.events.XMLEvent;
|
|||
import org.apache.commons.lang3.*;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.r4.model.BaseResource;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
|
@ -779,7 +779,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
List<IPrimitiveType> childElements = getContext().newTerser().getAllPopulatedChildElementsOfType(theResource, IPrimitiveType.class);
|
||||
for (@SuppressWarnings("rawtypes")
|
||||
IPrimitiveType nextType : childElements) {
|
||||
if (nextType instanceof StringDt || nextType.getClass().equals(StringType.class)) {
|
||||
if (nextType instanceof StringDt || nextType.getClass().getSimpleName().equals("StringType")) {
|
||||
String nextValue = nextType.getValueAsString();
|
||||
if (isNotBlank(nextValue)) {
|
||||
retVal.append(nextValue.replace("\n", " ").replace("\r", " "));
|
||||
|
@ -804,7 +804,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
private void populateResourceIdFromEntity(BaseHasResource theEntity, final IBaseResource theResource) {
|
||||
IIdType id = theEntity.getIdDt();
|
||||
if (getContext().getVersion().getVersion().isRi()) {
|
||||
id = new IdType(id.getValue());
|
||||
id = getContext().getVersion().newIdType().setValue(id.getValue());
|
||||
}
|
||||
theResource.setId(id);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import javax.persistence.NoResultException;
|
|||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
@ -990,7 +989,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
IIdType id = theEntity.getIdDt();
|
||||
if (getContext().getVersion().getVersion().isRi()) {
|
||||
id = new IdType(id.getValue());
|
||||
id = getContext().getVersion().newIdType().setValue(id.getValue());
|
||||
}
|
||||
|
||||
outcome.setId(id);
|
||||
|
|
|
@ -30,7 +30,7 @@ import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
|||
@ResourceDef(name = "Observation", profile = CustomObservationR4.PROFILE)
|
||||
public class CustomObservationR4 extends Observation {
|
||||
|
||||
public static final String PROFILE = "http://custom_ObservationDstu3";
|
||||
public static final String PROFILE = "http://custom_ObservationR4";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public class FhirResourceDaoQuestionnaireResponseR4 extends FhirResourceDaoR4<Qu
|
|||
// val.setValidateAgainstStandardSchema(false);
|
||||
// val.setValidateAgainstStandardSchematron(false);
|
||||
//
|
||||
// val.registerValidatorModule(myQuestionnaireResponseValidatorDstu3);
|
||||
// val.registerValidatorModule(myQuestionnaireResponseValidatorR4);
|
||||
//
|
||||
// ValidationResult result = val.validateWithResult(getContext().newJsonParser().parseResource(getContext().newJsonParser().encodeResourceToString(theResource)));
|
||||
// if (!result.isSuccessful()) {
|
||||
|
|
|
@ -53,7 +53,7 @@ public class FhirResourceDaoR4<T extends IAnyResource> extends BaseHapiFhirResou
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4.class);
|
||||
|
||||
@Autowired()
|
||||
@Qualifier("myInstanceValidatorDstu3")
|
||||
@Qualifier("myInstanceValidatorR4")
|
||||
private IValidatorModule myInstanceValidator;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,7 +49,7 @@ import ca.uhn.fhir.util.ElementUtil;
|
|||
public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainDstu3")
|
||||
@Qualifier("myJpaValidationSupportChainR4")
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -194,7 +194,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
}
|
||||
|
||||
/*
|
||||
* See FhirSystemDaoDstu3Test#testTransactionWithPlaceholderIdInMatchUrl
|
||||
* See FhirSystemDaoR4Test#testTransactionWithPlaceholderIdInMatchUrl
|
||||
* Basically if the resource has a match URL that references a placeholder,
|
||||
* we try to handle the resource with the placeholder first.
|
||||
*/
|
||||
|
|
|
@ -48,23 +48,23 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4 {
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaValidationSupportR4.class);
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myStructureDefinitionDaoDstu3")
|
||||
@Qualifier("myStructureDefinitionDaoR4")
|
||||
private IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myValueSetDaoDstu3")
|
||||
@Qualifier("myValueSetDaoR4")
|
||||
private IFhirResourceDao<ValueSet> myValueSetDao;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myQuestionnaireDaoDstu3")
|
||||
@Qualifier("myQuestionnaireDaoR4")
|
||||
private IFhirResourceDao<Questionnaire> myQuestionnaireDao;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myCodeSystemDaoDstu3")
|
||||
@Qualifier("myCodeSystemDaoR4")
|
||||
private IFhirResourceDao<CodeSystem> myCodeSystemDao;
|
||||
|
||||
@Autowired
|
||||
private FhirContext myDstu3Ctx;
|
||||
private FhirContext myR4Ctx;
|
||||
|
||||
public JpaValidationSupportR4() {
|
||||
super();
|
||||
|
@ -91,7 +91,7 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4 {
|
|||
localReference = true;
|
||||
}
|
||||
|
||||
String resourceName = myDstu3Ctx.getResourceDefinition(theClass).getName();
|
||||
String resourceName = myR4Ctx.getResourceDefinition(theClass).getName();
|
||||
IBundleProvider search;
|
||||
if ("ValueSet".equals(resourceName)) {
|
||||
if (localReference) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.interceptor;
|
||||
package ca.uhn.fhir.jpa.interceptor.r4;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
|
@ -43,6 +43,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.interceptor.BaseRestHookSubscriptionInterceptor;
|
||||
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
||||
import ca.uhn.fhir.jpa.thread.HttpRequestR4Job;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
|
@ -63,7 +64,7 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
|
|||
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
||||
|
||||
@Autowired
|
||||
@Qualifier("mySubscriptionDaoDstu3")
|
||||
@Qualifier("mySubscriptionDaoR4")
|
||||
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
||||
|
||||
private boolean notifyOnDelete = false;
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.interceptor.r4;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
||||
|
||||
public class WebSocketSubscriptionR4Interceptor extends ServerOperationInterceptorAdapter {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(WebSocketSubscriptionR4Interceptor.class);
|
||||
|
||||
private IFhirResourceDaoSubscription<Subscription> mySubscriptionDaoCasted;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("mySubscriptionDaoR4")
|
||||
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
||||
|
||||
@Override
|
||||
public boolean incomingRequestPostProcessed(RequestDetails theRequestDetails, HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException {
|
||||
if (theRequestDetails.getRestOperationType().equals(RestOperationTypeEnum.DELETE)) {
|
||||
mySubscriptionDaoCasted.pollForNewUndeliveredResources(theRequestDetails.getResourceName());
|
||||
}
|
||||
|
||||
return super.incomingRequestPostProcessed(theRequestDetails, theRequest, theResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for websocket subscriptions
|
||||
*
|
||||
* @param theRequestDetails
|
||||
* A bean containing details about the request that is about to be processed, including details such as the
|
||||
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||
* pulled out of the {@link HttpServletRequest servlet request}.
|
||||
* @param theResponseObject
|
||||
* The actual object which is being streamed to the client as a response
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject) {
|
||||
if (theRequestDetails.getResourceName() == null ||
|
||||
theRequestDetails.getResourceName().isEmpty() ||
|
||||
theRequestDetails.getResourceName().equals("Subscription")) {
|
||||
return super.outgoingResponse(theRequestDetails, theResponseObject);
|
||||
}
|
||||
|
||||
if (theRequestDetails.getRequestType().equals(RequestTypeEnum.POST) || theRequestDetails.getRequestType().equals(RequestTypeEnum.PUT)) {
|
||||
ourLog.info("Found POST or PUT for a non-subscription resource");
|
||||
mySubscriptionDaoCasted.pollForNewUndeliveredResources(theRequestDetails.getResourceName());
|
||||
}
|
||||
|
||||
return super.outgoingResponse(theRequestDetails, theResponseObject);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
mySubscriptionDaoCasted = (IFhirResourceDaoSubscription) mySubscriptionDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceDeleted(RequestDetails theRequest, IBaseResource theResource) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
// nothing
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|||
public class JpaSystemProviderR4 extends BaseJpaSystemProviderDstu2Plus<Bundle, Meta> {
|
||||
|
||||
@Autowired()
|
||||
@Qualifier("mySystemDaoDstu3")
|
||||
@Qualifier("mySystemDaoR4")
|
||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
|
||||
@Autowired
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.web.socket.*;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.ISubscriptionWebsocketHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
public class SubscriptionWebsocketHandlerR4 extends TextWebSocketHandler implements ISubscriptionWebsocketHandler, Runnable {
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionWebsocketHandlerR4.class);
|
||||
|
||||
private static IFhirResourceDaoSubscription<Subscription> ourSubscriptionDao;
|
||||
|
||||
private ScheduledFuture<?> myScheduleFuture;
|
||||
|
||||
private IState myState = new InitialState();
|
||||
|
||||
private IIdType mySubscriptionId;
|
||||
|
||||
private Long mySubscriptionPid;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("websocketTaskSchedulerR4")
|
||||
private TaskScheduler myTaskScheduler;
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession theSession, CloseStatus theStatus) throws Exception {
|
||||
super.afterConnectionClosed(theSession, theStatus);
|
||||
ourLog.info("Closing WebSocket connection from {}", theSession.getRemoteAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession theSession) throws Exception {
|
||||
super.afterConnectionEstablished(theSession);
|
||||
ourLog.info("Incoming WebSocket connection from {}", theSession.getRemoteAddress());
|
||||
}
|
||||
|
||||
protected void handleFailure(Exception theE) {
|
||||
ourLog.error("Failure during communication", theE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) throws Exception {
|
||||
ourLog.info("Textmessage: " + theMessage.getPayload());
|
||||
|
||||
myState.handleTextMessage(theSession, theMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession theSession, Throwable theException) throws Exception {
|
||||
super.handleTransportError(theSession, theException);
|
||||
ourLog.error("Transport error", theException);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
ourLog.info("Creating scheduled task for subscription websocket connection");
|
||||
myScheduleFuture = myTaskScheduler.scheduleWithFixedDelay(this, 1000);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void preDescroy() {
|
||||
ourLog.info("Cancelling scheduled task for subscription websocket connection");
|
||||
myScheduleFuture.cancel(true);
|
||||
IState state = myState;
|
||||
if (state != null) {
|
||||
state.closing();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Long subscriptionPid = mySubscriptionPid;
|
||||
if (subscriptionPid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ourLog.debug("Subscription {} websocket handler polling", subscriptionPid);
|
||||
|
||||
List<IBaseResource> results = ourSubscriptionDao.getUndeliveredResourcesAndPurge(subscriptionPid);
|
||||
if (results.isEmpty() == false) {
|
||||
myState.deliver(results);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCtx(FhirContext theCtx) {
|
||||
ourCtx = theCtx;
|
||||
}
|
||||
|
||||
public static void setSubscriptionDao(IFhirResourceDaoSubscription<Subscription> theSubscriptionDao) {
|
||||
ourSubscriptionDao = theSubscriptionDao;
|
||||
}
|
||||
|
||||
private class BoundDynamicSubscriptionState implements IState {
|
||||
|
||||
private EncodingEnum myEncoding;
|
||||
private WebSocketSession mySession;
|
||||
|
||||
public BoundDynamicSubscriptionState(WebSocketSession theSession, EncodingEnum theEncoding) {
|
||||
mySession = theSession;
|
||||
myEncoding = theEncoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closing() {
|
||||
ourLog.info("Deleting subscription {}", mySubscriptionId);
|
||||
try {
|
||||
ourSubscriptionDao.delete(mySubscriptionId, null);
|
||||
} catch (Exception e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliver(List<IBaseResource> theResults) {
|
||||
try {
|
||||
for (IBaseResource nextResource : theResults) {
|
||||
ourLog.info("Sending WebSocket message for resource: {}", nextResource.getIdElement());
|
||||
String encoded = myEncoding.newParser(ourCtx).encodeResourceToString(nextResource);
|
||||
String payload = "add " + mySubscriptionId.getIdPart() + '\n' + encoded;
|
||||
mySession.sendMessage(new TextMessage(payload));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) {
|
||||
try {
|
||||
theSession.sendMessage(new TextMessage("Unexpected client message: " + theMessage.getPayload()));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class BoundStaticSubscipriptionState implements IState {
|
||||
|
||||
private WebSocketSession mySession;
|
||||
|
||||
public BoundStaticSubscipriptionState(WebSocketSession theSession) {
|
||||
mySession = theSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closing() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliver(List<IBaseResource> theResults) {
|
||||
try {
|
||||
String payload = "ping " + mySubscriptionId.getIdPart();
|
||||
ourLog.info("Sending WebSocket message: {}", payload);
|
||||
mySession.sendMessage(new TextMessage(payload));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) {
|
||||
try {
|
||||
theSession.sendMessage(new TextMessage("Unexpected client message: " + theMessage.getPayload()));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class InitialState implements IState {
|
||||
|
||||
private IIdType bindSimple(WebSocketSession theSession, String theBindString) {
|
||||
IdType id = new IdType(theBindString);
|
||||
|
||||
if (!id.hasIdPart() || !id.isIdPartValid()) {
|
||||
try {
|
||||
String message = "Invalid bind request - No ID included";
|
||||
ourLog.warn(message);
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), message));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (id.hasResourceType() == false) {
|
||||
id = id.withResourceType("Subscription");
|
||||
}
|
||||
|
||||
try {
|
||||
Subscription subscription = ourSubscriptionDao.read(id, null);
|
||||
mySubscriptionPid = ourSubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
|
||||
mySubscriptionId = subscription.getIdElement();
|
||||
myState = new BoundStaticSubscipriptionState(theSession);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
try {
|
||||
String message = "Invalid bind request - Unknown subscription: " + id.getValue();
|
||||
ourLog.warn(message);
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), message));
|
||||
} catch (IOException e1) {
|
||||
handleFailure(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private IIdType bingSearch(WebSocketSession theSession, String theRemaining) {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subscription.setStatus(SubscriptionStatus.ACTIVE);
|
||||
subscription.setCriteria(theRemaining);
|
||||
|
||||
try {
|
||||
String params = theRemaining.substring(theRemaining.indexOf('?')+1);
|
||||
List<NameValuePair> paramValues = URLEncodedUtils.parse(params, Constants.CHARSET_UTF8, '&');
|
||||
EncodingEnum encoding = EncodingEnum.JSON;
|
||||
for (NameValuePair nameValuePair : paramValues) {
|
||||
if (Constants.PARAM_FORMAT.equals(nameValuePair.getName())) {
|
||||
EncodingEnum nextEncoding = EncodingEnum.forContentType(nameValuePair.getValue());
|
||||
if (nextEncoding != null) {
|
||||
encoding = nextEncoding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = ourSubscriptionDao.create(subscription).getId();
|
||||
|
||||
mySubscriptionPid = ourSubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
|
||||
mySubscriptionId = subscription.getIdElement();
|
||||
myState = new BoundDynamicSubscriptionState(theSession, encoding);
|
||||
|
||||
return id;
|
||||
} catch (UnprocessableEntityException e) {
|
||||
ourLog.warn("Failed to bind subscription: " + e.getMessage());
|
||||
try {
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - " + e.getMessage()));
|
||||
} catch (IOException e2) {
|
||||
handleFailure(e2);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
handleFailure(e);
|
||||
try {
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - No ID included"));
|
||||
} catch (IOException e2) {
|
||||
handleFailure(e2);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closing() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliver(List<IBaseResource> theResults) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) {
|
||||
String message = theMessage.getPayload();
|
||||
if (message.startsWith("bind ")) {
|
||||
String remaining = message.substring("bind ".length());
|
||||
|
||||
IIdType subscriptionId;
|
||||
if (remaining.contains("?")) {
|
||||
subscriptionId = bingSearch(theSession, remaining);
|
||||
} else {
|
||||
subscriptionId = bindSimple(theSession, remaining);
|
||||
if (subscriptionId == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
theSession.sendMessage(new TextMessage("bound " + subscriptionId.getIdPart()));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private interface IState {
|
||||
|
||||
void closing();
|
||||
|
||||
void deliver(List<IBaseResource> theResults);
|
||||
|
||||
void handleTextMessage(WebSocketSession theSession, TextMessage theMessage);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,361 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.web.socket.*;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* 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.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.ISubscriptionWebsocketHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
public class SubscriptionWebsocketReturnResourceHandlerR4 extends TextWebSocketHandler implements ISubscriptionWebsocketHandler, Runnable {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionWebsocketReturnResourceHandlerR4.class);
|
||||
|
||||
@Autowired
|
||||
private FhirContext myCtx;
|
||||
|
||||
private ScheduledFuture<?> myScheduleFuture;
|
||||
|
||||
private IState myState = new InitialState();
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDaoSubscription<Subscription> mySubscriptionDao;
|
||||
|
||||
private IIdType mySubscriptionId;
|
||||
private Long mySubscriptionPid;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("websocketTaskScheduler")
|
||||
private TaskScheduler myTaskScheduler;
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession theSession, CloseStatus theStatus) throws Exception {
|
||||
super.afterConnectionClosed(theSession, theStatus);
|
||||
ourLog.info("Closing WebSocket connection from {}", theSession.getRemoteAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession theSession) throws Exception {
|
||||
super.afterConnectionEstablished(theSession);
|
||||
ourLog.info("Incoming WebSocket connection from {}", theSession.getRemoteAddress());
|
||||
}
|
||||
|
||||
protected void handleFailure(Exception theE) {
|
||||
ourLog.error("Failure during communication", theE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) throws Exception {
|
||||
ourLog.info("Textmessage: " + theMessage.getPayload());
|
||||
|
||||
myState.handleTextMessage(theSession, theMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession theSession, Throwable theException) throws Exception {
|
||||
super.handleTransportError(theSession, theException);
|
||||
ourLog.error("Transport error", theException);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
ourLog.info("Creating scheduled task for subscription websocket connection");
|
||||
myScheduleFuture = myTaskScheduler.scheduleWithFixedDelay(this, 1000);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void preDescroy() {
|
||||
ourLog.info("Cancelling scheduled task for subscription websocket connection");
|
||||
myScheduleFuture.cancel(true);
|
||||
IState state = myState;
|
||||
if (state != null) {
|
||||
state.closing();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Long subscriptionPid = mySubscriptionPid;
|
||||
if (subscriptionPid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ourLog.debug("Subscription {} websocket handler polling", subscriptionPid);
|
||||
|
||||
List<IBaseResource> results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subscriptionPid);
|
||||
if (results.isEmpty() == false) {
|
||||
myState.deliver(results);
|
||||
}
|
||||
}
|
||||
|
||||
private class BoundDynamicSubscriptionState implements IState {
|
||||
|
||||
private EncodingEnum myEncoding;
|
||||
private WebSocketSession mySession;
|
||||
|
||||
public BoundDynamicSubscriptionState(WebSocketSession theSession, EncodingEnum theEncoding) {
|
||||
mySession = theSession;
|
||||
myEncoding = theEncoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closing() {
|
||||
ourLog.info("Deleting subscription {}", mySubscriptionId);
|
||||
try {
|
||||
mySubscriptionDao.delete(mySubscriptionId, null);
|
||||
} catch (Exception e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliver(List<IBaseResource> theResults) {
|
||||
try {
|
||||
for (IBaseResource nextResource : theResults) {
|
||||
ourLog.info("Sending WebSocket message for resource: {}", nextResource.getIdElement());
|
||||
String encoded = myEncoding.newParser(myCtx).encodeResourceToString(nextResource);
|
||||
String payload = "add " + mySubscriptionId.getIdPart() + '\n' + encoded;
|
||||
mySession.sendMessage(new TextMessage(payload));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) {
|
||||
try {
|
||||
theSession.sendMessage(new TextMessage("Unexpected client message: " + theMessage.getPayload()));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class BoundStaticSubscriptionState implements IState {
|
||||
|
||||
private EncodingEnum myEncoding;
|
||||
private WebSocketSession mySession;
|
||||
|
||||
public BoundStaticSubscriptionState(WebSocketSession theSession, EncodingEnum theEncoding) {
|
||||
mySession = theSession;
|
||||
myEncoding = theEncoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closing() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliver(List<IBaseResource> theResults) {
|
||||
try {
|
||||
for (IBaseResource nextResource : theResults) {
|
||||
ourLog.info("Sending WebSocket message for resource: {}", nextResource.getIdElement());
|
||||
String encoded = myEncoding.newParser(myCtx).encodeResourceToString(nextResource);
|
||||
String payload = "add " + mySubscriptionId.getIdPart() + '\n' + encoded;
|
||||
mySession.sendMessage(new TextMessage(payload));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) {
|
||||
try {
|
||||
theSession.sendMessage(new TextMessage("Unexpected client message: " + theMessage.getPayload()));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class InitialState implements IState {
|
||||
|
||||
private IIdType bindSimple(WebSocketSession theSession, String theBindString) {
|
||||
IdType id = new IdType(theBindString);
|
||||
|
||||
if (!id.hasIdPart() || !id.isIdPartValid()) {
|
||||
try {
|
||||
String message = "Invalid bind request - No ID included";
|
||||
ourLog.warn(message);
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), message));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (id.hasResourceType() == false) {
|
||||
id = id.withResourceType("Subscription");
|
||||
}
|
||||
|
||||
try {
|
||||
Subscription subscription = mySubscriptionDao.read(id, null);
|
||||
EncodingEnum encoding = EncodingEnum.JSON;
|
||||
String criteria = subscription.getCriteria();
|
||||
String params = criteria.substring(criteria.indexOf('?') + 1);
|
||||
List<NameValuePair> paramValues = URLEncodedUtils.parse(params, Constants.CHARSET_UTF8, '&');
|
||||
for (NameValuePair nameValuePair : paramValues) {
|
||||
if (Constants.PARAM_FORMAT.equals(nameValuePair.getName())) {
|
||||
EncodingEnum nextEncoding = EncodingEnum.forContentType(nameValuePair.getValue());
|
||||
if (nextEncoding != null) {
|
||||
encoding = nextEncoding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
|
||||
mySubscriptionId = subscription.getIdElement();
|
||||
myState = new BoundStaticSubscriptionState(theSession, encoding);
|
||||
} catch (ResourceNotFoundException e) {
|
||||
try {
|
||||
String message = "Invalid bind request - Unknown subscription: " + id.getValue();
|
||||
ourLog.warn(message);
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), message));
|
||||
} catch (IOException e1) {
|
||||
handleFailure(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private IIdType bindSearch(WebSocketSession theSession, String theRemaining) {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subscription.setStatus(SubscriptionStatus.ACTIVE);
|
||||
subscription.setCriteria(theRemaining);
|
||||
|
||||
try {
|
||||
String params = theRemaining.substring(theRemaining.indexOf('?')+1);
|
||||
List<NameValuePair> paramValues = URLEncodedUtils.parse(params, Constants.CHARSET_UTF8, '&');
|
||||
EncodingEnum encoding = EncodingEnum.JSON;
|
||||
for (NameValuePair nameValuePair : paramValues) {
|
||||
if (Constants.PARAM_FORMAT.equals(nameValuePair.getName())) {
|
||||
EncodingEnum nextEncoding = EncodingEnum.forContentType(nameValuePair.getValue());
|
||||
if (nextEncoding != null) {
|
||||
encoding = nextEncoding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = mySubscriptionDao.create(subscription).getId();
|
||||
|
||||
mySubscriptionPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id);
|
||||
mySubscriptionId = subscription.getIdElement();
|
||||
myState = new BoundDynamicSubscriptionState(theSession, encoding);
|
||||
|
||||
return id;
|
||||
} catch (UnprocessableEntityException e) {
|
||||
ourLog.warn("Failed to bind subscription: " + e.getMessage());
|
||||
try {
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - " + e.getMessage()));
|
||||
} catch (IOException e2) {
|
||||
handleFailure(e2);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
handleFailure(e);
|
||||
try {
|
||||
theSession.close(new CloseStatus(CloseStatus.PROTOCOL_ERROR.getCode(), "Invalid bind request - No ID included"));
|
||||
} catch (IOException e2) {
|
||||
handleFailure(e2);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closing() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliver(List<IBaseResource> theResults) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTextMessage(WebSocketSession theSession, TextMessage theMessage) {
|
||||
String message = theMessage.getPayload();
|
||||
if (message.startsWith("bind ")) {
|
||||
String remaining = message.substring("bind ".length());
|
||||
|
||||
IIdType subscriptionId;
|
||||
if (remaining.contains("?")) {
|
||||
subscriptionId = bindSearch(theSession, remaining);
|
||||
} else {
|
||||
subscriptionId = bindSimple(theSession, remaining);
|
||||
if (subscriptionId == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
theSession.sendMessage(new TextMessage("bound " + subscriptionId.getIdPart()));
|
||||
} catch (IOException e) {
|
||||
handleFailure(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private interface IState {
|
||||
|
||||
void closing();
|
||||
|
||||
void deliver(List<IBaseResource> theResults);
|
||||
|
||||
void handleTextMessage(WebSocketSession theSession, TextMessage theMessage);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -40,12 +40,12 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
|
@ -57,7 +57,8 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HapiTerminologySvcR4.class);
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemResourceDao;
|
||||
@Qualifier("myCodeSystemDaoR4")
|
||||
private IFhirResourceDao<CodeSystem> myCodeSystemResourceDao;
|
||||
|
||||
@Autowired
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
|
|
@ -19,6 +19,7 @@ public class TestDstu3WithoutLuceneConfig extends TestDstu3Config {
|
|||
/**
|
||||
* Disable fulltext searching
|
||||
*/
|
||||
@Override
|
||||
public IFulltextSearchSvc searchDaoDstu3() {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.context.annotation.*;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
public class TestR4Config extends BaseJavaConfigR4 {
|
||||
|
||||
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestR4Config.class);
|
||||
|
||||
@Bean()
|
||||
public DaoConfig daoConfig() {
|
||||
return new DaoConfig();
|
||||
}
|
||||
|
||||
private Exception myLastStackTrace;
|
||||
|
||||
@Bean()
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource() {
|
||||
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
ConnectionWrapper retVal;
|
||||
try {
|
||||
retVal = new ConnectionWrapper(super.getConnection());
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Exceeded maximum wait for connection", e);
|
||||
logGetConnectionStackTrace();
|
||||
System.exit(1);
|
||||
retVal = null;
|
||||
}
|
||||
|
||||
try {
|
||||
throw new Exception();
|
||||
} catch (Exception e) {
|
||||
myLastStackTrace = e;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void logGetConnectionStackTrace() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Last connection request stack trace:");
|
||||
for (StackTraceElement next : myLastStackTrace.getStackTrace()) {
|
||||
b.append("\n ");
|
||||
b.append(next.getClassName());
|
||||
b.append(".");
|
||||
b.append(next.getMethodName());
|
||||
b.append("(");
|
||||
b.append(next.getFileName());
|
||||
b.append(":");
|
||||
b.append(next.getLineNumber());
|
||||
b.append(")");
|
||||
}
|
||||
ourLog.info(b.toString());
|
||||
}
|
||||
|
||||
};
|
||||
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
|
||||
retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
|
||||
retVal.setMaxWaitMillis(10000);
|
||||
retVal.setUsername("");
|
||||
retVal.setPassword("");
|
||||
|
||||
/*
|
||||
* We use a randomized number of maximum threads in order to try
|
||||
* and catch any potential deadlocks caused by database connection
|
||||
* starvation
|
||||
*/
|
||||
int maxThreads = (int) (Math.random() * 6) + 1;
|
||||
retVal.setMaxTotal(maxThreads);
|
||||
|
||||
DataSource dataSource = ProxyDataSourceBuilder
|
||||
.create(retVal)
|
||||
// .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
|
||||
.logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
|
||||
.countQuery()
|
||||
.build();
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
|
||||
retVal.setPersistenceUnitName("PU_HapiFhirJpaR4");
|
||||
retVal.setDataSource(dataSource());
|
||||
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
|
||||
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
|
||||
retVal.setJpaProperties(jpaProperties());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
extraProperties.put("hibernate.jdbc.batch_size", "50");
|
||||
extraProperties.put("hibernate.format_sql", "false");
|
||||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||
return extraProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidatorR4());
|
||||
|
||||
return requestValidator;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
public class TestR4WithoutLuceneConfig extends TestR4Config {
|
||||
|
||||
/**
|
||||
* Disable fulltext searching
|
||||
*/
|
||||
@Override
|
||||
public IFulltextSearchSvc searchDaoR4() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
|
||||
retVal.setPersistenceUnitName("PU_HapiFhirJpaR4");
|
||||
retVal.setDataSource(dataSource());
|
||||
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
|
||||
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
|
||||
retVal.setJpaProperties(jpaProperties());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
extraProperties.put("hibernate.format_sql", "false");
|
||||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
|
||||
extraProperties.put("hibernate.search.autoregister_listeners", "false");
|
||||
return extraProperties;
|
||||
}
|
||||
|
||||
}
|
|
@ -67,6 +67,14 @@ public abstract class BaseJpaTest {
|
|||
return bundle;
|
||||
}
|
||||
|
||||
protected org.hl7.fhir.r4.model.Bundle toBundleR4(IBundleProvider theSearch) {
|
||||
org.hl7.fhir.r4.model.Bundle bundle = new org.hl7.fhir.r4.model.Bundle();
|
||||
for (IBaseResource next : theSearch.getResources(0, theSearch.size())) {
|
||||
bundle.addEntry().setResource((org.hl7.fhir.r4.model.Resource) next);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
protected abstract FhirContext getContext();
|
||||
|
||||
protected List<String> toUnqualifiedVersionlessIdValues(IBaseBundle theFound) {
|
||||
|
@ -132,6 +140,16 @@ public abstract class BaseJpaTest {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
protected List<IIdType> toUnqualifiedVersionlessIds(org.hl7.fhir.r4.model.Bundle theFound) {
|
||||
List<IIdType> retVal = new ArrayList<IIdType>();
|
||||
for (org.hl7.fhir.r4.model.Bundle.BundleEntryComponent next : theFound.getEntry()) {
|
||||
// if (next.getResource()!= null) {
|
||||
retVal.add(next.getResource().getIdElement().toUnqualifiedVersionless());
|
||||
// }
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected List<String> toUnqualifiedVersionlessIdValues(IBundleProvider theFound) {
|
||||
List<String> retVal = new ArrayList<String>();
|
||||
int size = theFound.size();
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
|
||||
import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider;
|
||||
import ca.uhn.fhir.rest.api.server.IRequestOperationCallback;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public abstract class BaseJpaR4SystemTest extends BaseJpaR4Test {
|
||||
protected ServletRequestDetails mySrd;
|
||||
private RestfulServer myServer;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Before
|
||||
public void before() throws ServletException {
|
||||
mySrd = mock(ServletRequestDetails.class);
|
||||
when(mySrd.getRequestOperationCallback()).thenReturn(mock(IRequestOperationCallback.class));
|
||||
|
||||
if (myServer == null) {
|
||||
myServer = new RestfulServer(myFhirCtx);
|
||||
|
||||
PatientResourceProvider patientRp = new PatientResourceProvider();
|
||||
patientRp.setDao(myPatientDao);
|
||||
myServer.setResourceProviders(patientRp);
|
||||
myServer.init(mock(ServletConfig.class));
|
||||
}
|
||||
|
||||
when(mySrd.getServer()).thenReturn(myServer);
|
||||
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
|
||||
when(mySrd.getServletRequest()).thenReturn(servletRequest);
|
||||
when(mySrd.getFhirServerBase()).thenReturn("http://example.com/base");
|
||||
when(servletRequest.getHeaderNames()).thenReturn(mock(Enumeration.class));
|
||||
when(servletRequest.getRequestURL()).thenReturn(new StringBuffer("/Patient"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hibernate.search.jpa.FullTextEntityManager;
|
||||
import org.hibernate.search.jpa.Search;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.search.*;
|
||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
//@formatter:off
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes= {TestR4Config.class})
|
||||
//@formatter:on
|
||||
public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||
|
||||
private static JpaValidationSupportChainR4 ourJpaValidationSupportChainR4;
|
||||
private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao;
|
||||
|
||||
// @Autowired
|
||||
// protected HapiWorkerContext myHapiWorkerContext;
|
||||
@Autowired
|
||||
@Qualifier("myAllergyIntoleranceDaoR4")
|
||||
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
||||
@Autowired
|
||||
protected ApplicationContext myAppCtx;
|
||||
@Autowired
|
||||
@Qualifier("myAppointmentDaoR4")
|
||||
protected IFhirResourceDao<Appointment> myAppointmentDao;
|
||||
@Autowired
|
||||
@Qualifier("myAuditEventDaoR4")
|
||||
protected IFhirResourceDao<AuditEvent> myAuditEventDao;
|
||||
@Autowired
|
||||
@Qualifier("myBundleDaoR4")
|
||||
protected IFhirResourceDao<Bundle> myBundleDao;
|
||||
@Autowired
|
||||
@Qualifier("myCarePlanDaoR4")
|
||||
protected IFhirResourceDao<CarePlan> myCarePlanDao;
|
||||
@Autowired
|
||||
@Qualifier("myCodeSystemDaoR4")
|
||||
protected IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myCompartmentDefinitionDaoR4")
|
||||
protected IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myConceptMapDaoR4")
|
||||
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
|
||||
@Autowired
|
||||
@Qualifier("myConditionDaoR4")
|
||||
protected IFhirResourceDao<Condition> myConditionDao;
|
||||
@Autowired
|
||||
protected DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
@Qualifier("myDeviceDaoR4")
|
||||
protected IFhirResourceDao<Device> myDeviceDao;
|
||||
@Autowired
|
||||
@Qualifier("myDiagnosticReportDaoR4")
|
||||
protected IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
|
||||
@Autowired
|
||||
@Qualifier("myEncounterDaoR4")
|
||||
protected IFhirResourceDao<Encounter> myEncounterDao;
|
||||
// @PersistenceContext()
|
||||
@Autowired
|
||||
protected EntityManager myEntityManager;
|
||||
@Autowired
|
||||
protected FhirContext myFhirCtx;
|
||||
@Autowired
|
||||
@Qualifier("myGroupDaoR4")
|
||||
protected IFhirResourceDao<Group> myGroupDao;
|
||||
@Autowired
|
||||
@Qualifier("myImmunizationDaoR4")
|
||||
protected IFhirResourceDao<Immunization> myImmunizationDao;
|
||||
@Autowired
|
||||
@Qualifier("myImmunizationRecommendationDaoR4")
|
||||
protected IFhirResourceDao<ImmunizationRecommendation> myImmunizationRecommendationDao;
|
||||
protected IServerInterceptor myInterceptor;
|
||||
@Autowired
|
||||
private JpaValidationSupportChainR4 myJpaValidationSupportChainR4;
|
||||
@Autowired
|
||||
@Qualifier("myLocationDaoR4")
|
||||
protected IFhirResourceDao<Location> myLocationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMediaDaoR4")
|
||||
protected IFhirResourceDao<Media> myMediaDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationAdministrationDaoR4")
|
||||
protected IFhirResourceDao<MedicationAdministration> myMedicationAdministrationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationDaoR4")
|
||||
protected IFhirResourceDao<Medication> myMedicationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationRequestDaoR4")
|
||||
protected IFhirResourceDao<MedicationRequest> myMedicationRequestDao;
|
||||
@Autowired
|
||||
@Qualifier("myNamingSystemDaoR4")
|
||||
protected IFhirResourceDao<NamingSystem> myNamingSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myObservationDaoR4")
|
||||
protected IFhirResourceDao<Observation> myObservationDao;
|
||||
@Autowired
|
||||
@Qualifier("myOperationDefinitionDaoR4")
|
||||
protected IFhirResourceDao<OperationDefinition> myOperationDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myOrganizationDaoR4")
|
||||
protected IFhirResourceDao<Organization> myOrganizationDao;
|
||||
@Autowired
|
||||
protected DatabaseBackedPagingProvider myPagingProvider;
|
||||
@Autowired
|
||||
@Qualifier("myPatientDaoR4")
|
||||
protected IFhirResourceDaoPatient<Patient> myPatientDao;
|
||||
@Autowired
|
||||
@Qualifier("myPractitionerDaoR4")
|
||||
protected IFhirResourceDao<Practitioner> myPractitionerDao;
|
||||
@Autowired
|
||||
@Qualifier("myProcedureRequestDaoR4")
|
||||
protected IFhirResourceDao<ProcedureRequest> myProcedureRequestDao;
|
||||
@Autowired
|
||||
@Qualifier("myQuestionnaireDaoR4")
|
||||
protected IFhirResourceDao<Questionnaire> myQuestionnaireDao;
|
||||
@Autowired
|
||||
@Qualifier("myQuestionnaireResponseDaoR4")
|
||||
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
||||
@Autowired
|
||||
@Qualifier("myResourceProvidersR4")
|
||||
protected Object myResourceProviders;
|
||||
@Autowired
|
||||
protected IResourceTableDao myResourceTableDao;
|
||||
@Autowired
|
||||
protected IResourceTagDao myResourceTagDao;
|
||||
@Autowired
|
||||
protected ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
@Autowired
|
||||
protected IFulltextSearchSvc mySearchDao;
|
||||
@Autowired
|
||||
protected ISearchDao mySearchEntityDao;
|
||||
@Autowired
|
||||
@Qualifier("mySearchParameterDaoR4")
|
||||
protected IFhirResourceDao<SearchParameter> mySearchParameterDao;
|
||||
@Autowired
|
||||
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
||||
@Autowired
|
||||
protected ISearchParamRegistry mySearchParamRegsitry;
|
||||
@Autowired
|
||||
protected IStaleSearchDeletingSvc myStaleSearchDeletingSvc;
|
||||
@Autowired
|
||||
@Qualifier("myStructureDefinitionDaoR4")
|
||||
protected IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("mySubscriptionDaoR4")
|
||||
protected IFhirResourceDaoSubscription<Subscription> mySubscriptionDao;
|
||||
@Autowired
|
||||
@Qualifier("mySubstanceDaoR4")
|
||||
protected IFhirResourceDao<Substance> mySubstanceDao;
|
||||
@Autowired
|
||||
@Qualifier("mySystemDaoR4")
|
||||
protected IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
@Autowired
|
||||
@Qualifier("mySystemProviderR4")
|
||||
protected JpaSystemProviderR4 mySystemProvider;
|
||||
@Autowired
|
||||
protected ITagDefinitionDao myTagDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myTaskDaoR4")
|
||||
protected IFhirResourceDao<Task> myTaskDao;
|
||||
@Autowired
|
||||
protected IHapiTerminologySvc myTermSvc;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myTransactionMgr;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myTxManager;
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainR4")
|
||||
protected IValidationSupport myValidationSupport;
|
||||
@Autowired
|
||||
@Qualifier("myValueSetDaoR4")
|
||||
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
|
||||
|
||||
@After()
|
||||
public void afterCleanupDao() {
|
||||
myDaoConfig.setExpireSearchResults(new DaoConfig().isExpireSearchResults());
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(new DaoConfig().getExpireSearchResultsAfterMillis());
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setSuppressUpdatesWithNoChange(new DaoConfig().isSuppressUpdatesWithNoChange());
|
||||
}
|
||||
|
||||
@After()
|
||||
public void afterGrabCaches() {
|
||||
ourValueSetDao = myValueSetDao;
|
||||
ourJpaValidationSupportChainR4 = myJpaValidationSupportChainR4;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeCreateInterceptor() {
|
||||
myInterceptor = mock(IServerInterceptor.class);
|
||||
myDaoConfig.setInterceptors(myInterceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
@Transactional
|
||||
public void beforeFlushFT() {
|
||||
FullTextEntityManager ftem = Search.getFullTextEntityManager(myEntityManager);
|
||||
ftem.purgeAll(ResourceTable.class);
|
||||
ftem.purgeAll(ResourceIndexedSearchParamString.class);
|
||||
ftem.flushToIndexes();
|
||||
|
||||
myDaoConfig.setSchedulingDisabled(true);
|
||||
}
|
||||
|
||||
@Before
|
||||
@Transactional()
|
||||
public void beforePurgeDatabase() {
|
||||
final EntityManager entityManager = this.myEntityManager;
|
||||
purgeDatabase(entityManager, myTxManager, mySearchParamPresenceSvc, mySearchCoordinatorSvc);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeResetConfig() {
|
||||
myDaoConfig.setHardSearchLimit(1000);
|
||||
myDaoConfig.setHardTagListLimit(1000);
|
||||
myDaoConfig.setIncludeLimit(2000);
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FhirContext getContext() {
|
||||
return myFhirCtx;
|
||||
}
|
||||
|
||||
protected <T extends IBaseResource> T loadResourceFromClasspath(Class<T> type, String resourceName) throws IOException {
|
||||
InputStream stream = FhirResourceDaoDstu2SearchNoFtTest.class.getResourceAsStream(resourceName);
|
||||
if (stream == null) {
|
||||
fail("Unable to load resource: " + resourceName);
|
||||
}
|
||||
String string = IOUtils.toString(stream, "UTF-8");
|
||||
IParser newJsonParser = EncodingEnum.detectEncodingNoDefault(string).newParser(myFhirCtx);
|
||||
return newJsonParser.parseResource(type, string);
|
||||
}
|
||||
|
||||
public TransactionTemplate newTxTemplate() {
|
||||
TransactionTemplate retVal = new TransactionTemplate(myTxManager);
|
||||
retVal.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
retVal.afterPropertiesSet();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContextBaseJpaR4Test() throws Exception {
|
||||
ourValueSetDao.purgeCaches();
|
||||
ourJpaValidationSupportChainR4.flush();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
public static String toSearchUuidFromLinkNext(Bundle theBundle) {
|
||||
String linkNext = theBundle.getLink("next").getUrl();
|
||||
linkNext = linkNext.substring(linkNext.indexOf('?'));
|
||||
Map<String, String[]> params = UrlUtil.parseQueryString(linkNext);
|
||||
String[] uuidParams = params.get(Constants.PARAM_PAGINGACTION);
|
||||
String uuid = uuidParams[0];
|
||||
return uuid;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
|
||||
@SuppressWarnings({ })
|
||||
public class FhirResourceDaoCustomTypeR4Test extends BaseJpaR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoCustomTypeR4Test.class);
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
myFhirCtx.setDefaultTypeForProfile(CustomObservationR4.PROFILE, CustomObservationR4.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAndRestore() {
|
||||
CustomObservationR4 obs = new CustomObservationR4();
|
||||
obs.setEyeColour(new StringType("blue"));
|
||||
|
||||
IIdType id = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
|
||||
|
||||
CustomObservationR4 read = (CustomObservationR4) myObservationDao.read(id);
|
||||
assertEquals("blue", read.getEyeColour().getValue());
|
||||
|
||||
IBundleProvider found = myObservationDao.search(new SearchParameterMap());
|
||||
assertEquals(1, found.size().intValue());
|
||||
CustomObservationR4 search = (CustomObservationR4) found.getResources(0, 1).get(0);
|
||||
assertEquals("blue", search.getEyeColour().getValue());
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
myFhirCtx.setDefaultTypeForProfile(CustomObservationR4.PROFILE, null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoDocumentR4Test extends BaseJpaR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDocumentR4Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPostDocument() throws Exception {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/sample-document.xml"), StandardCharsets.UTF_8);
|
||||
Bundle inputBundle = myFhirCtx.newXmlParser().parseResource(Bundle.class, input);
|
||||
DaoMethodOutcome responseBundle = myBundleDao.create(inputBundle, mySrd);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvc;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4CodeSystemTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4CodeSystemTest.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
BaseHapiTerminologySvc.setForceSaveDeferredAlwaysForUnitTest(false);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexContained() throws Exception {
|
||||
BaseHapiTerminologySvc.setForceSaveDeferredAlwaysForUnitTest(true);
|
||||
|
||||
String input = IOUtils.toString(getClass().getResource("/r4_codesystem_complete.json"), StandardCharsets.UTF_8);
|
||||
CodeSystem cs = myFhirCtx.newJsonParser().parseResource(CodeSystem.class, input);
|
||||
myCodeSystemDao.create(cs, mySrd);
|
||||
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
|
||||
int outcome = mySystemDao.performReindexingPass(100);
|
||||
assertNotEquals(-1, outcome); // -1 means there was a failure
|
||||
|
||||
myTermSvc.saveDeferred();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4ContainedTest.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void before() {
|
||||
myDaoConfig.setIndexContainedResources(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexContained() {
|
||||
Patient p = new Patient();
|
||||
p.setId("#some_patient");
|
||||
p.addName().setFamily("MYFAMILY").addGiven("MYGIVEN");
|
||||
|
||||
Observation o1 = new Observation();
|
||||
o1.getCode().setText("Some Observation");
|
||||
o1.setSubject(new Reference(p));
|
||||
IIdType oid1 = myObservationDao.create(o1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation o2 = new Observation();
|
||||
o2.getCode().setText("Some Observation");
|
||||
o2.setSubject(new Reference(p));
|
||||
IIdType oid2 = myObservationDao.create(o2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().setFamily("MYFAMILY").addGiven("MYGIVEN");
|
||||
IIdType pid2 = myPatientDao.create(p2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(o2));
|
||||
|
||||
|
||||
SearchParameterMap map;
|
||||
|
||||
// map = new SearchParameterMap();
|
||||
// map.add(Observation.SP_CODE, new TokenParam(null, "some observation").setModifier(TokenParamModifier.TEXT));
|
||||
// assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TODO: make sure match URLs don't delete
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4ExternalReferenceTest extends BaseJpaR4Test {
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@Before
|
||||
@After
|
||||
public void resetDefaultBehaviour() {
|
||||
// Reset to default
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
myDaoConfig.setTreatBaseUrlsAsLocal(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInternalReferenceBlockedByDefault() {
|
||||
Patient p = new Patient();
|
||||
p.getManagingOrganization().setReference("Organization/FOO");
|
||||
try {
|
||||
myPatientDao.create(p, mySrd);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Resource Organization/FOO not found, specified in path: Patient.managingOrganization", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalReferenceBlockedByDefault() {
|
||||
Organization org = new Organization();
|
||||
org.setId("FOO");
|
||||
org.setName("Org Name");
|
||||
myOrganizationDao.update(org, mySrd);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getManagingOrganization().setReference("http://example.com/base/Organization/FOO");
|
||||
try {
|
||||
myPatientDao.create(p, mySrd);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Resource contains external reference to URL \"http://example.com/base/Organization/FOO\" but this server is not configured to allow external references", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalReferenceAllowed() {
|
||||
Organization org = new Organization();
|
||||
org.setId("FOO");
|
||||
org.setName("Org Name");
|
||||
myOrganizationDao.update(org, mySrd);
|
||||
|
||||
myDaoConfig.setAllowExternalReferences(true);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getManagingOrganization().setReference("http://example.com/base/Organization/FOO");
|
||||
IIdType pid = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(Patient.SP_ORGANIZATION, new ReferenceParam("http://example.com/base/Organization/FOO"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(pid.getValue()));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_ORGANIZATION, new ReferenceParam("http://example2.com/base/Organization/FOO"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalReferenceReplaced() {
|
||||
Organization org = new Organization();
|
||||
org.setId("FOO");
|
||||
org.setName("Org Name");
|
||||
org.getPartOf().setDisplay("Parent"); // <-- no reference, make sure this works
|
||||
myOrganizationDao.update(org, mySrd);
|
||||
|
||||
Set<String> urls = new HashSet<String>();
|
||||
urls.add("http://example.com/base/");
|
||||
myDaoConfig.setTreatBaseUrlsAsLocal(urls);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getManagingOrganization().setReference("http://example.com/base/Organization/FOO");
|
||||
IIdType pid = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
p = myPatientDao.read(pid, mySrd);
|
||||
assertEquals("Organization/FOO", p.getManagingOrganization().getReference());
|
||||
|
||||
SearchParameterMap map;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_ORGANIZATION, new ReferenceParam("http://example.com/base/Organization/FOO"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(pid.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForInvalidLocalReference() {
|
||||
SearchParameterMap map;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_ORGANIZATION, new ReferenceParam("Organization/FOO"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_ORGANIZATION, new ReferenceParam("Organization/9999999999"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExternalReferenceReplacedWrongDoesntMatch() {
|
||||
Organization org = new Organization();
|
||||
org.setId("FOO");
|
||||
org.setName("Org Name");
|
||||
org.getPartOf().setDisplay("Parent"); // <-- no reference, make sure this works
|
||||
myOrganizationDao.update(org, mySrd);
|
||||
|
||||
Set<String> urls = new HashSet<String>();
|
||||
urls.add("http://example.com/base/");
|
||||
myDaoConfig.setTreatBaseUrlsAsLocal(urls);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getManagingOrganization().setReference("http://example.com/base/Organization/FOO");
|
||||
IIdType pid = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
p = myPatientDao.read(pid, mySrd);
|
||||
assertEquals("Organization/FOO", p.getManagingOrganization().getReference());
|
||||
|
||||
SearchParameterMap map;
|
||||
|
||||
// Different base
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_ORGANIZATION, new ReferenceParam("http://foo.com/base/Organization/FOO"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,473 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.DeleteMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.interceptor.IJpaServerInterceptor;
|
||||
import ca.uhn.fhir.jpa.interceptor.JpaServerInterceptorAdapter;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4InterceptorTest.class);
|
||||
private IJpaServerInterceptor myJpaInterceptor;
|
||||
private JpaServerInterceptorAdapter myJpaInterceptorAdapter = new JpaServerInterceptorAdapter();
|
||||
private IServerOperationInterceptor myServerOperationInterceptor;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
myDaoConfig.getInterceptors().remove(myJpaInterceptor);
|
||||
myDaoConfig.getInterceptors().remove(myJpaInterceptorAdapter);
|
||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
myJpaInterceptor = mock(IJpaServerInterceptor.class);
|
||||
|
||||
myServerOperationInterceptor = mock(IServerOperationInterceptor.class, new Answer<Object>() {
|
||||
@Override
|
||||
public Object answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
if (theInvocation.getMethod().getReturnType().equals(boolean.class)) {
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
myDaoConfig.getInterceptors().add(myJpaInterceptor);
|
||||
myDaoConfig.getInterceptors().add(myJpaInterceptorAdapter);
|
||||
myDaoConfig.getInterceptors().add(myServerOperationInterceptor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJpaCreate() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> detailsCapt;
|
||||
ArgumentCaptor<ResourceTable> tableCapt;
|
||||
|
||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
|
||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||
assertNotNull(tableCapt.getValue().getId());
|
||||
assertEquals(id, tableCapt.getValue().getId());
|
||||
|
||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
|
||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||
|
||||
/*
|
||||
* Not do a conditional create
|
||||
*/
|
||||
p = new Patient();
|
||||
p.addName().setFamily("PATIENT1");
|
||||
Long id2 = myPatientDao.create(p, "Patient?family=PATIENT", mySrd).getId().getIdPartAsLong();
|
||||
assertEquals(id, id2);
|
||||
|
||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
|
||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* *****************************************************
|
||||
* Note that non JPA specific operations get tested in individual
|
||||
* operation test methods too
|
||||
* *****************************************************
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testJpaDelete() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
myPatientDao.delete(new IdType("Patient", id), mySrd);
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> detailsCapt;
|
||||
ArgumentCaptor<ResourceTable> tableCapt;
|
||||
|
||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
|
||||
verify(myJpaInterceptor, times(1)).resourceDeleted(detailsCapt.capture(), tableCapt.capture());
|
||||
assertNotNull(tableCapt.getValue().getId());
|
||||
assertEquals(id, tableCapt.getValue().getId());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJpaUpdate() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
p = new Patient();
|
||||
p.setId(new IdType(id));
|
||||
p.addName().setFamily("PATIENT1");
|
||||
Long id2 = myPatientDao.update(p, mySrd).getId().getIdPartAsLong();
|
||||
assertEquals(id, id2);
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> detailsCapt;
|
||||
ArgumentCaptor<ResourceTable> tableCapt;
|
||||
|
||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
|
||||
verify(myJpaInterceptor, times(1)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||
assertNotNull(tableCapt.getValue().getId());
|
||||
assertEquals(id, tableCapt.getValue().getId());
|
||||
|
||||
/*
|
||||
* Now do a conditional update
|
||||
*/
|
||||
|
||||
p = new Patient();
|
||||
p.setId(new IdType(id));
|
||||
p.addName().setFamily("PATIENT2");
|
||||
id2 = myPatientDao.update(p, "Patient?family=PATIENT1", mySrd).getId().getIdPartAsLong();
|
||||
assertEquals(id, id2);
|
||||
|
||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
|
||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||
assertEquals(id, tableCapt.getAllValues().get(2).getId());
|
||||
|
||||
/*
|
||||
* Now do a conditional update where none will match (so this is actually a create)
|
||||
*/
|
||||
|
||||
p = new Patient();
|
||||
p.addName().setFamily("PATIENT3");
|
||||
id2 = myPatientDao.update(p, "Patient?family=ZZZ", mySrd).getId().getIdPartAsLong();
|
||||
assertNotEquals(id, id2);
|
||||
|
||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
|
||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||
verify(myJpaInterceptor, times(2)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||
assertEquals(id2, tableCapt.getAllValues().get(3).getId());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationCreate() {
|
||||
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||
myServerInterceptorList.add(interceptor);
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
||||
Long id = res.getIdElement().getIdPartAsLong();
|
||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
||||
|
||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerOperationCreate() {
|
||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
IIdType id = myPatientDao.create(p, (RequestDetails)null).getId();
|
||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
||||
|
||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testServerOperationUpdate() {
|
||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerOperationInterceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerOperationInterceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
IIdType id = myPatientDao.create(p, (RequestDetails)null).getId();
|
||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
||||
|
||||
p.addName().setFamily("2");
|
||||
myPatientDao.update(p);
|
||||
|
||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerOperationInterceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerOperationInterceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerOperationDelete() {
|
||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerOperationInterceptor, times(0)).resourceDeleted(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
IIdType id = myPatientDao.create(p, (RequestDetails)null).getId();
|
||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
||||
|
||||
p.addName().setFamily("2");
|
||||
myPatientDao.delete(p.getIdElement().toUnqualifiedVersionless());
|
||||
|
||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerOperationInterceptor, times(1)).resourceDeleted(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationDelete() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
||||
Long id = res.getIdElement().getIdPartAsLong();
|
||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
||||
|
||||
IIdType newId = myPatientDao.delete(new IdType("Patient/" + id), mySrd).getId();
|
||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||
|
||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationDeleteMulti() {
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id2 = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
||||
Long id = res.getIdElement().getIdPartAsLong();
|
||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
||||
|
||||
DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?name=PATIENT", mySrd);
|
||||
String oo = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
|
||||
ourLog.info(oo);
|
||||
assertThat(oo, containsString("deleted 2 resource(s)"));
|
||||
|
||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationTransactionCreate() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
||||
Long id = res.getIdElement().getIdPartAsLong();
|
||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
||||
|
||||
Bundle xactBundle = new Bundle();
|
||||
xactBundle.setType(BundleType.TRANSACTION);
|
||||
xactBundle
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.getRequest()
|
||||
.setUrl("Patient")
|
||||
.setMethod(HTTPVerb.POST);
|
||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
||||
|
||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals(1L, newId.getVersionIdPartAsLong().longValue());
|
||||
|
||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationTransactionDelete() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
||||
Long id = res.getIdElement().getIdPartAsLong();
|
||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
||||
|
||||
Bundle xactBundle = new Bundle();
|
||||
xactBundle.setType(BundleType.TRANSACTION);
|
||||
xactBundle
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setUrl("Patient/" + id)
|
||||
.setMethod(HTTPVerb.DELETE);
|
||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
||||
|
||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||
|
||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationTransactionDeleteMulti() {
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
Long id2 = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
||||
Long id = res.getIdElement().getIdPartAsLong();
|
||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
||||
|
||||
Bundle xactBundle = new Bundle();
|
||||
xactBundle.setType(BundleType.TRANSACTION);
|
||||
xactBundle
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setUrl("Patient?name=PATIENT")
|
||||
.setMethod(HTTPVerb.DELETE);
|
||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
||||
|
||||
String oo = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp);
|
||||
ourLog.info(oo);
|
||||
assertThat(oo, containsString("deleted 2 resource(s)"));
|
||||
|
||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationTransactionUpdate() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
p = new Patient();
|
||||
p.setId(new IdType("Patient/" + id));
|
||||
p.addName().setFamily("PATIENT2");
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
||||
|
||||
Bundle xactBundle = new Bundle();
|
||||
xactBundle.setType(BundleType.TRANSACTION);
|
||||
xactBundle
|
||||
.addEntry()
|
||||
.setResource(p)
|
||||
.getRequest()
|
||||
.setUrl("Patient/" + id)
|
||||
.setMethod(HTTPVerb.PUT);
|
||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
||||
|
||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||
|
||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestOperationUpdate() {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT");
|
||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
||||
res = (IBaseResource) theInvocation.getArguments()[1];
|
||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||
return null;
|
||||
}}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
||||
|
||||
p = new Patient();
|
||||
p.setId(new IdType("Patient/" + id));
|
||||
p.addName().setFamily("PATIENT2");
|
||||
IIdType newId = myPatientDao.update(p, mySrd).getId();
|
||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||
|
||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4ReferentialIntegrityTest extends BaseJpaR4Test {
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterResetConfig() {
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnWrite(new DaoConfig().isEnforceReferentialIntegrityOnWrite());
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUnknownReferenceFail() throws Exception {
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference("Organization/AAA"));
|
||||
try {
|
||||
myPatientDao.create(p);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Resource Organization/AAA not found, specified in path: Patient.managingOrganization", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateUnknownReferenceAllow() throws Exception {
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnWrite(false);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference("Organization/AAA"));
|
||||
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||
|
||||
p = myPatientDao.read(id);
|
||||
assertEquals("Organization/AAA", p.getManagingOrganization().getReference());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteFail() throws Exception {
|
||||
Organization o = new Organization();
|
||||
o.setName("FOO");
|
||||
IIdType oid = myOrganizationDao.create(o).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference(oid));
|
||||
IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||
|
||||
try {
|
||||
myOrganizationDao.delete(oid);
|
||||
fail();
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
assertEquals("Unable to delete Organization/"+oid.getIdPart()+" because at least one resource has a reference to this resource. First reference found was resource Organization/"+oid.getIdPart()+" in path Patient.managingOrganization", e.getMessage());
|
||||
}
|
||||
|
||||
myPatientDao.delete(pid);
|
||||
myOrganizationDao.delete(oid);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteAllow() throws Exception {
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(false);
|
||||
|
||||
Organization o = new Organization();
|
||||
o.setName("FOO");
|
||||
IIdType oid = myOrganizationDao.create(o).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setManagingOrganization(new Reference(oid));
|
||||
IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||
|
||||
myOrganizationDao.delete(oid);
|
||||
myPatientDao.delete(pid);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,883 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Appointment.AppointmentStatus;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchCustomSearchParamTest.class);
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamInvalidResourceName() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("PatientFoo.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Invalid SearchParameter.expression value \"PatientFoo.gender\": Unknown resource name \"PatientFoo\" (this name is not known in FHIR version \"R4\")", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidNoBase() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("SearchParameter.base is missing", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamMismatchedResourceName() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender or Observation.code");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Invalid SearchParameter.expression value \"Observation.code\". All paths in a single SearchParameter must match the same resource type", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamNoPath() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("SearchParameter.expression is missing", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamNoResourceName() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Invalid SearchParameter.expression value \"gender\". Must start with a resource name", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamParamNullStatus() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(null);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("SearchParameter.status is missing or invalid: null", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtensionWithNoValueIndexesWithoutFailure() {
|
||||
SearchParameter eyeColourSp = new SearchParameter();
|
||||
eyeColourSp.addBase("Patient");
|
||||
eyeColourSp.setCode("eyecolour");
|
||||
eyeColourSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
eyeColourSp.setTitle("Eye Colour");
|
||||
eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
|
||||
eyeColourSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
eyeColourSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
p1.addExtension().setUrl("http://acme.org/eyecolour").addExtension().setUrl("http://foo").setValue(new StringType("VAL"));
|
||||
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionToken() {
|
||||
SearchParameter eyeColourSp = new SearchParameter();
|
||||
eyeColourSp.addBase("Patient");
|
||||
eyeColourSp.setCode("eyecolour");
|
||||
eyeColourSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
eyeColourSp.setTitle("Eye Colour");
|
||||
eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
|
||||
eyeColourSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
eyeColourSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
p1.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("blue"));
|
||||
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.setActive(true);
|
||||
p2.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("green"));
|
||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||
|
||||
// Try with custom gender SP
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add("eyecolour", new TokenParam(null, "blue"));
|
||||
IBundleProvider results = myPatientDao.search(map);
|
||||
List<String> foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p1id.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepCoding() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new Coding().setSystem("foo").setCode("bar"));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new TokenParam("foo", "bar"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepCodeableConcept() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new CodeableConcept().addCoding(new Coding().setSystem("foo").setCode("bar")));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new TokenParam("foo", "bar"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepReferenceWrongType() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
siblingSp.getTarget().add(new CodeType("Observation"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
IIdType aptId = myAppointmentDao.create(apt).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new Reference(aptId.getValue()));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new ReferenceParam(aptId.getValue()));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepReferenceWithoutType() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
IIdType aptId = myAppointmentDao.create(apt).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new Reference(aptId.getValue()));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new ReferenceParam(aptId.getValue()));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepReference() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
siblingSp.getTarget().add(new CodeType("Appointment"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
IIdType aptId = myAppointmentDao.create(apt).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new Reference(aptId.getValue()));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new ReferenceParam(aptId.getValue()));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepDate() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.DATE);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
IIdType aptId = myAppointmentDao.create(apt).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new DateType("2012-01-02"));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new DateParam("2012-01-02"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepNumber() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.NUMBER);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new IntegerType(5));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new NumberParam("5"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepDecimal() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.NUMBER);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new DecimalType("2.1"));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new NumberParam("2.1"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionTwoDeepString() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("foobar");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.STRING);
|
||||
siblingSp.setTitle("FooBar");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/foo').extension('http://acme.org/bar')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
Extension extParent = patient
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/foo");
|
||||
extParent
|
||||
.addExtension()
|
||||
.setUrl("http://acme.org/bar")
|
||||
.setValue(new StringType("HELLOHELLO"));
|
||||
|
||||
IIdType p2id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add("foobar", new StringParam("hello"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionReferenceWithNonMatchingTarget() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("sibling");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
siblingSp.setTitle("Sibling");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/sibling')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().setFamily("P2");
|
||||
p2.addExtension().setUrl("http://acme.org/sibling").setValue(new Reference(p1id));
|
||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
// Search by ref
|
||||
map = new SearchParameterMap();
|
||||
map.add("sibling", new ReferenceParam(p1id.getValue()));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, empty());
|
||||
|
||||
// Search by chain
|
||||
map = new SearchParameterMap();
|
||||
map.add("sibling", new ReferenceParam("name", "P1"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, empty());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionReferenceWithoutTarget() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("sibling");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
siblingSp.setTitle("Sibling");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/sibling')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().setFamily("P2");
|
||||
p2.addExtension().setUrl("http://acme.org/sibling").setValue(new Reference(p1id));
|
||||
|
||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||
Appointment app = new Appointment();
|
||||
app.addParticipant().getActor().setReference(p2id.getValue());
|
||||
IIdType appid = myAppointmentDao.create(app).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
// Search by ref
|
||||
map = new SearchParameterMap();
|
||||
map.add("sibling", new ReferenceParam(p1id.getValue()));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
|
||||
// Search by chain
|
||||
map = new SearchParameterMap();
|
||||
map.add("sibling", new ReferenceParam("name", "P1"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
|
||||
// Search by two level chain
|
||||
map = new SearchParameterMap();
|
||||
map.add("patient", new ReferenceParam("sibling.name", "P1"));
|
||||
results = myAppointmentDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, containsInAnyOrder(appid.getValue()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchForExtensionReferenceWithTarget() {
|
||||
SearchParameter siblingSp = new SearchParameter();
|
||||
siblingSp.addBase("Patient");
|
||||
siblingSp.setCode("sibling");
|
||||
siblingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
siblingSp.setTitle("Sibling");
|
||||
siblingSp.setExpression("Patient.extension('http://acme.org/sibling')");
|
||||
siblingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
siblingSp.getTarget().add(new CodeType("Patient"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().setFamily("P2");
|
||||
p2.addExtension().setUrl("http://acme.org/sibling").setValue(new Reference(p1id));
|
||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||
|
||||
Appointment app = new Appointment();
|
||||
app.addParticipant().getActor().setReference(p2id.getValue());
|
||||
IIdType appid = myAppointmentDao.create(app).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
// Search by ref
|
||||
map = new SearchParameterMap();
|
||||
map.add("sibling", new ReferenceParam(p1id.getValue()));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
|
||||
// Search by chain
|
||||
map = new SearchParameterMap();
|
||||
map.add("sibling", new ReferenceParam("name", "P1"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(p2id.getValue()));
|
||||
|
||||
// Search by two level chain
|
||||
map = new SearchParameterMap();
|
||||
map.add("patient", new ReferenceParam("sibling.name", "P1"));
|
||||
results = myAppointmentDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, containsInAnyOrder(appid.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeExtensionReferenceAsRecurse() {
|
||||
SearchParameter attendingSp = new SearchParameter();
|
||||
attendingSp.addBase("Patient");
|
||||
attendingSp.setCode("attending");
|
||||
attendingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
attendingSp.setTitle("Attending");
|
||||
attendingSp.setExpression("Patient.extension('http://acme.org/attending')");
|
||||
attendingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
attendingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
attendingSp.getTarget().add(new CodeType("Practitioner"));
|
||||
IIdType spId = mySearchParameterDao.create(attendingSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Practitioner p1 = new Practitioner();
|
||||
p1.addName().setFamily("P1");
|
||||
IIdType p1id = myPractitionerDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().setFamily("P2");
|
||||
p2.addExtension().setUrl("http://acme.org/attending").setValue(new Reference(p1id));
|
||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||
|
||||
Appointment app = new Appointment();
|
||||
app.addParticipant().getActor().setReference(p2id.getValue());
|
||||
IIdType appId = myAppointmentDao.create(app).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.addInclude(new Include("Appointment:patient", true));
|
||||
map.addInclude(new Include("Patient:attending", true));
|
||||
results = myAppointmentDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(appId.getValue(), p2id.getValue(), p1id.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithCustomParam() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pat2 = new Patient();
|
||||
pat.setGender(AdministrativeGender.FEMALE);
|
||||
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
// Try with custom gender SP
|
||||
map = new SearchParameterMap();
|
||||
map.add("foo", new TokenParam(null, "male"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
// Try with normal gender SP
|
||||
map = new SearchParameterMap();
|
||||
map.add("gender", new TokenParam(null, "male"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
// Delete the param
|
||||
mySearchParameterDao.delete(spId, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySystemDao.performReindexingPass(100);
|
||||
|
||||
// Try with custom gender SP
|
||||
map = new SearchParameterMap();
|
||||
map.add("foo", new TokenParam(null, "male"));
|
||||
try {
|
||||
myPatientDao.search(map).size();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unknown search parameter foo for resource type Patient", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithCustomParamDraft() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.DRAFT);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pat2 = new Patient();
|
||||
pat.setGender(AdministrativeGender.FEMALE);
|
||||
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
// Try with custom gender SP (should find nothing)
|
||||
map = new SearchParameterMap();
|
||||
map.add("foo", new TokenParam(null, "male"));
|
||||
try {
|
||||
myPatientDao.search(map).size();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Unknown search parameter foo for resource type Patient", e.getMessage());
|
||||
}
|
||||
|
||||
// Try with normal gender SP
|
||||
map = new SearchParameterMap();
|
||||
map.add("gender", new TokenParam(null, "male"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomReferenceParameter() throws Exception {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.addBase("Patient");
|
||||
sp.setCode("myDoctor");
|
||||
sp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
sp.setTitle("My Doctor");
|
||||
sp.setExpression("Patient.extension('http://fmcna.com/myDoctor')");
|
||||
sp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
sp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(sp);
|
||||
|
||||
org.hl7.fhir.r4.model.Practitioner pract = new org.hl7.fhir.r4.model.Practitioner();
|
||||
pract.setId("A");
|
||||
pract.addName().setFamily("PRACT");
|
||||
myPractitionerDao.update(pract);
|
||||
|
||||
Patient pat = myFhirCtx.newJsonParser().parseResource(Patient.class, loadClasspath("/r4_custom_resource_patient.json"));
|
||||
IIdType pid = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("myDoctor", new ReferenceParam("A"));
|
||||
IBundleProvider outcome = myPatientDao.search(params);
|
||||
List<String> ids = toUnqualifiedVersionlessIdValues(outcome);
|
||||
ourLog.info("IDS: " + ids);
|
||||
assertThat(ids, contains(pid.getValue()));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,565 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchFtTest.class);
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCodeTextSearch() {
|
||||
Observation obs1 = new Observation();
|
||||
obs1.getCode().setText("Systolic Blood Pressure");
|
||||
obs1.setStatus(ObservationStatus.FINAL);
|
||||
obs1.setValue(new Quantity(123));
|
||||
obs1.setComment("obs1");
|
||||
IIdType id1 = myObservationDao.create(obs1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.getCode().setText("Diastolic Blood Pressure");
|
||||
obs2.setStatus(ObservationStatus.FINAL);
|
||||
obs2.setValue(new Quantity(81));
|
||||
IIdType id2 = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Observation.SP_CODE, new TokenParam(null, "systolic").setModifier(TokenParamModifier.TEXT));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1)));
|
||||
|
||||
// map = new SearchParameterMap();
|
||||
// map.add(Observation.SP_CODE, new TokenParam(null, "blood").setModifier(TokenParamModifier.TEXT));
|
||||
// assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
|
||||
//
|
||||
// map = new SearchParameterMap();
|
||||
// map.add(Observation.SP_CODE, new TokenParam(null, "blood").setModifier(TokenParamModifier.TEXT));
|
||||
// assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
//
|
||||
// map = new SearchParameterMap();
|
||||
// map.add(Observation.SP_CODE, new TokenParam(null, "blood").setModifier(TokenParamModifier.TEXT));
|
||||
// map.add(Constants.PARAM_CONTENT, new StringParam("obs1"));
|
||||
// assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testResourceTextSearch() {
|
||||
Observation obs1 = new Observation();
|
||||
obs1.getCode().setText("Systolic Blood Pressure");
|
||||
obs1.setStatus(ObservationStatus.FINAL);
|
||||
obs1.setValue(new Quantity(123));
|
||||
obs1.setComment("obs1");
|
||||
IIdType id1 = myObservationDao.create(obs1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.getCode().setText("Diastolic Blood Pressure");
|
||||
obs2.setStatus(ObservationStatus.FINAL);
|
||||
obs2.setValue(new Quantity(81));
|
||||
IIdType id2 = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("systolic"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("blood"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("obs1"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1)));
|
||||
|
||||
}
|
||||
|
||||
private ServletRequestDetails mockSrd() {
|
||||
return mySrd;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testStringTextSearch() {
|
||||
Observation obs1 = new Observation();
|
||||
obs1.getCode().setText("AAAAA");
|
||||
obs1.setValue(new StringType("Systolic Blood Pressure"));
|
||||
obs1.setStatus(ObservationStatus.FINAL);
|
||||
IIdType id1 = myObservationDao.create(obs1, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs1.getCode().setText("AAAAA");
|
||||
obs1.setValue(new StringType("Diastolic Blood Pressure"));
|
||||
obs2.setStatus(ObservationStatus.FINAL);
|
||||
IIdType id2 = myObservationDao.create(obs2, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Observation.SP_VALUE_STRING, new StringParam("sure").setContains(true));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSuggestIgnoresBase64Content() {
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("testSuggest");
|
||||
IIdType ptId = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Media med = new Media();
|
||||
med.getSubject().setReferenceElement(ptId);
|
||||
med.getSubtype().setText("Systolic Blood Pressure");
|
||||
med.getContent().setContentType("LCws");
|
||||
med.getContent().setDataElement(new Base64BinaryType(new byte[] {44,44,44,44,44,44,44,44}));
|
||||
med.getContent().setTitle("bbbb syst");
|
||||
myMediaDao.create(med, mockSrd());
|
||||
ourLog.info(myFhirCtx.newJsonParser().encodeResourceToString(med));
|
||||
|
||||
List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "press");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(2, output.size());
|
||||
assertEquals("Pressure", output.get(0).getTerm());
|
||||
assertEquals("Systolic Blood Pressure", output.get(1).getTerm());
|
||||
|
||||
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "prezure");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(2, output.size());
|
||||
assertEquals("Pressure", output.get(0).getTerm());
|
||||
assertEquals("Systolic Blood Pressure", output.get(1).getTerm());
|
||||
|
||||
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "syst");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(4, output.size());
|
||||
assertEquals("syst", output.get(0).getTerm());
|
||||
assertEquals("bbbb syst", output.get(1).getTerm());
|
||||
assertEquals("Systolic", output.get(2).getTerm());
|
||||
assertEquals("Systolic Blood Pressure", output.get(3).getTerm());
|
||||
|
||||
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "LCws");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(0, output.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggest() {
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("testSuggest");
|
||||
IIdType ptId = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(ptId);
|
||||
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
|
||||
myObservationDao.create(obs, mockSrd());
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(ptId);
|
||||
obs.getCode().setText("MNBVCXZ");
|
||||
myObservationDao.create(obs, mockSrd());
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(ptId);
|
||||
obs.getCode().setText("ZXC HELLO");
|
||||
obs.addComponent().getCode().setText("HHHHHHHHHH");
|
||||
myObservationDao.create(obs, mockSrd());
|
||||
|
||||
/*
|
||||
* These shouldn't match since they're for another patient
|
||||
*/
|
||||
patient = new Patient();
|
||||
patient.addName().setFamily("testSuggest2");
|
||||
IIdType ptId2 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.getSubject().setReferenceElement(ptId2);
|
||||
obs2.getCode().setText("ZXCVBNMZZ");
|
||||
myObservationDao.create(obs2, mockSrd());
|
||||
|
||||
List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZXCVBNM");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(4, output.size());
|
||||
assertEquals("ZXCVBNM", output.get(0).getTerm());
|
||||
assertEquals("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL", output.get(1).getTerm());
|
||||
assertEquals("ZXC", output.get(2).getTerm());
|
||||
assertEquals("ZXC HELLO", output.get(3).getTerm());
|
||||
|
||||
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZXC");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(4, output.size());
|
||||
assertEquals("ZXC", output.get(0).getTerm());
|
||||
assertEquals("ZXC HELLO", output.get(1).getTerm());
|
||||
assertEquals("ZXCVBNM", output.get(2).getTerm());
|
||||
assertEquals("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL", output.get(3).getTerm());
|
||||
|
||||
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "HELO");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(2, output.size());
|
||||
assertEquals("HELLO", output.get(0).getTerm());
|
||||
assertEquals("ZXC HELLO", output.get(1).getTerm());
|
||||
|
||||
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "Z");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(0, output.size());
|
||||
|
||||
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZX");
|
||||
ourLog.info("Found: " + output);
|
||||
assertEquals(2, output.size());
|
||||
assertEquals("ZXC", output.get(0).getTerm());
|
||||
assertEquals("ZXC HELLO", output.get(1).getTerm());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchAndReindex() {
|
||||
Patient patient;
|
||||
SearchParameterMap map;
|
||||
|
||||
patient = new Patient();
|
||||
patient.getText().setDivAsString("<div>DIVAAA</div>");
|
||||
patient.addName().addGiven("NAMEAAA");
|
||||
IIdType pId1 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_TEXT, new StringParam("DIVAAA"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
/*
|
||||
* Reindex
|
||||
*/
|
||||
|
||||
patient = new Patient();
|
||||
patient.setId(pId1);
|
||||
patient.getText().setDivAsString("<div>DIVBBB</div>");
|
||||
patient.addName().addGiven("NAMEBBB");
|
||||
myPatientDao.update(patient, mockSrd());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_NAME, new StringParam("NAMEBBB"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_TEXT, new StringParam("DIVBBB"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingInstanceWithContentFilter() {
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("Everything").addGiven("Arthur");
|
||||
IIdType ptId1 = myPatientDao.create(pt1, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.addName().setFamily("Everything").addGiven("Arthur");
|
||||
IIdType ptId2 = myPatientDao.create(pt2, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Device dev1 = new Device();
|
||||
dev1.setManufacturer("Some Manufacturer");
|
||||
IIdType devId1 = myDeviceDao.create(dev1, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Device dev2 = new Device();
|
||||
dev2.setManufacturer("Some Manufacturer 2");
|
||||
myDeviceDao.create(dev2, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs1 = new Observation();
|
||||
obs1.getText().setDivAsString("<div>OBSTEXT1</div>");
|
||||
obs1.getSubject().setReferenceElement(ptId1);
|
||||
obs1.getCode().addCoding().setCode("CODE1");
|
||||
obs1.setValue(new StringType("obsvalue1"));
|
||||
obs1.getDevice().setReferenceElement(devId1);
|
||||
IIdType obsId1 = myObservationDao.create(obs1, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.getSubject().setReferenceElement(ptId1);
|
||||
obs2.getCode().addCoding().setCode("CODE2");
|
||||
obs2.setValue(new StringType("obsvalue2"));
|
||||
IIdType obsId2 = myObservationDao.create(obs2, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs3 = new Observation();
|
||||
obs3.getSubject().setReferenceElement(ptId2);
|
||||
obs3.getCode().addCoding().setCode("CODE3");
|
||||
obs3.setValue(new StringType("obsvalue3"));
|
||||
IIdType obsId3 = myObservationDao.create(obs3, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
HttpServletRequest request;
|
||||
List<String> actual;
|
||||
request = mock(HttpServletRequest.class);
|
||||
StringAndListParam param;
|
||||
|
||||
ourLog.info("Pt1:{} Pt2:{} Obs1:{} Obs2:{} Obs3:{}", new Object[] {ptId1.getIdPart(), ptId2.getIdPart(), obsId1.getIdPart(), obsId2.getIdPart(), obsId3.getIdPart()});
|
||||
|
||||
param = new StringAndListParam();
|
||||
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
|
||||
|
||||
param = new StringAndListParam();
|
||||
param.addAnd(new StringOrListParam().addOr(new StringParam("obstext1")));
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, param, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
|
||||
|
||||
request = mock(HttpServletRequest.class);
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId2, devId1)));
|
||||
|
||||
/*
|
||||
* Add another match
|
||||
*/
|
||||
|
||||
Observation obs4 = new Observation();
|
||||
obs4.getSubject().setReferenceElement(ptId1);
|
||||
obs4.getCode().addCoding().setCode("CODE1");
|
||||
obs4.setValue(new StringType("obsvalue1"));
|
||||
IIdType obsId4 = myObservationDao.create(obs4, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
|
||||
|
||||
param = new StringAndListParam();
|
||||
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId4, devId1)));
|
||||
|
||||
/*
|
||||
* Make one previous match no longer match
|
||||
*/
|
||||
|
||||
obs1 = new Observation();
|
||||
obs1.setId(obsId1);
|
||||
obs1.getSubject().setReferenceElement(ptId1);
|
||||
obs1.getCode().addCoding().setCode("CODE2");
|
||||
obs1.setValue(new StringType("obsvalue2"));
|
||||
myObservationDao.update(obs1, mockSrd());
|
||||
|
||||
param = new StringAndListParam();
|
||||
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId4)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingTypeWithContentFilter() {
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("Everything").addGiven("Arthur");
|
||||
IIdType ptId1 = myPatientDao.create(pt1, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.addName().setFamily("Everything").addGiven("Arthur");
|
||||
IIdType ptId2 = myPatientDao.create(pt2, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Device dev1 = new Device();
|
||||
dev1.setManufacturer("Some Manufacturer");
|
||||
IIdType devId1 = myDeviceDao.create(dev1, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Device dev2 = new Device();
|
||||
dev2.setManufacturer("Some Manufacturer 2");
|
||||
myDeviceDao.create(dev2, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs1 = new Observation();
|
||||
obs1.getSubject().setReferenceElement(ptId1);
|
||||
obs1.getCode().addCoding().setCode("CODE1");
|
||||
obs1.setValue(new StringType("obsvalue1"));
|
||||
obs1.getDevice().setReferenceElement(devId1);
|
||||
IIdType obsId1 = myObservationDao.create(obs1, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.getSubject().setReferenceElement(ptId1);
|
||||
obs2.getCode().addCoding().setCode("CODE2");
|
||||
obs2.setValue(new StringType("obsvalue2"));
|
||||
IIdType obsId2 = myObservationDao.create(obs2, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs3 = new Observation();
|
||||
obs3.getSubject().setReferenceElement(ptId2);
|
||||
obs3.getCode().addCoding().setCode("CODE3");
|
||||
obs3.setValue(new StringType("obsvalue3"));
|
||||
IIdType obsId3 = myObservationDao.create(obs3, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
HttpServletRequest request;
|
||||
List<String> actual;
|
||||
request = mock(HttpServletRequest.class);
|
||||
StringAndListParam param;
|
||||
|
||||
ourLog.info("Pt1:{} Pt2:{} Obs1:{} Obs2:{} Obs3:{}", new Object[] {ptId1.getIdPart(), ptId2.getIdPart(), obsId1.getIdPart(), obsId2.getIdPart(), obsId3.getIdPart()});
|
||||
|
||||
param = new StringAndListParam();
|
||||
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, devId1)));
|
||||
|
||||
request = mock(HttpServletRequest.class);
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, null, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId2, devId1, ptId2, obsId3)));
|
||||
|
||||
/*
|
||||
* Add another match
|
||||
*/
|
||||
|
||||
Observation obs4 = new Observation();
|
||||
obs4.getSubject().setReferenceElement(ptId1);
|
||||
obs4.getCode().addCoding().setCode("CODE1");
|
||||
obs4.setValue(new StringType("obsvalue1"));
|
||||
IIdType obsId4 = myObservationDao.create(obs4, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
|
||||
|
||||
param = new StringAndListParam();
|
||||
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId1, obsId4, devId1)));
|
||||
|
||||
/*
|
||||
* Make one previous match no longer match
|
||||
*/
|
||||
|
||||
obs1 = new Observation();
|
||||
obs1.setId(obsId1);
|
||||
obs1.getSubject().setReferenceElement(ptId1);
|
||||
obs1.getCode().addCoding().setCode("CODE2");
|
||||
obs1.setValue(new StringType("obsvalue2"));
|
||||
myObservationDao.update(obs1, mockSrd());
|
||||
|
||||
param = new StringAndListParam();
|
||||
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
|
||||
actual = toUnqualifiedVersionlessIdValues(myPatientDao.patientTypeEverything(request, null, null, null, param, null, mockSrd()));
|
||||
assertThat(actual, containsInAnyOrder(toValues(ptId1, obsId4)));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When processing transactions, we do two passes. Make sure we don't update the lucene index twice since that would
|
||||
* be inefficient
|
||||
*/
|
||||
@Test
|
||||
public void testSearchDontReindexForUpdateWithIndexDisabled() {
|
||||
Patient patient;
|
||||
SearchParameterMap map;
|
||||
|
||||
patient = new Patient();
|
||||
patient.getText().setDivAsString("<div>DIVAAA</div>");
|
||||
patient.addName().addGiven("NAMEAAA");
|
||||
IIdType pId1 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_TEXT, new StringParam("DIVAAA"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
/*
|
||||
* Update but don't reindex
|
||||
*/
|
||||
|
||||
patient = new Patient();
|
||||
patient.setId(pId1);
|
||||
patient.getText().setDivAsString("<div>DIVBBB</div>");
|
||||
patient.addName().addGiven("NAMEBBB");
|
||||
myPatientDao.update(patient, null, false, mockSrd());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), not(contains(toValues(pId1))));
|
||||
|
||||
myPatientDao.update(patient, null, true, mockSrd());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), empty());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_NAME, new StringParam("NAMEBBB"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Constants.PARAM_TEXT, new StringParam("DIVBBB"));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), contains(toValues(pId1)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithChainedParams() {
|
||||
String methodName = "testSearchWithChainedParams";
|
||||
IIdType pId1;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addGiven(methodName);
|
||||
patient.addAddress().addLine("My fulltext address");
|
||||
pId1 = myPatientDao.create(patient, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId1);
|
||||
obs.setValue(new StringType("This is the FULLtext of the observation"));
|
||||
IIdType oId1 = myObservationDao.create(obs, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId1);
|
||||
obs.setValue(new StringType("Another fullText"));
|
||||
IIdType oId2 = myObservationDao.create(obs, mockSrd()).getId().toUnqualifiedVersionless();
|
||||
|
||||
List<String> patients;
|
||||
SearchParameterMap params;
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Constants.PARAM_CONTENT, new StringParam("fulltext"));
|
||||
patients = toUnqualifiedVersionlessIdValues(myPatientDao.search(params));
|
||||
assertThat(patients, containsInAnyOrder(toValues(pId1)));
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Constants.PARAM_CONTENT, new StringParam("FULLTEXT"));
|
||||
patients = toUnqualifiedVersionlessIdValues(myObservationDao.search(params));
|
||||
assertThat(patients, containsInAnyOrder(toValues(oId1, oId2)));
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,174 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
|
||||
public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@After()
|
||||
public void after() {
|
||||
StaleSearchDeletingSvcImpl staleSearchDeletingSvc = AopTestUtils.getTargetObject(myStaleSearchDeletingSvc);
|
||||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(StaleSearchDeletingSvcImpl.DEFAULT_CUTOFF_SLACK);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
StaleSearchDeletingSvcImpl staleSearchDeletingSvc = AopTestUtils.getTargetObject(myStaleSearchDeletingSvc);
|
||||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpirePagesAfterSingleUse() throws Exception {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
|
||||
SearchParameterMap params;
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(500);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(750);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(bundleProvider.getUuid()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpirePagesAfterReuse() throws Exception {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("EXPIRE");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(1000L);
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(500L);
|
||||
|
||||
final String searchUuid1;
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
searchUuid1 = bundleProvider.getUuid();
|
||||
Validate.notBlank(searchUuid1);
|
||||
}
|
||||
|
||||
Thread.sleep(250);
|
||||
|
||||
String searchUuid2;
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
searchUuid2 = bundleProvider.getUuid();
|
||||
Validate.notBlank(searchUuid2);
|
||||
}
|
||||
assertEquals(searchUuid1, searchUuid2);
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
// We're now past 500ms so we shouldn't reuse the search
|
||||
|
||||
final String searchUuid3;
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("EXPIRE"));
|
||||
final IBundleProvider bundleProvider = myPatientDao.search(params);
|
||||
assertThat(toUnqualifiedVersionlessIds(bundleProvider), containsInAnyOrder(pid1, pid2));
|
||||
searchUuid3 = bundleProvider.getUuid();
|
||||
Validate.notBlank(searchUuid3);
|
||||
}
|
||||
assertNotEquals(searchUuid1, searchUuid3);
|
||||
|
||||
// Search just got used so it shouldn't be deleted
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNotNull(mySearchEntityDao.findByUuid(searchUuid1));
|
||||
assertNotNull(mySearchEntityDao.findByUuid(searchUuid3));
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(750);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(searchUuid1));
|
||||
assertNotNull(mySearchEntityDao.findByUuid(searchUuid3));
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(300);
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
newTxTemplate().execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
assertNull(mySearchEntityDao.findByUuid(searchUuid1));
|
||||
assertNull(mySearchEntityDao.findByUuid(searchUuid3));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.config.TestR4WithoutLuceneConfig;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
// @RunWith(SpringJUnit4ClassRunner.class)
|
||||
// @ContextConfiguration(classes= {TestR4WithoutLuceneConfig.class})
|
||||
// @SuppressWarnings("unchecked")
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { TestR4WithoutLuceneConfig.class })
|
||||
public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchWithLuceneDisabledTest.class);
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myAllergyIntoleranceDaoR4")
|
||||
private IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
||||
@Autowired
|
||||
@Qualifier("myAppointmentDaoR4")
|
||||
private IFhirResourceDao<Appointment> myAppointmentDao;
|
||||
@Autowired
|
||||
@Qualifier("myAuditEventDaoR4")
|
||||
private IFhirResourceDao<AuditEvent> myAuditEventDao;
|
||||
@Autowired
|
||||
@Qualifier("myBundleDaoR4")
|
||||
private IFhirResourceDao<Bundle> myBundleDao;
|
||||
@Autowired
|
||||
@Qualifier("myCarePlanDaoR4")
|
||||
private IFhirResourceDao<CarePlan> myCarePlanDao;
|
||||
@Autowired
|
||||
@Qualifier("myCodeSystemDaoR4")
|
||||
private IFhirResourceDao<CodeSystem> myCodeSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myCompartmentDefinitionDaoR4")
|
||||
private IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myConceptMapDaoR4")
|
||||
private IFhirResourceDao<ConceptMap> myConceptMapDao;
|
||||
@Autowired
|
||||
@Qualifier("myConditionDaoR4")
|
||||
private IFhirResourceDao<Condition> myConditionDao;
|
||||
@Autowired
|
||||
protected DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
@Qualifier("myDeviceDaoR4")
|
||||
private IFhirResourceDao<Device> myDeviceDao;
|
||||
@Autowired
|
||||
@Qualifier("myDiagnosticReportDaoR4")
|
||||
private IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
|
||||
@Autowired
|
||||
@Qualifier("myEncounterDaoR4")
|
||||
private IFhirResourceDao<Encounter> myEncounterDao;
|
||||
// @PersistenceContext()
|
||||
@Autowired
|
||||
private EntityManager myEntityManager;
|
||||
@Autowired
|
||||
private FhirContext myFhirCtx;
|
||||
@Autowired
|
||||
@Qualifier("myImmunizationDaoR4")
|
||||
private IFhirResourceDao<Immunization> myImmunizationDao;
|
||||
@Autowired
|
||||
@Qualifier("myLocationDaoR4")
|
||||
private IFhirResourceDao<Location> myLocationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMediaDaoR4")
|
||||
private IFhirResourceDao<Media> myMediaDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationDaoR4")
|
||||
private IFhirResourceDao<Medication> myMedicationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationRequestDaoR4")
|
||||
private IFhirResourceDao<MedicationRequest> myMedicationRequestDao;
|
||||
@Autowired
|
||||
@Qualifier("myNamingSystemDaoR4")
|
||||
private IFhirResourceDao<NamingSystem> myNamingSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myObservationDaoR4")
|
||||
private IFhirResourceDao<Observation> myObservationDao;
|
||||
@Autowired
|
||||
@Qualifier("myOperationDefinitionDaoR4")
|
||||
private IFhirResourceDao<OperationDefinition> myOperationDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myOrganizationDaoR4")
|
||||
private IFhirResourceDao<Organization> myOrganizationDao;
|
||||
@Autowired
|
||||
@Qualifier("myPatientDaoR4")
|
||||
private IFhirResourceDaoPatient<Patient> myPatientDao;
|
||||
@Autowired
|
||||
@Qualifier("myPractitionerDaoR4")
|
||||
private IFhirResourceDao<Practitioner> myPractitionerDao;
|
||||
@Autowired
|
||||
@Qualifier("myQuestionnaireDaoR4")
|
||||
private IFhirResourceDao<Questionnaire> myQuestionnaireDao;
|
||||
@Autowired
|
||||
@Qualifier("myQuestionnaireResponseDaoR4")
|
||||
private IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
||||
@Autowired
|
||||
@Qualifier("myResourceProvidersR4")
|
||||
private Object myResourceProviders;
|
||||
@Autowired
|
||||
@Qualifier("myStructureDefinitionDaoR4")
|
||||
private IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("mySubscriptionDaoR4")
|
||||
private IFhirResourceDaoSubscription<Subscription> mySubscriptionDao;
|
||||
@Autowired
|
||||
@Qualifier("mySubstanceDaoR4")
|
||||
private IFhirResourceDao<Substance> mySubstanceDao;
|
||||
@Autowired
|
||||
@Qualifier("mySystemDaoR4")
|
||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
@Autowired
|
||||
@Qualifier("mySystemProviderR4")
|
||||
private JpaSystemProviderR4 mySystemProvider;
|
||||
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myTxManager;
|
||||
@Autowired
|
||||
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainR4")
|
||||
private IValidationSupport myValidationSupport;
|
||||
@Autowired
|
||||
protected ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
|
||||
@Before
|
||||
@Transactional()
|
||||
public void beforePurgeDatabase() {
|
||||
final EntityManager entityManager = this.myEntityManager;
|
||||
purgeDatabase(entityManager, myTxManager, mySearchParamPresenceSvc, mySearchCoordinatorSvc);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeResetConfig() {
|
||||
myDaoConfig.setHardSearchLimit(1000);
|
||||
myDaoConfig.setHardTagListLimit(1000);
|
||||
myDaoConfig.setIncludeLimit(2000);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FhirContext getContext() {
|
||||
return myFhirCtx;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithRegularParam() throws Exception {
|
||||
String methodName = "testEverythingIncludesBackReferences";
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName(methodName);
|
||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(Organization.SP_NAME, new StringParam(methodName));
|
||||
myOrganizationDao.search(map);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithContent() throws Exception {
|
||||
String methodName = "testEverythingIncludesBackReferences";
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName(methodName);
|
||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, new StringParam(methodName));
|
||||
try {
|
||||
myOrganizationDao.search(map).size();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Fulltext search is not enabled on this service, can not process parameter: _content", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithText() throws Exception {
|
||||
String methodName = "testEverythingIncludesBackReferences";
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName(methodName);
|
||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, new StringParam(methodName));
|
||||
try {
|
||||
myOrganizationDao.search(map).size();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Fulltext search is not enabled on this service, can not process parameter: _text", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,530 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISubscriptionFlaggedResourceDataDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISubscriptionTableDao;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4SubscriptionTest extends BaseJpaR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SubscriptionTest.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISubscriptionFlaggedResourceDataDao mySubscriptionFlaggedResourceDataDao;
|
||||
|
||||
@Autowired
|
||||
private ISubscriptionTableDao mySubscriptionTableDao;
|
||||
|
||||
@Before
|
||||
public void beforeEnableSubscription() {
|
||||
myDaoConfig.setSubscriptionEnabled(true);
|
||||
myDaoConfig.setSubscriptionPurgeInactiveAfterSeconds(60);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionGetsPurgedIfItIsNeverActive() throws Exception {
|
||||
myDaoConfig.setSubscriptionPurgeInactiveAfterSeconds(1);
|
||||
|
||||
Subscription subs = new Subscription();
|
||||
subs.setCriteria("Observation?subject=Patient/123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
|
||||
IIdType id = mySubscriptionDao.create(subs, mySrd).getId().toUnqualifiedVersionless();
|
||||
mySubscriptionDao.purgeInactiveSubscriptions();
|
||||
mySubscriptionDao.read(id, mySrd);
|
||||
|
||||
Thread.sleep(1500);
|
||||
|
||||
myDaoConfig.setSchedulingDisabled(false);
|
||||
mySubscriptionDao.purgeInactiveSubscriptions();
|
||||
try {
|
||||
mySubscriptionDao.read(id, mySrd);
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeDisableScheduling() {
|
||||
myDaoConfig.setSchedulingDisabled(true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSubscriptionGetsPurgedIfItIsInactive() throws Exception {
|
||||
myDaoConfig.setSubscriptionPurgeInactiveAfterSeconds(1);
|
||||
|
||||
Subscription subs = new Subscription();
|
||||
subs.setCriteria("Observation?subject=Patient/123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
|
||||
IIdType id = mySubscriptionDao.create(subs, mySrd).getId().toUnqualifiedVersionless();
|
||||
mySubscriptionDao.purgeInactiveSubscriptions();
|
||||
mySubscriptionDao.read(id, mySrd);
|
||||
|
||||
mySubscriptionDao.getUndeliveredResourcesAndPurge(mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id));
|
||||
|
||||
Thread.sleep(1500);
|
||||
|
||||
myDaoConfig.setSchedulingDisabled(false);
|
||||
mySubscriptionDao.purgeInactiveSubscriptions();
|
||||
try {
|
||||
mySubscriptionDao.read(id, mySrd);
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSubscription() {
|
||||
Subscription subs = new Subscription();
|
||||
subs.setCriteria("Observation?subject=Patient/123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
|
||||
IIdType id = mySubscriptionDao.create(subs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
TypedQuery<SubscriptionTable> q = myEntityManager.createQuery("SELECT t from SubscriptionTable t WHERE t.mySubscriptionResource.myId = :id", SubscriptionTable.class);
|
||||
q.setParameter("id", id.getIdPartAsLong());
|
||||
final SubscriptionTable table = q.getSingleResult();
|
||||
|
||||
assertNotNull(table);
|
||||
assertNotNull(table.getNextCheck());
|
||||
assertEquals(table.getNextCheck(), table.getSubscriptionResource().getPublished().getValue());
|
||||
assertEquals(SubscriptionStatus.REQUESTED.toCode(), myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
|
||||
assertEquals(SubscriptionStatus.REQUESTED, mySubscriptionDao.read(id, mySrd).getStatusElement().getValue());
|
||||
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
mySubscriptionDao.update(subs, mySrd);
|
||||
|
||||
assertEquals(SubscriptionStatus.ACTIVE.toCode(), myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
|
||||
assertEquals(SubscriptionStatus.ACTIVE, mySubscriptionDao.read(id, mySrd).getStatusElement().getValue());
|
||||
|
||||
mySubscriptionDao.delete(id, mySrd);
|
||||
|
||||
assertNull(myEntityManager.find(SubscriptionTable.class, table.getId()));
|
||||
|
||||
/*
|
||||
* Re-create again
|
||||
*/
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setCriteria("Observation?subject=Patient/123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setId(id);
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
mySubscriptionDao.update(subs, mySrd);
|
||||
|
||||
assertEquals(SubscriptionStatus.REQUESTED.toCode(), myEntityManager.createQuery("SELECT t FROM SubscriptionTable t WHERE t.myResId = " + id.getIdPart(), SubscriptionTable.class).getSingleResult().getStatus());
|
||||
assertEquals(SubscriptionStatus.REQUESTED, mySubscriptionDao.read(id, mySrd).getStatusElement().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSubscriptionInvalidCriteria() {
|
||||
Subscription subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("Observation");
|
||||
try {
|
||||
mySubscriptionDao.create(subs, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Subscription.criteria must be in the form \"{Resource Type}?[params]\""));
|
||||
}
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("http://foo.com/Observation?AAA=BBB");
|
||||
try {
|
||||
mySubscriptionDao.create(subs, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Subscription.criteria must be in the form \"{Resource Type}?[params]\""));
|
||||
}
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("ObservationZZZZ?a=b");
|
||||
try {
|
||||
mySubscriptionDao.create(subs, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Subscription.criteria contains invalid/unsupported resource type: ObservationZZZZ"));
|
||||
}
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
try {
|
||||
mySubscriptionDao.create(subs, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Subscription.channel.type must be populated"));
|
||||
}
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
try {
|
||||
mySubscriptionDao.create(subs, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Subscription.channel.payload must be populated for rest-hook subscriptions"));
|
||||
}
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
subs.getChannel().setPayload("text/html");
|
||||
try {
|
||||
mySubscriptionDao.create(subs, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Invalid value for Subscription.channel.payload: text/html"));
|
||||
}
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
subs.getChannel().setPayload("application/fhir+xml");
|
||||
try {
|
||||
mySubscriptionDao.create(subs, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("Rest-hook subscriptions must have Subscription.channel.endpoint defined"));
|
||||
}
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
assertTrue(mySubscriptionDao.create(subs, mySrd).getId().hasIdPart());
|
||||
|
||||
subs = new Subscription();
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
subs.getChannel().setPayload("application/fhir+json");
|
||||
subs.getChannel().setEndpoint("http://localhost:8080");
|
||||
assertTrue(mySubscriptionDao.create(subs, mySrd).getId().hasIdPart());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteSubscriptionWithFlaggedResources() throws Exception {
|
||||
myDaoConfig.setSubscriptionPollDelay(0);
|
||||
|
||||
String methodName = "testDeleteSubscriptionWithFlaggedResources";
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType pId = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Subscription subs;
|
||||
|
||||
/*
|
||||
* Create 2 identical subscriptions
|
||||
*/
|
||||
|
||||
subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
IIdType subsId = mySubscriptionDao.create(subs, mySrd).getId().toUnqualifiedVersionless();
|
||||
Long subsPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(subsId);
|
||||
|
||||
assertNull(mySubscriptionTableDao.findOne(subsPid).getLastClientPoll());
|
||||
|
||||
Thread.sleep(100);
|
||||
ourLog.info("Before: {}", System.currentTimeMillis());
|
||||
assertThat(mySubscriptionFlaggedResourceDataDao.count(), not(greaterThan(0L)));
|
||||
assertThat(mySubscriptionTableDao.count(), equalTo(1L));
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
ourLog.info("After: {}", System.currentTimeMillis());
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
assertThat(mySubscriptionFlaggedResourceDataDao.count(), greaterThan(0L));
|
||||
assertThat(mySubscriptionTableDao.count(), greaterThan(0L));
|
||||
|
||||
/*
|
||||
* Delete the subscription
|
||||
*/
|
||||
|
||||
mySubscriptionDao.delete(subsId, mySrd);
|
||||
|
||||
assertThat(mySubscriptionFlaggedResourceDataDao.count(), not(greaterThan(0L)));
|
||||
assertThat(mySubscriptionTableDao.count(), not(greaterThan(0L)));
|
||||
|
||||
/*
|
||||
* Delete a second time just to make sure that works
|
||||
*/
|
||||
mySubscriptionDao.delete(subsId, mySrd);
|
||||
|
||||
/*
|
||||
* Re-create the subscription
|
||||
*/
|
||||
|
||||
subs.setId(subsId);
|
||||
mySubscriptionDao.update(subs, mySrd).getId();
|
||||
|
||||
assertThat(mySubscriptionFlaggedResourceDataDao.count(), not(greaterThan(0L)));
|
||||
assertThat(mySubscriptionTableDao.count(), (greaterThan(0L)));
|
||||
|
||||
/*
|
||||
* Create another resource and make sure it gets flagged
|
||||
*/
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
assertThat(mySubscriptionFlaggedResourceDataDao.count(), greaterThan(0L));
|
||||
assertThat(mySubscriptionTableDao.count(), greaterThan(0L));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionResourcesAppear() throws Exception {
|
||||
myDaoConfig.setSubscriptionPollDelay(0);
|
||||
|
||||
String methodName = "testSubscriptionResourcesAppear";
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType pId = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Subscription subs;
|
||||
|
||||
/*
|
||||
* Create 2 identical subscriptions
|
||||
*/
|
||||
|
||||
subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
Long subsId1 = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(mySubscriptionDao.create(subs, mySrd).getId());
|
||||
|
||||
subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
Long subsId2 = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(mySubscriptionDao.create(subs, mySrd).getId());
|
||||
|
||||
assertNull(mySubscriptionTableDao.findOne(subsId1).getLastClientPoll());
|
||||
|
||||
Thread.sleep(100);
|
||||
ourLog.info("Before: {}", System.currentTimeMillis());
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId2 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
ourLog.info("After: {}", System.currentTimeMillis());
|
||||
|
||||
List<IBaseResource> results;
|
||||
List<IIdType> resultIds;
|
||||
|
||||
assertEquals(4, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
|
||||
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId1);
|
||||
resultIds = toUnqualifiedVersionlessIds(results);
|
||||
assertThat(resultIds, contains(afterId1, afterId2));
|
||||
|
||||
Date lastClientPoll = mySubscriptionTableDao.findOne(subsId1).getLastClientPoll();
|
||||
assertNotNull(lastClientPoll);
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId2);
|
||||
resultIds = toUnqualifiedVersionlessIds(results);
|
||||
assertThat(resultIds, contains(afterId1, afterId2));
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId1);
|
||||
resultIds = toUnqualifiedVersionlessIds(results);
|
||||
assertThat(resultIds, empty());
|
||||
|
||||
assertNotEquals(lastClientPoll, mySubscriptionTableDao.findOne(subsId1).getLastClientPoll());
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId2);
|
||||
resultIds = toUnqualifiedVersionlessIds(results);
|
||||
assertThat(resultIds, empty());
|
||||
|
||||
/*
|
||||
* Make sure that reindexing doesn't trigger
|
||||
*/
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(100);
|
||||
|
||||
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
|
||||
/*
|
||||
* Update resources on disk
|
||||
*/
|
||||
IBundleProvider allObs = myObservationDao.search(new SearchParameterMap());
|
||||
ourLog.info("Updating {} observations", allObs.size());
|
||||
for (IBaseResource next : allObs.getResources(0, allObs.size())) {
|
||||
ourLog.info("Updating observation");
|
||||
Observation nextObs = (Observation) next;
|
||||
nextObs.addPerformer().setDisplay("Some display");
|
||||
myObservationDao.update(nextObs, mySrd);
|
||||
}
|
||||
|
||||
assertEquals(6, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSubscriptionResourcesAppear2() throws Exception {
|
||||
myDaoConfig.setSubscriptionPollDelay(0);
|
||||
|
||||
String methodName = "testSubscriptionResourcesAppear2";
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType pId = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType oId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Subscription subs;
|
||||
|
||||
/*
|
||||
* Create 2 identical subscriptions
|
||||
*/
|
||||
|
||||
subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
Long subsId1 = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(mySubscriptionDao.create(subs, mySrd).getId());
|
||||
|
||||
assertNull(mySubscriptionTableDao.findOne(subsId1).getLastClientPoll());
|
||||
|
||||
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
|
||||
ourLog.info("pId: {} - oId: {}", pId, oId);
|
||||
|
||||
myObservationDao.update(myObservationDao.read(oId, mySrd), mySrd);
|
||||
|
||||
assertEquals(1, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
ourLog.info("Between passes");
|
||||
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
|
||||
Thread.sleep(100);
|
||||
ourLog.info("Before: {}", System.currentTimeMillis());
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
ourLog.info("After: {}", System.currentTimeMillis());
|
||||
|
||||
assertEquals(2, mySubscriptionDao.pollForNewUndeliveredResources());
|
||||
assertEquals(3, mySubscriptionFlaggedResourceDataDao.count());
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
assertEquals(3, mySubscriptionFlaggedResourceDataDao.count());
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
assertEquals(3, mySubscriptionFlaggedResourceDataDao.count());
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
assertEquals(4, mySubscriptionFlaggedResourceDataDao.count());
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
assertEquals(4, mySubscriptionFlaggedResourceDataDao.count());
|
||||
}
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,868 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4UpdateTest.class);
|
||||
|
||||
@Test
|
||||
public void testCreateAndUpdateWithoutRequest() throws Exception {
|
||||
String methodName = "testUpdateByUrl";
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
|
||||
IIdType id = myPatientDao.create(p).getId().toUnqualified();
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
|
||||
p.setActive(true);
|
||||
IIdType id2 = myPatientDao.create(p, "Patient?identifier=urn:system|" + methodName + "2").getId().toUnqualified();
|
||||
assertEquals(id.getValue(), id2.getValue());
|
||||
|
||||
p = new Patient();
|
||||
p.setId(id);
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
|
||||
p.setActive(false);
|
||||
myPatientDao.update(p).getId();
|
||||
|
||||
p.setActive(true);
|
||||
id2 = myPatientDao.update(p, "Patient?identifier=urn:system|" + methodName + "2").getId().toUnqualified();
|
||||
assertEquals(id.getIdPart(), id2.getIdPart());
|
||||
assertEquals("3", id2.getVersionIdPart());
|
||||
|
||||
Patient newPatient = myPatientDao.read(id);
|
||||
assertEquals("1", newPatient.getIdElement().getVersionIdPart());
|
||||
|
||||
newPatient = myPatientDao.read(id.toVersionless());
|
||||
assertEquals("3", newPatient.getIdElement().getVersionIdPart());
|
||||
|
||||
myPatientDao.delete(id.toVersionless());
|
||||
|
||||
try {
|
||||
myPatientDao.read(id.toVersionless());
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateProfilesIgnored() {
|
||||
String name = "testDuplicateProfilesIgnored";
|
||||
IIdType id;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily(name);
|
||||
|
||||
List<IdType> tl = new ArrayList<IdType>();
|
||||
tl.add(new IdType("http://foo/bar"));
|
||||
tl.add(new IdType("http://foo/bar"));
|
||||
tl.add(new IdType("http://foo/bar"));
|
||||
patient.getMeta().getProfile().addAll(tl);
|
||||
|
||||
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
// Do a read
|
||||
{
|
||||
Patient patient = myPatientDao.read(id, mySrd);
|
||||
List<UriType> tl = patient.getMeta().getProfile();
|
||||
assertEquals(1, tl.size());
|
||||
assertEquals("http://foo/bar", tl.get(0).getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterResetDao() {
|
||||
myDaoConfig.setResourceMetaCountHardLimit(new DaoConfig().getResourceMetaCountHardLimit());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHardMetaCapIsEnforcedOnCreate() {
|
||||
myDaoConfig.setResourceMetaCountHardLimit(3);
|
||||
|
||||
IIdType id;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getMeta().addTag().setSystem("http://foo").setCode("1");
|
||||
patient.getMeta().addTag().setSystem("http://foo").setCode("2");
|
||||
patient.getMeta().addTag().setSystem("http://foo").setCode("3");
|
||||
patient.getMeta().addTag().setSystem("http://foo").setCode("4");
|
||||
patient.setActive(true);
|
||||
try {
|
||||
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Resource contains 4 meta entries (tag/profile/security label), maximum is 3", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHardMetaCapIsEnforcedOnMetaAdd() {
|
||||
myDaoConfig.setResourceMetaCountHardLimit(3);
|
||||
|
||||
IIdType id;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
{
|
||||
Meta meta = new Meta();
|
||||
meta.addTag().setSystem("http://foo").setCode("1");
|
||||
meta.addTag().setSystem("http://foo").setCode("2");
|
||||
meta.addTag().setSystem("http://foo").setCode("3");
|
||||
meta.addTag().setSystem("http://foo").setCode("4");
|
||||
try {
|
||||
myPatientDao.metaAddOperation(id, meta, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Resource contains 4 meta entries (tag/profile/security label), maximum is 3", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateTagsOnAddTagsIgnored() {
|
||||
IIdType id;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
Meta meta = new Meta();
|
||||
meta.addTag().setSystem("http://foo").setCode("bar").setDisplay("Val1");
|
||||
meta.addTag().setSystem("http://foo").setCode("bar").setDisplay("Val2");
|
||||
meta.addTag().setSystem("http://foo").setCode("bar").setDisplay("Val3");
|
||||
myPatientDao.metaAddOperation(id, meta, null);
|
||||
|
||||
// Do a read
|
||||
{
|
||||
Patient patient = myPatientDao.read(id, mySrd);
|
||||
List<Coding> tl = patient.getMeta().getTag();
|
||||
assertEquals(1, tl.size());
|
||||
assertEquals("http://foo", tl.get(0).getSystem());
|
||||
assertEquals("bar", tl.get(0).getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateTagsOnUpdateIgnored() {
|
||||
IIdType id;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setActive(true);
|
||||
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setId(id);
|
||||
patient.setActive(true);
|
||||
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val1");
|
||||
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val2");
|
||||
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val3");
|
||||
myPatientDao.update(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
// Do a read on second version
|
||||
{
|
||||
Patient patient = myPatientDao.read(id, mySrd);
|
||||
List<Coding> tl = patient.getMeta().getTag();
|
||||
assertEquals(1, tl.size());
|
||||
assertEquals("http://foo", tl.get(0).getSystem());
|
||||
assertEquals("bar", tl.get(0).getCode());
|
||||
}
|
||||
|
||||
// Do a read on first version
|
||||
{
|
||||
Patient patient = myPatientDao.read(id.withVersion("1"), mySrd);
|
||||
List<Coding> tl = patient.getMeta().getTag();
|
||||
assertEquals(0, tl.size());
|
||||
}
|
||||
|
||||
Meta meta = new Meta();
|
||||
meta.addTag().setSystem("http://foo").setCode("bar").setDisplay("Val1");
|
||||
meta.addTag().setSystem("http://foo").setCode("bar").setDisplay("Val2");
|
||||
meta.addTag().setSystem("http://foo").setCode("bar").setDisplay("Val3");
|
||||
myPatientDao.metaAddOperation(id.withVersion("1"), meta, null);
|
||||
|
||||
// Do a read on first version
|
||||
{
|
||||
Patient patient = myPatientDao.read(id.withVersion("1"), mySrd);
|
||||
List<Coding> tl = patient.getMeta().getTag();
|
||||
assertEquals(1, tl.size());
|
||||
assertEquals("http://foo", tl.get(0).getSystem());
|
||||
assertEquals("bar", tl.get(0).getCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleUpdatesWithNoChangesDoesNotResultInAnUpdateForDiscreteUpdates() {
|
||||
|
||||
// First time
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
p.setId("Patient/A");
|
||||
String id = myPatientDao.update(p).getId().getValue();
|
||||
assertThat(id, endsWith("Patient/A/_history/1"));
|
||||
|
||||
// Second time should not result in an update
|
||||
p = new Patient();
|
||||
p.setActive(true);
|
||||
p.setId("Patient/A");
|
||||
id = myPatientDao.update(p).getId().getValue();
|
||||
assertThat(id, endsWith("Patient/A/_history/1"));
|
||||
|
||||
// And third time should not result in an update
|
||||
p = new Patient();
|
||||
p.setActive(true);
|
||||
p.setId("Patient/A");
|
||||
id = myPatientDao.update(p).getId().getValue();
|
||||
assertThat(id, endsWith("Patient/A/_history/1"));
|
||||
|
||||
myPatientDao.read(new IdType("Patient/A"));
|
||||
myPatientDao.read(new IdType("Patient/A/_history/1"));
|
||||
try {
|
||||
myPatientDao.read(new IdType("Patient/A/_history/2"));
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// good
|
||||
}
|
||||
try {
|
||||
myPatientDao.read(new IdType("Patient/A/_history/3"));
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
// Create one more
|
||||
p = new Patient();
|
||||
p.setActive(false);
|
||||
p.setId("Patient/A");
|
||||
id = myPatientDao.update(p).getId().getValue();
|
||||
assertThat(id, endsWith("Patient/A/_history/2"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAndGetHistoryResource() throws InterruptedException {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
|
||||
MethodOutcome outcome = myPatientDao.create(patient, mySrd);
|
||||
assertNotNull(outcome.getId());
|
||||
assertFalse(outcome.getId().isEmpty());
|
||||
|
||||
assertEquals("1", outcome.getId().getVersionIdPart());
|
||||
|
||||
Date now = new Date();
|
||||
Patient retrieved = myPatientDao.read(outcome.getId(), mySrd);
|
||||
InstantType updated = retrieved.getMeta().getLastUpdatedElement().copy();
|
||||
assertTrue(updated.before(now));
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
reset(myInterceptor);
|
||||
retrieved.getIdentifier().get(0).setValue("002");
|
||||
MethodOutcome outcome2 = myPatientDao.update(retrieved, mySrd);
|
||||
assertEquals(outcome.getId().getIdPart(), outcome2.getId().getIdPart());
|
||||
assertNotEquals(outcome.getId().getVersionIdPart(), outcome2.getId().getVersionIdPart());
|
||||
assertEquals("2", outcome2.getId().getVersionIdPart());
|
||||
|
||||
// Verify interceptor
|
||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.UPDATE), detailsCapt.capture());
|
||||
ActionRequestDetails details = detailsCapt.getValue();
|
||||
assertNotNull(details.getId());
|
||||
assertEquals("Patient", details.getResourceType());
|
||||
assertEquals(Patient.class, details.getResource().getClass());
|
||||
|
||||
Date now2 = new Date();
|
||||
|
||||
Patient retrieved2 = myPatientDao.read(outcome.getId().toVersionless(), mySrd);
|
||||
|
||||
assertEquals("2", retrieved2.getIdElement().getVersionIdPart());
|
||||
assertEquals("002", retrieved2.getIdentifier().get(0).getValue());
|
||||
InstantType updated2 = retrieved2.getMeta().getLastUpdatedElement();
|
||||
assertTrue(updated2.after(now));
|
||||
assertTrue(updated2.before(now2));
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
/*
|
||||
* Get history
|
||||
*/
|
||||
|
||||
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, null, mySrd);
|
||||
|
||||
assertEquals(2, historyBundle.size().intValue());
|
||||
|
||||
List<IBaseResource> history = historyBundle.getResources(0, 2);
|
||||
|
||||
ourLog.info("updated : {}", updated.getValueAsString());
|
||||
ourLog.info(" * Exp : {}", ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
ourLog.info("updated2: {}", updated2.getValueAsString());
|
||||
ourLog.info(" * Exp : {}", ((Resource) history.get(0)).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
|
||||
assertEquals("1", history.get(1).getIdElement().getVersionIdPart());
|
||||
assertEquals("2", history.get(0).getIdElement().getVersionIdPart());
|
||||
assertEquals(updated.getValueAsString(), ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
assertEquals("001", ((Patient) history.get(1)).getIdentifier().get(0).getValue());
|
||||
assertEquals(updated2.getValueAsString(), ((Resource) history.get(0)).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
assertEquals("002", ((Patient) history.get(0)).getIdentifier().get(0).getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateByUrl() {
|
||||
String methodName = "testUpdateByUrl";
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
||||
ourLog.info("Created patient, got it: {}", id);
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/" + methodName);
|
||||
|
||||
myPatientDao.update(p, "Patient?identifier=urn%3Asystem%7C" + methodName, mySrd);
|
||||
|
||||
p = myPatientDao.read(id.toVersionless(), mySrd);
|
||||
assertThat(p.getIdElement().toVersionless().toString(), not(containsString("test")));
|
||||
assertEquals(id.toVersionless(), p.getIdElement().toVersionless());
|
||||
assertNotEquals(id, p.getIdElement());
|
||||
assertThat(p.getIdElement().toString(), endsWith("/_history/2"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConditionalByLastUpdated() throws Exception {
|
||||
String methodName = "testUpdateByUrl";
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
|
||||
myPatientDao.create(p, mySrd).getId();
|
||||
|
||||
InstantDt start = InstantDt.withCurrentTime();
|
||||
ourLog.info("First time: {}", start.getValueAsString());
|
||||
Thread.sleep(100);
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
||||
ourLog.info("Created patient, got ID: {}", id);
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/" + methodName);
|
||||
|
||||
String matchUrl = "Patient?_lastUpdated=gt" + start.getValueAsString();
|
||||
ourLog.info("URL is: {}", matchUrl);
|
||||
myPatientDao.update(p, matchUrl, mySrd);
|
||||
|
||||
p = myPatientDao.read(id.toVersionless(), mySrd);
|
||||
assertThat(p.getIdElement().toVersionless().toString(), not(containsString("test")));
|
||||
assertEquals(id.toVersionless(), p.getIdElement().toVersionless());
|
||||
assertNotEquals(id, p.getIdElement());
|
||||
assertThat(p.getIdElement().toString(), endsWith("/_history/2"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConditionalByLastUpdatedWithWrongTimezone() throws Exception {
|
||||
TimeZone def = TimeZone.getDefault();
|
||||
try {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT-0:00"));
|
||||
String methodName = "testUpdateByUrl";
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName + "2");
|
||||
myPatientDao.create(p, mySrd).getId();
|
||||
|
||||
InstantDt start = InstantDt.withCurrentTime();
|
||||
Thread.sleep(100);
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
||||
ourLog.info("Created patient, got it: {}", id);
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/" + methodName);
|
||||
|
||||
myPatientDao.update(p, "Patient?_lastUpdated=gt" + start.getValueAsString(), mySrd);
|
||||
|
||||
p = myPatientDao.read(id.toVersionless(), mySrd);
|
||||
assertThat(p.getIdElement().toVersionless().toString(), not(containsString("test")));
|
||||
assertEquals(id.toVersionless(), p.getIdElement().toVersionless());
|
||||
assertNotEquals(id, p.getIdElement());
|
||||
assertThat(p.getIdElement().toString(), endsWith("/_history/2"));
|
||||
} finally {
|
||||
TimeZone.setDefault(def);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateCreatesTextualIdIfItDoesntAlreadyExist() {
|
||||
Patient p = new Patient();
|
||||
String methodName = "testUpdateCreatesTextualIdIfItDoesntAlreadyExist";
|
||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/" + methodName);
|
||||
|
||||
IIdType id = myPatientDao.update(p, mySrd).getId();
|
||||
assertEquals("Patient/" + methodName, id.toUnqualifiedVersionless().getValue());
|
||||
|
||||
p = myPatientDao.read(id, mySrd);
|
||||
assertEquals(methodName, p.getIdentifier().get(0).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDoesntFailForUnknownIdWithNumberThenText() {
|
||||
String methodName = "testUpdateFailsForUnknownIdWithNumberThenText";
|
||||
Patient p = new Patient();
|
||||
p.setId("0" + methodName);
|
||||
p.addName().setFamily(methodName);
|
||||
|
||||
myPatientDao.update(p, mySrd);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testUpdateIgnoresIdenticalVersions() {
|
||||
String methodName = "testUpdateIgnoresIdenticalVersions";
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||
p1.addName().setFamily("Tester").addGiven(methodName);
|
||||
IIdType p1id = myPatientDao.create(p1, mySrd).getId();
|
||||
|
||||
IIdType p1id2 = myPatientDao.update(p1, mySrd).getId();
|
||||
assertEquals(p1id.getValue(), p1id2.getValue());
|
||||
|
||||
p1.addName().addGiven("NewGiven");
|
||||
IIdType p1id3 = myPatientDao.update(p1, mySrd).getId();
|
||||
assertNotEquals(p1id.getValue(), p1id3.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMaintainsSearchParams() {
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsDstu2AAA");
|
||||
p1.addName().setFamily("Tester").addGiven("testUpdateMaintainsSearchParamsDstu2AAA");
|
||||
IIdType p1id = myPatientDao.create(p1, mySrd).getId();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsDstu2BBB");
|
||||
p2.addName().setFamily("Tester").addGiven("testUpdateMaintainsSearchParamsDstu2BBB");
|
||||
myPatientDao.create(p2, mySrd).getId();
|
||||
|
||||
Set<Long> ids = myPatientDao.searchForIds(new SearchParameterMap(Patient.SP_GIVEN, new StringParam("testUpdateMaintainsSearchParamsDstu2AAA")));
|
||||
assertEquals(1, ids.size());
|
||||
assertThat(ids, contains(p1id.getIdPartAsLong()));
|
||||
|
||||
// Update the name
|
||||
p1.getName().get(0).getGiven().get(0).setValue("testUpdateMaintainsSearchParamsDstu2BBB");
|
||||
MethodOutcome update2 = myPatientDao.update(p1, mySrd);
|
||||
IIdType p1id2 = update2.getId();
|
||||
|
||||
ids = myPatientDao.searchForIds(new SearchParameterMap(Patient.SP_GIVEN, new StringParam("testUpdateMaintainsSearchParamsDstu2AAA")));
|
||||
assertEquals(0, ids.size());
|
||||
|
||||
ids = myPatientDao.searchForIds(new SearchParameterMap(Patient.SP_GIVEN, new StringParam("testUpdateMaintainsSearchParamsDstu2BBB")));
|
||||
assertEquals(2, ids.size());
|
||||
|
||||
// Make sure vreads work
|
||||
p1 = myPatientDao.read(p1id, mySrd);
|
||||
assertEquals("testUpdateMaintainsSearchParamsDstu2AAA", p1.getName().get(0).getGivenAsSingleString());
|
||||
|
||||
p1 = myPatientDao.read(p1id2, mySrd);
|
||||
assertEquals("testUpdateMaintainsSearchParamsDstu2BBB", p1.getName().get(0).getGivenAsSingleString());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Per the spec, update should preserve tags and security labels but not profiles
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateMaintainsTagsAndSecurityLabels() {
|
||||
String methodName = "testUpdateMaintainsTagsAndSecurityLabels";
|
||||
|
||||
IIdType p1id;
|
||||
{
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily(methodName);
|
||||
|
||||
p1.getMeta().addTag("tag_scheme1", "tag_term1", null);
|
||||
p1.getMeta().addSecurity("sec_scheme1", "sec_term1", null);
|
||||
p1.getMeta().addProfile("http://foo1");
|
||||
|
||||
p1id = myPatientDao.create(p1, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
{
|
||||
Patient p1 = new Patient();
|
||||
p1.setId(p1id);
|
||||
p1.addName().setFamily(methodName);
|
||||
|
||||
p1.getMeta().addTag("tag_scheme2", "tag_term2", null);
|
||||
p1.getMeta().addSecurity("sec_scheme2", "sec_term2", null);
|
||||
p1.getMeta().addProfile("http://foo2");
|
||||
|
||||
myPatientDao.update(p1, mySrd);
|
||||
}
|
||||
{
|
||||
Patient p1 = myPatientDao.read(p1id, mySrd);
|
||||
List<Coding> tagList = p1.getMeta().getTag();
|
||||
Set<String> secListValues = new HashSet<String>();
|
||||
for (Coding next : tagList) {
|
||||
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
|
||||
}
|
||||
assertThat(secListValues, containsInAnyOrder("tag_scheme1|tag_term1", "tag_scheme2|tag_term2"));
|
||||
List<Coding> secList = p1.getMeta().getSecurity();
|
||||
secListValues = new HashSet<String>();
|
||||
for (Coding next : secList) {
|
||||
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
|
||||
}
|
||||
assertThat(secListValues, containsInAnyOrder("sec_scheme1|sec_term1", "sec_scheme2|sec_term2"));
|
||||
List<UriType> profileList = p1.getMeta().getProfile();
|
||||
assertEquals(1, profileList.size());
|
||||
assertEquals("http://foo2", profileList.get(0).getValueAsString()); // no foo1
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateModifiesProfiles() {
|
||||
String name = "testUpdateModifiesProfiles";
|
||||
IIdType id;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily(name);
|
||||
|
||||
List<IdType> tl = new ArrayList<IdType>();
|
||||
tl.add(new IdType("http://foo/bar"));
|
||||
patient.getMeta().getProfile().addAll(tl);
|
||||
|
||||
id = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
// Do a read
|
||||
{
|
||||
Patient patient = myPatientDao.read(id, mySrd);
|
||||
List<UriType> tl = patient.getMeta().getProfile();
|
||||
assertEquals(1, tl.size());
|
||||
assertEquals("http://foo/bar", tl.get(0).getValue());
|
||||
}
|
||||
|
||||
// Update
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setId(id);
|
||||
patient.addName().setFamily(name);
|
||||
|
||||
List<IdType> tl = new ArrayList<IdType>();
|
||||
tl.add(new IdType("http://foo/baz"));
|
||||
patient.getMeta().getProfile().clear();
|
||||
patient.getMeta().getProfile().addAll(tl);
|
||||
|
||||
id = myPatientDao.update(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
// Do a read
|
||||
{
|
||||
Patient patient = myPatientDao.read(id, mySrd);
|
||||
List<UriType> tl = patient.getMeta().getProfile();
|
||||
assertEquals(1, tl.size());
|
||||
assertEquals("http://foo/baz", tl.get(0).getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateRejectsInvalidTypes() {
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateRejectsInvalidTypes");
|
||||
p1.addName().setFamily("Tester").addGiven("testUpdateRejectsInvalidTypes");
|
||||
IIdType p1id = myPatientDao.create(p1, mySrd).getId();
|
||||
|
||||
Organization p2 = new Organization();
|
||||
p2.getNameElement().setValue("testUpdateRejectsInvalidTypes");
|
||||
try {
|
||||
p2.setId(new IdType("Organization/" + p1id.getIdPart()));
|
||||
myOrganizationDao.update(p2, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
try {
|
||||
p2.setId(new IdType("Patient/" + p1id.getIdPart()));
|
||||
myOrganizationDao.update(p2, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
ourLog.error("Good", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateUnknownNumericIdFails() {
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/9999999999999999");
|
||||
try {
|
||||
myPatientDao.update(p, mySrd);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertThat(e.getMessage(), containsString("Can not create resource with ID[9999999999999999], no resource with this ID exists and clients may only"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithInvalidIdFails() {
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/123:456");
|
||||
try {
|
||||
myPatientDao.update(p, mySrd);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Can not process entity with ID[123:456], this is not a valid FHIR ID", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoChangeDetectionDisabledUpdateUnchanged() {
|
||||
myDaoConfig.setSuppressUpdatesWithNoChange(false);
|
||||
|
||||
String name = "testUpdateUnchanged";
|
||||
IIdType id1, id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily(name);
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
// Update
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setId(id1);
|
||||
patient.addName().setFamily(name);
|
||||
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
assertNotEquals(id1.getValue(), id2.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoChangeDetectionUpdateTagAdded() {
|
||||
String name = "testUpdateUnchanged";
|
||||
IIdType id1, id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily(name);
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
// Update
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getMeta().addTag().setCode("CODE");
|
||||
patient.setId(id1);
|
||||
patient.addName().setFamily(name);
|
||||
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
assertNotEquals(id1.getValue(), id2.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoChangeDetectionUpdateTagMetaRemoved() {
|
||||
String name = "testUpdateUnchanged";
|
||||
IIdType id1, id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getMeta().addTag().setCode("CODE");
|
||||
patient.addName().setFamily(name);
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
Meta meta = new Meta();
|
||||
meta.addTag().setCode("CODE");
|
||||
myPatientDao.metaDeleteOperation(id1, meta, null);
|
||||
|
||||
meta = myPatientDao.metaGetOperation(Meta.class, id1, null);
|
||||
assertEquals(0, meta.getTag().size());
|
||||
|
||||
// Update
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setId(id1);
|
||||
patient.addName().setFamily(name);
|
||||
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
assertEquals(id1.getValue(), id2.getValue());
|
||||
|
||||
meta = myPatientDao.metaGetOperation(Meta.class, id2, null);
|
||||
assertEquals(0, meta.getTag().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoChangeDetectionUpdateTagNoChange() {
|
||||
String name = "testUpdateUnchanged";
|
||||
IIdType id1, id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily(name);
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
// Add tag
|
||||
Meta meta = new Meta();
|
||||
meta.addTag().setCode("CODE");
|
||||
myPatientDao.metaAddOperation(id1, meta, null);
|
||||
|
||||
// Update with tag
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getMeta().addTag().setCode("CODE");
|
||||
patient.setId(id1);
|
||||
patient.addName().setFamily(name);
|
||||
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
assertEquals(id1.getValue(), id2.getValue());
|
||||
|
||||
meta = myPatientDao.metaGetOperation(Meta.class, id2, null);
|
||||
assertEquals(1, meta.getTag().size());
|
||||
assertEquals("CODE", meta.getTag().get(0).getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoChangeDetectionUpdateTagRemoved() {
|
||||
String name = "testUpdateUnchanged";
|
||||
IIdType id1, id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getMeta().addTag().setCode("CODE");
|
||||
patient.addName().setFamily(name);
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
// Update
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setId(id1);
|
||||
patient.addName().setFamily(name);
|
||||
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
assertEquals(id1.getValue(), id2.getValue());
|
||||
|
||||
Meta meta = myPatientDao.metaGetOperation(Meta.class, id2, null);
|
||||
assertEquals(1, meta.getTag().size());
|
||||
assertEquals("CODE", meta.getTag().get(0).getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNoChangeDetectionUpdateUnchanged() {
|
||||
String name = "testUpdateUnchanged";
|
||||
IIdType id1, id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily(name);
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
// Update
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.setId(id1);
|
||||
patient.addName().setFamily(name);
|
||||
id2 = myPatientDao.update(patient, mySrd).getId().toUnqualified();
|
||||
}
|
||||
|
||||
assertEquals(id1.getValue(), id2.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNumericIdFails() {
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/123");
|
||||
try {
|
||||
myPatientDao.update(p, mySrd);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertThat(e.getMessage(), containsString("clients may only assign IDs which contain at least one non-numeric"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateWithNumericThenTextIdSucceeds() {
|
||||
Patient p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
|
||||
p.addName().setFamily("Hello");
|
||||
p.setId("Patient/123abc");
|
||||
IIdType id = myPatientDao.update(p, mySrd).getId();
|
||||
assertEquals("123abc", id.getIdPart());
|
||||
assertEquals("1", id.getVersionIdPart());
|
||||
|
||||
p = myPatientDao.read(id.toUnqualifiedVersionless(), mySrd);
|
||||
assertEquals("Patient/123abc", p.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Hello", p.getName().get(0).getFamily());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4ValidateTest.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateStructureDefinition() throws Exception {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/sd-david-dhtest7.json"), StandardCharsets.UTF_8);
|
||||
StructureDefinition sd = myFhirCtx.newJsonParser().parseResource(StructureDefinition.class, input);
|
||||
|
||||
|
||||
ourLog.info("Starting validation");
|
||||
try {
|
||||
myStructureDefinitionDao.validate(sd, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
} catch (PreconditionFailedException e) {
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
}
|
||||
ourLog.info("Done validation");
|
||||
|
||||
StopWatch sw = new StopWatch();
|
||||
ourLog.info("Starting validation");
|
||||
try {
|
||||
myStructureDefinitionDao.validate(sd, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
} catch (PreconditionFailedException e) {
|
||||
// ok
|
||||
}
|
||||
ourLog.info("Done validation in {}ms", sw.getMillis());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateDocument() throws Exception {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/document-bundle-r4.json"), StandardCharsets.UTF_8);
|
||||
Bundle document = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
|
||||
|
||||
|
||||
ourLog.info("Starting validation");
|
||||
try {
|
||||
MethodOutcome outcome = myBundleDao.validate(document, null, null, null, ValidationModeEnum.CREATE, null, mySrd);
|
||||
} catch (PreconditionFailedException e) {
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
}
|
||||
ourLog.info("Done validation");
|
||||
|
||||
// ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateResourceContainingProfileDeclarationJson() throws Exception {
|
||||
String methodName = "testValidateResourceContainingProfileDeclarationJson";
|
||||
OperationOutcome outcome = doTestValidateResourceContainingProfileDeclaration(methodName, EncodingEnum.JSON);
|
||||
|
||||
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||
ourLog.info(ooString);
|
||||
assertThat(ooString, containsString("Element '.subject': minimum required = 1, but only found 0"));
|
||||
assertThat(ooString, containsString("Element encounter @ : max allowed = 0, but found 1"));
|
||||
assertThat(ooString, containsString("Element '.device': minimum required = 1, but only found 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateResourceContainingProfileDeclarationXml() throws Exception {
|
||||
String methodName = "testValidateResourceContainingProfileDeclarationXml";
|
||||
OperationOutcome outcome = doTestValidateResourceContainingProfileDeclaration(methodName, EncodingEnum.XML);
|
||||
|
||||
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||
ourLog.info(ooString);
|
||||
assertThat(ooString, containsString("Element '/f:Observation.subject': minimum required = 1, but only found 0"));
|
||||
assertThat(ooString, containsString("Element encounter @ /f:Observation: max allowed = 0, but found 1"));
|
||||
assertThat(ooString, containsString("Element '/f:Observation.device': minimum required = 1, but only found 0"));
|
||||
}
|
||||
|
||||
private OperationOutcome doTestValidateResourceContainingProfileDeclaration(String methodName, EncodingEnum enc) throws IOException {
|
||||
Bundle vss = loadResourceFromClasspath(Bundle.class, "/org/hl7/fhir/r4/model/valueset/valuesets.xml");
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-status"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-category"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-codes"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-methods"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-valueabsentreason"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-interpretation"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "body-site"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "referencerange-meaning"), mySrd);
|
||||
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-relationshiptypes"), mySrd);
|
||||
|
||||
StructureDefinition sd = loadResourceFromClasspath(StructureDefinition.class, "/org/hl7/fhir/r4/model/profile/devicemetricobservation.profile.xml");
|
||||
sd.setId(new IdType());
|
||||
sd.setUrl("http://example.com/foo/bar/" + methodName);
|
||||
myStructureDefinitionDao.create(sd, mySrd);
|
||||
|
||||
Observation input = new Observation();
|
||||
input.getMeta().getProfile().add(new IdType(sd.getUrl()));
|
||||
|
||||
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
||||
input.getContext().setReference("http://foo.com/Encounter/9");
|
||||
input.setStatus(ObservationStatus.FINAL);
|
||||
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
|
||||
|
||||
String encoded = null;
|
||||
MethodOutcome outcome = null;
|
||||
ValidationModeEnum mode = ValidationModeEnum.CREATE;
|
||||
switch (enc) {
|
||||
case JSON:
|
||||
encoded = myFhirCtx.newJsonParser().encodeResourceToString(input);
|
||||
try {
|
||||
myObservationDao.validate(input, null, encoded, EncodingEnum.JSON, mode, null, mySrd);
|
||||
fail();
|
||||
} catch (PreconditionFailedException e) {
|
||||
return (OperationOutcome) e.getOperationOutcome();
|
||||
}
|
||||
case XML:
|
||||
encoded = myFhirCtx.newXmlParser().encodeResourceToString(input);
|
||||
try {
|
||||
myObservationDao.validate(input, null, encoded, EncodingEnum.XML, mode, null, mySrd);
|
||||
fail();
|
||||
} catch (PreconditionFailedException e) {
|
||||
return (OperationOutcome) e.getOperationOutcome();
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException(); // shouldn't get here
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateResourceContainingProfileDeclarationInvalid() throws Exception {
|
||||
String methodName = "testValidateResourceContainingProfileDeclarationInvalid";
|
||||
|
||||
Observation input = new Observation();
|
||||
String profileUri = "http://example.com/" + methodName;
|
||||
input.getMeta().getProfile().add(new IdType(profileUri));
|
||||
|
||||
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
||||
input.getContext().setReference("http://foo.com/Encounter/9");
|
||||
input.setStatus(ObservationStatus.FINAL);
|
||||
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
|
||||
|
||||
ValidationModeEnum mode = ValidationModeEnum.CREATE;
|
||||
String encoded = myFhirCtx.newJsonParser().encodeResourceToString(input);
|
||||
MethodOutcome outcome = myObservationDao.validate(input, null, encoded, EncodingEnum.JSON, mode, null, mySrd);
|
||||
|
||||
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
|
||||
ourLog.info(ooString);
|
||||
assertThat(ooString, containsString("StructureDefinition reference \\\"" + profileUri + "\\\" could not be resolved"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateForCreate() {
|
||||
String methodName = "testValidateForCreate";
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setId("Patient/123");
|
||||
pat.addName().setFamily(methodName);
|
||||
|
||||
try {
|
||||
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.CREATE, null, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("ID must not be populated"));
|
||||
}
|
||||
|
||||
pat.setId("");
|
||||
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.CREATE, null, mySrd);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateForUpdate() {
|
||||
String methodName = "testValidateForUpdate";
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setId("Patient/123");
|
||||
pat.addName().setFamily(methodName);
|
||||
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
|
||||
pat.setId("");
|
||||
|
||||
try {
|
||||
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("ID must be populated"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateForUpdateWithContained() {
|
||||
String methodName = "testValidateForUpdate";
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setId("#123");
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setId("Patient/123");
|
||||
pat.addName().setFamily(methodName);
|
||||
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
|
||||
pat.setId("");
|
||||
|
||||
try {
|
||||
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), containsString("ID must be populated"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateForDelete() {
|
||||
String methodName = "testValidateForDelete";
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName(methodName);
|
||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.addName().setFamily(methodName);
|
||||
pat.getManagingOrganization().setReference(orgId.getValue());
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
OperationOutcome outcome = null;
|
||||
try {
|
||||
myOrganizationDao.validate(null, orgId, null, null, ValidationModeEnum.DELETE, null, mySrd);
|
||||
fail();
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
outcome = (OperationOutcome) e.getOperationOutcome();
|
||||
}
|
||||
|
||||
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||
ourLog.info(ooString);
|
||||
assertThat(ooString, containsString("Unable to delete Organization"));
|
||||
|
||||
pat.setId(patId);
|
||||
pat.getManagingOrganization().setReference("");
|
||||
myPatientDao.update(pat, mySrd);
|
||||
|
||||
outcome = (OperationOutcome) myOrganizationDao.validate(null, orgId, null, null, ValidationModeEnum.DELETE, null, mySrd).getOperationOutcome();
|
||||
ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
|
||||
ourLog.info(ooString);
|
||||
assertThat(ooString, containsString("Ok to delete"));
|
||||
|
||||
}
|
||||
|
||||
private IBaseResource findResourceByIdInBundle(Bundle vss, String name) {
|
||||
IBaseResource retVal = null;
|
||||
for (BundleEntryComponent next : vss.getEntry()) {
|
||||
if (next.getResource().getIdElement().getIdPart().equals(name)) {
|
||||
retVal = next.getResource();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retVal == null) {
|
||||
fail("Can't find VS: " + name);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format has changed, this is out of date
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateNewQuestionnaireFormat() throws Exception {
|
||||
String input =IOUtils.toString(FhirResourceDaoR4ValidateTest.class.getResourceAsStream("/questionnaire_r4.xml"));
|
||||
try {
|
||||
MethodOutcome results = myQuestionnaireDao.validate(null, null, input, EncodingEnum.XML, ValidationModeEnum.UPDATE, null, mySrd);
|
||||
OperationOutcome oo = (OperationOutcome) results.getOperationOutcome();
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
|
||||
} catch (PreconditionFailedException e) {
|
||||
// this is a failure of the test
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,242 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.CodeType;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.UriType;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4ValueSetTest.class);
|
||||
|
||||
private IIdType myExtensionalVsId;
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
@Transactional
|
||||
public void before02() throws IOException {
|
||||
ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
|
||||
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
CodeSystem upload2 = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||
myCodeSystemDao.create(upload2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByCodeAndSystemBad() {
|
||||
UriType valueSetIdentifier = null;
|
||||
IdType id = null;
|
||||
CodeType code = new CodeType("8450-9-XXX");
|
||||
UriType system = new UriType("http://acme.org");
|
||||
StringType display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertFalse(result.isResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByCodeAndSystemGood() {
|
||||
UriType valueSetIdentifier = null;
|
||||
IdType id = null;
|
||||
CodeType code = new CodeType("8450-9");
|
||||
UriType system = new UriType("http://acme.org");
|
||||
StringType display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure--expiration", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByIdentifierAndCodeAndSystem() {
|
||||
UriType valueSetIdentifier = new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
IdType id = null;
|
||||
CodeType code = new CodeType("11378-7");
|
||||
UriType system = new UriType("http://acme.org");
|
||||
StringType display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByIdentifierAndCodeAndSystemAndBadDisplay() {
|
||||
UriType valueSetIdentifier = new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
IdType id = null;
|
||||
CodeType code = new CodeType("11378-7");
|
||||
UriType system = new UriType("http://acme.org");
|
||||
StringType display = new StringType("Systolic blood pressure at First encounterXXXX");
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertFalse(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByIdentifierAndCodeAndSystemAndGoodDisplay() {
|
||||
UriType valueSetIdentifier = new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||
IdType id = null;
|
||||
CodeType code = new CodeType("11378-7");
|
||||
UriType system = new UriType("http://acme.org");
|
||||
StringType display = new StringType("Systolic blood pressure at First encounter");
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByResourceIdAndCodeableConcept() {
|
||||
UriType valueSetIdentifier = null;
|
||||
IIdType id = myExtensionalVsId;
|
||||
CodeType code = null;
|
||||
UriType system = null;
|
||||
StringType display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
codeableConcept.addCoding().setSystem("http://acme.org").setCode("11378-7");
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByResourceIdAndCodeAndSystem() {
|
||||
UriType valueSetIdentifier = null;
|
||||
IIdType id = myExtensionalVsId;
|
||||
CodeType code = new CodeType("11378-7");
|
||||
UriType system = new UriType("http://acme.org");
|
||||
StringType display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept, mySrd);
|
||||
assertTrue(result.isResult());
|
||||
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandById() throws IOException {
|
||||
String resp;
|
||||
|
||||
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null, mySrd);
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
|
||||
assertThat(resp, containsString("<expansion>"));
|
||||
assertThat(resp, containsString("<contains>"));
|
||||
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||
assertThat(resp, containsString("<code value=\"8450-9\"/>"));
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure--expiration\"/>"));
|
||||
assertThat(resp, containsString("</contains>"));
|
||||
assertThat(resp, containsString("<contains>"));
|
||||
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||
assertThat(resp, containsString("<code value=\"11378-7\"/>"));
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, containsString("</contains>"));
|
||||
assertThat(resp, containsString("</expansion>"));
|
||||
|
||||
/*
|
||||
* Filter with display name
|
||||
*/
|
||||
|
||||
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"), mySrd);
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
//@formatter:off
|
||||
assertThat(resp, stringContainsInOrder(
|
||||
"<code value=\"11378-7\"/>",
|
||||
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testExpandByIdentifier() {
|
||||
ValueSet expanded = myValueSetDao.expandByIdentifier("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", "11378");
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
//@formatter:off
|
||||
assertThat(resp, stringContainsInOrder(
|
||||
"<code value=\"11378-7\"/>",
|
||||
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
//@formatter:on
|
||||
|
||||
assertThat(resp, not(containsString("<code value=\"8450-9\"/>")));
|
||||
}
|
||||
|
||||
/**
|
||||
* This type of expansion doesn't really make sense..
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testExpandByValueSet() throws IOException {
|
||||
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
|
||||
ValueSet expanded = myValueSetDao.expand(toExpand, "11378");
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
//@formatter:off
|
||||
assertThat(resp, stringContainsInOrder(
|
||||
"<code value=\"11378-7\"/>",
|
||||
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
//@formatter:on
|
||||
|
||||
assertThat(resp, not(containsString("<code value=\"8450-9\"/>")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValiedateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
|
||||
IPrimitiveType<String> display = null;
|
||||
Coding coding = null;
|
||||
CodeableConcept codeableConcept = null;
|
||||
StringType vsIdentifier = new StringType("http://hl7.org/fhir/ValueSet/v2-0487");
|
||||
StringType code = new StringType("BRN");
|
||||
StringType system = new StringType("http://hl7.org/fhir/v2/0487");
|
||||
ValidateCodeResult result = myValueSetDao.validateCode(vsIdentifier, null, code, system, display, coding, codeableConcept, mySrd);
|
||||
|
||||
ourLog.info(result.getMessage());
|
||||
assertTrue(result.getMessage(), result.isResult());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirSearchDaoR4Test extends BaseJpaR4Test {
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
private IFulltextSearchSvc mySearchDao;
|
||||
|
||||
@Test
|
||||
public void testContentSearch() {
|
||||
Long id1;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().addGiven("testSearchStringParamWithNonNormalized_h\u00F6ra");
|
||||
patient.addName().addGiven("AAAS");
|
||||
patient.addName().addGiven("CCC");
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getIdPartAsLong();
|
||||
}
|
||||
Long id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("002");
|
||||
patient.addName().addGiven("testSearchStringParamWithNonNormalized_HORA");
|
||||
patient.addName().addGiven("AAAB");
|
||||
patient.addName().addGiven("CCC");
|
||||
id2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getIdPartAsLong();
|
||||
}
|
||||
Long id3;
|
||||
{
|
||||
Organization org = new Organization();
|
||||
org.setName("DDD");
|
||||
id3 = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless().getIdPartAsLong();
|
||||
}
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
String resourceName = "Patient";
|
||||
|
||||
// One term
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
|
||||
|
||||
map.add(Constants.PARAM_CONTENT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1));
|
||||
}
|
||||
// OR
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")).addOr(new StringParam("AAAB")));
|
||||
|
||||
map.add(Constants.PARAM_CONTENT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1, id2));
|
||||
}
|
||||
// AND
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
|
||||
|
||||
map.add(Constants.PARAM_CONTENT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1));
|
||||
}
|
||||
// AND OR
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAB")).addOr(new StringParam("AAAS")));
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
|
||||
|
||||
map.add(Constants.PARAM_CONTENT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1, id2));
|
||||
}
|
||||
// All Resource Types
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")).addOr(new StringParam("DDD")));
|
||||
|
||||
map.add(Constants.PARAM_CONTENT, content);
|
||||
List<Long> found = mySearchDao.search(null, map);
|
||||
assertThat(found, containsInAnyOrder(id1, id2, id3));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNarrativeSearch() {
|
||||
Long id1;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getText().setDivAsString("<div>AAAS<p>FOO</p> CCC </div>");
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getIdPartAsLong();
|
||||
}
|
||||
Long id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getText().setDivAsString("<div>AAAB<p>FOO</p> CCC </div>");
|
||||
id2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getIdPartAsLong();
|
||||
}
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getText().setDivAsString("<div>ZZYZXY</div>");
|
||||
myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getIdPartAsLong();
|
||||
}
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
String resourceName = "Patient";
|
||||
|
||||
// One term
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
|
||||
|
||||
map.add(Constants.PARAM_TEXT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1));
|
||||
}
|
||||
// OR
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")).addOr(new StringParam("AAAB")));
|
||||
|
||||
map.add(Constants.PARAM_TEXT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1, id2));
|
||||
}
|
||||
// AND
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
|
||||
|
||||
map.add(Constants.PARAM_TEXT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1));
|
||||
}
|
||||
// AND OR
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAB")).addOr(new StringParam("AAAS")));
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
|
||||
|
||||
map.add(Constants.PARAM_TEXT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, containsInAnyOrder(id1, id2));
|
||||
}
|
||||
// Tag Contents
|
||||
{
|
||||
StringAndListParam content = new StringAndListParam();
|
||||
content.addAnd(new StringOrListParam().addOr(new StringParam("div")));
|
||||
|
||||
map.add(Constants.PARAM_TEXT, content);
|
||||
List<Long> found = mySearchDao.search(resourceName, map);
|
||||
assertThat(found, empty());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirSystemDaoR4SearchTest extends BaseJpaR4SystemTest {
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchByParans() {
|
||||
// code to come.. just here to prevent a failure
|
||||
}
|
||||
|
||||
/*//@formatter:off
|
||||
* [ERROR] Search parameter action has conflicting types token and reference
|
||||
* [ERROR] Search parameter source has conflicting types token and reference
|
||||
* [ERROR] Search parameter plan has conflicting types reference and token
|
||||
* [ERROR] Search parameter version has conflicting types token and string
|
||||
* [ERROR] Search parameter source has conflicting types reference and uri
|
||||
* [ERROR] Search parameter location has conflicting types reference and uri
|
||||
* [ERROR] Search parameter title has conflicting types string and token
|
||||
* [ERROR] Search parameter manufacturer has conflicting types string and reference
|
||||
* [ERROR] Search parameter address has conflicting types token and string
|
||||
* [ERROR] Search parameter source has conflicting types reference and string
|
||||
* [ERROR] Search parameter destination has conflicting types reference and string
|
||||
* [ERROR] Search parameter responsible has conflicting types reference and string
|
||||
* [ERROR] Search parameter value has conflicting types token and string
|
||||
* [ERROR] Search parameter address has conflicting types token and string
|
||||
* [ERROR] Search parameter address has conflicting types token and string
|
||||
* [ERROR] Search parameter address has conflicting types token and string
|
||||
* [ERROR] Search parameter address has conflicting types token and string
|
||||
* [ERROR] Search parameter action has conflicting types reference and token
|
||||
* [ERROR] Search parameter version has conflicting types token and string
|
||||
* [ERROR] Search parameter address has conflicting types token and string
|
||||
* [ERROR] Search parameter base has conflicting types reference and token
|
||||
* [ERROR] Search parameter target has conflicting types reference and token
|
||||
* [ERROR] Search parameter base has conflicting types reference and uri
|
||||
* [ERROR] Search parameter contact has conflicting types string and token
|
||||
* [ERROR] Search parameter substance has conflicting types token and reference
|
||||
* [ERROR] Search parameter provider has conflicting types reference and token
|
||||
* [ERROR] Search parameter system has conflicting types token and uri
|
||||
* [ERROR] Search parameter reference has conflicting types reference and uri
|
||||
* //@formatter:off
|
||||
*/
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,73 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SearchParamExtractorR4Test {
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static IValidationSupport ourValidationSupport;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourValidationSupport = new DefaultProfileValidationSupport();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParamWithOrInPath() {
|
||||
Observation obs = new Observation();
|
||||
obs.addCategory().addCoding().setSystem("SYSTEM").setCode("CODE");
|
||||
|
||||
ISearchParamRegistry searchParamRegistry = new ISearchParamRegistry() {
|
||||
@Override
|
||||
public Map<String,RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
||||
RuntimeResourceDefinition nextResDef = ourCtx.getResourceDefinition(theResourceName);
|
||||
Map<String, RuntimeSearchParam> sps = new HashMap<String, RuntimeSearchParam>();
|
||||
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
|
||||
sps.put(nextSp.getName(), nextSp);
|
||||
}
|
||||
return sps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceRefresh() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Map<String, RuntimeSearchParam>> getActiveSearchParams() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
Set<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(new ResourceTable(), obs);
|
||||
assertEquals(1, tokens.size());
|
||||
ResourceIndexedSearchParamToken token = (ResourceIndexedSearchParamToken) tokens.iterator().next();
|
||||
assertEquals("category", token.getParamName());
|
||||
assertEquals("SYSTEM", token.getSystem());
|
||||
assertEquals("CODE", token.getValue());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,302 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.auth.*;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class AuthorizationInterceptorResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
unregisterInterceptors();
|
||||
}
|
||||
|
||||
|
||||
private void unregisterInterceptors() {
|
||||
for (IServerInterceptor next : new ArrayList<IServerInterceptor>(ourRestServer.getInterceptors())) {
|
||||
if (next instanceof AuthorizationInterceptor) {
|
||||
ourRestServer.unregisterInterceptor(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #503
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteIsBlocked() {
|
||||
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.deny().delete().allResources().withAnyId().andThen()
|
||||
.allowAll()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
IIdType id = ourClient.create().resource(patient).execute().getId();
|
||||
|
||||
try {
|
||||
ourClient.delete().resourceById(id.toUnqualifiedVersionless()).execute();
|
||||
fail();
|
||||
} catch (ForbiddenOperationException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
patient = ourClient.read().resource(Patient.class).withId(id.toUnqualifiedVersionless()).execute();
|
||||
assertEquals(id.getValue(), patient.getId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #503
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteIsAllowedForCompartment() {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
final IIdType id = ourClient.create().resource(patient).execute().getId();
|
||||
|
||||
Observation obsInCompartment = new Observation();
|
||||
obsInCompartment.setStatus(ObservationStatus.FINAL);
|
||||
obsInCompartment.getSubject().setReferenceElement(id.toUnqualifiedVersionless());
|
||||
IIdType obsInCompartmentId = ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obsNotInCompartment = new Observation();
|
||||
obsNotInCompartment.setStatus(ObservationStatus.FINAL);
|
||||
IIdType obsNotInCompartmentId = ourClient.create().resource(obsNotInCompartment).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.allow().delete().resourcesOfType(Observation.class).inCompartment("Patient", id).andThen()
|
||||
.deny().delete().allResources().withAnyId().andThen()
|
||||
.allowAll()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
ourClient.delete().resourceById(obsInCompartmentId.toUnqualifiedVersionless()).execute();
|
||||
|
||||
try {
|
||||
ourClient.delete().resourceById(obsNotInCompartmentId.toUnqualifiedVersionless()).execute();
|
||||
fail();
|
||||
} catch (ForbiddenOperationException e) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateConditional() {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
final MethodOutcome output1 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
|
||||
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
//@formatter:off
|
||||
return new RuleBuilder()
|
||||
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/" + output1.getId().getIdPart())).andThen()
|
||||
.allow().updateConditional().allResources()
|
||||
.build();
|
||||
//@formatter:on
|
||||
}
|
||||
});
|
||||
|
||||
patient = new Patient();
|
||||
patient.setId(output1.getId().toUnqualifiedVersionless());
|
||||
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());
|
||||
|
||||
patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
try {
|
||||
ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|101").execute();
|
||||
fail();
|
||||
} catch (ForbiddenOperationException e) {
|
||||
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
||||
}
|
||||
|
||||
patient = new Patient();
|
||||
patient.setId("999");
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
try {
|
||||
ourClient.update().resource(patient).execute();
|
||||
fail();
|
||||
} catch (ForbiddenOperationException e) {
|
||||
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #667
|
||||
*/
|
||||
@Test
|
||||
public void testBlockUpdatingPatientUserDoesnNotHaveAccessTo() throws IOException {
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setActive(true);
|
||||
final IIdType pid1 = ourClient.create().resource(pt1).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setActive(false);
|
||||
final IIdType pid2 = ourClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.allow().write().allResources().inCompartment("Patient", pid1).andThen()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
obs.setSubject(new Reference(pid1));
|
||||
IIdType oid = ourClient.create().resource(obs).execute().getId().toUnqualified();
|
||||
|
||||
|
||||
unregisterInterceptors();
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
return new RuleBuilder()
|
||||
.allow().write().allResources().inCompartment("Patient", pid2).andThen()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Try to update to a new patient. The user has access to write to things in
|
||||
* pid2's compartment, so this would normally be ok, but in this case they are overwriting
|
||||
* a resource that is already in pid1's compartment, which shouldn't be allowed.
|
||||
*/
|
||||
obs = new Observation();
|
||||
obs.setId(oid);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
obs.setSubject(new Reference(pid2));
|
||||
|
||||
try {
|
||||
ourClient.update().resource(obs).execute();
|
||||
fail();
|
||||
} catch (ForbiddenOperationException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteResourceConditional() throws IOException {
|
||||
String methodName = "testDeleteResourceConditional";
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily(methodName);
|
||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
final IdType id;
|
||||
try {
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
||||
id = new IdType(newIdString);
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
pt = new Patient();
|
||||
pt.addName().setFamily("FOOFOOFOO");
|
||||
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||
|
||||
post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
response = ourHttpClient.execute(post);
|
||||
final IdType id2;
|
||||
try {
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
||||
id2 = new IdType(newIdString);
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
//@formatter:off
|
||||
return new RuleBuilder()
|
||||
.allow("Rule 2").delete().allResources().inCompartment("Patient", new IdDt("Patient/" + id.getIdPart())).andThen()
|
||||
.build();
|
||||
//@formatter:on
|
||||
}
|
||||
});
|
||||
|
||||
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?name=" + methodName);
|
||||
response = ourHttpClient.execute(delete);
|
||||
try {
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
delete = new HttpDelete(ourServerBase + "/Patient?name=FOOFOOFOO");
|
||||
response = ourHttpClient.execute(delete);
|
||||
try {
|
||||
assertEquals(403, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
import org.springframework.web.context.ContextLoader;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.*;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.r4.WebsocketR4Config;
|
||||
import ca.uhn.fhir.jpa.config.r4.WebsocketR4DispatcherConfig;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.dao.r4.SearchParamRegistryR4;
|
||||
import ca.uhn.fhir.jpa.interceptor.r4.RestHookSubscriptionR4Interceptor;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
||||
|
||||
protected static JpaValidationSupportChainR4 myValidationSupport;
|
||||
protected static IGenericClient ourClient;
|
||||
protected static CloseableHttpClient ourHttpClient;
|
||||
protected static int ourPort;
|
||||
protected static RestfulServer ourRestServer;
|
||||
private static Server ourServer;
|
||||
protected static String ourServerBase;
|
||||
private static GenericWebApplicationContext ourWebApplicationContext;
|
||||
private TerminologyUploaderProviderR4 myTerminologyUploaderProvider;
|
||||
protected static SearchParamRegistryR4 ourSearchParamRegistry;
|
||||
protected static DatabaseBackedPagingProvider ourPagingProvider;
|
||||
protected static RestHookSubscriptionR4Interceptor ourRestHookSubscriptionInterceptor;
|
||||
protected static ISearchDao mySearchEntityDao;
|
||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
|
||||
public BaseResourceProviderR4Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
myFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
|
||||
if (ourServer == null) {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
|
||||
ourRestServer = new RestfulServer(myFhirCtx);
|
||||
|
||||
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
||||
|
||||
ourRestServer.setResourceProviders((List) myResourceProviders);
|
||||
|
||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderR4.class);
|
||||
|
||||
ourRestServer.setPlainProviders(mySystemProvider, myTerminologyUploaderProvider);
|
||||
|
||||
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(ourRestServer, mySystemDao, myDaoConfig);
|
||||
confProvider.setImplementationDescription("THIS IS THE DESC");
|
||||
ourRestServer.setServerConformanceProvider(confProvider);
|
||||
|
||||
ourPagingProvider = myAppCtx.getBean(DatabaseBackedPagingProvider.class);
|
||||
|
||||
Server server = new Server(ourPort);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(ourRestServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
|
||||
ourWebApplicationContext = new GenericWebApplicationContext();
|
||||
ourWebApplicationContext.setParent(myAppCtx);
|
||||
ourWebApplicationContext.refresh();
|
||||
// ContextLoaderListener loaderListener = new ContextLoaderListener(webApplicationContext);
|
||||
// loaderListener.initWebApplicationContext(mock(ServletContext.class));
|
||||
//
|
||||
proxyHandler.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ourWebApplicationContext);
|
||||
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet();
|
||||
// dispatcherServlet.setApplicationContext(webApplicationContext);
|
||||
dispatcherServlet.setContextClass(AnnotationConfigWebApplicationContext.class);
|
||||
ServletHolder subsServletHolder = new ServletHolder();
|
||||
subsServletHolder.setServlet(dispatcherServlet);
|
||||
subsServletHolder.setInitParameter(
|
||||
ContextLoader.CONFIG_LOCATION_PARAM,
|
||||
WebsocketR4Config.class.getName() + "\n" +
|
||||
WebsocketR4DispatcherConfig.class.getName());
|
||||
proxyHandler.addServlet(subsServletHolder, "/*");
|
||||
|
||||
// Register a CORS filter
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
CorsInterceptor corsInterceptor = new CorsInterceptor(config);
|
||||
config.addAllowedHeader("x-fhir-starter");
|
||||
config.addAllowedHeader("Origin");
|
||||
config.addAllowedHeader("Accept");
|
||||
config.addAllowedHeader("X-Requested-With");
|
||||
config.addAllowedHeader("Content-Type");
|
||||
config.addAllowedHeader("Access-Control-Request-Method");
|
||||
config.addAllowedHeader("Access-Control-Request-Headers");
|
||||
config.addAllowedOrigin("*");
|
||||
config.addExposedHeader("Location");
|
||||
config.addExposedHeader("Content-Location");
|
||||
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
ourRestServer.registerInterceptor(corsInterceptor);
|
||||
|
||||
server.setHandler(proxyHandler);
|
||||
server.start();
|
||||
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(subsServletHolder.getServlet().getServletConfig().getServletContext());
|
||||
myValidationSupport = wac.getBean(JpaValidationSupportChainR4.class);
|
||||
mySearchCoordinatorSvc = wac.getBean(ISearchCoordinatorSvc.class);
|
||||
mySearchEntityDao = wac.getBean(ISearchDao.class);
|
||||
ourRestHookSubscriptionInterceptor = wac.getBean(RestHookSubscriptionR4Interceptor.class);
|
||||
ourSearchParamRegistry = wac.getBean(SearchParamRegistryR4.class);
|
||||
|
||||
myFhirCtx.getRestfulClientFactory().setSocketTimeout(5000000);
|
||||
ourClient = myFhirCtx.newRestfulGenericClient(ourServerBase);
|
||||
if (shouldLogClient()) {
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
}
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
builder.setMaxConnPerRoute(99);
|
||||
ourHttpClient = builder.build();
|
||||
|
||||
ourServer = server;
|
||||
}
|
||||
|
||||
ourRestServer.setPagingProvider(ourPagingProvider);
|
||||
}
|
||||
|
||||
protected boolean shouldLogClient() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected List<String> toNameList(Bundle resp) {
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (BundleEntryComponent next : resp.getEntry()) {
|
||||
Patient nextPt = (Patient) next.getResource();
|
||||
String nextStr = nextPt.getName().size() > 0 ? nextPt.getName().get(0).getGivenAsSingleString() + " " + nextPt.getName().get(0).getFamily() : "";
|
||||
if (isNotBlank(nextStr)) {
|
||||
names.add(nextStr);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContextBaseResourceProviderR4Test() throws Exception {
|
||||
ourServer.stop();
|
||||
ourHttpClient.close();
|
||||
ourServer = null;
|
||||
ourHttpClient = null;
|
||||
myValidationSupport.flush();
|
||||
myValidationSupport = null;
|
||||
ourWebApplicationContext.close();
|
||||
ourWebApplicationContext = null;
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class CorsR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CorsR4Test.class);
|
||||
|
||||
@Test
|
||||
public void saveLocalOrigin() throws IOException {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Patient?name=test");
|
||||
get.addHeader("Origin", "file://");
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(get);
|
||||
|
||||
ourLog.info(resp.toString());
|
||||
|
||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||
assertEquals(200, resp.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.Encounter.EncounterStatus;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class PatientEverythingR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PatientEverythingR4Test.class);
|
||||
private String orgId;
|
||||
private String patId;
|
||||
private String encId1;
|
||||
private String encId2;
|
||||
private ArrayList<String> myObsIds;
|
||||
private String myWrongPatId;
|
||||
private String myWrongEnc1;
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setEverythingIncludesFetchPageSize(new DaoConfig().getEverythingIncludesFetchPageSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName("an org");
|
||||
orgId = ourClient.create().resource(org).execute().getId().toUnqualifiedVersionless().getValue();
|
||||
ourLog.info("OrgId: {}", orgId);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.getManagingOrganization().setReference(orgId);
|
||||
patId = ourClient.create().resource(patient).execute().getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Patient patient2 = new Patient();
|
||||
patient2.getManagingOrganization().setReference(orgId);
|
||||
myWrongPatId = ourClient.create().resource(patient2).execute().getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter enc1 = new Encounter();
|
||||
enc1.setStatus(EncounterStatus.CANCELLED);
|
||||
enc1.getSubject().setReference(patId);
|
||||
enc1.getServiceProvider().setReference(orgId);
|
||||
encId1 = ourClient.create().resource(enc1).execute().getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter enc2 = new Encounter();
|
||||
enc2.setStatus(EncounterStatus.ARRIVED);
|
||||
enc2.getSubject().setReference(patId);
|
||||
enc2.getServiceProvider().setReference(orgId);
|
||||
encId2 = ourClient.create().resource(enc2).execute().getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter wrongEnc1 = new Encounter();
|
||||
wrongEnc1.setStatus(EncounterStatus.ARRIVED);
|
||||
wrongEnc1.getSubject().setReference(myWrongPatId);
|
||||
wrongEnc1.getServiceProvider().setReference(orgId);
|
||||
myWrongEnc1 = ourClient.create().resource(wrongEnc1).execute().getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
myObsIds = new ArrayList<String>();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReference(patId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
String obsId = ourClient.create().resource(obs).execute().getId().toUnqualifiedVersionless().getValue();
|
||||
myObsIds.add(obsId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #674
|
||||
*/
|
||||
@Test
|
||||
public void testEverythingReturnsCorrectResources() throws Exception {
|
||||
|
||||
Bundle bundle = fetchBundle(ourServerBase + "/" + patId + "/$everything?_format=json&_count=100", EncodingEnum.JSON);
|
||||
|
||||
assertNull(bundle.getLink("next"));
|
||||
|
||||
Set<String> actual = new TreeSet<String>();
|
||||
for (BundleEntryComponent nextEntry : bundle.getEntry()) {
|
||||
actual.add(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
ourLog.info("Found IDs: {}", actual);
|
||||
|
||||
assertThat(actual, hasItem(patId));
|
||||
assertThat(actual, hasItem(encId1));
|
||||
assertThat(actual, hasItem(encId2));
|
||||
assertThat(actual, hasItem(orgId));
|
||||
assertThat(actual, hasItems(myObsIds.toArray(new String[0])));
|
||||
assertThat(actual, not(hasItem(myWrongPatId)));
|
||||
assertThat(actual, not(hasItem(myWrongEnc1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #674
|
||||
*/
|
||||
@Test
|
||||
public void testEverythingReturnsCorrectResourcesSmallPage() throws Exception {
|
||||
myDaoConfig.setEverythingIncludesFetchPageSize(1);
|
||||
|
||||
Bundle bundle = fetchBundle(ourServerBase + "/" + patId + "/$everything?_format=json&_count=100", EncodingEnum.JSON);
|
||||
|
||||
assertNull(bundle.getLink("next"));
|
||||
|
||||
Set<String> actual = new TreeSet<String>();
|
||||
for (BundleEntryComponent nextEntry : bundle.getEntry()) {
|
||||
actual.add(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
ourLog.info("Found IDs: {}", actual);
|
||||
|
||||
assertThat(actual, hasItem(patId));
|
||||
assertThat(actual, hasItem(encId1));
|
||||
assertThat(actual, hasItem(encId2));
|
||||
assertThat(actual, hasItem(orgId));
|
||||
assertThat(actual, hasItems(myObsIds.toArray(new String[0])));
|
||||
assertThat(actual, not(hasItem(myWrongPatId)));
|
||||
assertThat(actual, not(hasItem(myWrongEnc1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* See #674
|
||||
*/
|
||||
@Test
|
||||
public void testEverythingPagesWithCorrectEncodingJson() throws Exception {
|
||||
|
||||
Bundle bundle = fetchBundle(ourServerBase + "/" + patId + "/$everything?_format=json&_count=1", EncodingEnum.JSON);
|
||||
|
||||
assertNotNull(bundle.getLink("next").getUrl());
|
||||
assertThat(bundle.getLink("next").getUrl(), containsString("_format=json"));
|
||||
bundle = fetchBundle(bundle.getLink("next").getUrl(), EncodingEnum.JSON);
|
||||
|
||||
assertNotNull(bundle.getLink("next").getUrl());
|
||||
assertThat(bundle.getLink("next").getUrl(), containsString("_format=json"));
|
||||
bundle = fetchBundle(bundle.getLink("next").getUrl(), EncodingEnum.JSON);
|
||||
}
|
||||
|
||||
/**
|
||||
* See #674
|
||||
*/
|
||||
@Test
|
||||
public void testEverythingPagesWithCorrectEncodingXml() throws Exception {
|
||||
|
||||
Bundle bundle = fetchBundle(ourServerBase + "/" + patId + "/$everything?_format=xml&_count=1", EncodingEnum.XML);
|
||||
|
||||
assertNotNull(bundle.getLink("next").getUrl());
|
||||
ourLog.info("Next link: {}", bundle.getLink("next").getUrl());
|
||||
assertThat(bundle.getLink("next").getUrl(), containsString("_format=xml"));
|
||||
bundle = fetchBundle(bundle.getLink("next").getUrl(), EncodingEnum.XML);
|
||||
|
||||
assertNotNull(bundle.getLink("next").getUrl());
|
||||
ourLog.info("Next link: {}", bundle.getLink("next").getUrl());
|
||||
assertThat(bundle.getLink("next").getUrl(), containsString("_format=xml"));
|
||||
bundle = fetchBundle(bundle.getLink("next").getUrl(), EncodingEnum.XML);
|
||||
}
|
||||
|
||||
private Bundle fetchBundle(String theUrl, EncodingEnum theEncoding) throws IOException, ClientProtocolException {
|
||||
Bundle bundle;
|
||||
HttpGet get = new HttpGet(theUrl);
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(theEncoding.getResourceContentTypeNonLegacy(), resp.getFirstHeader(ca.uhn.fhir.rest.api.Constants.HEADER_CONTENT_TYPE).getValue().replaceAll(";.*", ""));
|
||||
bundle = theEncoding.newParser(myFhirCtx).parseResource(Bundle.class, IOUtils.toString(resp.getEntity().getContent(), Charsets.UTF_8));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp);
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import org.hl7.fhir.r4.model.Questionnaire;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
public class QuestionnaireResourceProviderR4 extends JpaResourceProviderR4<Questionnaire> {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Questionnaire.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,428 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.*;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.SearchParameter.XPathUsageType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.gclient.ReferenceClientParam;
|
||||
import ca.uhn.fhir.rest.gclient.TokenClientParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveCreateSearchParamInvalidWithMissingStatus() throws IOException {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setCode("foo");
|
||||
sp.setExpression("Patient.gender");
|
||||
sp.setXpathUsage(XPathUsageType.NORMAL);
|
||||
sp.setTitle("Foo Param");
|
||||
|
||||
try {
|
||||
ourClient.create().resource(sp).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: SearchParameter.status is missing or invalid: null", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeExtensionReferenceAsRecurse() throws Exception, IOException {
|
||||
SearchParameter attendingSp = new SearchParameter();
|
||||
attendingSp.addBase("Patient");
|
||||
attendingSp.setCode("attending");
|
||||
attendingSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
attendingSp.setTitle("Attending");
|
||||
attendingSp.setExpression("Patient.extension('http://acme.org/attending')");
|
||||
attendingSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
attendingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
attendingSp.getTarget().add(new CodeType("Practitioner"));
|
||||
IIdType spId = mySearchParameterDao.create(attendingSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Practitioner p1 = new Practitioner();
|
||||
p1.addName().setFamily("P1");
|
||||
IIdType p1id = myPractitionerDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().setFamily("P2");
|
||||
p2.addExtension().setUrl("http://acme.org/attending").setValue(new Reference(p1id));
|
||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||
|
||||
Appointment app = new Appointment();
|
||||
app.addParticipant().getActor().setReference(p2id.getValue());
|
||||
IIdType appId = myAppointmentDao.create(app).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Appointment?_include:recurse=Appointment:patient&_include:recurse=Appointment:location&_include:recurse=Patient:attending&_pretty=true");
|
||||
CloseableHttpResponse response = ourHttpClient.execute(get);
|
||||
try {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), Constants.CHARSET_UTF8);
|
||||
ourLog.info(resp);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(resp, containsString("<fullUrl value=\"http://localhost:" + ourPort + "/fhir/context/Practitioner/"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchForExtension() {
|
||||
SearchParameter eyeColourSp = new SearchParameter();
|
||||
eyeColourSp.addBase("Patient");
|
||||
eyeColourSp.setCode("eyecolour");
|
||||
eyeColourSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
eyeColourSp.setTitle("Eye Colour");
|
||||
eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
|
||||
eyeColourSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
eyeColourSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(eyeColourSp));
|
||||
|
||||
ourClient
|
||||
.create()
|
||||
.resource(eyeColourSp)
|
||||
.execute();
|
||||
|
||||
// mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
p1.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("blue"));
|
||||
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p1));
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.setActive(true);
|
||||
p2.addExtension().setUrl("http://acme.org/eyecolour").setValue(new CodeType("green"));
|
||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||
|
||||
Bundle bundle = ourClient
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.where(new TokenClientParam("eyecolour").exactly().code("blue"))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
|
||||
List<String> foundResources = toUnqualifiedVersionlessIdValues(bundle);
|
||||
assertThat(foundResources, contains(p1id.getValue()));
|
||||
|
||||
}
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderCustomSearchParamR4Test.class);
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void beforeResetConfig() {
|
||||
super.beforeResetConfig();
|
||||
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConformanceOverrideAllowed() {
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||
|
||||
CapabilityStatement conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
Map<String, CapabilityStatementRestResourceSearchParamComponent> map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
CapabilityStatementRestResourceSearchParamComponent param = map.get("foo");
|
||||
assertNull(param);
|
||||
|
||||
param = map.get("gender");
|
||||
assertNotNull(param);
|
||||
|
||||
TransactionTemplate txTemplate = newTxTemplate();
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
// Add a custom search parameter
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
}
|
||||
});
|
||||
|
||||
// Disable an existing parameter
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("gender");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("Gender");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
}
|
||||
});
|
||||
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
param = map.get("foo");
|
||||
assertEquals("foo", param.getName());
|
||||
|
||||
param = map.get("gender");
|
||||
assertNull(param);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConformanceOverrideNotAllowed() {
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(false);
|
||||
|
||||
CapabilityStatement conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
Map<String, CapabilityStatementRestResourceSearchParamComponent> map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
CapabilityStatementRestResourceSearchParamComponent param = map.get("foo");
|
||||
assertNull(param);
|
||||
|
||||
param = map.get("gender");
|
||||
assertNotNull(param);
|
||||
|
||||
// Add a custom search parameter
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
// Disable an existing parameter
|
||||
fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("gender");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("Gender");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
param = map.get("foo");
|
||||
assertEquals("foo", param.getName());
|
||||
|
||||
param = map.get("gender");
|
||||
assertNotNull(param);
|
||||
|
||||
}
|
||||
|
||||
private Map<String, CapabilityStatementRestResourceSearchParamComponent> extractSearchParams(CapabilityStatement conformance, String resType) {
|
||||
Map<String, CapabilityStatementRestResourceSearchParamComponent> map = new HashMap<String, CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent>();
|
||||
for (CapabilityStatementRestComponent nextRest : conformance.getRest()) {
|
||||
for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) {
|
||||
if (!resType.equals(nextResource.getType())) {
|
||||
continue;
|
||||
}
|
||||
for (CapabilityStatementRestResourceSearchParamComponent nextParam : nextResource.getSearchParam()) {
|
||||
map.put(nextParam.getName(), nextParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchWithCustomParam() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pat2 = new Patient();
|
||||
pat2.setGender(AdministrativeGender.FEMALE);
|
||||
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
Bundle result;
|
||||
|
||||
result = ourClient
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.where(new TokenClientParam("foo").exactly().code("male"))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
foundResources = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatingParamMarksCorrectResourcesForReindexing() {
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.setStatus(ObservationStatus.FINAL);
|
||||
IIdType obsId = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ResourceTable res = myResourceTableDao.findOne(patId.getIdPartAsLong());
|
||||
assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue());
|
||||
res = myResourceTableDao.findOne(obsId.getIdPartAsLong());
|
||||
assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue());
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
res = myResourceTableDao.findOne(patId.getIdPartAsLong());
|
||||
assertEquals(null, res.getIndexStatus());
|
||||
res = myResourceTableDao.findOne(obsId.getIdPartAsLong());
|
||||
assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue());
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchQualifiedWithCustomReferenceParam() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.addBase("Patient");
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.r4.model.Enumerations.SearchParamType.REFERENCE);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setExpression("Observation.subject");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.r4.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs1 = new Observation();
|
||||
obs1.getSubject().setReferenceElement(patId);
|
||||
IIdType obsId1 = myObservationDao.create(obs1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.setStatus(org.hl7.fhir.r4.model.Observation.ObservationStatus.FINAL);
|
||||
IIdType obsId2 = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
Bundle result;
|
||||
|
||||
result = ourClient
|
||||
.search()
|
||||
.forResource(Observation.class)
|
||||
.where(new ReferenceClientParam("foo").hasChainedProperty(Patient.GENDER.exactly().code("male")))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
foundResources = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(foundResources, contains(obsId1.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderInterceptorR4Test.class);
|
||||
private IServerInterceptor myDaoInterceptor;
|
||||
|
||||
private IServerInterceptor myServerInterceptor;
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
|
||||
myDaoConfig.getInterceptors().remove(myDaoInterceptor);
|
||||
ourRestServer.unregisterInterceptor(myServerInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
myServerInterceptor = mock(IServerInterceptor.class);
|
||||
myDaoInterceptor = mock(IServerInterceptor.class);
|
||||
|
||||
resetServerInterceptor();
|
||||
|
||||
myDaoConfig.getInterceptors().add(myDaoInterceptor);
|
||||
ourRestServer.registerInterceptor(myServerInterceptor);
|
||||
|
||||
ourRestServer.registerInterceptor(new InterceptorAdapter() {
|
||||
@Override
|
||||
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest) {
|
||||
super.incomingRequestPreHandled(theOperation, theProcessedRequest);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void resetServerInterceptor() throws ServletException, IOException {
|
||||
reset(myServerInterceptor);
|
||||
when(myServerInterceptor.handleException(any(RequestDetails.class), any(BaseServerResponseException.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||
when(myServerInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||
when(myServerInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class))).thenReturn(true);
|
||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateResource() throws IOException {
|
||||
String methodName = "testCreateResource";
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily(methodName);
|
||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response was: {}", resp);
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myServerInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getValue());
|
||||
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
||||
assertNotNull(ardCaptor.getValue().getResource());
|
||||
|
||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myDaoInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getValue());
|
||||
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
||||
assertNotNull(ardCaptor.getValue().getResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateResourceWithVersionedReference() throws IOException, ServletException {
|
||||
String methodName = "testCreateResourceWithVersionedReference";
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName("orgName");
|
||||
IIdType orgId = ourClient.create().resource(org).execute().getId().toUnqualified();
|
||||
assertNotNull(orgId.getVersionIdPartAsLong());
|
||||
|
||||
resetServerInterceptor();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily(methodName);
|
||||
pt.setManagingOrganization(new Reference(orgId));
|
||||
|
||||
IParser parser = myFhirCtx.newXmlParser();
|
||||
parser.setDontStripVersionsFromReferencesAtPaths("Patient.managingOrganization");
|
||||
parser.setPrettyPrint(true);
|
||||
String resource = parser.encodeResourceToString(pt);
|
||||
|
||||
ourLog.info(resource);
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response was: {}", resp);
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myServerInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
|
||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getValue());
|
||||
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
||||
assertNotNull(ardCaptor.getValue().getResource());
|
||||
|
||||
Patient patient;
|
||||
patient = (Patient) ardCaptor.getAllValues().get(0).getResource();
|
||||
assertEquals(orgId.getValue(), patient.getManagingOrganization().getReference());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateResourceInTransaction() throws IOException {
|
||||
String methodName = "testCreateResourceInTransaction";
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily(methodName);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
BundleEntryComponent entry = bundle.addEntry();
|
||||
entry.setFullUrl("Patient");
|
||||
entry.setResource(pt);
|
||||
entry.getRequest().setMethod(HTTPVerb.POST);
|
||||
entry.getRequest().setUrl("Patient");
|
||||
|
||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Server Interceptor
|
||||
*/
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myServerInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
||||
assertEquals(null, ardCaptor.getAllValues().get(0).getResourceType());
|
||||
assertNotNull(ardCaptor.getAllValues().get(0).getResource());
|
||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getAllValues().get(1));
|
||||
assertEquals("Patient", ardCaptor.getAllValues().get(1).getResourceType());
|
||||
assertNotNull(ardCaptor.getAllValues().get(1).getResource());
|
||||
|
||||
ArgumentCaptor<RequestDetails> rdCaptor = ArgumentCaptor.forClass(RequestDetails.class);
|
||||
ArgumentCaptor<HttpServletRequest> srCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
||||
ArgumentCaptor<HttpServletResponse> sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
||||
verify(myServerInterceptor, times(1)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
||||
|
||||
/*
|
||||
* DAO Interceptor
|
||||
*/
|
||||
|
||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myDaoInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
||||
assertEquals("Bundle", ardCaptor.getAllValues().get(0).getResourceType());
|
||||
assertNotNull(ardCaptor.getAllValues().get(0).getResource());
|
||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getAllValues().get(1));
|
||||
assertEquals("Patient", ardCaptor.getAllValues().get(1).getResourceType());
|
||||
assertNotNull(ardCaptor.getAllValues().get(1).getResource());
|
||||
|
||||
rdCaptor = ArgumentCaptor.forClass(RequestDetails.class);
|
||||
srCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
||||
sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
|
||||
import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseStatus;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
|
||||
public class ResourceProviderQuestionnaireResponseR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderQuestionnaireResponseR4Test.class);
|
||||
private static RequestValidatingInterceptor ourValidatingInterceptor;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
ourRestServer.unregisterInterceptor(ourValidatingInterceptor);
|
||||
ourValidatingInterceptor = null;
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
if (ourValidatingInterceptor == null) {
|
||||
ourValidatingInterceptor = new RequestValidatingInterceptor();
|
||||
ourValidatingInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
|
||||
Collection<IValidatorModule> validators = myAppCtx.getBeansOfType(IValidatorModule.class).values();
|
||||
for (IValidatorModule next : validators) {
|
||||
ourValidatingInterceptor.addValidatorModule(next);
|
||||
}
|
||||
ourRestServer.registerInterceptor(ourValidatingInterceptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testCreateWithLocalReference() {
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("Everything").addGiven("Arthur");
|
||||
IIdType ptId1 = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Questionnaire q1 = new Questionnaire();
|
||||
q1.addItem().setLinkId("link1").setType(QuestionnaireItemType.STRING);
|
||||
IIdType qId = myQuestionnaireDao.create(q1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
QuestionnaireResponse qr1 = new QuestionnaireResponse();
|
||||
qr1.getQuestionnaire().setReferenceElement(qId);
|
||||
qr1.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qr1.addItem().setLinkId("link1").addAnswer().setValue(new DecimalType(123));
|
||||
try {
|
||||
ourClient.create().resource(qr1).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.toString(), containsString("Answer value must be of type string"));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testCreateWithAbsoluteReference() {
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("Everything").addGiven("Arthur");
|
||||
IIdType ptId1 = myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Questionnaire q1 = new Questionnaire();
|
||||
q1.addItem().setLinkId("link1").setType(QuestionnaireItemType.STRING);
|
||||
IIdType qId = myQuestionnaireDao.create(q1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
QuestionnaireResponse qr1 = new QuestionnaireResponse();
|
||||
qr1.getQuestionnaire().setReferenceElement(qId.withServerBase("http://example.com", "Questionnaire"));
|
||||
qr1.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qr1.addItem().setLinkId("link1").addAnswer().setValue(new DecimalType(123));
|
||||
try {
|
||||
ourClient.create().resource(qr1).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.toString(), containsString("Answer value must be of type string"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveQuestionnaire() throws Exception {
|
||||
String input = "<QuestionnaireResponse xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <status value=\"completed\"/>\n" +
|
||||
" <authored value=\"2016-05-03T13:05:20-04:00\"/>\n" +
|
||||
" <item>\n" +
|
||||
" <linkId value=\"breast-feeding-intention\"/>\n" +
|
||||
" <text value=\"Breast Feeding Intention:\"/>\n" +
|
||||
" <answer>\n" +
|
||||
" <valueCoding>\n" +
|
||||
" <system value=\"http://example.org/codesystem-breastfeeding-intention\"/>\n" +
|
||||
" <code value=\"true\"/>\n" +
|
||||
" <display value=\"Mother wants to provide formula exclusively\"/>\n" +
|
||||
" </valueCoding>\n" +
|
||||
" </answer>\n" +
|
||||
" </item>\n" +
|
||||
" <item>\n" +
|
||||
" <linkId value=\"breast-feeding-education\"/>\n" +
|
||||
" <text value=\"Answer if not exclusive BM:\"/>\n" +
|
||||
" <answer>\n" +
|
||||
" <valueCoding>\n" +
|
||||
" <system value=\"http://example.org/codesystem-breastfeeding-education\"/>\n" +
|
||||
" <code value=\"true\"/>\n" +
|
||||
" <display value=\"Mother not given comprehensive education per protocol\"/>\n" +
|
||||
" </valueCoding>\n" +
|
||||
" </answer>\n" +
|
||||
" </item>\n" +
|
||||
" <item>\n" +
|
||||
" <linkId value=\"breast-feeding-exclusion\"/>\n" +
|
||||
" <text value=\"Exclusion Criteria:\"/>\n" +
|
||||
" <answer>\n" +
|
||||
" <valueCoding>\n" +
|
||||
" <system value=\"http://example.org/codesystem-breastfeeding-exclusion\"/>\n" +
|
||||
" <code value=\"true\"/>\n" +
|
||||
" <display\n" +
|
||||
" value=\"Maternal use of drugs of abuse, antimetabolites, chemotherapeutic agents, or radioisotopes\"\n" +
|
||||
" />\n" +
|
||||
" </valueCoding>\n" +
|
||||
" </answer>\n" +
|
||||
" </item>\n" +
|
||||
"</QuestionnaireResponse>";
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/QuestionnaireResponse");
|
||||
post.setEntity(new StringEntity(input, ContentType.create(ca.uhn.fhir.rest.api.Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
final IdType id2;
|
||||
try {
|
||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response: {}", responseString);
|
||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
||||
String newIdString = response.getFirstHeader(ca.uhn.fhir.rest.api.Constants.HEADER_LOCATION_LC).getValue();
|
||||
assertThat(newIdString, startsWith(ourServerBase + "/QuestionnaireResponse/"));
|
||||
id2 = new IdType(newIdString);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/QuestionnaireResponse/" + id2.getIdPart() + "?_format=xml&_pretty=true");
|
||||
response = ourHttpClient.execute(get);
|
||||
try {
|
||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response: {}", responseString);
|
||||
assertThat(responseString, containsString("Exclusion Criteria"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateOnNoId() throws Exception {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/QuestionnaireResponse/$validate");
|
||||
CloseableHttpResponse response = ourHttpClient.execute(get);
|
||||
try {
|
||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response: {}", responseString);
|
||||
assertThat(responseString, containsString("No resource supplied for $validate operation"));
|
||||
assertEquals(400, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* From a Skype message from Brian Postlethwaite
|
||||
*/
|
||||
@Test
|
||||
public void testValidateQuestionnaireResponseWithNoIdForCreate() throws Exception {
|
||||
|
||||
String input = "{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"mode\",\"valueString\":\"create\"},{\"name\":\"resource\",\"resource\":{\"resourceType\":\"QuestionnaireResponse\",\"questionnaire\":{\"reference\":\"http://fhirtest.uhn.ca/baseDstu2/Questionnaire/MedsCheckEligibility\"},\"text\":{\"status\":\"generated\",\"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">!-- populated from the rendered HTML below --></div>\"},\"status\":\"completed\",\"authored\":\"2017-02-10T00:02:58.098Z\"}}]}";
|
||||
HttpPost post = new HttpPost(ourServerBase + "/QuestionnaireResponse/$validate?_pretty=true");
|
||||
post.setEntity(new StringEntity(input, ContentType.APPLICATION_JSON));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response: {}", responseString);
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* From a Skype message from Brian Postlethwaite
|
||||
*/
|
||||
@Test
|
||||
public void testValidateQuestionnaireResponseWithNoIdForUpdate() throws Exception {
|
||||
|
||||
String input = "{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"mode\",\"valueString\":\"update\"},{\"name\":\"resource\",\"resource\":{\"resourceType\":\"QuestionnaireResponse\",\"questionnaire\":{\"reference\":\"http://fhirtest.uhn.ca/baseDstu2/Questionnaire/MedsCheckEligibility\"},\"text\":{\"status\":\"generated\",\"div\":\"<div xmlns=\\\"http://www.w3.org/1999/xhtml\\\">!-- populated from the rendered HTML below --></div>\"},\"status\":\"completed\",\"authored\":\"2017-02-10T00:02:58.098Z\"}}]}";
|
||||
HttpPost post = new HttpPost(ourServerBase + "/QuestionnaireResponse/$validate?_pretty=true");
|
||||
post.setEntity(new StringEntity(input, ContentType.APPLICATION_JSON));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info("Response: {}", responseString);
|
||||
assertThat(responseString, containsString("Resource has no ID"));
|
||||
assertEquals(422, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Composition;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4BundleTest.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #401
|
||||
*/
|
||||
@Test
|
||||
public void testBundlePreservesFullUrl() throws Exception {
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.DOCUMENT);
|
||||
|
||||
Composition composition = new Composition();
|
||||
composition.setTitle("Visit Summary");
|
||||
bundle.addEntry().setFullUrl("http://foo").setResource(composition);
|
||||
|
||||
IIdType id = ourClient.create().resource(bundle).execute().getId();
|
||||
|
||||
Bundle retBundle = ourClient.read().resource(Bundle.class).withId(id).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(retBundle));
|
||||
|
||||
assertEquals("http://foo", bundle.getEntry().get(0).getFullUrl());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4CodeSystemTest.class);
|
||||
private IIdType myExtensionalVsId;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
@Transactional
|
||||
public void before02() throws IOException {
|
||||
CodeSystem cs = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||
myCodeSystemDao.create(cs, mySrd);
|
||||
|
||||
ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
|
||||
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOnExternalCode() {
|
||||
ResourceProviderR4ValueSetTest.createExternalCs(myCodeSystemDao, myResourceTableDao, myTermSvc, mySrd);
|
||||
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "code", new CodeType("ParentA"))
|
||||
.andParameter("system", new UriType(FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM))
|
||||
.execute();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue());
|
||||
|
||||
// With HTTP GET
|
||||
respParam = ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "code", new CodeType("ParentA"))
|
||||
.andParameter("system", new UriType(FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM))
|
||||
.useHttpGet()
|
||||
.execute();
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
assertEquals("Parent A", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByCodeAndSystemBuiltInCode() {
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "code", new CodeType("ACSN"))
|
||||
.andParameter("system", new UriType("http://hl7.org/fhir/v2/0203"))
|
||||
.execute();
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
assertEquals("Accession ID", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByCodeAndSystemBuiltInNonexistantCode() {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "code", new CodeType("ACSNAAAAAA"))
|
||||
.andParameter("system", new UriType("http://hl7.org/fhir/v2/0203"))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// good
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByCodeAndSystemUserDefinedCode() {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
|
||||
.andParameter("system", new UriType("http://acme.org"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
assertEquals(("Systolic blood pressure--expiration"), ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByCodeAndSystemUserDefinedNonExistantCode() {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "code", new CodeType("8450-9AAAAA"))
|
||||
.andParameter("system", new UriType("http://acme.org"))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// good
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByCoding() {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "coding", new Coding().setSystem("http://acme.org").setCode("8450-9"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals(("Unknown"), ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
assertEquals(("Systolic blood pressure--expiration"), ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).getValue().booleanValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByInvalidCombination() {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "coding", new Coding().setSystem("http://acme.org").setCode("8450-9"))
|
||||
.andParameter("code", new CodeType("8450-9"))
|
||||
.andParameter("system", new UriType("http://acme.org"))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: $lookup can only validate (system AND code) OR (coding.system AND coding.code)", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByInvalidCombination2() {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "coding", new Coding().setSystem("http://acme.org").setCode("8450-9"))
|
||||
.andParameter("system", new UriType("http://acme.org"))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: $lookup can only validate (system AND code) OR (coding.system AND coding.code)", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLookupOperationByInvalidCombination3() {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "coding", new Coding().setSystem("http://acme.org").setCode(null))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: No code, coding, or codeableConcept provided to validate", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Ignore
|
||||
public void testLookupOperationForBuiltInCode() {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(CodeSystem.class)
|
||||
.named("lookup")
|
||||
.withParameter(Parameters.class, "code", new CodeType("M"))
|
||||
.andParameter("system", new UriType("http://hl7.org/fhir/v3/MaritalStatus"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals("name", respParam.getParameter().get(0).getName());
|
||||
assertEquals("Unknown", ((StringType)respParam.getParameter().get(0).getValue()).getValue());
|
||||
assertEquals("display", respParam.getParameter().get(1).getName());
|
||||
assertEquals("Married", ((StringType)respParam.getParameter().get(1).getValue()).getValue());
|
||||
assertEquals("abstract", respParam.getParameter().get(2).getName());
|
||||
assertEquals(false, ((BooleanType)respParam.getParameter().get(2).getValue()).booleanValue());
|
||||
}
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,533 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM;
|
||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4ValueSetTest.class);
|
||||
private IIdType myExtensionalVsId;
|
||||
private IIdType myLocalValueSetId;
|
||||
private ValueSet myLocalVs;
|
||||
|
||||
@Before
|
||||
@Transactional
|
||||
public void before02() throws IOException {
|
||||
CodeSystem cs = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||
myCodeSystemDao.create(cs, mySrd);
|
||||
|
||||
ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
|
||||
myExtensionalVsId = myValueSetDao.create(upload, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
/**
|
||||
* #516
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidFilter() throws Exception {
|
||||
String string = IOUtils.toString(getClass().getResourceAsStream("/bug_516_invalid_expansion.json"), StandardCharsets.UTF_8);
|
||||
HttpPost post = new HttpPost(ourServerBase+"/ValueSet/%24expand");
|
||||
post.setEntity(new StringEntity(string, ContentType.parse(ca.uhn.fhir.rest.api.Constants.CT_FHIR_JSON_NEW)));
|
||||
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(post);
|
||||
try {
|
||||
|
||||
String respString = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(respString);
|
||||
|
||||
ourLog.info(resp.toString());
|
||||
|
||||
assertEquals(400, resp.getStatusLine().getStatusCode());
|
||||
assertThat(respString, containsString("Unknown FilterOperator code 'n'"));
|
||||
|
||||
}finally {
|
||||
IOUtils.closeQuietly(resp);
|
||||
}
|
||||
}
|
||||
|
||||
private CodeSystem createExternalCs() {
|
||||
IFhirResourceDao<CodeSystem> codeSystemDao = myCodeSystemDao;
|
||||
IResourceTableDao resourceTableDao = myResourceTableDao;
|
||||
IHapiTerminologySvc termSvc = myTermSvc;
|
||||
|
||||
return createExternalCs(codeSystemDao, resourceTableDao, termSvc, mySrd);
|
||||
}
|
||||
|
||||
public static CodeSystem createExternalCs(IFhirResourceDao<CodeSystem> theCodeSystemDao, IResourceTableDao theResourceTableDao, IHapiTerminologySvc theTermSvc, ServletRequestDetails theRequestDetails) {
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||
codeSystem.setContent(CodeSystemContentMode.NOTPRESENT);
|
||||
IIdType id = theCodeSystemDao.create(codeSystem, theRequestDetails).getId().toUnqualified();
|
||||
|
||||
ResourceTable table = theResourceTableDao.findOne(id.getIdPartAsLong());
|
||||
|
||||
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||
cs.setResource(table);
|
||||
cs.setResourceVersionId(table.getVersion());
|
||||
|
||||
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
|
||||
cs.getConcepts().add(parentA);
|
||||
|
||||
TermConcept childAA = new TermConcept(cs, "childAA").setDisplay("Child AA");
|
||||
parentA.addChild(childAA, RelationshipTypeEnum.ISA);
|
||||
|
||||
TermConcept childAAA = new TermConcept(cs, "childAAA").setDisplay("Child AAA");
|
||||
childAA.addChild(childAAA, RelationshipTypeEnum.ISA);
|
||||
|
||||
TermConcept childAAB = new TermConcept(cs, "childAAB").setDisplay("Child AAB");
|
||||
childAA.addChild(childAAB, RelationshipTypeEnum.ISA);
|
||||
|
||||
TermConcept childAB = new TermConcept(cs, "childAB").setDisplay("Child AB");
|
||||
parentA.addChild(childAB, RelationshipTypeEnum.ISA);
|
||||
|
||||
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
|
||||
cs.getConcepts().add(parentB);
|
||||
|
||||
theTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, cs);
|
||||
return codeSystem;
|
||||
}
|
||||
|
||||
private void createExternalCsAndLocalVs() {
|
||||
CodeSystem codeSystem = createExternalCs();
|
||||
|
||||
createLocalVs(codeSystem);
|
||||
}
|
||||
|
||||
private void createExternalCsAndLocalVsWithUnknownCode() {
|
||||
CodeSystem codeSystem = createExternalCs();
|
||||
|
||||
createLocalVsWithUnknownCode(codeSystem);
|
||||
}
|
||||
|
||||
private void createLocalCsAndVs() {
|
||||
//@formatter:off
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
|
||||
codeSystem
|
||||
.addConcept().setCode("A").setDisplay("Code A")
|
||||
.addConcept(new ConceptDefinitionComponent().setCode("AA").setDisplay("Code AA")
|
||||
.addConcept(new ConceptDefinitionComponent().setCode("AAA").setDisplay("Code AAA"))
|
||||
)
|
||||
.addConcept(new ConceptDefinitionComponent().setCode("AB").setDisplay("Code AB"));
|
||||
codeSystem
|
||||
.addConcept().setCode("B").setDisplay("Code B")
|
||||
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
|
||||
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
|
||||
//@formatter:on
|
||||
myCodeSystemDao.create(codeSystem, mySrd);
|
||||
|
||||
createLocalVs(codeSystem);
|
||||
}
|
||||
|
||||
private void createLocalVs(CodeSystem codeSystem) {
|
||||
myLocalVs = new ValueSet();
|
||||
myLocalVs.setUrl(URL_MY_VALUE_SET);
|
||||
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
|
||||
include.setSystem(codeSystem.getUrl());
|
||||
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childAA");
|
||||
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
private void createLocalVsPointingAtBuiltInCodeSystem() {
|
||||
myLocalVs = new ValueSet();
|
||||
myLocalVs.setUrl(URL_MY_VALUE_SET);
|
||||
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
|
||||
include.setSystem("http://hl7.org/fhir/v3/MaritalStatus");
|
||||
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
private void createLocalVsWithUnknownCode(CodeSystem codeSystem) {
|
||||
myLocalVs = new ValueSet();
|
||||
myLocalVs.setUrl(URL_MY_VALUE_SET);
|
||||
ConceptSetComponent include = myLocalVs.getCompose().addInclude();
|
||||
include.setSystem(codeSystem.getUrl());
|
||||
include.addFilter().setProperty("concept").setOp(FilterOperator.ISA).setValue("childFOOOOOOO");
|
||||
myLocalValueSetId = myValueSetDao.create(myLocalVs, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandById() throws IOException {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withNoParameters(Parameters.class)
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<ValueSet xmlns=\"http://hl7.org/fhir\">"));
|
||||
assertThat(resp, containsString("<expansion>"));
|
||||
assertThat(resp, containsString("<contains>"));
|
||||
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||
assertThat(resp, containsString("<code value=\"8450-9\"/>"));
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure--expiration\"/>"));
|
||||
assertThat(resp, containsString("</contains>"));
|
||||
assertThat(resp, containsString("<contains>"));
|
||||
assertThat(resp, containsString("<system value=\"http://acme.org\"/>"));
|
||||
assertThat(resp, containsString("<code value=\"11378-7\"/>"));
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, containsString("</contains>"));
|
||||
assertThat(resp, containsString("</expansion>"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandByIdentifier() {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "identifier", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
//@formatter:off
|
||||
assertThat(resp, stringContainsInOrder(
|
||||
"<code value=\"11378-7\"/>",
|
||||
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Test
|
||||
public void testExpandByIdWithFilter() throws IOException {
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "filter", new StringType("first"))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
assertThat(resp, containsString("<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
assertThat(resp, not(containsString("<display value=\"Systolic blood pressure--expiration\"/>")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandByValueSet() throws IOException {
|
||||
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs.xml");
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "valueSet", toExpand)
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
//@formatter:off
|
||||
assertThat(resp, stringContainsInOrder(
|
||||
"<code value=\"11378-7\"/>",
|
||||
"<display value=\"Systolic blood pressure at First encounter\"/>"));
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandInlineVsAgainstBuiltInCs() throws IOException {
|
||||
createLocalVsPointingAtBuiltInCodeSystem();
|
||||
assertNotNull(myLocalValueSetId);
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "valueSet", myLocalVs)
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"M\"/>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandInlineVsAgainstExternalCs() throws IOException {
|
||||
createExternalCsAndLocalVs();
|
||||
assertNotNull(myLocalVs);
|
||||
myLocalVs.setId("");
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "valueSet", myLocalVs)
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAA\"/>"));
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
|
||||
assertThat(resp, not(containsStringIgnoringCase("<code value=\"ParentA\"/>")));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExpandInvalidParams() throws IOException {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withNoParameters(Parameters.class)
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: $expand operation at the type level (no ID specified) requires an identifier or a valueSet as a part of the request", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-r4.xml");
|
||||
ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "valueSet", toExpand)
|
||||
.andParameter("identifier", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: $expand must EITHER be invoked at the instance level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-r4.xml");
|
||||
ourClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "valueSet", toExpand)
|
||||
.andParameter("identifier", new UriType("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2"))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: $expand must EITHER be invoked at the instance level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandLocalVsAgainstBuiltInCs() throws IOException {
|
||||
createLocalVsPointingAtBuiltInCodeSystem();
|
||||
assertNotNull(myLocalValueSetId);
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onInstance(myLocalValueSetId)
|
||||
.named("expand")
|
||||
.withNoParameters(Parameters.class)
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"M\"/>"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testExpandLocalVsAgainstExternalCs() throws IOException {
|
||||
createExternalCsAndLocalVs();
|
||||
assertNotNull(myLocalValueSetId);
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onInstance(myLocalValueSetId)
|
||||
.named("expand")
|
||||
.withNoParameters(Parameters.class)
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAA\"/>"));
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
|
||||
assertThat(resp, not(containsStringIgnoringCase("<code value=\"ParentA\"/>")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandLocalVsCanonicalAgainstExternalCs() throws IOException {
|
||||
createExternalCsAndLocalVs();
|
||||
assertNotNull(myLocalValueSetId);
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("expand")
|
||||
.withParameter(Parameters.class, "identifier", new UriType(URL_MY_VALUE_SET))
|
||||
.execute();
|
||||
ValueSet expanded = (ValueSet) respParam.getParameter().get(0).getResource();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAA\"/>"));
|
||||
assertThat(resp, containsStringIgnoringCase("<code value=\"childAAB\"/>"));
|
||||
assertThat(resp, not(containsStringIgnoringCase("<code value=\"ParentA\"/>")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandLocalVsWithUnknownCode() throws IOException {
|
||||
createExternalCsAndLocalVsWithUnknownCode();
|
||||
assertNotNull(myLocalValueSetId);
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onInstance(myLocalValueSetId)
|
||||
.named("expand")
|
||||
.withNoParameters(Parameters.class)
|
||||
.execute();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Invalid filter criteria - code does not exist: {http://example.com/my_code_system}childFOOOOOOO", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValiedateCodeAgainstBuiltInSystem() {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("validate-code")
|
||||
.withParameter(Parameters.class, "code", new StringType("BRN"))
|
||||
.andParameter("identifier", new StringType("http://hl7.org/fhir/ValueSet/v2-0487"))
|
||||
.andParameter("system", new StringType("http://hl7.org/fhir/v2/0487"))
|
||||
.useHttpGet()
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals("result", respParam.getParameter().get(0).getName());
|
||||
assertEquals(true, ((BooleanType)respParam.getParameter().get(0).getValue()).getValue().booleanValue());
|
||||
|
||||
assertEquals("message", respParam.getParameter().get(1).getName());
|
||||
assertThat(((StringType)respParam.getParameter().get(1).getValue()).getValue(), containsStringIgnoringCase("succeeded"));
|
||||
|
||||
assertEquals("display", respParam.getParameter().get(2).getName());
|
||||
assertEquals("Burn", ((StringType)respParam.getParameter().get(2).getValue()).getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByCodeAndSystemInstance() {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onInstance(myExtensionalVsId)
|
||||
.named("validate-code")
|
||||
.withParameter(Parameters.class, "code", new CodeType("8495-4"))
|
||||
.andParameter("system", new UriType("http://acme.org"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals(true, ((BooleanType)respParam.getParameter().get(0).getValue()).booleanValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateCodeOperationByCodeAndSystemType() {
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onType(ValueSet.class)
|
||||
.named("validate-code")
|
||||
.withParameter(Parameters.class, "code", new CodeType("8450-9"))
|
||||
.andParameter("system", new UriType("http://acme.org"))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertEquals(true, ((BooleanType)respParam.getParameter().get(0).getValue()).booleanValue());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ServerR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerR4Test.class);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* See #519
|
||||
*/
|
||||
@Test
|
||||
public void saveIdParamOnlyAppearsOnce() throws IOException {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/metadata?_pretty=true&_format=xml");
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(get);
|
||||
try {
|
||||
ourLog.info(resp.toString());
|
||||
assertEquals(200, resp.getStatusLine().getStatusCode());
|
||||
|
||||
String respString = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(respString);
|
||||
|
||||
CapabilityStatement cs = myFhirCtx.newXmlParser().parseResource(CapabilityStatement.class, respString);
|
||||
|
||||
for (CapabilityStatementRestResourceComponent nextResource : cs.getRest().get(0).getResource()) {
|
||||
ourLog.info("Testing resource: " + nextResource.getType());
|
||||
Set<String> sps = new HashSet<String>();
|
||||
for (CapabilityStatementRestResourceSearchParamComponent nextSp : nextResource.getSearchParam()) {
|
||||
if (sps.add(nextSp.getName()) == false) {
|
||||
fail("Duplicate search parameter " + nextSp.getName() + " for resource " + nextResource.getType());
|
||||
}
|
||||
}
|
||||
|
||||
if (!sps.contains("_id")) {
|
||||
fail("No search parameter _id for resource " + nextResource.getType());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.blankOrNullString;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
import ca.uhn.fhir.rest.gclient.IClientExecutable;
|
||||
import ca.uhn.fhir.rest.gclient.IQuery;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class StaleSearchDeletingSvcR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StaleSearchDeletingSvcR4Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
@After()
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
StaleSearchDeletingSvcImpl staleSearchDeletingSvc = AopTestUtils.getTargetObject(myStaleSearchDeletingSvc);
|
||||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(StaleSearchDeletingSvcImpl.DEFAULT_CUTOFF_SLACK);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
StaleSearchDeletingSvcImpl staleSearchDeletingSvc = AopTestUtils.getTargetObject(myStaleSearchDeletingSvc);
|
||||
staleSearchDeletingSvc.setCutoffSlackForUnitTest(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingInstanceWithContentFilter() throws Exception {
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("Everything").addGiven("Arthur");
|
||||
myPatientDao.create(pt1, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
IClientExecutable<IQuery<Bundle>, Bundle> search = ourClient
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.where(Patient.NAME.matches().value("Everything"))
|
||||
.returnBundle(Bundle.class);
|
||||
//@formatter:on
|
||||
|
||||
Bundle resp1 = search.execute();
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
search.execute();
|
||||
}
|
||||
|
||||
BundleLinkComponent nextLink = resp1.getLink("next");
|
||||
assertNotNull(nextLink);
|
||||
String nextLinkUrl = nextLink.getUrl();
|
||||
assertThat(nextLinkUrl, not(blankOrNullString()));
|
||||
|
||||
Bundle resp2 = ourClient.search().byUrl(nextLinkUrl).returnBundle(Bundle.class).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp2));
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
|
||||
ourClient.search().byUrl(nextLinkUrl).returnBundle(Bundle.class).execute();
|
||||
|
||||
Thread.sleep(20);
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(10);
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearchesAndDeleteThem();
|
||||
|
||||
try {
|
||||
ourClient.search().byUrl(nextLinkUrl).returnBundle(Bundle.class).execute();
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
assertThat(e.getMessage(), containsString("does not exist and may have expired"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,515 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.*;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorR4;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SubscriptionsR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionsR4Test.class);
|
||||
|
||||
private static final String WEBSOCKET_PATH = "/websocket/r4";
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void beforeCreateInterceptor() {
|
||||
super.beforeCreateInterceptor();
|
||||
|
||||
SubscriptionsRequireManualActivationInterceptorR4 interceptor = new SubscriptionsRequireManualActivationInterceptorR4();
|
||||
interceptor.setDao(mySubscriptionDao);
|
||||
myDaoConfig.getInterceptors().add(interceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeEnableScheduling() {
|
||||
myDaoConfig.setSchedulingDisabled(false);
|
||||
}
|
||||
|
||||
|
||||
private void sleepUntilPingCount(BaseSocket socket, int wantPingCount) throws InterruptedException {
|
||||
/*
|
||||
* In a separate thread, start a polling for new resources. Normally the scheduler would
|
||||
* take care of this, but that can take longer which makes the unit tests run much slower
|
||||
* so we simulate that part..
|
||||
*/
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
ourLog.warn("Interrupted", e);
|
||||
}
|
||||
ourLog.info("About to poll in separate thread");
|
||||
mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
ourLog.info("Done poll in separate thread");
|
||||
}}.start();
|
||||
|
||||
ourLog.info("Entering loop");
|
||||
for (long start = System.currentTimeMillis(), now = System.currentTimeMillis(); now - start <= 20000; now = System.currentTimeMillis()) {
|
||||
ourLog.debug("Starting");
|
||||
if (socket.myError != null) {
|
||||
fail(socket.myError);
|
||||
}
|
||||
if (socket.myPingCount >= wantPingCount) {
|
||||
ourLog.info("Breaking loop");
|
||||
break;
|
||||
}
|
||||
ourLog.debug("Sleeping");
|
||||
Thread.sleep(100);
|
||||
}
|
||||
|
||||
ourLog.info("Out of loop, pingcount {} error {}", socket.myPingCount, socket.myError);
|
||||
|
||||
assertNull(socket.myError, socket.myError);
|
||||
assertEquals(wantPingCount, socket.myPingCount);
|
||||
}
|
||||
|
||||
private void stopClientAndWaitForStopped(WebSocketClient client) throws Exception {
|
||||
client.stop();
|
||||
|
||||
/*
|
||||
* When websocket closes, the subscription is automatically deleted. This
|
||||
* can cause deadlocks if the test returns too quickly since it also
|
||||
* tries to delete the subscription
|
||||
*/
|
||||
Bundle found = null;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
found = ourClient.search().forResource("Subscription").returnBundle(Bundle.class).execute();
|
||||
if (found.getEntry().size() > 0) {
|
||||
Thread.sleep(200);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertEquals(0, found.getEntry().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidNoStatus() {
|
||||
Subscription subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
subs.getChannel().setPayload("application/fhir+json");
|
||||
subs.getChannel().setEndpoint("http://localhost:8888");
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
try {
|
||||
ourClient.create().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Can not create resource: Subscription.status must be populated", e.getMessage());
|
||||
}
|
||||
|
||||
subs.setId("ABC");
|
||||
try {
|
||||
ourClient.update().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Can not create resource: Subscription.status must be populated", e.getMessage());
|
||||
}
|
||||
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
ourClient.update().resource(subs).execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidWrongStatus() {
|
||||
Subscription subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
try {
|
||||
ourClient.create().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status must be 'off' or 'requested' on a newly created subscription", e.getMessage());
|
||||
}
|
||||
|
||||
subs.setId("ABC");
|
||||
try {
|
||||
ourClient.update().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status must be 'off' or 'requested' on a newly created subscription", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionDynamic() throws Exception {
|
||||
myDaoConfig.setSubscriptionEnabled(true);
|
||||
myDaoConfig.setSubscriptionPollDelay(0);
|
||||
|
||||
String methodName = "testSubscriptionDynamic";
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType pId = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
String criteria = "Observation?subject=Patient/" + pId.getIdPart();
|
||||
DynamicEchoSocket socket = new DynamicEchoSocket(criteria, EncodingEnum.JSON);
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
try {
|
||||
client.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + WEBSOCKET_PATH);
|
||||
client.connect(socket, echoUri, new ClientUpgradeRequest());
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
|
||||
sleepUntilPingCount(socket, 1);
|
||||
|
||||
mySubscriptionDao.read(new IdDt("Subscription", socket.mySubsId), mySrd);
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId2 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
sleepUntilPingCount(socket, 3);
|
||||
|
||||
obs = (Observation) socket.myReceived.get(0);
|
||||
assertEquals(afterId1.getValue(), obs.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
|
||||
obs = (Observation) socket.myReceived.get(1);
|
||||
assertEquals(afterId2.getValue(), obs.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId3 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
sleepUntilPingCount(socket, 4);
|
||||
|
||||
obs = (Observation) socket.myReceived.get(2);
|
||||
assertEquals(afterId3.getValue(), obs.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
|
||||
} finally {
|
||||
try {
|
||||
stopClientAndWaitForStopped(client);
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Failure", e);
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSubscriptionDynamicXml() throws Exception {
|
||||
myDaoConfig.setSubscriptionEnabled(true);
|
||||
myDaoConfig.setSubscriptionPollDelay(0);
|
||||
|
||||
String methodName = "testSubscriptionDynamic";
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType pId = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
String criteria = "Observation?subject=Patient/" + pId.getIdPart() + "&_format=xml";
|
||||
DynamicEchoSocket socket = new DynamicEchoSocket(criteria, EncodingEnum.XML);
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
try {
|
||||
client.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + WEBSOCKET_PATH);
|
||||
client.connect(socket, echoUri, new ClientUpgradeRequest());
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
|
||||
sleepUntilPingCount(socket, 1);
|
||||
|
||||
mySubscriptionDao.read(new IdDt("Subscription", socket.mySubsId), mySrd);
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getMeta().addProfile("http://foo");
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId2 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
sleepUntilPingCount(socket, 3);
|
||||
|
||||
obs = (Observation) socket.myReceived.get(0);
|
||||
assertEquals(afterId1.getValue(), obs.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
|
||||
obs = (Observation) socket.myReceived.get(1);
|
||||
assertEquals(afterId2.getValue(), obs.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId3 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
sleepUntilPingCount(socket, 4);
|
||||
|
||||
obs = (Observation) socket.myReceived.get(2);
|
||||
assertEquals(afterId3.getValue(), obs.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
|
||||
} finally {
|
||||
try {
|
||||
stopClientAndWaitForStopped(client);
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Failure", e);
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionSimple() throws Exception {
|
||||
myDaoConfig.setSubscriptionEnabled(true);
|
||||
myDaoConfig.setSubscriptionPollDelay(0);
|
||||
|
||||
String methodName = "testSubscriptionResourcesAppear";
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType pId = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Subscription subs = new Subscription();
|
||||
subs.getMeta().addProfile("http://foo");
|
||||
subs.getChannel().setType(SubscriptionChannelType.WEBSOCKET);
|
||||
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
String subsId = mySubscriptionDao.create(subs, mySrd).getId().getIdPart();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId2 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(100);
|
||||
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
SimpleEchoSocket socket = new SimpleEchoSocket(subsId);
|
||||
try {
|
||||
client.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + WEBSOCKET_PATH);
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
client.connect(socket, echoUri, request);
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
|
||||
sleepUntilPingCount(socket, 1);
|
||||
|
||||
obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(pId);
|
||||
obs.setStatus(ObservationStatus.FINAL);
|
||||
IIdType afterId3 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
sleepUntilPingCount(socket, 2);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
client.stop();
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Failure", e);
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpdateFails() {
|
||||
Subscription subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
subs.getChannel().setPayload("application/fhir+json");
|
||||
subs.getChannel().setEndpoint("http://localhost:8888");
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
IIdType id = ourClient.create().resource(subs).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
subs.setId(id);
|
||||
|
||||
try {
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
ourClient.update().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status can not be changed from 'requested' to 'active'", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
subs.setStatus((SubscriptionStatus) null);
|
||||
ourClient.update().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Can not update resource: Subscription.status must be populated", e.getMessage());
|
||||
}
|
||||
|
||||
subs.setStatus(SubscriptionStatus.OFF);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpdateToInvalidStatus() {
|
||||
Subscription subs = new Subscription();
|
||||
subs.getChannel().setType(SubscriptionChannelType.RESTHOOK);
|
||||
subs.getChannel().setPayload("application/fhir+json");
|
||||
subs.getChannel().setEndpoint("http://localhost:8888");
|
||||
subs.setCriteria("Observation?identifier=123");
|
||||
subs.setStatus(SubscriptionStatus.REQUESTED);
|
||||
IIdType id = ourClient.create().resource(subs).execute().getId();
|
||||
subs.setId(id);
|
||||
|
||||
try {
|
||||
subs.setStatus(SubscriptionStatus.ACTIVE);
|
||||
ourClient.update().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status can not be changed from 'requested' to 'active'", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
subs.setStatus((SubscriptionStatus) null);
|
||||
ourClient.update().resource(subs).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Can not update resource: Subscription.status must be populated", e.getMessage());
|
||||
}
|
||||
|
||||
subs.setStatus(SubscriptionStatus.OFF);
|
||||
ourClient.update().resource(subs).execute();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
public class BaseSocket {
|
||||
protected String myError;
|
||||
protected boolean myGotBound;
|
||||
protected int myPingCount;
|
||||
protected String mySubsId;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Echo Client Socket
|
||||
*/
|
||||
@WebSocket(maxTextMessageSize = 64 * 1024)
|
||||
public class DynamicEchoSocket extends BaseSocket {
|
||||
|
||||
private String myCriteria;
|
||||
private EncodingEnum myEncoding;
|
||||
private List<IBaseResource> myReceived = new ArrayList<IBaseResource>();
|
||||
@SuppressWarnings("unused")
|
||||
private Session session;
|
||||
|
||||
public DynamicEchoSocket(String theCriteria, EncodingEnum theEncoding) {
|
||||
myCriteria = theCriteria;
|
||||
myEncoding = theEncoding;
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session session) {
|
||||
ourLog.info("Got connect: {}", session);
|
||||
this.session = session;
|
||||
try {
|
||||
String sending = "bind " + myCriteria;
|
||||
ourLog.info("Sending: {}", sending);
|
||||
session.getRemote().sendString(sending);
|
||||
} catch (Throwable t) {
|
||||
ourLog.error("Failure", t);
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String theMsg) {
|
||||
ourLog.info("Got msg: {}", theMsg);
|
||||
if (theMsg.startsWith("bound ")) {
|
||||
myGotBound = true;
|
||||
mySubsId = (theMsg.substring("bound ".length()));
|
||||
myPingCount++;
|
||||
} else if (myGotBound && theMsg.startsWith("add " + mySubsId + "\n")) {
|
||||
String text = theMsg.substring(("add " + mySubsId + "\n").length());
|
||||
IBaseResource res = myEncoding.newParser(myFhirCtx).parseResource(text);
|
||||
myReceived.add(res);
|
||||
myPingCount++;
|
||||
} else {
|
||||
myError = "Unexpected message: " + theMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Echo Client Socket
|
||||
*/
|
||||
@WebSocket(maxTextMessageSize = 64 * 1024)
|
||||
public class SimpleEchoSocket extends BaseSocket {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Session session;
|
||||
|
||||
public SimpleEchoSocket(String theSubsId) {
|
||||
mySubsId = theSubsId;
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session session) {
|
||||
ourLog.info("Got connect: {}", session);
|
||||
this.session = session;
|
||||
try {
|
||||
String sending = "bind " + mySubsId;
|
||||
ourLog.info("Sending: {}", sending);
|
||||
session.getRemote().sendString(sending);
|
||||
} catch (Throwable t) {
|
||||
ourLog.error("Failure", t);
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String theMsg) {
|
||||
ourLog.info("Got msg: {}", theMsg);
|
||||
if (theMsg.equals("bound " + mySubsId)) {
|
||||
myGotBound = true;
|
||||
} else if (myGotBound && theMsg.startsWith("ping " + mySubsId)) {
|
||||
myPingCount++;
|
||||
} else {
|
||||
myError = "Unexpected message: " + theMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,662 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||
import ca.uhn.fhir.jpa.rp.r4.*;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
|
||||
public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||
|
||||
private static RestfulServer myRestServer;
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static CloseableHttpClient ourHttpClient;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SystemProviderR4Test.class);
|
||||
private static Server ourServer;
|
||||
private static String ourServerBase;
|
||||
private SimpleRequestHeaderInterceptor mySimpleHeaderInterceptor;
|
||||
|
||||
@Test
|
||||
public void testTransactionWithInlineConditionalUrl() throws Exception {
|
||||
myDaoConfig.setAllowInlineMatchUrlReferences(true);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("van de Heuvelcx85ioqWJbI").addGiven("Pietercx85ioqWJbI");
|
||||
myPatientDao.create(p, mySrd);
|
||||
|
||||
Organization o = new Organization();
|
||||
o.addIdentifier().setSystem("urn:oid:2.16.840.1.113883.2.4.6.1").setValue("07-8975469");
|
||||
myOrganizationDao.create(o, mySrd);
|
||||
|
||||
//@formatter:off
|
||||
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <id value=\"20160113160203\"/>\n" +
|
||||
" <type value=\"transaction\"/>\n" +
|
||||
" <entry>\n" +
|
||||
" <fullUrl value=\"urn:uuid:c72aa430-2ddc-456e-7a09-dea8264671d8\"/>\n" +
|
||||
" <resource>\n" +
|
||||
" <Encounter>\n" +
|
||||
" <identifier>\n" +
|
||||
" <use value=\"official\"/>\n" +
|
||||
" <system value=\"http://healthcare.example.org/identifiers/encounter\"/>\n" +
|
||||
" <value value=\"845962.8975469\"/>\n" +
|
||||
" </identifier>\n" +
|
||||
" <status value=\"in-progress\"/>\n" +
|
||||
" <class value=\"inpatient\"/>\n" +
|
||||
" <patient>\n" +
|
||||
" <reference value=\"Patient?family=van%20de%20Heuvelcx85ioqWJbI&given=Pietercx85ioqWJbI\"/>\n" +
|
||||
" </patient>\n" +
|
||||
" <serviceProvider>\n" +
|
||||
" <reference value=\"Organization?identifier=urn:oid:2.16.840.1.113883.2.4.6.1|07-8975469\"/>\n" +
|
||||
" </serviceProvider>\n" +
|
||||
" </Encounter>\n" +
|
||||
" </resource>\n" +
|
||||
" <request>\n" +
|
||||
" <method value=\"POST\"/>\n" +
|
||||
" <url value=\"Encounter\"/>\n" +
|
||||
" </request>\n" +
|
||||
" </entry>\n" +
|
||||
"</Bundle>";
|
||||
//@formatter:off
|
||||
|
||||
HttpPost req = new HttpPost(ourServerBase);
|
||||
req.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
||||
try {
|
||||
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, containsString("transaction-response"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTransactionDeleteWithDuplicateDeletes() throws Exception {
|
||||
myDaoConfig.setAllowInlineMatchUrlReferences(true);
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("van de Heuvelcx85ioqWJbI").addGiven("Pietercx85ioqWJbI");
|
||||
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ourClient.read().resource(Patient.class).withId(id);
|
||||
|
||||
Bundle inputBundle = new Bundle();
|
||||
inputBundle.setType(BundleType.TRANSACTION);
|
||||
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl(id.getValue());
|
||||
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl(id.getValue());
|
||||
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl("Patient?name=Pietercx85ioqWJbI");
|
||||
String input = myFhirCtx.newXmlParser().encodeResourceToString(inputBundle);
|
||||
|
||||
HttpPost req = new HttpPost(ourServerBase + "?_pretty=true");
|
||||
req.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
||||
try {
|
||||
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, containsString("transaction-response"));
|
||||
|
||||
Bundle response = myFhirCtx.newXmlParser().parseResource(Bundle.class, encoded);
|
||||
assertEquals(3, response.getEntry().size());
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||
}
|
||||
|
||||
try {
|
||||
ourClient.read().resource(Patient.class).withId(id).execute();
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void beforeStartServer() throws Exception {
|
||||
if (myRestServer == null) {
|
||||
PatientResourceProvider patientRp = new PatientResourceProvider();
|
||||
patientRp.setDao(myPatientDao);
|
||||
|
||||
QuestionnaireResourceProviderR4 questionnaireRp = new QuestionnaireResourceProviderR4();
|
||||
questionnaireRp.setDao(myQuestionnaireDao);
|
||||
|
||||
ObservationResourceProvider observationRp = new ObservationResourceProvider();
|
||||
observationRp.setDao(myObservationDao);
|
||||
|
||||
OrganizationResourceProvider organizationRp = new OrganizationResourceProvider();
|
||||
organizationRp.setDao(myOrganizationDao);
|
||||
|
||||
RestfulServer restServer = new RestfulServer(ourCtx);
|
||||
restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp);
|
||||
|
||||
restServer.setPlainProviders(mySystemProvider);
|
||||
|
||||
int myPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(myPort);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ourServerBase = "http://localhost:" + myPort + "/fhir/context";
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(restServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
|
||||
ourCtx = FhirContext.forR4();
|
||||
restServer.setFhirContext(ourCtx);
|
||||
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourHttpClient = builder.build();
|
||||
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(600 * 1000);
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.setLogRequestAndResponse(true);
|
||||
myRestServer = restServer;
|
||||
}
|
||||
|
||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||
myRestServer.setPagingProvider(myPagingProvider);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
mySimpleHeaderInterceptor = new SimpleRequestHeaderInterceptor();
|
||||
ourClient.registerInterceptor(mySimpleHeaderInterceptor);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testResponseUsesCorrectContentType() throws Exception {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase);
|
||||
// get.addHeader("Accept", "application/xml, text/html");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
assertThat(http.getFirstHeader("Content-Type").getValue(), containsString("application/fhir+json"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FOrmat has changed, source is no longer valid
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateUsingIncomingResources() throws Exception {
|
||||
FhirInstanceValidator val = new FhirInstanceValidator(myValidationSupport);
|
||||
RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor();
|
||||
interceptor.addValidatorModule(val);
|
||||
interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
interceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
myRestServer.registerInterceptor(interceptor);
|
||||
try {
|
||||
|
||||
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/questionnaire-sdc-profile-example-ussg-fht.xml");
|
||||
String bundleStr = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
|
||||
HttpPost req = new HttpPost(ourServerBase);
|
||||
req.setEntity(new StringEntity(bundleStr, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||
|
||||
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
||||
try {
|
||||
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(encoded);
|
||||
|
||||
//@formatter:off
|
||||
assertThat(encoded, containsString("Questionnaire/54127-6/_history/"));
|
||||
//@formatter:on
|
||||
|
||||
for (Header next : resp.getHeaders(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_NAME)) {
|
||||
ourLog.info(next.toString());
|
||||
}
|
||||
} finally {
|
||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||
}
|
||||
} finally {
|
||||
myRestServer.unregisterInterceptor(interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingReturnsCorrectFormatInPagingLink() throws Exception {
|
||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
myRestServer.setPagingProvider(new FifoMemoryPagingProvider(1).setDefaultPageSize(10));
|
||||
ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor();
|
||||
myRestServer.registerInterceptor(interceptor);
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("Name" + i);
|
||||
ourClient.create().resource(p).execute();
|
||||
}
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
|
||||
get.addHeader("Accept", "application/xml, text/html");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
|
||||
try {
|
||||
String response = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(response);
|
||||
assertThat(response, containsString("_format=json"));
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
|
||||
myRestServer.unregisterInterceptor(interceptor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingReturnsCorrectBundleType() throws Exception {
|
||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
myRestServer.setPagingProvider(new FifoMemoryPagingProvider(1).setDefaultPageSize(10));
|
||||
ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor();
|
||||
myRestServer.registerInterceptor(interceptor);
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("Name" + i);
|
||||
ourClient.create().resource(p).execute();
|
||||
}
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
|
||||
get.addHeader("Accept", "application/xml+fhir");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
try {
|
||||
String response = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(response);
|
||||
assertThat(response, not(containsString("_format")));
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle responseBundle = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
assertEquals(BundleType.SEARCHSET, responseBundle.getTypeElement().getValue());
|
||||
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
|
||||
myRestServer.unregisterInterceptor(interceptor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingType() throws Exception {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkResourcesForReindexing() throws Exception {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/$mark-all-resources-for-reindexing");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
try {
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(output);
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(http);;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
@Test
|
||||
public void testSuggestKeywords() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("testSuggest");
|
||||
IIdType ptId = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
|
||||
obs.getSubject().setReferenceElement(ptId);
|
||||
IIdType obsId = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.setId(obsId);
|
||||
obs.getSubject().setReferenceElement(ptId);
|
||||
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
|
||||
myObservationDao.update(obs, mySrd);
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/$suggest-keywords?context=Patient/" + ptId.getIdPart() + "/$everything&searchParam=_content&text=zxc&_pretty=true&_format=xml");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(output);
|
||||
|
||||
Parameters parameters = ourCtx.newXmlParser().parseResource(Parameters.class, output);
|
||||
assertEquals(2, parameters.getParameter().size());
|
||||
assertEquals("keyword", parameters.getParameter().get(0).getPart().get(0).getName());
|
||||
assertEquals(("ZXCVBNM"), ((StringType) parameters.getParameter().get(0).getPart().get(0).getValue()).getValueAsString());
|
||||
assertEquals("score", parameters.getParameter().get(0).getPart().get(1).getName());
|
||||
assertEquals(("1.0"), ((DecimalType) parameters.getParameter().get(0).getPart().get(1).getValue()).getValueAsString());
|
||||
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestKeywordsInvalid() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("testSuggest");
|
||||
IIdType ptId = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getSubject().setReferenceElement(ptId);
|
||||
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
|
||||
myObservationDao.create(obs, mySrd);
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/$suggest-keywords");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(400, http.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(output);
|
||||
assertThat(output, containsString("Parameter 'context' must be provided"));
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
|
||||
get = new HttpGet(ourServerBase + "/$suggest-keywords?context=Patient/" + ptId.getIdPart() + "/$everything");
|
||||
http = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(400, http.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(output);
|
||||
assertThat(output, containsString("Parameter 'searchParam' must be provided"));
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
|
||||
get = new HttpGet(ourServerBase + "/$suggest-keywords?context=Patient/" + ptId.getIdPart() + "/$everything&searchParam=aa");
|
||||
http = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(400, http.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(output);
|
||||
assertThat(output, containsString("Parameter 'text' must be provided"));
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOperationDefinition() {
|
||||
OperationDefinition op = ourClient.read(OperationDefinition.class, "-s-get-resource-counts");
|
||||
assertEquals("get-resource-counts", op.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle() throws Exception {
|
||||
InputStream bundleRes = SystemProviderR4Test.class.getResourceAsStream("/transaction_link_patient_eve.xml");
|
||||
String bundle = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
ourLog.info(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithIncompleteBundle() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
patient.setGender(AdministrativeGender.MALE);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
bundle.addEntry().setResource(patient);
|
||||
|
||||
try {
|
||||
ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertThat(e.toString(), containsString("missing or invalid HTTP Verb"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle2() throws Exception {
|
||||
|
||||
InputStream bundleRes = SystemProviderR4Test.class.getResourceAsStream("/transaction_link_patient_eve_temp.xml");
|
||||
String bundle = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
ourLog.info(response);
|
||||
|
||||
Bundle resp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
IdType id1_1 = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals("Provenance", id1_1.getResourceType());
|
||||
IdType id1_2 = new IdType(resp.getEntry().get(1).getResponse().getLocation());
|
||||
IdType id1_3 = new IdType(resp.getEntry().get(2).getResponse().getLocation());
|
||||
IdType id1_4 = new IdType(resp.getEntry().get(3).getResponse().getLocation());
|
||||
|
||||
/*
|
||||
* Same bundle!
|
||||
*/
|
||||
|
||||
bundleRes = SystemProviderR4Test.class.getResourceAsStream("/transaction_link_patient_eve_temp.xml");
|
||||
bundle = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
response = ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
ourLog.info(response);
|
||||
|
||||
resp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
IdType id2_1 = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||
IdType id2_2 = new IdType(resp.getEntry().get(1).getResponse().getLocation());
|
||||
IdType id2_3 = new IdType(resp.getEntry().get(2).getResponse().getLocation());
|
||||
IdType id2_4 = new IdType(resp.getEntry().get(3).getResponse().getLocation());
|
||||
|
||||
assertNotEquals(id1_1.toVersionless(), id2_1.toVersionless());
|
||||
assertEquals("Provenance", id2_1.getResourceType());
|
||||
assertEquals(id1_2.toVersionless(), id2_2.toVersionless());
|
||||
assertEquals(id1_3.toVersionless(), id2_3.toVersionless());
|
||||
assertEquals(id1_4.toVersionless(), id2_4.toVersionless());
|
||||
}
|
||||
|
||||
/**
|
||||
* This is Gramahe's test transaction - it requires some set up in order to work
|
||||
*/
|
||||
// @Test
|
||||
public void testTransactionFromBundle3() throws Exception {
|
||||
|
||||
InputStream bundleRes = SystemProviderR4Test.class.getResourceAsStream("/grahame-transaction.xml");
|
||||
String bundle = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
ourLog.info(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle4() throws Exception {
|
||||
InputStream bundleRes = SystemProviderR4Test.class.getResourceAsStream("/simone_bundle.xml");
|
||||
String bundle = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
ourLog.info(response);
|
||||
Bundle bundleResp = ourCtx.newXmlParser().parseResource(Bundle.class, response);
|
||||
IdType id = new IdType(bundleResp.getEntry().get(0).getResponse().getLocation());
|
||||
assertEquals("Patient", id.getResourceType());
|
||||
assertTrue(id.hasIdPart());
|
||||
assertTrue(id.isIdPartValidLong());
|
||||
assertTrue(id.hasVersionIdPart());
|
||||
assertTrue(id.isVersionIdPartValidLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle5() throws Exception {
|
||||
InputStream bundleRes = SystemProviderR4Test.class.getResourceAsStream("/simone_bundle2.xml");
|
||||
String bundle = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
try {
|
||||
ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
|
||||
assertEquals("Invalid placeholder ID found: uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'", oo.getIssue().get(0).getDiagnostics());
|
||||
assertEquals("processing", oo.getIssue().get(0).getCode().toCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionFromBundle6() throws Exception {
|
||||
InputStream bundleRes = SystemProviderR4Test.class.getResourceAsStream("/simone_bundle3.xml");
|
||||
String bundle = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||
ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||
// try {
|
||||
// fail();
|
||||
// } catch (InvalidRequestException e) {
|
||||
// OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
|
||||
// assertEquals("Invalid placeholder ID found: uri:uuid:bb0cd4bc-1839-4606-8c46-ba3069e69b1d - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'", oo.getIssue().get(0).getDiagnostics());
|
||||
// assertEquals("processing", oo.getIssue().get(0).getCode());
|
||||
// }
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionSearch() throws Exception {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT_" + i);
|
||||
myPatientDao.create(p, mySrd);
|
||||
}
|
||||
|
||||
Bundle req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl("Patient?");
|
||||
Bundle resp = ourClient.transaction().withBundle(req).execute();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
assertEquals(1, resp.getEntry().size());
|
||||
Bundle respSub = (Bundle) resp.getEntry().get(0).getResource();
|
||||
assertEquals("self", respSub.getLink().get(0).getRelation());
|
||||
assertEquals(ourServerBase + "/Patient", respSub.getLink().get(0).getUrl());
|
||||
assertEquals("next", respSub.getLink().get(1).getRelation());
|
||||
assertThat(respSub.getLink().get(1).getUrl(), containsString("/fhir/context?_getpages"));
|
||||
assertThat(respSub.getEntry().get(0).getFullUrl(), startsWith(ourServerBase + "/Patient/"));
|
||||
assertEquals(Patient.class, respSub.getEntry().get(0).getResource().getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCount() throws Exception {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PATIENT_" + i);
|
||||
myPatientDao.create(p, mySrd);
|
||||
}
|
||||
|
||||
Bundle req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl("Patient?_summary=count");
|
||||
Bundle resp = ourClient.transaction().withBundle(req).execute();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||
|
||||
assertEquals(1, resp.getEntry().size());
|
||||
Bundle respSub = (Bundle) resp.getEntry().get(0).getResource();
|
||||
assertEquals(20, respSub.getTotal());
|
||||
assertEquals(0, respSub.getEntry().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateWithPreferHeader() throws Exception {
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
|
||||
Bundle req;
|
||||
Bundle resp;
|
||||
|
||||
// No prefer header
|
||||
req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||
resp = ourClient.transaction().withBundle(req).execute();
|
||||
assertEquals(null, resp.getEntry().get(0).getResource());
|
||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||
|
||||
// Prefer return=minimal
|
||||
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
||||
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_MINIMAL);
|
||||
req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||
resp = ourClient.transaction().withBundle(req).execute();
|
||||
assertEquals(null, resp.getEntry().get(0).getResource());
|
||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||
|
||||
// Prefer return=representation
|
||||
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
||||
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_REPRESENTATION);
|
||||
req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||
resp = ourClient.transaction().withBundle(req).execute();
|
||||
assertEquals(Patient.class, resp.getEntry().get(0).getResource().getClass());
|
||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Bundle.*;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.rp.r4.*;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SystemProviderTransactionSearchR4Test extends BaseJpaR4Test {
|
||||
|
||||
private static RestfulServer myRestServer;
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static CloseableHttpClient ourHttpClient;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SystemProviderTransactionSearchR4Test.class);
|
||||
private static Server ourServer;
|
||||
private static String ourServerBase;
|
||||
private SimpleRequestHeaderInterceptor mySimpleHeaderInterceptor;
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
myDaoConfig.setMaximumSearchResultCountInTransaction(new DaoConfig().getMaximumSearchResultCountInTransaction());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
mySimpleHeaderInterceptor = new SimpleRequestHeaderInterceptor();
|
||||
ourClient.registerInterceptor(mySimpleHeaderInterceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeStartServer() throws Exception {
|
||||
if (myRestServer == null) {
|
||||
PatientResourceProvider patientRp = new PatientResourceProvider();
|
||||
patientRp.setDao(myPatientDao);
|
||||
|
||||
QuestionnaireResourceProviderR4 questionnaireRp = new QuestionnaireResourceProviderR4();
|
||||
questionnaireRp.setDao(myQuestionnaireDao);
|
||||
|
||||
ObservationResourceProvider observationRp = new ObservationResourceProvider();
|
||||
observationRp.setDao(myObservationDao);
|
||||
|
||||
OrganizationResourceProvider organizationRp = new OrganizationResourceProvider();
|
||||
organizationRp.setDao(myOrganizationDao);
|
||||
|
||||
RestfulServer restServer = new RestfulServer(ourCtx);
|
||||
restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp);
|
||||
|
||||
restServer.setPlainProviders(mySystemProvider);
|
||||
|
||||
int myPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(myPort);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ourServerBase = "http://localhost:" + myPort + "/fhir/context";
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(restServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
|
||||
ourCtx = FhirContext.forR4();
|
||||
restServer.setFhirContext(ourCtx);
|
||||
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourHttpClient = builder.build();
|
||||
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(600 * 1000);
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.setLogRequestAndResponse(true);
|
||||
myRestServer = restServer;
|
||||
}
|
||||
|
||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||
myRestServer.setPagingProvider(myPagingProvider);
|
||||
}
|
||||
|
||||
|
||||
private List<String> create20Patients() {
|
||||
List<String> ids = new ArrayList<String>();
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Patient patient = new Patient();
|
||||
patient.setGender(AdministrativeGender.MALE);
|
||||
patient.addIdentifier().setSystem("urn:foo").setValue("A");
|
||||
patient.addName().setFamily("abcdefghijklmnopqrstuvwxyz".substring(i, i+1));
|
||||
String id = myPatientDao.create(patient).getId().toUnqualifiedVersionless().getValue();
|
||||
ids.add(id);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchWithGetHardLimitLargeSynchronous() throws Exception {
|
||||
List<String> ids = create20Patients();
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.BATCH);
|
||||
input
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?_count=5");
|
||||
|
||||
myDaoConfig.setMaximumSearchResultCountInTransaction(100);
|
||||
|
||||
Bundle output = ourClient.transaction().withBundle(input).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(1, output.getEntry().size());
|
||||
Bundle respBundle = (Bundle) output.getEntry().get(0).getResource();
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
assertEquals(null, respBundle.getLink("next"));
|
||||
List<String> actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(0, 5).toArray(new String[0])));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchWithGetNormalSearch() throws Exception {
|
||||
List<String> ids = create20Patients();
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.BATCH);
|
||||
input
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?_count=5&_sort=name");
|
||||
|
||||
Bundle output = ourClient.transaction().withBundle(input).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(1, output.getEntry().size());
|
||||
Bundle respBundle = (Bundle) output.getEntry().get(0).getResource();
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
List<String> actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(0, 5).toArray(new String[0])));
|
||||
|
||||
String nextPageLink = respBundle.getLink("next").getUrl();
|
||||
output = ourClient.loadPage().byUrl(nextPageLink).andReturnBundle(Bundle.class).execute();
|
||||
respBundle = output;
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(5, 10).toArray(new String[0])));
|
||||
}
|
||||
|
||||
/**
|
||||
* 30 searches in one batch! Whoa!
|
||||
*/
|
||||
@Test
|
||||
public void testBatchWithManyGets() throws Exception {
|
||||
List<String> ids = create20Patients();
|
||||
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.BATCH);
|
||||
for (int i = 0; i < 30; i++) {
|
||||
input
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?_count=5&identifier=urn:foo|A,AAAAA" + i);
|
||||
}
|
||||
|
||||
Bundle output = ourClient.transaction().withBundle(input).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(30, output.getEntry().size());
|
||||
for (int i = 0; i < 30; i++) {
|
||||
Bundle respBundle = (Bundle) output.getEntry().get(i).getResource();
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
assertThat(respBundle.getLink("next").getUrl(), not(nullValue()));
|
||||
List<String> actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(0, 5).toArray(new String[0])));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithGetHardLimitLargeSynchronous() throws Exception {
|
||||
List<String> ids = create20Patients();
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
input
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?_count=5");
|
||||
|
||||
myDaoConfig.setMaximumSearchResultCountInTransaction(100);
|
||||
|
||||
Bundle output = ourClient.transaction().withBundle(input).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(1, output.getEntry().size());
|
||||
Bundle respBundle = (Bundle) output.getEntry().get(0).getResource();
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
assertEquals(null, respBundle.getLink("next"));
|
||||
List<String> actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(0, 5).toArray(new String[0])));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithGetNormalSearch() throws Exception {
|
||||
List<String> ids = create20Patients();
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
input
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?_count=5&_sort=name");
|
||||
|
||||
Bundle output = ourClient.transaction().withBundle(input).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(1, output.getEntry().size());
|
||||
Bundle respBundle = (Bundle) output.getEntry().get(0).getResource();
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
List<String> actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(0, 5).toArray(new String[0])));
|
||||
|
||||
String nextPageLink = respBundle.getLink("next").getUrl();
|
||||
output = ourClient.loadPage().byUrl(nextPageLink).andReturnBundle(Bundle.class).execute();
|
||||
respBundle = output;
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(5, 10).toArray(new String[0])));
|
||||
}
|
||||
|
||||
/**
|
||||
* 30 searches in one Transaction! Whoa!
|
||||
*/
|
||||
@Test
|
||||
public void testTransactionWithManyGets() throws Exception {
|
||||
List<String> ids = create20Patients();
|
||||
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
for (int i = 0; i < 30; i++) {
|
||||
input
|
||||
.addEntry()
|
||||
.getRequest()
|
||||
.setMethod(HTTPVerb.GET)
|
||||
.setUrl("Patient?_count=5&identifier=urn:foo|A,AAAAA" + i);
|
||||
}
|
||||
|
||||
Bundle output = ourClient.transaction().withBundle(input).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(30, output.getEntry().size());
|
||||
for (int i = 0; i < 30; i++) {
|
||||
Bundle respBundle = (Bundle) output.getEntry().get(i).getResource();
|
||||
assertEquals(5, respBundle.getEntry().size());
|
||||
assertThat(respBundle.getLink("next").getUrl(), not(nullValue()));
|
||||
List<String> actualIds = toIds(respBundle);
|
||||
assertThat(actualIds, contains(ids.subList(0, 5).toArray(new String[0])));
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> toIds(Bundle theRespBundle) {
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (BundleEntryComponent next : theRespBundle.getEntry()) {
|
||||
retVal.add(next.getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.r4.model.Attachment;
|
||||
import org.hl7.fhir.r4.model.IntegerType;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.UriType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class TerminologyUploaderProviderR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyUploaderProviderR4Test.class);
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testUploadSct() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadLoinc() throws Exception {
|
||||
byte[] packageBytes = createLoincZip();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URL))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
|
||||
/*
|
||||
* Try uploading a second time
|
||||
*/
|
||||
|
||||
//@formatter:off
|
||||
respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.LOINC_URL))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadSctLocalFile() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
File tempFile = File.createTempFile("tmp", ".zip");
|
||||
tempFile.deleteOnExit();
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(tempFile);
|
||||
fos.write(packageBytes);
|
||||
fos.close();
|
||||
|
||||
//@formatter:off
|
||||
Parameters respParam = ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
|
||||
.andParameter("localfile", new StringType(tempFile.getAbsolutePath()))
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
|
||||
ourLog.info(resp);
|
||||
|
||||
assertThat(((IntegerType)respParam.getParameter().get(0).getValue()).getValue(), greaterThan(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadInvalidUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL + "FOO"))
|
||||
.andParameter("package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: http://snomed.info/sctFOO", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingUrl() throws Exception {
|
||||
byte[] packageBytes = createSctZip();
|
||||
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "package", new Attachment().setData(packageBytes))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Unknown URL: ", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUploadMissingPackage() throws Exception {
|
||||
//@formatter:off
|
||||
try {
|
||||
ourClient
|
||||
.operation()
|
||||
.onServer()
|
||||
.named("upload-external-code-system")
|
||||
.withParameter(Parameters.class, "url", new UriType(IHapiTerminologyLoaderSvc.SCT_URL))
|
||||
.execute();
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: No 'localfile' or 'package' parameter, or package had no data", e.getMessage());
|
||||
}
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private byte[] createSctZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
||||
List<String> inputNames = Arrays.asList("sct2_Concept_Full_INT_20160131.txt","sct2_Concept_Full-en_INT_20160131.txt","sct2_Description_Full-en_INT_20160131.txt","sct2_Identifier_Full_INT_20160131.txt","sct2_Relationship_Full_INT_20160131.txt","sct2_StatedRelationship_Full_INT_20160131.txt","sct2_TextDefinition_Full-en_INT_20160131.txt");
|
||||
for (String nextName : inputNames) {
|
||||
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + nextName));
|
||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/sct/" + nextName)));
|
||||
}
|
||||
zos.close();
|
||||
byte[] packageBytes = bos.toByteArray();
|
||||
return packageBytes;
|
||||
}
|
||||
|
||||
private byte[] createLoincZip() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zos = new ZipOutputStream(bos);
|
||||
|
||||
zos.putNextEntry(new ZipEntry("loinc.csv"));
|
||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/loinc.csv")));
|
||||
zos.putNextEntry(new ZipEntry("LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV"));
|
||||
zos.write(IOUtils.toByteArray(getClass().getResourceAsStream("/loinc/LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV")));
|
||||
zos.close();
|
||||
|
||||
byte[] packageBytes = bos.toByteArray();
|
||||
return packageBytes;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package ca.uhn.fhir.jpa.search.r4;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.leftPad;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.*;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
|
||||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class PagingMultinodeProviderR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private SearchCoordinatorSvcImpl mySearchCoordinatorSvcRaw;
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
|
||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
|
||||
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(null);
|
||||
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(SearchCoordinatorSvcImpl.DEFAULT_SYNC_SIZE);
|
||||
mySearchCoordinatorSvcRaw.setNeverUseLocalSearchForUnitTests(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
|
||||
mySearchCoordinatorSvcRaw = AopTestUtils.getTargetObject(mySearchCoordinatorSvc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() {
|
||||
{
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Patient patient = new Patient();
|
||||
String id = "A" + leftPad(Integer.toString(i), 3, '0');
|
||||
patient.setId(id);
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("A" + i);
|
||||
patient.addName().setFamily(id);
|
||||
myPatientDao.update(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
}
|
||||
|
||||
Bundle found;
|
||||
|
||||
mySearchCoordinatorSvcRaw.setLoadingThrottleForUnitTests(50);
|
||||
mySearchCoordinatorSvcRaw.setSyncSizeForUnitTests(10);
|
||||
mySearchCoordinatorSvcRaw.setNeverUseLocalSearchForUnitTests(true);
|
||||
|
||||
found = ourClient
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.sort().ascending(Patient.SP_FAMILY)
|
||||
.count(10)
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), contains("Patient/A000", "Patient/A001", "Patient/A002", "Patient/A003", "Patient/A004", "Patient/A005", "Patient/A006", "Patient/A007", "Patient/A008", "Patient/A009"));
|
||||
|
||||
found = ourClient
|
||||
.loadPage()
|
||||
.next(found)
|
||||
.execute();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), contains("Patient/A010", "Patient/A011", "Patient/A012", "Patient/A013", "Patient/A014", "Patient/A015", "Patient/A016", "Patient/A017", "Patient/A018", "Patient/A019"));
|
||||
|
||||
found = ourClient
|
||||
.loadPage()
|
||||
.next(found)
|
||||
.execute();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), contains("Patient/A020", "Patient/A021", "Patient/A022", "Patient/A023", "Patient/A024", "Patient/A025", "Patient/A026", "Patient/A027", "Patient/A028", "Patient/A029"));
|
||||
|
||||
found = ourClient
|
||||
.loadPage()
|
||||
.next(found)
|
||||
.execute();
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), contains("Patient/A030", "Patient/A031", "Patient/A032", "Patient/A033", "Patient/A034", "Patient/A035", "Patient/A036", "Patient/A037", "Patient/A038", "Patient/A039"));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
|
||||
public class FhirR4Util {
|
||||
|
||||
public static final String LPI_CODESYSTEM = "http://cognitivemedicine.com/lpi";
|
||||
public static final String LPI_CODE = "LPI-FHIR";
|
||||
|
||||
public static Subscription createSubscription(String criteria, String payload, String endpoint, IGenericClient client) {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED);
|
||||
subscription.setCriteria(criteria);
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setPayload(payload);
|
||||
channel.setEndpoint(endpoint);
|
||||
subscription.setChannel(channel);
|
||||
|
||||
MethodOutcome methodOutcome = client.create().resource(subscription).execute();
|
||||
subscription.setId(methodOutcome.getId().getIdPart());
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public static Observation getSnomedObservation() {
|
||||
Coding snomedCoding = new Coding();
|
||||
snomedCoding.setSystem("SNOMED-CT");
|
||||
snomedCoding.setCode("1000000050");
|
||||
|
||||
Observation observation = new Observation();
|
||||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
observation.getCode().addCoding(snomedCoding);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
||||
public static Observation getLoincObservation() {
|
||||
Coding snomedCoding = new Coding();
|
||||
snomedCoding.setSystem("http://loinc.org");
|
||||
snomedCoding.setCode("55284-4");
|
||||
snomedCoding.setDisplay("Blood Pressure");
|
||||
|
||||
Observation observation = new Observation();
|
||||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
observation.getCode().addCoding(snomedCoding);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a patient object for the test
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Patient getPatient() {
|
||||
String patientId = "1";
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
|
||||
Identifier identifier = patient.addIdentifier();
|
||||
identifier.setValue(patientId);
|
||||
identifier.setSystem(LPI_CODESYSTEM);
|
||||
|
||||
IBaseMetaType meta = patient.getMeta();
|
||||
IBaseCoding tag = meta.addTag();
|
||||
tag.setCode(LPI_CODE);
|
||||
tag.setSystem(LPI_CODESYSTEM);
|
||||
setTag(patient);
|
||||
return patient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tag for a resource
|
||||
*
|
||||
* @param resource
|
||||
*/
|
||||
public static void setTag(IBaseResource resource) {
|
||||
IBaseMetaType meta = resource.getMeta();
|
||||
IBaseCoding tag = meta.addTag();
|
||||
tag.setCode(LPI_CODE);
|
||||
tag.setSystem(LPI_CODESYSTEM);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
|
||||
import ca.uhn.fhir.jpa.subscription.SocketImplementation;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
|
||||
/**
|
||||
* Adds a FHIR subscription with criteria through the rest interface. Then creates a websocket with the id of the
|
||||
* subscription
|
||||
* <p>
|
||||
* Note: This test only returns a ping with the subscription id, Check FhirSubscriptionWithSubscriptionIdR4Test for
|
||||
* a test that returns the xml of the observation
|
||||
* <p>
|
||||
* To execute the following test, execute it the following way:
|
||||
* 0. execute 'clean' test
|
||||
* 1. Execute the 'createPatient' test
|
||||
* 2. Update the patient id static variable
|
||||
* 3. Execute the 'createSubscription' test
|
||||
* 4. Update the subscription id static variable
|
||||
* 5. Execute the 'attachWebSocket' test
|
||||
* 6. Execute the 'sendObservation' test
|
||||
* 7. Look in the 'attachWebSocket' terminal execution and wait for your ping with the subscription id
|
||||
*/
|
||||
public class FhirSubscriptionWithCriteriaR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSubscriptionWithCriteriaR4Test.class);
|
||||
|
||||
private String myPatientId;
|
||||
private String mySubscriptionId;
|
||||
private WebSocketClient myWebSocketClient;
|
||||
private SocketImplementation mySocketImplementation;
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
myDaoConfig.setSubscriptionEnabled(new DaoConfig().isSubscriptionEnabled());
|
||||
myDaoConfig.setSubscriptionPollDelay(new DaoConfig().getSubscriptionPollDelay());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
myDaoConfig.setSubscriptionEnabled(true);
|
||||
myDaoConfig.setSubscriptionPollDelay(0L);
|
||||
|
||||
/*
|
||||
* Create patient
|
||||
*/
|
||||
|
||||
Patient patient = FhirR4Util.getPatient();
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(patient).execute();
|
||||
myPatientId = methodOutcome.getId().getIdPart();
|
||||
|
||||
/*
|
||||
* Create subscription
|
||||
*/
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
// subscription.setCriteria("Observation?subject=Patient/" + PATIENT_ID);
|
||||
subscription.setCriteria("Observation?code=SNOMED-CT|82313006&_format=xml");
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.WEBSOCKET);
|
||||
channel.setPayload("application/json");
|
||||
subscription.setChannel(channel);
|
||||
|
||||
methodOutcome = ourClient.create().resource(subscription).execute();
|
||||
mySubscriptionId = methodOutcome.getId().getIdPart();
|
||||
|
||||
/*
|
||||
* Attach websocket
|
||||
*/
|
||||
|
||||
myWebSocketClient = new WebSocketClient();
|
||||
mySocketImplementation = new SocketImplementation(mySubscriptionId, EncodingEnum.JSON);
|
||||
|
||||
myWebSocketClient.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + "/websocket/r4");
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request);
|
||||
Session session = connection.get(2, TimeUnit.SECONDS);
|
||||
|
||||
ourLog.info("Connected to WS: {}", session.isOpen());
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterCloseWebsocket() throws Exception {
|
||||
ourLog.info("Shutting down websocket client");
|
||||
myWebSocketClient.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createObservation() throws Exception {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode("82313006");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
Reference reference = new Reference();
|
||||
reference.setReference("Patient/" + myPatientId);
|
||||
observation.setSubject(reference);
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome2 = ourClient.create().resource(observation).execute();
|
||||
String observationId = methodOutcome2.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
|
||||
ourLog.info("Observation id generated by server is: " + observationId);
|
||||
|
||||
int changes = mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
ourLog.info("Polling showed {}", changes);
|
||||
assertEquals(1, changes);
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
ourLog.info("WS Messages: {}", mySocketImplementation.getMessages());
|
||||
assertThat(mySocketImplementation.getMessages(), contains("bound " + mySubscriptionId, "ping " + mySubscriptionId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createObservationThatDoesNotMatch() throws Exception {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode("8231");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
Reference reference = new Reference();
|
||||
reference.setReference("Patient/" + myPatientId);
|
||||
observation.setSubject(reference);
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome2 = ourClient.create().resource(observation).execute();
|
||||
String observationId = methodOutcome2.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
|
||||
ourLog.info("Observation id generated by server is: " + observationId);
|
||||
|
||||
int changes = mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
ourLog.info("Polling showed {}", changes);
|
||||
assertEquals(0, changes);
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
ourLog.info("WS Messages: {}", mySocketImplementation.getMessages());
|
||||
assertThat(mySocketImplementation.getMessages(), contains("bound " + mySubscriptionId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
|
||||
import ca.uhn.fhir.jpa.subscription.SocketImplementation;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
|
||||
/**
|
||||
* Adds a FHIR subscription with criteria through the rest interface. Then creates a websocket with the id of the
|
||||
* subscription
|
||||
* <p>
|
||||
* Note: This test only returns a ping with the subscription id, Check FhirSubscriptionWithSubscriptionIdR4Test for
|
||||
* a test that returns the xml of the observation
|
||||
* <p>
|
||||
* To execute the following test, execute it the following way:
|
||||
* 0. execute 'clean' test
|
||||
* 1. Execute the 'createPatient' test
|
||||
* 2. Update the patient id static variable
|
||||
* 3. Execute the 'createSubscription' test
|
||||
* 4. Update the subscription id static variable
|
||||
* 5. Execute the 'attachWebSocket' test
|
||||
* 6. Execute the 'sendObservation' test
|
||||
* 7. Look in the 'attachWebSocket' terminal execution and wait for your ping with the subscription id
|
||||
*/
|
||||
public class FhirSubscriptionWithSubscriptionIdR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSubscriptionWithSubscriptionIdR4Test.class);
|
||||
|
||||
private String myPatientId;
|
||||
private String mySubscriptionId;
|
||||
private WebSocketClient myWebSocketClient;
|
||||
private SocketImplementation mySocketImplementation;
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
myDaoConfig.setSubscriptionEnabled(new DaoConfig().isSubscriptionEnabled());
|
||||
myDaoConfig.setSubscriptionPollDelay(new DaoConfig().getSubscriptionPollDelay());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
myDaoConfig.setSubscriptionEnabled(true);
|
||||
myDaoConfig.setSubscriptionPollDelay(0L);
|
||||
|
||||
/*
|
||||
* Create patient
|
||||
*/
|
||||
|
||||
Patient patient = FhirR4Util.getPatient();
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(patient).execute();
|
||||
myPatientId = methodOutcome.getId().getIdPart();
|
||||
|
||||
/*
|
||||
* Create subscription
|
||||
*/
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
// subscription.setCriteria("Observation?subject=Patient/" + PATIENT_ID);
|
||||
subscription.setCriteria("Observation?code=SNOMED-CT|82313006");
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.WEBSOCKET);
|
||||
channel.setPayload("application/json");
|
||||
subscription.setChannel(channel);
|
||||
|
||||
methodOutcome = ourClient.create().resource(subscription).execute();
|
||||
mySubscriptionId = methodOutcome.getId().getIdPart();
|
||||
|
||||
/*
|
||||
* Attach websocket
|
||||
*/
|
||||
|
||||
myWebSocketClient = new WebSocketClient();
|
||||
mySocketImplementation = new SocketImplementation(mySubscriptionId, EncodingEnum.JSON);
|
||||
|
||||
myWebSocketClient.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + "/websocket/r4");
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request);
|
||||
Session session = connection.get(2, TimeUnit.SECONDS);
|
||||
|
||||
ourLog.info("Connected to WS: {}", session.isOpen());
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterCloseWebsocket() throws Exception {
|
||||
ourLog.info("Shutting down websocket client");
|
||||
myWebSocketClient.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createObservation() throws Exception {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode("82313006");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
Reference reference = new Reference();
|
||||
reference.setReference("Patient/" + myPatientId);
|
||||
observation.setSubject(reference);
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome2 = ourClient.create().resource(observation).execute();
|
||||
String observationId = methodOutcome2.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
|
||||
ourLog.info("Observation id generated by server is: " + observationId);
|
||||
|
||||
int changes = mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
ourLog.info("Polling showed {}", changes);
|
||||
assertEquals(1, changes);
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
ourLog.info("WS Messages: {}", mySocketImplementation.getMessages());
|
||||
assertThat(mySocketImplementation.getMessages(), contains("bound " + mySubscriptionId, "ping " + mySubscriptionId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createObservationThatDoesNotMatch() throws Exception {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode("8231");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
Reference reference = new Reference();
|
||||
reference.setReference("Patient/" + myPatientId);
|
||||
observation.setSubject(reference);
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome2 = ourClient.create().resource(observation).execute();
|
||||
String observationId = methodOutcome2.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
|
||||
ourLog.info("Observation id generated by server is: " + observationId);
|
||||
|
||||
int changes = mySubscriptionDao.pollForNewUndeliveredResources();
|
||||
ourLog.info("Polling showed {}", changes);
|
||||
assertEquals(0, changes);
|
||||
|
||||
Thread.sleep(2000);
|
||||
|
||||
ourLog.info("WS Messages: {}", mySocketImplementation.getMessages());
|
||||
assertThat(mySocketImplementation.getMessages(), contains("bound " + mySubscriptionId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,362 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
/**
|
||||
* Test the rest-hook subscriptions
|
||||
*/
|
||||
public class RestHookTestR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static List<String> ourContentTypes = new ArrayList<String>();
|
||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
||||
private static int ourListenerPort;
|
||||
private static RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestR4Test.class);
|
||||
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
|
||||
@After
|
||||
public void afterUnregisterRestHookListener() {
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
ourLog.info("Deleting all subscriptions");
|
||||
ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute();
|
||||
ourLog.info("Done deleting all subscriptions");
|
||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||
|
||||
ourRestServer.unregisterInterceptor(ourRestHookSubscriptionInterceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeRegisterRestHookListener() {
|
||||
ourRestServer.registerInterceptor(ourRestHookSubscriptionInterceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeReset() {
|
||||
ourCreatedObservations.clear();
|
||||
ourUpdatedObservations.clear();
|
||||
ourContentTypes.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionInvalidCriteria() throws Exception {
|
||||
String payload = "application/xml";
|
||||
|
||||
String criteria1 = "Observation?codeeeee=SNOMED-CT";
|
||||
|
||||
try {
|
||||
createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("HTTP 400 Bad Request: Invalid criteria: Failed to parse match URL[Observation?codeeeee=SNOMED-CT] - Resource type Observation does not have a parameter with name: codeeeee", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Subscription createSubscription(String theCriteria, String thePayload, String theEndpoint) {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
subscription.setCriteria(theCriteria);
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setPayload(thePayload);
|
||||
channel.setEndpoint(theEndpoint);
|
||||
subscription.setChannel(channel);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
|
||||
subscription.setId(methodOutcome.getId().getIdPart());
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
private Observation sendObservation(String code, String system) {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code);
|
||||
coding.setSystem(system);
|
||||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(observation).execute();
|
||||
|
||||
String observationId = methodOutcome.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionApplicationFhirJson() throws Exception {
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(1, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionApplicationJson() throws Exception {
|
||||
String payload = "application/json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
Subscription subscription1 = createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
Subscription subscription2 = createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
Observation observation1 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(1, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
||||
|
||||
Subscription subscriptionTemp = ourClient.read(Subscription.class, subscription2.getId());
|
||||
Assert.assertNotNull(subscriptionTemp);
|
||||
|
||||
subscriptionTemp.setCriteria(criteria1);
|
||||
ourClient.update().resource(subscriptionTemp).withId(subscriptionTemp.getIdElement()).execute();
|
||||
|
||||
|
||||
Observation observation2 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see two subscription notifications
|
||||
Thread.sleep(500);
|
||||
assertEquals(3, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
|
||||
|
||||
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation3.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code + "111");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3).withId(observation3.getIdElement()).execute();
|
||||
|
||||
// Should see no subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
|
||||
CodeableConcept codeableConcept1 = new CodeableConcept();
|
||||
observation3a.setCode(codeableConcept1);
|
||||
Coding coding1 = codeableConcept1.addCoding();
|
||||
coding1.setCode(code);
|
||||
coding1.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3a).withId(observation3a.getIdElement()).execute();
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(1, ourUpdatedObservations.size());
|
||||
|
||||
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
|
||||
Assert.assertFalse(observation1.getId().isEmpty());
|
||||
Assert.assertFalse(observation2.getId().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionApplicationXmlJson() throws Exception {
|
||||
String payload = "application/fhir+xml";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
Subscription subscription1 = createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
Subscription subscription2 = createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
Observation observation1 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(1, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, ourContentTypes.get(0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionApplicationXml() throws Exception {
|
||||
String payload = "application/xml";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
Subscription subscription1 = createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
Subscription subscription2 = createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
Observation observation1 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(1, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW, ourContentTypes.get(0));
|
||||
|
||||
Subscription subscriptionTemp = ourClient.read(Subscription.class, subscription2.getId());
|
||||
Assert.assertNotNull(subscriptionTemp);
|
||||
|
||||
subscriptionTemp.setCriteria(criteria1);
|
||||
ourClient.update().resource(subscriptionTemp).withId(subscriptionTemp.getIdElement()).execute();
|
||||
|
||||
|
||||
Observation observation2 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see two subscription notifications
|
||||
Thread.sleep(500);
|
||||
assertEquals(3, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
|
||||
|
||||
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation3.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code + "111");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3).withId(observation3.getIdElement()).execute();
|
||||
|
||||
// Should see no subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
|
||||
CodeableConcept codeableConcept1 = new CodeableConcept();
|
||||
observation3a.setCode(codeableConcept1);
|
||||
Coding coding1 = codeableConcept1.addCoding();
|
||||
coding1.setCode(code);
|
||||
coding1.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3a).withId(observation3a.getIdElement()).execute();
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(1, ourUpdatedObservations.size());
|
||||
|
||||
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
|
||||
Assert.assertFalse(observation1.getId().isEmpty());
|
||||
Assert.assertFalse(observation2.getId().isEmpty());
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startListenerServer() throws Exception {
|
||||
ourListenerPort = RandomServerPortProvider.findFreePort();
|
||||
ourListenerRestServer = new RestfulServer(FhirContext.forR4());
|
||||
ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context";
|
||||
|
||||
ObservationListener obsListener = new ObservationListener();
|
||||
ourListenerRestServer.setResourceProviders(obsListener);
|
||||
|
||||
ourListenerServer = new Server(ourListenerPort);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(ourListenerRestServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
|
||||
ourListenerServer.setHandler(proxyHandler);
|
||||
ourListenerServer.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopListenerServer() throws Exception {
|
||||
ourListenerServer.stop();
|
||||
}
|
||||
|
||||
public static class ObservationListener implements IResourceProvider {
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
||||
ourLog.info("Received Listener Create");
|
||||
ourContentTypes.add(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE).replaceAll(";.*", ""));
|
||||
ourCreatedObservations.add(theObservation);
|
||||
return new MethodOutcome(new IdType("Observation/1"), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Observation.class;
|
||||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(@ResourceParam Observation theObservation, HttpServletRequest theRequest) {
|
||||
ourLog.info("Received Listener Update");
|
||||
ourUpdatedObservations.add(theObservation);
|
||||
ourContentTypes.add(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE).replaceAll(";.*", ""));
|
||||
return new MethodOutcome(new IdType("Observation/1"), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.subscription.r4;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
|
||||
/**
|
||||
* Test the rest-hook subscriptions
|
||||
*/
|
||||
public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static List<Observation> ourCreatedObservations = Lists.newArrayList();
|
||||
private static int ourListenerPort;
|
||||
private static RestfulServer ourListenerRestServer;
|
||||
private static Server ourListenerServer;
|
||||
private static String ourListenerServerBase;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigR4Test.class);
|
||||
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
|
||||
|
||||
@Override
|
||||
protected boolean shouldLogClient() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterUnregisterRestHookListener() {
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
ourLog.info("Deleting all subscriptions");
|
||||
ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute();
|
||||
ourLog.info("Done deleting all subscriptions");
|
||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||
|
||||
myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeRegisterRestHookListener() {
|
||||
myDaoConfig.getInterceptors().add(ourRestHookSubscriptionInterceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeReset() {
|
||||
ourCreatedObservations.clear();
|
||||
ourUpdatedObservations.clear();
|
||||
}
|
||||
|
||||
private Subscription createSubscription(String criteria, String payload, String endpoint) {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
|
||||
subscription.setCriteria(criteria);
|
||||
|
||||
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
|
||||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setPayload(payload);
|
||||
channel.setEndpoint(endpoint);
|
||||
subscription.setChannel(channel);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
|
||||
subscription.setId(methodOutcome.getId().getIdPart());
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
private Observation sendObservation(String code, String system) {
|
||||
Observation observation = new Observation();
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code);
|
||||
coding.setSystem(system);
|
||||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(observation).execute();
|
||||
|
||||
String observationId = methodOutcome.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionJson() throws Exception {
|
||||
String payload = "application/json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
Subscription subscription1 = createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
Subscription subscription2 = createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
Observation observation1 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(1, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Subscription subscriptionTemp = ourClient.read(Subscription.class, subscription2.getId());
|
||||
Assert.assertNotNull(subscriptionTemp);
|
||||
|
||||
subscriptionTemp.setCriteria(criteria1);
|
||||
ourClient.update().resource(subscriptionTemp).withId(subscriptionTemp.getIdElement()).execute();
|
||||
|
||||
|
||||
Observation observation2 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see two subscription notifications
|
||||
Thread.sleep(500);
|
||||
assertEquals(3, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
|
||||
|
||||
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation3.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code + "111");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3).withId(observation3.getIdElement()).execute();
|
||||
|
||||
// Should see no subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
|
||||
CodeableConcept codeableConcept1 = new CodeableConcept();
|
||||
observation3a.setCode(codeableConcept1);
|
||||
Coding coding1 = codeableConcept1.addCoding();
|
||||
coding1.setCode(code);
|
||||
coding1.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3a).withId(observation3a.getIdElement()).execute();
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(1, ourUpdatedObservations.size());
|
||||
|
||||
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
|
||||
Assert.assertFalse(observation1.getId().isEmpty());
|
||||
Assert.assertFalse(observation2.getId().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionXml() throws Exception {
|
||||
String payload = "application/xml";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
Subscription subscription1 = createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
Subscription subscription2 = createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
Observation observation1 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(1, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Subscription subscriptionTemp = ourClient.read(Subscription.class, subscription2.getId());
|
||||
Assert.assertNotNull(subscriptionTemp);
|
||||
|
||||
subscriptionTemp.setCriteria(criteria1);
|
||||
ourClient.update().resource(subscriptionTemp).withId(subscriptionTemp.getIdElement()).execute();
|
||||
|
||||
|
||||
Observation observation2 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see two subscription notifications
|
||||
Thread.sleep(500);
|
||||
assertEquals(3, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
|
||||
|
||||
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation3.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code + "111");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3).withId(observation3.getIdElement()).execute();
|
||||
|
||||
// Should see no subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
|
||||
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
|
||||
CodeableConcept codeableConcept1 = new CodeableConcept();
|
||||
observation3a.setCode(codeableConcept1);
|
||||
Coding coding1 = codeableConcept1.addCoding();
|
||||
coding1.setCode(code);
|
||||
coding1.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3a).withId(observation3a.getIdElement()).execute();
|
||||
|
||||
// Should see only one subscription notification
|
||||
Thread.sleep(500);
|
||||
assertEquals(4, ourCreatedObservations.size());
|
||||
assertEquals(1, ourUpdatedObservations.size());
|
||||
|
||||
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
|
||||
Assert.assertFalse(observation1.getId().isEmpty());
|
||||
Assert.assertFalse(observation2.getId().isEmpty());
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startListenerServer() throws Exception {
|
||||
ourListenerPort = RandomServerPortProvider.findFreePort();
|
||||
ourListenerRestServer = new RestfulServer(FhirContext.forR4());
|
||||
ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context";
|
||||
|
||||
ObservationListener obsListener = new ObservationListener();
|
||||
ourListenerRestServer.setResourceProviders(obsListener);
|
||||
|
||||
ourListenerServer = new Server(ourListenerPort);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(ourListenerRestServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
|
||||
ourListenerServer.setHandler(proxyHandler);
|
||||
ourListenerServer.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopListenerServer() throws Exception {
|
||||
ourListenerServer.stop();
|
||||
}
|
||||
|
||||
public static class ObservationListener implements IResourceProvider {
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(@ResourceParam Observation theObservation) {
|
||||
ourLog.info("Received Listener Create");
|
||||
ourCreatedObservations.add(theObservation);
|
||||
return new MethodOutcome(new IdType("Observation/1"), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Observation.class;
|
||||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(@ResourceParam Observation theObservation) {
|
||||
ourLog.info("Received Listener Update");
|
||||
ourUpdatedObservations.add(theObservation);
|
||||
return new MethodOutcome(new IdType("Observation/1"), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,9 @@ import java.io.*;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.Identifier;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.exceptions.*;
|
||||
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
|
@ -109,4 +112,22 @@ public class ObjectConverter {
|
|||
return c;
|
||||
}
|
||||
|
||||
public static Identifier readAsIdentifier(Element item) {
|
||||
Identifier r = new Identifier();
|
||||
r.setSystem(item.getNamedChildValue("system"));
|
||||
r.setValue(item.getNamedChildValue("value"));
|
||||
return r;
|
||||
}
|
||||
|
||||
public static Reference readAsReference(Element item) {
|
||||
Reference r = new Reference();
|
||||
r.setDisplay(item.getNamedChildValue("display"));
|
||||
r.setReference(item.getNamedChildValue("reference"));
|
||||
List<Element> identifier = item.getChildrenByName("identifier");
|
||||
if (identifier.isEmpty() == false) {
|
||||
r.setIdentifier(readAsIdentifier(identifier.get(0)));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
|
|||
|
||||
retVal.setPublisher(myPublisher);
|
||||
retVal.setDateElement(conformanceDate());
|
||||
retVal.setFhirVersion(FhirVersionEnum.DSTU3.getFhirVersionString());
|
||||
retVal.setFhirVersion(FhirVersionEnum.R4.getFhirVersionString());
|
||||
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big
|
||||
// effort since the parser
|
||||
// needs to be modified to actually allow it
|
||||
|
|
|
@ -2,16 +2,14 @@ package org.hl7.fhir.r4.model;
|
|||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang3.time.FastDateFormat;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
public abstract class BaseDateTimeType extends PrimitiveType<Date> {
|
||||
|
|
|
@ -29,13 +29,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
package org.hl7.fhir.r4.model;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.*;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,18 +29,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
package org.hl7.fhir.r4.model;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Primitive type "date" in FHIR: any day in a gregorian calendar
|
||||
*/
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,11 +31,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
package org.hl7.fhir.r4.model;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.*;
|
||||
import java.util.zip.DataFormatException;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,16 +30,14 @@ package org.hl7.fhir.r4.model;
|
|||
*/
|
||||
|
||||
// Generated on Sat, Jul 8, 2017 23:19+1000 for FHIR v3.1.0
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.ChildOrder;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.Block;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
/**
|
||||
* A time period defined by a start and end date and optionally time.
|
||||
*/
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
package org.hl7.fhir.r4.model;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
|
||||
public enum TemporalPrecisionEnum {
|
||||
|
||||
YEAR(Calendar.YEAR) {
|
||||
@Override
|
||||
public Date add(Date theInput, int theAmount) {
|
||||
return DateUtils.addYears(theInput, theAmount);
|
||||
}
|
||||
},
|
||||
|
||||
MONTH(Calendar.MONTH) {
|
||||
@Override
|
||||
public Date add(Date theInput, int theAmount) {
|
||||
return DateUtils.addMonths(theInput, theAmount);
|
||||
}
|
||||
},
|
||||
DAY(Calendar.DATE) {
|
||||
@Override
|
||||
public Date add(Date theInput, int theAmount) {
|
||||
return DateUtils.addDays(theInput, theAmount);
|
||||
}
|
||||
},
|
||||
MINUTE(Calendar.MINUTE) {
|
||||
@Override
|
||||
public Date add(Date theInput, int theAmount) {
|
||||
return DateUtils.addMinutes(theInput, theAmount);
|
||||
}
|
||||
},
|
||||
SECOND(Calendar.SECOND) {
|
||||
@Override
|
||||
public Date add(Date theInput, int theAmount) {
|
||||
return DateUtils.addSeconds(theInput, theAmount);
|
||||
}
|
||||
},
|
||||
MILLI(Calendar.MILLISECOND) {
|
||||
@Override
|
||||
public Date add(Date theInput, int theAmount) {
|
||||
return DateUtils.addMilliseconds(theInput, theAmount);
|
||||
}
|
||||
},
|
||||
|
||||
;
|
||||
|
||||
private int myCalendarConstant;
|
||||
|
||||
TemporalPrecisionEnum(int theCalendarConstant) {
|
||||
myCalendarConstant = theCalendarConstant;
|
||||
}
|
||||
|
||||
public abstract Date add(Date theInput, int theAmount);
|
||||
|
||||
public int getCalendarConstant() {
|
||||
return myCalendarConstant;
|
||||
}
|
||||
|
||||
}
|
|
@ -166,7 +166,7 @@ public class ValueSetExpanderSimple implements ValueSetExpander {
|
|||
|
||||
private void addCodeAndDescendents(CodeSystem cs, String system, ConceptDefinitionComponent def, ValueSetExpansionContainsComponent parent, ExpansionProfile profile, List<ValueSet> filters)
|
||||
throws FHIRException {
|
||||
def.checkNoModifiers("Code in Code System", "expanding");
|
||||
// def.checkNoModifiers("Code in Code System", "expanding");
|
||||
if (!CodeSystemUtilities.isDeprecated(cs, def)) {
|
||||
ValueSetExpansionContainsComponent np = null;
|
||||
boolean abs = CodeSystemUtilities.isNotSelectable(cs, def);
|
||||
|
|
|
@ -1,54 +1,23 @@
|
|||
package org.hl7.fhir.r4.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import org.hl7.fhir.exceptions.*;
|
||||
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.elementmodel.ObjectConverter;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.DateTimeType;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.DecimalType;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode.CollectionStatus;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode.Function;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode.Kind;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode.Operation;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode.SourceLocation;
|
||||
import org.hl7.fhir.r4.model.IntegerType;
|
||||
import org.hl7.fhir.r4.model.Property;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ExpressionNode.*;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.r4.model.TemporalPrecisionEnum;
|
||||
import org.hl7.fhir.r4.model.TimeType;
|
||||
import org.hl7.fhir.r4.model.TypeDetails;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.TypeDetails.ProfiledType;
|
||||
import org.hl7.fhir.r4.utils.FHIRLexer.FHIRLexerException;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.exceptions.UcumException;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.ucum.Decimal;
|
||||
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ public class ClientR4Test {
|
|||
HttpPost post = (HttpPost) capt.getValue();
|
||||
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
|
||||
assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue());
|
||||
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
|
||||
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
|
||||
assertEquals("200", response.getId().getVersionIdPart());
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1038,7 @@ public class ClientR4Test {
|
|||
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
|
||||
assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue());
|
||||
assertEquals("200", response.getId().getVersionIdPart());
|
||||
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
|
||||
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1058,15 +1058,14 @@ public class ClientR4Test {
|
|||
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray(Constants.HEADER_LOCATION, "http://example.com/fhir/Patient/100/_history/200"));
|
||||
|
||||
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
client.updatePatient(new IdType("Patient/100/_history/200"), patient);
|
||||
MethodOutcome resp = client.updatePatient(new IdType("Patient/100/_history/200"), patient);
|
||||
assertNull(resp.getResource());
|
||||
assertNull(resp.getOperationOutcome());
|
||||
|
||||
assertEquals(HttpPut.class, capt.getValue().getClass());
|
||||
HttpPut post = (HttpPut) capt.getValue();
|
||||
assertEquals("http://foo/Patient/100", post.getURI().toASCIIString());
|
||||
|
||||
Header h = post.getFirstHeader(Constants.HEADER_LOCATION);
|
||||
assertEquals("Patient/100/_history/200", h.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = ResourceVersionConflictException.class)
|
||||
|
@ -1105,7 +1104,6 @@ public class ClientR4Test {
|
|||
HttpPut post = (HttpPut) capt.getValue();
|
||||
assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/100"));
|
||||
assertThat(IOUtils.toString(post.getEntity().getContent(), Charsets.UTF_8), StringContains.containsString("<Patient"));
|
||||
assertThat(post.getFirstHeader(Constants.HEADER_LOCATION).getValue(), StringEndsWith.endsWith("Patient/100/_history/200"));
|
||||
assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue());
|
||||
assertEquals("200", response.getId().getVersionIdPart());
|
||||
}
|
||||
|
@ -1204,12 +1202,12 @@ public class ClientR4Test {
|
|||
// Older resource
|
||||
{
|
||||
BundleEntryComponent olderEntry = response.getEntry().get(0);
|
||||
assertEquals("http://acme.com/Patient/111", olderEntry.getId());
|
||||
assertEquals("http://acme.com/Patient/111", olderEntry.getResource().getId());
|
||||
}
|
||||
// Newer resource
|
||||
{
|
||||
BundleEntryComponent newerEntry = response.getEntry().get(1);
|
||||
assertEquals("http://acme.com/Patient/222", newerEntry.getId());
|
||||
assertEquals("http://acme.com/Patient/222", newerEntry.getResource().getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,25 @@ public class ClientServerValidationDstu1Test {
|
|||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@Test
|
||||
public void testServerReturnsRightVersionDstu() throws Exception {
|
||||
CapabilityStatement conf = new CapabilityStatement();
|
||||
conf.setFhirVersion("3.1.0");
|
||||
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
|
||||
myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
||||
myCtx.newRestfulGenericClient("http://foo").forceConformanceCheck();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
|
|
@ -458,13 +458,6 @@ public class GenericClientTest {
|
|||
lm.setTimeZoneZulu(true);
|
||||
assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString());
|
||||
|
||||
List<Coding> tags = response.getMeta().getTag();
|
||||
assertNotNull(tags);
|
||||
assertEquals(1, tags.size());
|
||||
assertEquals("http://hl7.org/fhir/tag", tags.get(0).getSystem());
|
||||
assertEquals("http://foo/tagdefinition.html", tags.get(0).getCode());
|
||||
assertEquals("Some tag", tags.get(0).getDisplay());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -81,7 +81,7 @@ public class LoggingInterceptorTest {
|
|||
public boolean matches(final Object argument) {
|
||||
String formattedMessage = ((LoggingEvent) argument).getFormattedMessage();
|
||||
System.out.println("Verifying: " + formattedMessage);
|
||||
return formattedMessage.replace("; ", ";").toLowerCase().contains("Content-Type: application/xml+fhir;charset=utf-8".toLowerCase());
|
||||
return formattedMessage.replace("; ", ";").toLowerCase().contains("Content-Type: application/fhir+xml;charset=utf-8".toLowerCase());
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -96,7 +96,7 @@ public class LoggingInterceptorTest {
|
|||
public boolean matches(final Object argument) {
|
||||
String formattedMessage = ((LoggingEvent) argument).getFormattedMessage();
|
||||
System.out.println("Verifying: " + formattedMessage);
|
||||
return formattedMessage.replace("; ", ";").toLowerCase().contains("Content-Type: application/xml+fhir;charset=utf-8".toLowerCase());
|
||||
return formattedMessage.replace("; ", ";").toLowerCase().contains("Content-Type: application/fhir+xml;charset=utf-8".toLowerCase());
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,140 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Encounter;
|
||||
import org.junit.*;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.param.TokenOrListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SearchClientTest {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchClientTest.class);
|
||||
|
||||
private FhirContext ourCtx;
|
||||
private HttpClient ourHttpClient;
|
||||
private HttpResponse ourHttpResponse;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
|
||||
ourHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(ourHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
|
||||
ourHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPostOnLongParamsList() throws Exception {
|
||||
String resp = createBundle();
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML_NEW + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(resp), Charset.forName("UTF-8")));
|
||||
|
||||
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
Set<Include> includes = new HashSet<Include>();
|
||||
includes.add(new Include("one"));
|
||||
includes.add(new Include("two"));
|
||||
TokenOrListParam params = new TokenOrListParam();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
params.add(new TokenParam("system", "value"));
|
||||
}
|
||||
List<Encounter> found = client.searchByList(params, includes);
|
||||
|
||||
assertEquals(1, found.size());
|
||||
|
||||
Encounter encounter = found.get(0);
|
||||
assertNotNull(encounter.getSubject().getReference());
|
||||
HttpUriRequest value = capt.getValue();
|
||||
|
||||
assertTrue("Expected request of type POST on long params list", value instanceof HttpPost);
|
||||
HttpPost post = (HttpPost) value;
|
||||
String body = IOUtils.toString(post.getEntity().getContent());
|
||||
ourLog.info(body);
|
||||
assertThat(body, Matchers.containsString("_include=one"));
|
||||
assertThat(body, Matchers.containsString("_include=two"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnTypedList() throws Exception {
|
||||
|
||||
String resp = createBundle();
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(ourHttpClient.execute(capt.capture())).thenReturn(ourHttpResponse);
|
||||
when(ourHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(ourHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML_NEW + "; charset=UTF-8"));
|
||||
when(ourHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(resp), Charset.forName("UTF-8")));
|
||||
|
||||
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
List<Encounter> found = client.search();
|
||||
assertEquals(1, found.size());
|
||||
|
||||
Encounter encounter = found.get(0);
|
||||
assertNotNull(encounter.getSubject().getReference());
|
||||
}
|
||||
|
||||
private String createBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
|
||||
Encounter enc = new Encounter();
|
||||
enc.getSubject().setReference("Patient/1");
|
||||
|
||||
bundle.addEntry().setResource(enc);
|
||||
|
||||
String retVal = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private interface ITestClient extends IBasicClient {
|
||||
|
||||
@Search
|
||||
List<Encounter> search();
|
||||
|
||||
@Search
|
||||
List<Encounter> searchByList(@RequiredParam(name = Encounter.SP_IDENTIFIER) TokenOrListParam tokenOrListParam, @IncludeParam Set<Include> theIncludes) throws BaseServerResponseException;
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -80,7 +80,7 @@ public class SortClientTest {
|
|||
|
||||
assertEquals(HttpGet.class, capt.getValue().getClass());
|
||||
HttpGet get = (HttpGet) capt.getValue();
|
||||
assertEquals("http://foo/Patient?name=hello&_sort%3Adesc=given&_sort%3Aasc=family", get.getURI().toString());
|
||||
assertEquals("http://foo/Patient?name=hello&_sort=-given%2Cfamily", get.getURI().toString());
|
||||
}
|
||||
|
||||
private String createBundle() {
|
||||
|
|
|
@ -66,9 +66,9 @@ public class IncludeTest {
|
|||
|
||||
assertEquals(3, bundle.getEntry().size());
|
||||
|
||||
assertEquals(new IdType("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
assertEquals(new IdType("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
assertEquals(new IdType("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
assertEquals(("Patient/p1"), bundle.getEntry().get(0).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
assertEquals(("Patient/p2"), bundle.getEntry().get(1).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
assertEquals(("Organization/o1"), bundle.getEntry().get(2).getResource().getIdElement().toUnqualifiedVersionless().getValue());
|
||||
|
||||
Patient p1 = (Patient) bundle.getEntry().get(0).getResource();
|
||||
assertEquals(0, p1.getContained().size());
|
||||
|
|
|
@ -31,7 +31,7 @@ public class PropertyTest {
|
|||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
final String sdString = IOUtils.toString(getClass().getResourceAsStream("/customPatientSd.xml"), StandardCharsets.UTF_8);
|
||||
final String sdString = IOUtils.toString(PropertyTest.class.getResourceAsStream("/customPatientSd.xml"), StandardCharsets.UTF_8);
|
||||
final IParser parser = ourCtx.newXmlParser();
|
||||
sd = parser.parseResource(StructureDefinition.class, sdString);
|
||||
workerContext = new HapiWorkerContext(ourCtx, new DefaultProfileValidationSupport());
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.io.InputStream;
|
|||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.exceptions.*;
|
||||
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
|
@ -333,15 +334,6 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
source = Source.InstanceValidator;
|
||||
}
|
||||
|
||||
public InstanceValidator(ValidationEngine engine) {
|
||||
super();
|
||||
this.context = engine.getContext();
|
||||
fpe = engine.getFpe();
|
||||
this.externalHostServices = fpe.getHostServices();
|
||||
fpe.setHostServices(new ValidatorHostServices());
|
||||
source = Source.InstanceValidator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNoInvariantChecks() {
|
||||
return noInvariantChecks;
|
||||
|
@ -1427,16 +1419,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
|
||||
private void checkReference(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition container, String parentType, NodeStack stack) throws FHIRException, IOException {
|
||||
String ref = null;
|
||||
try {
|
||||
// Do this inside a try because invalid instances might provide more than one reference.
|
||||
ref = element.getNamedChildValue("reference");
|
||||
} catch (Error e) {
|
||||
|
||||
}
|
||||
Reference reference = ObjectConverter.readAsReference(element);
|
||||
|
||||
String ref = reference.getReference();
|
||||
if (Utilities.noString(ref)) {
|
||||
// todo - what should we do in this case?
|
||||
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !Utilities.noString(element.getNamedChildValue("display")), "A Reference without an actual reference should have a display");
|
||||
if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) {
|
||||
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !Utilities.noString(element.getNamedChildValue("display")), "A Reference without an actual reference or identifier should have a display");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
|
||||
/**
|
||||
* Placeholdr class only, do not use
|
||||
*/
|
||||
public class ValidationEngine {
|
||||
|
||||
public IWorkerContext getContext() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public FHIRPathEngine getFpe() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -43,7 +43,7 @@ import ca.uhn.fhir.util.TestUtil;
|
|||
public class FhirInstanceValidatorR4Test {
|
||||
|
||||
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidatorR4Test.class);
|
||||
private FhirInstanceValidator myInstanceVal;
|
||||
private IValidationSupport myMockSupport;
|
||||
|
@ -157,20 +157,6 @@ public class FhirInstanceValidatorR4Test {
|
|||
ourLog.info("Validated the following:\n{}", ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* FHIRPathEngine was throwing Error...
|
||||
*/
|
||||
@Test
|
||||
public void testValidateCrucibleCarePlan() throws Exception {
|
||||
org.hl7.fhir.r4.model.Bundle bundle;
|
||||
String name = "profiles-resources";
|
||||
ourLog.info("Uploading " + name);
|
||||
String vsContents;
|
||||
vsContents = IOUtils.toString(FhirInstanceValidatorR4Test.class.getResourceAsStream("/crucible-condition.xml"), "UTF-8");
|
||||
|
||||
ValidationResult output = myVal.validateWithResult(vsContents);
|
||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
|
@ -201,7 +187,7 @@ public class FhirInstanceValidatorR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test @Ignore
|
||||
public void testValidateDocument() throws Exception {
|
||||
String vsContents = IOUtils.toString(FhirInstanceValidatorR4Test.class.getResourceAsStream("/sample-document.xml"), "UTF-8");
|
||||
|
||||
|
@ -367,6 +353,7 @@ public class FhirInstanceValidatorR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateBigRawJsonResource() throws Exception {
|
||||
InputStream stream = FhirInstanceValidatorR4Test.class.getResourceAsStream("/conformance.json.gz");
|
||||
stream = new GZIPInputStream(stream);
|
||||
|
@ -389,6 +376,7 @@ public class FhirInstanceValidatorR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateQuestionnaireResponse() throws IOException {
|
||||
String input = IOUtils.toString(FhirInstanceValidatorR4Test.class.getResourceAsStream("/qr_jon.xml"));
|
||||
|
||||
|
@ -520,6 +508,7 @@ public class FhirInstanceValidatorR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testValidateRawJsonResourceFromExamples() throws Exception {
|
||||
// @formatter:off
|
||||
String input = IOUtils.toString(FhirInstanceValidator.class.getResourceAsStream("/testscript-search.json"));
|
||||
|
@ -598,7 +587,7 @@ public class FhirInstanceValidatorR4Test {
|
|||
ourLog.info(output.getMessages().get(0).getLocationString());
|
||||
ourLog.info(output.getMessages().get(0).getMessage());
|
||||
assertEquals("/f:Patient", output.getMessages().get(0).getLocationString());
|
||||
assertEquals("Undefined element 'foo\"", output.getMessages().get(0).getMessage());
|
||||
assertEquals("Undefined element 'foo'", output.getMessages().get(0).getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -52,8 +52,12 @@ public abstract class BaseJavaConfig${versionCapitalized} extends ca.uhn.fhir.jp
|
|||
IFhirResourceDaoValueSet<ca.uhn.fhir.model.dstu2.resource.ValueSet, ca.uhn.fhir.model.dstu2.composite.CodingDt, ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt>
|
||||
#elseif ( ${versionCapitalized} == 'Dstu3' && ${res.name} == 'ValueSet' )
|
||||
IFhirResourceDaoValueSet<org.hl7.fhir.dstu3.model.ValueSet, org.hl7.fhir.dstu3.model.Coding, org.hl7.fhir.dstu3.model.CodeableConcept>
|
||||
#elseif ( ${versionCapitalized} == 'R4' && ${res.name} == 'ValueSet' )
|
||||
IFhirResourceDaoValueSet<org.hl7.fhir.r4.model.ValueSet, org.hl7.fhir.r4.model.Coding, org.hl7.fhir.r4.model.CodeableConcept>
|
||||
#elseif ( ${versionCapitalized} == 'Dstu3' && ${res.name} == 'CodeSystem' )
|
||||
IFhirResourceDaoCodeSystem<org.hl7.fhir.dstu3.model.CodeSystem, org.hl7.fhir.dstu3.model.Coding, org.hl7.fhir.dstu3.model.CodeableConcept>
|
||||
#elseif ( ${versionCapitalized} == 'R4' && ${res.name} == 'CodeSystem' )
|
||||
IFhirResourceDaoCodeSystem<org.hl7.fhir.r4.model.CodeSystem, org.hl7.fhir.r4.model.Coding, org.hl7.fhir.r4.model.CodeableConcept>
|
||||
#elseif ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'SearchParameter'))
|
||||
IFhirResourceDao${res.name}<${resourcePackage}.${res.declaringClassNameComplete}>
|
||||
#else
|
||||
|
|
Loading…
Reference in New Issue