Reject subscriptions in JPA server if status field is not set

This commit is contained in:
jamesagnew 2019-06-22 17:03:22 -04:00
parent 0fbde2a4e5
commit 3ba194acbe
7 changed files with 95 additions and 20 deletions

View File

@ -84,6 +84,10 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
}
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
if (theResource.getStatus() == null) {
throw new UnprocessableEntityException("Can not process submitted Subscription - Subscription.status must be populated");
}
String query = theResource.getCriteria();
if (isBlank(query)) {
throw new UnprocessableEntityException("Subscription.criteria must be populated");

View File

@ -106,7 +106,11 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
}
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
switch (ObjectUtils.defaultIfNull(theResource.getStatus(), SubscriptionStatus.OFF)) {
if (theResource.getStatus() == null) {
throw new UnprocessableEntityException("Can not process submitted Subscription - Subscription.status must be populated");
}
switch (theResource.getStatus()) {
case REQUESTED:
case ACTIVE:
break;

View File

@ -103,7 +103,11 @@ public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscriptio
@Nullable
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
switch (ObjectUtils.defaultIfNull(theResource.getStatus(), Subscription.SubscriptionStatus.OFF)) {
if (theResource.getStatus() == null) {
throw new UnprocessableEntityException("Can not process submitted Subscription - Subscription.status must be populated");
}
switch (theResource.getStatus()) {
case REQUESTED:
case ACTIVE:
break;

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.jetbrains.annotations.NotNull;
import org.junit.*;
import org.springframework.beans.factory.annotation.Autowired;
@ -34,8 +35,8 @@ import java.util.List;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.subscription.resthook.RestHookTestDstu3Test.logAllInterceptors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.*;
import ca.uhn.fhir.test.utilities.JettyUtil;
@ -90,6 +91,19 @@ public class RestHookTestDstu2Test extends BaseResourceProviderDstu2Test {
}
private Subscription createSubscription(String criteria, String payload, String endpoint) throws InterruptedException {
Subscription subscription = newSubscription(criteria, payload, endpoint);
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
subscription.setId(methodOutcome.getId().getIdPart());
mySubscriptionIds.add(methodOutcome.getId());
waitForQueueToDrain();
return subscription;
}
@NotNull
private Subscription newSubscription(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(SubscriptionStatusEnum.REQUESTED);
@ -100,13 +114,6 @@ public class RestHookTestDstu2Test extends BaseResourceProviderDstu2Test {
channel.setPayload(payload);
channel.setEndpoint(endpoint);
subscription.setChannel(channel);
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
subscription.setId(methodOutcome.getId().getIdPart());
mySubscriptionIds.add(methodOutcome.getId());
waitForQueueToDrain();
return subscription;
}
@ -295,6 +302,20 @@ public class RestHookTestDstu2Test extends BaseResourceProviderDstu2Test {
Assert.assertFalse(observation2.getId().isEmpty());
}
@Test
public void testSubscriptionWithNoStatusIsRejected() {
Subscription subscription = newSubscription("Observation?", "application/json", null);
subscription.getStatusElement().setValueAsEnum(null);
try {
ourClient.create().resource(subscription).execute();
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Can not process submitted Subscription - Subscription.status must be populated"));
}
}
private void waitForQueueToDrain() throws InterruptedException {
mySubscriptionTestUtil.waitForQueueToDrain();
}

View File

@ -24,6 +24,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.jetbrains.annotations.NotNull;
import org.junit.*;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,6 +36,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;
import ca.uhn.fhir.test.utilities.JettyUtil;
@ -104,6 +106,18 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
private Subscription createSubscription(String theCriteria, String thePayload, String theEndpoint,
List<StringType> headers) throws InterruptedException {
Subscription subscription = newSubscription(theCriteria, thePayload, theEndpoint, headers);
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
mySubscriptionIds.add(methodOutcome.getId());
waitForQueueToDrain();
return (Subscription) methodOutcome.getResource();
}
@NotNull
private Subscription newSubscription(String theCriteria, String thePayload, String theEndpoint, List<StringType> headers) {
Subscription subscription = new Subscription();
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED);
@ -117,13 +131,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
channel.setHeader(headers);
}
subscription.setChannel(channel);
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
mySubscriptionIds.add(methodOutcome.getId());
waitForQueueToDrain();
return (Subscription) methodOutcome.getResource();
return subscription;
}
private Observation sendObservation(String code, String system) {
@ -514,6 +522,20 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
assertTrue("Timed out waiting for subscription to match", communicationRequestListenerLatch.await(10, TimeUnit.SECONDS));
}
@Test
public void testSubscriptionWithNoStatusIsRejected() {
Subscription subscription = newSubscription("Observation?", "application/json", null, null);
subscription.setStatus(null);
try {
ourClient.create().resource(subscription).execute();
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Can not process submitted Subscription - Subscription.status must be populated"));
}
}
public static class ObservationListener implements IResourceProvider {
@Create

View File

@ -6,6 +6,8 @@ import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionConstants;
import ca.uhn.fhir.rest.api.CacheControlDirective;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.r4.model.*;
@ -20,8 +22,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.matchesPattern;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
@ -876,6 +877,20 @@ public class RestHookTestR4Test extends BaseSubscriptionsR4Test {
return toUnqualifiedVersionlessIdValues(found).size();
}
@Test
public void testSubscriptionWithNoStatusIsRejected() {
Subscription subscription = newSubscription("Observation?", "application/json");
subscription.setStatus(null);
try {
ourClient.create().resource(subscription).execute();
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Can not process submitted Subscription - Subscription.status must be populated"));
}
}
@Test
public void testBadSubscriptionDoesntPersist() {
assertEquals(0, subscriptionCount());

View File

@ -132,6 +132,11 @@
JPA server because of an indexing error. Thanks to Brian Reinhold for
reporting!
</action>
<action type="add">
The JPA server now rejects subscriptions being submitted with no value in
Subscription.status (this field is mandatory, but the subscription was previously ignored
if no value was provided)
</action>
</release>
<release version="3.8.0" date="2019-05-30" description="Hippo">
<action type="fix">