mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-06 21:18:21 +00:00
improve validation for R4 backport subscriptions in SubscriptionValidatingInterceptor (#5973)
* still need to genericise the rest of the SubscriptionValidatingInterceptorTest tests also there are Msg.code FIXMEs * cleanup still need to genericise the rest of the SubscriptionValidatingInterceptorTest tests * cleanup still need to genericise the rest of the SubscriptionValidatingInterceptorTest tests * done * done * javadoc * changelog * fix test * fix test * fix test * fix test * fix test
This commit is contained in:
parent
4ac65da2ee
commit
ac3a5e2ad2
@ -464,6 +464,21 @@ public final class TerserUtil {
|
||||
mergeFields(theTerser, theResource, childDefinition, theFromFieldValues, theToFieldValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the provided field with the given values. This method will add to the collection of existing field values
|
||||
* in case of multiple cardinality. Use {@link #clearField(FhirContext, IBaseResource, String)}
|
||||
* to remove values before setting
|
||||
*
|
||||
* @param theFhirContext Context holding resource definition
|
||||
* @param theFieldName Child field name of the resource to set
|
||||
* @param theResource The resource to set the values on
|
||||
* @param theValue The String value to set on the resource child field name. This value is converted to the appropriate primitive type before the value is set
|
||||
*/
|
||||
public static void setStringField(
|
||||
FhirContext theFhirContext, String theFieldName, IBaseResource theResource, String theValue) {
|
||||
setField(theFhirContext, theFieldName, theResource, theFhirContext.newPrimitiveString(theValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified value at the FHIR path provided.
|
||||
*
|
||||
@ -493,6 +508,20 @@ public final class TerserUtil {
|
||||
setFieldByFhirPath(theFhirContext.newTerser(), theFhirPath, theResource, theValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified String value at the FHIR path provided.
|
||||
*
|
||||
* @param theFhirContext Context holding resource definition
|
||||
* @param theFhirPath The FHIR path to set the field at
|
||||
* @param theResource The resource on which the value should be set
|
||||
* @param theValue The String value to set. The string is converted to the appropriate primitive type before setting the field
|
||||
*/
|
||||
public static void setStringFieldByFhirPath(
|
||||
FhirContext theFhirContext, String theFhirPath, IBaseResource theResource, String theValue) {
|
||||
setFieldByFhirPath(
|
||||
theFhirContext.newTerser(), theFhirPath, theResource, theFhirContext.newPrimitiveString(theValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns field values ant the specified FHIR path from the resource.
|
||||
*
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
type: fix
|
||||
issue: 5973
|
||||
title: "Previously, subscription criteria on R4 backport subscriptions were not validated by the
|
||||
SubscriptionValidatingInterceptor. This has been corrected."
|
@ -46,15 +46,21 @@ import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.subscription.SubscriptionConstants;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.util.SubscriptionUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Extension;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.hl7.fhir.r5.model.SubscriptionTopic;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
@ -62,9 +68,6 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
@Interceptor
|
||||
public class SubscriptionValidatingInterceptor {
|
||||
|
||||
@Autowired
|
||||
private SubscriptionCanonicalizer mySubscriptionCanonicalizer;
|
||||
|
||||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
|
||||
@ -74,6 +77,9 @@ public class SubscriptionValidatingInterceptor {
|
||||
@Autowired
|
||||
private SubscriptionStrategyEvaluator mySubscriptionStrategyEvaluator;
|
||||
|
||||
@Autowired
|
||||
private SubscriptionCanonicalizer mySubscriptionCanonicalizer;
|
||||
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@Autowired
|
||||
@ -150,27 +156,13 @@ public class SubscriptionValidatingInterceptor {
|
||||
|
||||
if (!finished) {
|
||||
|
||||
if (subscription.isTopicSubscription()) {
|
||||
if (myFhirContext.getVersion().getVersion()
|
||||
!= FhirVersionEnum
|
||||
.R4) { // In R4 topic subscriptions exist without a corresponidng SubscriptionTopic
|
||||
// resource
|
||||
Optional<IBaseResource> oTopic = findSubscriptionTopicByUrl(subscription.getTopic());
|
||||
if (!oTopic.isPresent()) {
|
||||
throw new UnprocessableEntityException(
|
||||
Msg.code(2322) + "No SubscriptionTopic exists with topic: " + subscription.getTopic());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validateQuery(subscription.getCriteriaString(), "Subscription.criteria");
|
||||
|
||||
if (subscription.getPayloadSearchCriteria() != null) {
|
||||
validateQuery(
|
||||
subscription.getPayloadSearchCriteria(),
|
||||
"Subscription.extension(url='" + HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA
|
||||
+ "')");
|
||||
}
|
||||
if (subscription.getPayloadSearchCriteria() != null) {
|
||||
validateQuery(
|
||||
subscription.getPayloadSearchCriteria(),
|
||||
"Subscription.extension(url='" + HapiExtensions.EXT_SUBSCRIPTION_PAYLOAD_SEARCH_CRITERIA
|
||||
+ "')");
|
||||
}
|
||||
validateCriteria(theSubscription, subscription);
|
||||
|
||||
validateChannelType(subscription);
|
||||
|
||||
@ -197,6 +189,52 @@ public class SubscriptionValidatingInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCriteria(IBaseResource theSubscription, CanonicalSubscription theCanonicalSubscription) {
|
||||
if (theCanonicalSubscription.isTopicSubscription()) {
|
||||
if (myFhirContext.getVersion().getVersion() == FhirVersionEnum.R4) {
|
||||
validateR4BackportSubscription((Subscription) theSubscription);
|
||||
} else {
|
||||
validateR5PlusTopicSubscription(theCanonicalSubscription);
|
||||
}
|
||||
} else {
|
||||
validateQuery(theCanonicalSubscription.getCriteriaString(), "Subscription.criteria");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateR5PlusTopicSubscription(CanonicalSubscription theCanonicalSubscription) {
|
||||
Optional<IBaseResource> oTopic = findSubscriptionTopicByUrl(theCanonicalSubscription.getTopic());
|
||||
if (!oTopic.isPresent()) {
|
||||
throw new UnprocessableEntityException(
|
||||
Msg.code(2322) + "No SubscriptionTopic exists with topic: " + theCanonicalSubscription.getTopic());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateR4BackportSubscription(Subscription theSubscription) {
|
||||
// This is an R4 backport topic subscription
|
||||
// In R4, topic subscriptions exist without a corresponding SubscriptionTopic
|
||||
Subscription r4Subscription = theSubscription;
|
||||
List<String> filterUrls = new ArrayList<>();
|
||||
List<Extension> filterUrlExtensions = r4Subscription
|
||||
.getCriteriaElement()
|
||||
.getExtensionsByUrl(SubscriptionConstants.SUBSCRIPTION_TOPIC_FILTER_URL);
|
||||
filterUrlExtensions.forEach(filterUrlExtension -> {
|
||||
StringType filterUrlElement = (StringType) filterUrlExtension.getValue();
|
||||
if (filterUrlElement != null) {
|
||||
filterUrls.add(filterUrlElement.getValue());
|
||||
}
|
||||
});
|
||||
if (filterUrls.isEmpty()) {
|
||||
// Trigger a "no criteria" validation exception
|
||||
validateQuery(
|
||||
null,
|
||||
"Subscription.criteria.extension with url " + SubscriptionConstants.SUBSCRIPTION_TOPIC_FILTER_URL);
|
||||
} else {
|
||||
filterUrls.forEach(filterUrl -> validateQuery(
|
||||
filterUrl,
|
||||
"Subscription.criteria.extension with url " + SubscriptionConstants.SUBSCRIPTION_TOPIC_FILTER_URL));
|
||||
}
|
||||
}
|
||||
|
||||
protected void validatePermissions(
|
||||
IBaseResource theSubscription,
|
||||
CanonicalSubscription theCanonicalSubscription,
|
||||
|
@ -0,0 +1,83 @@
|
||||
package ca.uhn.fhir.jpa.subscription.submit.interceptor;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||
import ca.uhn.fhir.subscription.SubscriptionConstants;
|
||||
import ca.uhn.fhir.util.TerserUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseEnumeration;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.StringType;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Version independent utility class for setting fields on subscriptions
|
||||
*/
|
||||
|
||||
public final class SubscriptionUtil {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionUtil.class);
|
||||
|
||||
private SubscriptionUtil() {}
|
||||
|
||||
public static void setStatus(FhirContext theFhirContext, IBaseResource theSubscription, String theStatus) {
|
||||
IBaseEnumeration newValue = switch (theFhirContext.getVersion().getVersion()) {
|
||||
case DSTU3 -> new org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatusEnumFactory().fromType(new org.hl7.fhir.dstu3.model.StringType(theStatus));
|
||||
case R4 -> new org.hl7.fhir.r4.model.Subscription.SubscriptionStatusEnumFactory().fromType(new org.hl7.fhir.r4.model.StringType(theStatus));
|
||||
case R4B -> new org.hl7.fhir.r4b.model.Enumerations.SubscriptionStatusEnumFactory().fromType(new org.hl7.fhir.r4b.model.StringType(theStatus));
|
||||
case R5 -> new org.hl7.fhir.r5.model.Enumerations.SubscriptionStatusCodesEnumFactory().fromType(new org.hl7.fhir.r5.model.StringType(theStatus));
|
||||
default -> null;
|
||||
};
|
||||
TerserUtil.setField(theFhirContext, "status", theSubscription, newValue);
|
||||
}
|
||||
|
||||
public static void setCriteria(FhirContext theFhirContext, IBaseResource theSubscription, String theCriteria) {
|
||||
SubscriptionCanonicalizer canonicalizer = new SubscriptionCanonicalizer(theFhirContext);
|
||||
CanonicalSubscription canonicalSubscription = canonicalizer.canonicalize(theSubscription);
|
||||
if (canonicalSubscription.isTopicSubscription()) {
|
||||
if (theFhirContext.getVersion().getVersion() == FhirVersionEnum.R5) {
|
||||
// Nothing to do on R5
|
||||
return;
|
||||
}
|
||||
Subscription subscription = (Subscription)theSubscription;
|
||||
subscription.getCriteriaElement().addExtension(SubscriptionConstants.SUBSCRIPTION_TOPIC_FILTER_URL, new StringType(theCriteria));
|
||||
} else {
|
||||
TerserUtil.setStringField(theFhirContext, "criteria", theSubscription, theCriteria);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setChannelType(FhirContext theFhirContext, IBaseResource theSubscription, String theChannelType) {
|
||||
FhirVersionEnum version = theFhirContext.getVersion().getVersion();
|
||||
IBase newValue = switch (version) {
|
||||
case DSTU3 -> new org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelTypeEnumFactory().fromType(new org.hl7.fhir.dstu3.model.StringType(theChannelType));
|
||||
case R4 -> new org.hl7.fhir.r4.model.Subscription.SubscriptionChannelTypeEnumFactory().fromType(new org.hl7.fhir.r4.model.StringType(theChannelType));
|
||||
case R4B -> new org.hl7.fhir.r4b.model.Subscription.SubscriptionChannelTypeEnumFactory().fromType(new org.hl7.fhir.r4b.model.StringType(theChannelType));
|
||||
case R5 -> CanonicalSubscriptionChannelType.valueOf(theChannelType.toUpperCase()).toR5Coding();
|
||||
default -> null;
|
||||
};
|
||||
String fhirPath = switch(version) {
|
||||
case DSTU3 -> "channel.type";
|
||||
case R4 -> "channel.type";
|
||||
case R4B -> "channel.type";
|
||||
case R5 -> "channelType";
|
||||
default -> null;
|
||||
};
|
||||
TerserUtil.setFieldByFhirPath(theFhirContext, fhirPath, theSubscription, newValue);
|
||||
}
|
||||
|
||||
public static void setEndpoint(FhirContext theFhirContext, IBaseResource theSubscription, String theEndpoint) {
|
||||
FhirVersionEnum version = theFhirContext.getVersion().getVersion();
|
||||
String fhirPath = switch(version) {
|
||||
case DSTU3 -> "channel.endpoint";
|
||||
case R4 -> "channel.endpoint";
|
||||
case R4B -> "channel.endpoint";
|
||||
case R5 -> "endpoint";
|
||||
default -> null;
|
||||
};
|
||||
TerserUtil.setStringFieldByFhirPath(theFhirContext, fhirPath, theSubscription, theEndpoint);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package ca.uhn.fhir.jpa.subscription.submit.interceptor;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
@ -8,11 +9,16 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.subscription.SubscriptionConstants;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4b.model.CanonicalType;
|
||||
import org.hl7.fhir.r4b.model.Enumerations;
|
||||
import org.hl7.fhir.r4b.model.Subscription;
|
||||
@ -20,6 +26,8 @@ import org.hl7.fhir.r4b.model.SubscriptionTopic;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.Mock;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -29,14 +37,18 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static ca.uhn.fhir.subscription.SubscriptionTestDataHelper.TEST_TOPIC;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
@ -58,17 +70,20 @@ public class SubscriptionValidatingInterceptorTest {
|
||||
private IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
|
||||
@Mock
|
||||
private IFhirResourceDao<SubscriptionTopic> mySubscriptionTopicDao;
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
setFhirContext(FhirVersionEnum.R4B);
|
||||
when(myDaoRegistry.isResourceTypeSupported(any())).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptySub() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion345")
|
||||
public void testEmptySub(IBaseResource theSubscription) {
|
||||
try {
|
||||
Subscription badSub = new Subscription();
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
setFhirContext(theSubscription);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(8) + "Can not process submitted Subscription - Subscription.status must be populated on this server"));
|
||||
@ -76,94 +91,93 @@ public class SubscriptionValidatingInterceptorTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyStatus() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion34") // R5 subscriptions don't have criteria
|
||||
public void testEmptyCriteria(IBaseResource theSubscription) {
|
||||
try {
|
||||
Subscription badSub = new Subscription();
|
||||
badSub.setStatus(Enumerations.SubscriptionStatus.ACTIVE);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
initSubscription(theSubscription);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(11) + "Subscription.criteria must be populated"));
|
||||
assertThat(e.getMessage(), startsWith(Msg.code(11) + "Subscription."));
|
||||
assertThat(e.getMessage(), endsWith( " must be populated"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadCriteria() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion34")
|
||||
public void testBadCriteria(IBaseResource theSubscription) {
|
||||
try {
|
||||
Subscription badSub = new Subscription();
|
||||
badSub.setStatus(Enumerations.SubscriptionStatus.ACTIVE);
|
||||
badSub.setCriteria("Patient");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(14) + "Subscription.criteria must be in the form \"{Resource Type}?[params]\""));
|
||||
assertThat(e.getMessage(), endsWith("criteria must be in the form \"{Resource Type}?[params]\""));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadChannel() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion34")
|
||||
public void testBadChannel(IBaseResource theSubscription) {
|
||||
try {
|
||||
Subscription badSub = new Subscription();
|
||||
badSub.setStatus(Enumerations.SubscriptionStatus.ACTIVE);
|
||||
badSub.setCriteria("Patient?");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient?");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(20) + "Subscription.channel.type must be populated"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyEndpoint() {
|
||||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion345")
|
||||
public void testEmptyEndpoint(IBaseResource theSubscription) {
|
||||
try {
|
||||
Subscription badSub = new Subscription();
|
||||
badSub.setStatus(Enumerations.SubscriptionStatus.ACTIVE);
|
||||
badSub.setCriteria("Patient?");
|
||||
Subscription.SubscriptionChannelComponent channel = badSub.getChannel();
|
||||
channel.setType(Subscription.SubscriptionChannelType.MESSAGE);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient?");
|
||||
SubscriptionUtil.setChannelType(myFhirContext, theSubscription, "message");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(16) + "No endpoint defined for message subscription"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMalformedEndpoint() {
|
||||
Subscription badSub = new Subscription();
|
||||
badSub.setStatus(Enumerations.SubscriptionStatus.ACTIVE);
|
||||
badSub.setCriteria("Patient?");
|
||||
Subscription.SubscriptionChannelComponent channel = badSub.getChannel();
|
||||
channel.setType(Subscription.SubscriptionChannelType.MESSAGE);
|
||||
@ParameterizedTest
|
||||
@MethodSource("subscriptionByFhirVersion345")
|
||||
public void testMalformedEndpoint(IBaseResource theSubscription) {
|
||||
initSubscription(theSubscription);
|
||||
SubscriptionUtil.setCriteria(myFhirContext, theSubscription, "Patient?");
|
||||
SubscriptionUtil.setChannelType(myFhirContext, theSubscription, "message");
|
||||
SubscriptionUtil.setEndpoint(myFhirContext, theSubscription, "foo");
|
||||
|
||||
channel.setEndpoint("foo");
|
||||
try {
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(17) + "Only 'channel' protocol is supported for Subscriptions with channel type 'message'"));
|
||||
}
|
||||
|
||||
channel.setEndpoint("channel");
|
||||
SubscriptionUtil.setEndpoint(myFhirContext, theSubscription, "channel");
|
||||
try {
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(17) + "Only 'channel' protocol is supported for Subscriptions with channel type 'message'"));
|
||||
}
|
||||
|
||||
channel.setEndpoint("channel:");
|
||||
SubscriptionUtil.setEndpoint(myFhirContext, theSubscription, "channel:");
|
||||
try {
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage(), is(Msg.code(19) + "Invalid subscription endpoint uri channel:"));
|
||||
}
|
||||
|
||||
// Happy path
|
||||
channel.setEndpoint("channel:my-queue-name");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(badSub, null, null);
|
||||
SubscriptionUtil.setEndpoint(myFhirContext, theSubscription, "channel:my-queue-name");
|
||||
mySubscriptionValidatingInterceptor.resourcePreCreate(theSubscription, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -213,6 +227,58 @@ public class SubscriptionValidatingInterceptorTest {
|
||||
mySubscriptionValidatingInterceptor.validateSubmittedSubscription(badSub, null, null, Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED);
|
||||
}
|
||||
|
||||
|
||||
private void initSubscription(IBaseResource theSubscription) {
|
||||
setFhirContext(theSubscription);
|
||||
SubscriptionUtil.setStatus(myFhirContext, theSubscription, "active");
|
||||
if (myFhirContext.getVersion().getVersion() == FhirVersionEnum.R5) {
|
||||
initR5();
|
||||
org.hl7.fhir.r5.model.Subscription subscription = (org.hl7.fhir.r5.model.Subscription) theSubscription;
|
||||
subscription.setTopic(TEST_TOPIC);
|
||||
}
|
||||
}
|
||||
|
||||
void initR5() {
|
||||
when(myDaoRegistry.getResourceDao("SubscriptionTopic")).thenReturn(mySubscriptionTopicDao);
|
||||
org.hl7.fhir.r5.model.SubscriptionTopic topic = new org.hl7.fhir.r5.model.SubscriptionTopic();
|
||||
IBundleProvider provider = new SimpleBundleProvider(topic);
|
||||
when(mySubscriptionTopicDao.search(any(SearchParameterMap.class), any(RequestDetails.class))).thenReturn(provider);
|
||||
}
|
||||
|
||||
public static Stream<IBaseResource> subscriptionByFhirVersion345() {
|
||||
return subscriptionByFhirVersion(true);
|
||||
}
|
||||
|
||||
public static Stream<IBaseResource> subscriptionByFhirVersion34() {
|
||||
return subscriptionByFhirVersion(false);
|
||||
}
|
||||
|
||||
private void setFhirContext(IBaseResource theSubscription) {
|
||||
FhirVersionEnum fhirVersion = theSubscription.getStructureFhirVersionEnum();
|
||||
setFhirContext(fhirVersion);
|
||||
}
|
||||
|
||||
private void setFhirContext(FhirVersionEnum fhirVersion) {
|
||||
myFhirContext = FhirContext.forCached(fhirVersion);
|
||||
mySubscriptionValidatingInterceptor.setFhirContext(myFhirContext);
|
||||
mySubscriptionValidatingInterceptor.setSubscriptionCanonicalizerForUnitTest(new SubscriptionCanonicalizer(myFhirContext, myStorageSettings));
|
||||
}
|
||||
|
||||
private static @Nonnull Stream<IBaseResource> subscriptionByFhirVersion(boolean theIncludeR5) {
|
||||
List<IBaseResource> resources = new ArrayList<>();
|
||||
resources.add(new org.hl7.fhir.dstu3.model.Subscription());
|
||||
resources.add(new org.hl7.fhir.r4.model.Subscription());
|
||||
org.hl7.fhir.r4.model.Subscription r4Backport = new org.hl7.fhir.r4.model.Subscription();
|
||||
r4Backport.getMeta().addProfile(SubscriptionConstants.SUBSCRIPTION_TOPIC_PROFILE_URL);
|
||||
resources.add(r4Backport);
|
||||
resources.add(new org.hl7.fhir.r4b.model.Subscription());
|
||||
if (theIncludeR5) {
|
||||
resources.add(new org.hl7.fhir.r5.model.Subscription());
|
||||
}
|
||||
|
||||
return resources.stream();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class SpringConfig {
|
||||
@Bean
|
||||
|
@ -24,6 +24,7 @@ import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.hl7.fhir.dstu2.model.Subscription;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
@ -158,4 +159,8 @@ public enum CanonicalSubscriptionChannelType {
|
||||
public Subscription.SubscriptionChannelType toCanonical() {
|
||||
return Subscription.SubscriptionChannelType.fromCode(toCode());
|
||||
}
|
||||
|
||||
public Coding toR5Coding() {
|
||||
return new Coding().setSystem(getSystem()).setCode(toCode());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user