Merge remote-tracking branch 'origin/master' into rel_7_3_tracking
This commit is contained in:
242
src/test/java/ca/uhn/fhir/jpa/starter/CdsHooksServletIT.java
Normal file
242
src/test/java/ca/uhn/fhir/jpa/starter/CdsHooksServletIT.java
Normal file
@@ -0,0 +1,242 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.cr.config.RepositoryConfig;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.config.NicknameServiceConfig;
|
||||
import ca.uhn.fhir.jpa.starter.cdshooks.StarterCdsHooksConfig;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.hapi.fhir.cdshooks.api.ICdsServiceRegistry;
|
||||
import ca.uhn.hapi.fhir.cdshooks.config.CdsHooksConfig;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = {
|
||||
Application.class,
|
||||
NicknameServiceConfig.class,
|
||||
RepositoryConfig.class,
|
||||
CdsHooksConfig.class,
|
||||
StarterCdsHooksConfig.class
|
||||
}, properties = {
|
||||
"spring.profiles.include=storageSettingsTest",
|
||||
"spring.datasource.url=jdbc:h2:mem:dbr4",
|
||||
"hapi.fhir.enable_repository_validating_interceptor=true",
|
||||
"hapi.fhir.fhir_version=r4",
|
||||
"hapi.fhir.cr.enabled=true",
|
||||
"hapi.fhir.cr.caregaps.section_author=Organization/alphora-author",
|
||||
"hapi.fhir.cr.caregaps.reporter=Organization/alphora",
|
||||
"hapi.fhir.cdshooks.enabled=true",
|
||||
"spring.main.allow-bean-definition-overriding=true"})
|
||||
class CdsHooksServletIT implements IServerSupport {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CdsHooksServletIT.class);
|
||||
private final FhirContext ourCtx = FhirContext.forR4Cached();
|
||||
private final IParser ourParser = ourCtx.newJsonParser();
|
||||
private IGenericClient ourClient;
|
||||
private String ourCdsBase;
|
||||
|
||||
@Autowired
|
||||
DaoRegistry myDaoRegistry;
|
||||
|
||||
@Autowired
|
||||
ICdsServiceRegistry myCdsServiceRegistry;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private String ourServerBase;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourCdsBase = "http://localhost:" + port + "/cds-services";
|
||||
|
||||
var cdsServicesJson = myCdsServiceRegistry.getCdsServicesJson();
|
||||
if (cdsServicesJson != null && cdsServicesJson.getServices() != null && !cdsServicesJson.getServices().isEmpty()) {
|
||||
var services = cdsServicesJson.getServices();
|
||||
for (int i = 0; i < services.size(); i++) {
|
||||
myCdsServiceRegistry.unregisterService(services.get(i).getId(), "CR");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean hasCdsServices() throws IOException {
|
||||
var response = callCdsServicesDiscovery();
|
||||
return response.getEntity().getContentLength() > 21 || response.getEntity().isChunked();
|
||||
}
|
||||
|
||||
private CloseableHttpResponse callCdsServicesDiscovery() {
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
HttpGet request = new HttpGet(ourCdsBase);
|
||||
request.addHeader("Content-Type", "application/json");
|
||||
return httpClient.execute(request);
|
||||
} catch (IOException ioe) {
|
||||
fail(ioe.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetCdsServices() {
|
||||
var response = callCdsServicesDiscovery();
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCdsHooks() throws IOException, InterruptedException {
|
||||
loadBundle("r4/HelloWorld-Bundle.json", ourCtx, ourClient);
|
||||
await().atMost(10000, TimeUnit.MILLISECONDS).until(() -> hasCdsServices());
|
||||
var cdsRequest = "{\n" +
|
||||
" \"hookInstance\": \"12345\",\n" +
|
||||
" \"hook\": \"patient-view\",\n" +
|
||||
" \"context\": {\n" +
|
||||
" \"userId\": \"Practitioner/example\",\n" +
|
||||
" \"patientId\": \"Patient/example-hello-world\"\n" +
|
||||
" },\n" +
|
||||
" \"prefetch\": {\n" +
|
||||
" \"item1\": {\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"id\": \"example-hello-world\",\n" +
|
||||
" \"gender\": \"male\",\n" +
|
||||
" \"birthDate\": \"2000-01-01\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
HttpPost request = new HttpPost(ourCdsBase + "/hello-world");
|
||||
request.setEntity(new StringEntity(cdsRequest));
|
||||
request.addHeader("Content-Type", "application/json");
|
||||
|
||||
CloseableHttpResponse httpResponse = httpClient.execute(request);
|
||||
String result = EntityUtils.toString(httpResponse.getEntity());
|
||||
Gson gsonResponse = new Gson();
|
||||
JsonObject response = gsonResponse.fromJson(result, JsonObject.class);
|
||||
assertNotNull(response);
|
||||
JsonArray cards = response.getAsJsonArray("cards");
|
||||
assertEquals(1, cards.size());
|
||||
assertEquals("\"Hello World!\"", cards.get(0).getAsJsonObject().get("summary").toString());
|
||||
} catch (IOException ioe) {
|
||||
fail(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRec10() throws IOException {
|
||||
loadBundle("r4/opioidcds-10-order-sign-bundle.json", ourCtx, ourClient);
|
||||
await().atMost(20000, TimeUnit.MILLISECONDS).until(() -> hasCdsServices());
|
||||
var fhirServer = " \"fhirServer\": " + "\"" + ourServerBase + "\"" + ",\n";
|
||||
var cdsRequest = "{\n" +
|
||||
" \"hookInstance\": \"055b009c-4a7d-4db4-a35e-0e5198918ed1\",\n" +
|
||||
" \"hook\": \"order-sign\",\n" +
|
||||
fhirServer +
|
||||
" \"context\": {\n" +
|
||||
" \"patientId\": \"example-rec-10-order-sign-illicit-POS-Cocaine-drugs\",\n" +
|
||||
" \"userId\": \"COREPRACTITIONER1\",\n" +
|
||||
" \"draftOrders\": {\n" +
|
||||
" \"resourceType\": \"Bundle\",\n" +
|
||||
" \"entry\": [\n" +
|
||||
" {\n" +
|
||||
" \"resource\": {\n" +
|
||||
" \"resourceType\": \"MedicationRequest\",\n" +
|
||||
" \"id\": \"request-123\",\n" +
|
||||
" \"status\": \"draft\",\n" +
|
||||
" \"subject\": {\n" +
|
||||
" \"reference\": \"Patient/example-rec-10-order-sign-illicit-POS-Cocaine-drugs\"\n" +
|
||||
" },\n" +
|
||||
" \"authoredOn\": \"2024-03-27\",\n" +
|
||||
" \"dosageInstruction\": [\n" +
|
||||
" {\n" +
|
||||
" \"timing\": {\n" +
|
||||
" \"repeat\": {\n" +
|
||||
" \"frequency\": 1,\n" +
|
||||
" \"period\": 1,\n" +
|
||||
" \"periodUnit\": \"d\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"doseAndRate\": [\n" +
|
||||
" {\n" +
|
||||
" \"doseQuantity\": {\n" +
|
||||
" \"value\": 1,\n" +
|
||||
" \"system\": \"http://unitsofmeasure.org\",\n" +
|
||||
" \"code\": \"{pill}\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"dispenseRequest\": {\n" +
|
||||
" \"expectedSupplyDuration\": {\n" +
|
||||
" \"value\": 90,\n" +
|
||||
" \"unit\": \"days\",\n" +
|
||||
" \"system\": \"http://unitsofmeasure.org\",\n" +
|
||||
" \"code\": \"d\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"intent\": \"order\",\n" +
|
||||
" \"category\": {\n" +
|
||||
" \"coding\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"http://terminology.hl7.org/CodeSystem/medicationrequest-category\",\n" +
|
||||
" \"code\": \"community\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"medicationCodeableConcept\": {\n" +
|
||||
" \"coding\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"http://www.nlm.nih.gov/research/umls/rxnorm\",\n" +
|
||||
" \"code\": \"1049502\",\n" +
|
||||
" \"display\": \"12 HR oxycodone hydrochloride 10 MG Extended Release Oral Tablet\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
HttpPost request = new HttpPost(ourCdsBase + "/opioidcds-10-order-sign");
|
||||
request.setEntity(new StringEntity(cdsRequest));
|
||||
request.addHeader("Content-Type", "application/json");
|
||||
|
||||
CloseableHttpResponse httpResponse = httpClient.execute(request);
|
||||
String result = EntityUtils.toString(httpResponse.getEntity());
|
||||
Gson gsonResponse = new Gson();
|
||||
JsonObject response = gsonResponse.fromJson(result, JsonObject.class);
|
||||
assertNotNull(response);
|
||||
JsonArray cards = response.getAsJsonArray("cards");
|
||||
assertEquals(0, cards.size());
|
||||
// assertEquals("\"Hello World!\"", cards.get(0).getAsJsonObject().get("summary").toString());
|
||||
} catch (IOException ioe) {
|
||||
fail(ioe.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,13 +151,6 @@ class ExampleServerDstu3IT implements IServerSupport {
|
||||
return count;
|
||||
}
|
||||
|
||||
private Bundle loadBundle(String theLocation, FhirContext theCtx, IGenericClient theClient) throws IOException {
|
||||
String json = stringFromResource(theLocation);
|
||||
Bundle bundle = (Bundle) theCtx.newJsonParser().parseResource(json);
|
||||
Bundle result = theClient.transaction().withBundle(bundle).execute();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWebsocketSubscription() throws Exception {
|
||||
/*
|
||||
|
||||
@@ -61,8 +61,8 @@ import static org.opencds.cqf.fhir.utility.r4.Parameters.stringPart;
|
||||
"hapi.fhir.subscription.websocket_enabled=true",
|
||||
//"hapi.fhir.mdm_enabled=true",
|
||||
"hapi.fhir.cr.enabled=true",
|
||||
"hapi.fhir.cr.caregaps_section_author=Organization/alphora-author",
|
||||
"hapi.fhir.cr.caregaps_reporter=Organization/alphora",
|
||||
"hapi.fhir.cr.caregaps.section_author=Organization/alphora-author",
|
||||
"hapi.fhir.cr.caregaps.reporter=Organization/alphora",
|
||||
"hapi.fhir.implementationguides.dk-core.name=hl7.fhir.dk.core",
|
||||
"hapi.fhir.implementationguides.dk-core.version=1.1.0",
|
||||
"hapi.fhir.auto_create_placeholder_reference_targets=true",
|
||||
@@ -130,13 +130,6 @@ class ExampleServerR4IT implements IServerSupport {
|
||||
assertEquals(measureUrl + "|0.0.003", report.getMeasure());
|
||||
}
|
||||
|
||||
private org.hl7.fhir.r4.model.Bundle loadBundle(String theLocation, FhirContext theCtx, IGenericClient theClient) throws IOException {
|
||||
String json = stringFromResource(theLocation);
|
||||
org.hl7.fhir.r4.model.Bundle bundle = (org.hl7.fhir.r4.model.Bundle) theCtx.newJsonParser().parseResource(json);
|
||||
org.hl7.fhir.r4.model.Bundle result = theClient.transaction().withBundle(bundle).execute();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Parameters runCqlExecution(Parameters parameters) {
|
||||
|
||||
var results = ourClient.operation().onServer()
|
||||
@@ -274,8 +267,8 @@ class ExampleServerR4IT implements IServerSupport {
|
||||
@Test
|
||||
void testCareGaps() throws IOException {
|
||||
|
||||
var reporter = crProperties.getCareGapsReporter();
|
||||
var author = crProperties.getCareGapsSectionAuthor();
|
||||
var reporter = crProperties.getCareGaps().getReporter();
|
||||
var author = crProperties.getCareGaps().getSection_author();
|
||||
|
||||
assertTrue(reporter.equals("Organization/alphora"));
|
||||
assertTrue(author.equals("Organization/alphora-author"));
|
||||
|
||||
@@ -3,8 +3,10 @@ package ca.uhn.fhir.jpa.starter;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -28,6 +30,12 @@ public interface IServerSupport {
|
||||
}
|
||||
}
|
||||
|
||||
default IBaseBundle loadBundle(String theLocation, FhirContext theFhirContext, IGenericClient theClient) throws IOException {
|
||||
String json = stringFromResource(theLocation);
|
||||
IBaseBundle bundle = (IBaseBundle) theFhirContext.newJsonParser().parseResource(json);
|
||||
return theClient.transaction().withBundle(bundle).execute();
|
||||
}
|
||||
|
||||
default String stringFromResource(String theLocation) throws IOException {
|
||||
InputStream is = null;
|
||||
if (theLocation.startsWith(File.separator)) {
|
||||
|
||||
309
src/test/resources/r4/HelloWorld-Bundle.json
Normal file
309
src/test/resources/r4/HelloWorld-Bundle.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user