2829 - Add DSTU3 Support To UploadTerminologyCommand (#2832)

This commit is contained in:
Kevin Dougan SmileCDR 2021-08-05 13:07:50 -04:00 committed by GitHub
parent 67682a86fb
commit 35d3e3689b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 233113 additions and 289 deletions

View File

@ -39,8 +39,8 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.CountingInputStream; import org.apache.commons.io.input.CountingInputStream;
import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.ICompositeType; import org.hl7.fhir.instance.model.api.ICompositeType;
import org.hl7.fhir.r4.model.CodeSystem;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
@ -154,7 +154,7 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand {
throw new ParseException("Could not detect FHIR encoding for file: " + nextDataFile); throw new ParseException("Could not detect FHIR encoding for file: " + nextDataFile);
} }
CodeSystem resource = encoding.newParser(myFhirCtx).parseResource(CodeSystem.class, contents); IBaseResource resource = encoding.newParser(myFhirCtx).parseResource(contents);
ParametersUtil.addParameterToParameters(myFhirCtx, inputParameters, TerminologyUploaderProvider.PARAM_CODESYSTEM, resource); ParametersUtil.addParameterToParameters(myFhirCtx, inputParameters, TerminologyUploaderProvider.PARAM_CODESYSTEM, resource);
} else { } else {

View File

@ -0,0 +1,197 @@
package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.term.UploadStatistics;
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.test.utilities.JettyUtil;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.ParseException;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.r4.model.IdType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class HeaderPassthroughOptionTest {
final String FHIR_VERSION = "r4";
private FhirContext myCtx = FhirContext.forR4();
private Server myServer;
private int myPort;
private final String headerKey1 = "test-header-key-1";
private final String headerValue1 = "test header value-1";
private static final String myConceptsFileName = "target/concepts.csv";
private static File myConceptsFile = new File(myConceptsFileName);
private static final String myHierarchyFileName = "target/hierarchy.csv";
private static File myHierarchyFile = new File(myHierarchyFileName);
private final CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
private final UploadTerminologyCommand testedCommand =
new RequestCapturingUploadTerminologyCommand(myCapturingInterceptor);
@Mock
protected ITermLoaderSvc myTermLoaderSvc;
@BeforeEach
public void beforeEach() throws Exception {
myServer = new Server(0);
TerminologyUploaderProvider provider = new TerminologyUploaderProvider(myCtx, myTermLoaderSvc);
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(myCtx);
servlet.registerProvider(provider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
myServer.setHandler(proxyHandler);
JettyUtil.startServer(myServer);
myPort = JettyUtil.getPortForStartedServer(myServer);
writeConceptAndHierarchyFiles();
when(myTermLoaderSvc.loadCustom(eq("http://foo"), anyList(), any()))
.thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101")));
}
@Test
public void oneHeader() throws Exception {
String[] args = new String[] {
"-v", FHIR_VERSION,
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName,
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\""
};
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
testedCommand.run(commandLine);
assertNotNull(myCapturingInterceptor.getLastRequest());
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
assertFalse(allHeaders.isEmpty());
assertTrue(allHeaders.containsKey(headerKey1));
assertEquals(1, allHeaders.get(headerKey1).size());
assertThat(allHeaders.get(headerKey1), hasItems(headerValue1));
}
@Test
public void twoHeadersSameKey() throws Exception {
final String headerValue2 = "test header value-2";
String[] args = new String[] {
"-v", FHIR_VERSION,
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName,
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\"",
"-hp", "\"" + headerKey1 + ":" + headerValue2 + "\""
};
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
testedCommand.run(commandLine);
assertNotNull(myCapturingInterceptor.getLastRequest());
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
assertFalse(allHeaders.isEmpty());
assertEquals(2, allHeaders.get(headerKey1).size());
assertTrue(allHeaders.containsKey(headerKey1));
assertEquals(2, allHeaders.get(headerKey1).size());
assertEquals(headerValue1, allHeaders.get(headerKey1).get(0));
assertEquals(headerValue2, allHeaders.get(headerKey1).get(1));
}
@Test
public void twoHeadersDifferentKeys() throws Exception {
final String headerKey2 = "test-header-key-2";
final String headerValue2 = "test header value-2";
String[] args = new String[] {
"-v", FHIR_VERSION,
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort,
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName,
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\"",
"-hp", "\"" + headerKey2 + ":" + headerValue2 + "\""
};
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
testedCommand.run(commandLine);
assertNotNull(myCapturingInterceptor.getLastRequest());
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
assertFalse(allHeaders.isEmpty());
assertTrue(allHeaders.containsKey(headerKey1));
assertEquals(1, allHeaders.get(headerKey1).size());
assertThat(allHeaders.get(headerKey1), hasItems(headerValue1));
assertTrue(allHeaders.containsKey(headerKey2));
assertEquals(1, allHeaders.get(headerKey2).size());
assertThat(allHeaders.get(headerKey2), hasItems(headerValue2));
}
private synchronized void writeConceptAndHierarchyFiles() throws IOException {
if (!myConceptsFile.exists()) {
try (FileWriter w = new FileWriter(myConceptsFile, false)) {
w.append("CODE,DISPLAY\n");
w.append("ANIMALS,Animals\n");
w.append("CATS,Cats\n");
w.append("DOGS,Dogs\n");
}
}
if (!myHierarchyFile.exists()) {
try (FileWriter w = new FileWriter(myHierarchyFile, false)) {
w.append("PARENT,CHILD\n");
w.append("ANIMALS,CATS\n");
w.append("ANIMALS,DOGS\n");
}
}
}
private class RequestCapturingUploadTerminologyCommand extends UploadTerminologyCommand {
private CapturingInterceptor myCapturingInterceptor;
public RequestCapturingUploadTerminologyCommand(CapturingInterceptor theCapturingInterceptor) {
myCapturingInterceptor = theCapturingInterceptor;
}
@Override
protected IGenericClient newClient(CommandLine theCommandLine) throws ParseException {
IGenericClient client = super.newClient(theCommandLine);
client.getInterceptorService().registerInterceptor(myCapturingInterceptor);
return client;
}
}
}

View File

@ -4,31 +4,21 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.term.UploadStatistics; import ca.uhn.fhir.jpa.term.UploadStatistics;
import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc; import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.test.BaseTest;
import ca.uhn.fhir.test.utilities.JettyUtil; import ca.uhn.fhir.test.utilities.JettyUtil;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
@ -41,65 +31,108 @@ import java.io.FileOutputStream;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.stream.Stream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.matchesPattern; import static org.hamcrest.Matchers.matchesPattern;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.anyList;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class UploadTerminologyCommandTest extends BaseTest { public class UploadTerminologyCommandTest {
private static final String FHIR_VERSION_DSTU3 = "DSTU3";
private static final String FHIR_VERSION_R4 = "R4";
private FhirContext myCtx;
private final String myConceptsFileName = "target/concepts.csv";
private File myConceptsFile = new File(myConceptsFileName);
private final String myHierarchyFileName = "target/hierarchy.csv";
private File myHierarchyFile = new File(myHierarchyFileName);
private final String myCodeSystemFileName = "target/codesystem.json";
private File myCodeSystemFile = new File(myCodeSystemFileName);
private final String myTextFileName = "target/hello.txt";
private File myTextFile = new File(myTextFileName);
private final String myPropertiesFileName = "target/hello.properties";
private File myPropertiesFile = new File(myTextFileName);
private File myArchiveFile;
private String myArchiveFileName;
private final String myICD10URL = "http://hl7.org/fhir/sid/icd-10-cm";
private final String myICD10FileName = new File("src/test/resources").getAbsolutePath() + "/icd10cm_tabular_2021.xml";
private File myICD10File = new File(myICD10FileName);
private Server myServer;
private int myPort;
@Mock
protected ITermLoaderSvc myTermLoaderSvc;
@Captor
protected ArgumentCaptor<List<ITermLoaderSvc.FileDescriptor>> myDescriptorListCaptor;
static { static {
System.setProperty("test", "true"); System.setProperty("test", "true");
} }
private Server myServer; static Stream<String> paramsProvider() {
private FhirContext myCtx = FhirContext.forR4(); return Stream.of(FHIR_VERSION_DSTU3, FHIR_VERSION_R4);
@Mock }
private ITermLoaderSvc myTermLoaderSvc;
@Captor
private ArgumentCaptor<List<ITermLoaderSvc.FileDescriptor>> myDescriptorListCaptor;
private int myPort;
private String myConceptsFileName = "target/concepts.csv";
private File myConceptsFile = new File(myConceptsFileName);
private String myHierarchyFileName = "target/hierarchy.csv";
private File myHierarchyFile = new File(myHierarchyFileName);
private String myCodeSystemFileName = "target/codesystem.json";
private File myCodeSystemFile = new File(myCodeSystemFileName);
private String myTextFileName = "target/hello.txt";
private File myTextFile = new File(myTextFileName);
private File myArchiveFile;
private String myArchiveFileName;
private String myPropertiesFileName = "target/hello.properties";
private File myPropertiesFile = new File(myTextFileName);
@Test
public void testDeltaAdd() throws IOException {
@BeforeEach
public void beforeEach(TestInfo testInfo) throws Exception {
writeConceptAndHierarchyFiles(); writeConceptAndHierarchyFiles();
if (testInfo.getDisplayName().endsWith(FHIR_VERSION_DSTU3)) {
myCtx = FhirContext.forDstu3();
} else if (testInfo.getDisplayName().endsWith(FHIR_VERSION_R4)) {
myCtx = FhirContext.forR4();
} else {
fail("Unknown FHIR Version param provided: " + testInfo.getDisplayName());
}
myServer = new Server(0);
TerminologyUploaderProvider provider = new TerminologyUploaderProvider(myCtx, myTermLoaderSvc);
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(myCtx);
servlet.registerProvider(provider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
myServer.setHandler(proxyHandler);
JettyUtil.startServer(myServer);
myPort = JettyUtil.getPortForStartedServer(myServer);
}
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101"))); @AfterEach
public void afterEach() throws Exception {
JettyUtil.closeServer(myServer);
FileUtils.deleteQuietly(myConceptsFile);
FileUtils.deleteQuietly(myHierarchyFile);
FileUtils.deleteQuietly(myCodeSystemFile);
FileUtils.deleteQuietly(myTextFile);
FileUtils.deleteQuietly(myArchiveFile);
FileUtils.deleteQuietly(myPropertiesFile);
UploadTerminologyCommand.setTransferSizeLimitForUnitTest(-1);
}
@ParameterizedTest
@MethodSource("paramsProvider")
public void testDeltaAdd(String theFhirVersion) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
} else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "ADD", "-m", "ADD",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -115,20 +148,30 @@ public class UploadTerminologyCommandTest extends BaseTest {
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100)); assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
} }
@Test @ParameterizedTest
public void testDeltaAddUsingCodeSystemResource() throws IOException { @MethodSource("paramsProvider")
public void testDeltaAddUsingCodeSystemResource(String theFhirVersion) throws IOException {
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) { if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
CodeSystem cs = new CodeSystem(); try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
cs.addConcept().setCode("CODE").setDisplay("Display"); org.hl7.fhir.dstu3.model.CodeSystem cs = new org.hl7.fhir.dstu3.model.CodeSystem();
myCtx.newJsonParser().encodeResourceToWriter(cs, w); cs.addConcept().setCode("CODE").setDisplay("Display");
myCtx.newJsonParser().encodeResourceToWriter(cs, w);
}
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
org.hl7.fhir.r4.model.CodeSystem cs = new org.hl7.fhir.r4.model.CodeSystem();
cs.addConcept().setCode("CODE").setDisplay("Display");
myCtx.newJsonParser().encodeResourceToWriter(cs, w);
}
} else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
} }
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101"))); when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "ADD", "-m", "ADD",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -144,19 +187,29 @@ public class UploadTerminologyCommandTest extends BaseTest {
assertThat(uploadFile, uploadFile, containsString("\"CODE\",\"Display\"")); assertThat(uploadFile, uploadFile, containsString("\"CODE\",\"Display\""));
} }
@Test @ParameterizedTest
public void testDeltaAddInvalidResource() throws IOException { @MethodSource("paramsProvider")
public void testDeltaAddInvalidResource(String theFhirVersion) throws IOException {
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) { if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
Patient patient = new Patient(); try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
patient.setActive(true); org.hl7.fhir.dstu3.model.Patient patient = new org.hl7.fhir.dstu3.model.Patient();
myCtx.newJsonParser().encodeResourceToWriter(patient, w); patient.setActive(true);
myCtx.newJsonParser().encodeResourceToWriter(patient, w);
}
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
try (FileWriter w = new FileWriter(myCodeSystemFile, false)) {
org.hl7.fhir.r4.model.Patient patient = new org.hl7.fhir.r4.model.Patient();
patient.setActive(true);
myCtx.newJsonParser().encodeResourceToWriter(patient, w);
}
} else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
} }
try { try {
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "ADD", "-m", "ADD",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -164,13 +217,13 @@ public class UploadTerminologyCommandTest extends BaseTest {
}); });
fail(); fail();
} catch (Error e) { } catch (Error e) {
assertThat(e.toString(), containsString("Incorrect resource type found, expected \"CodeSystem\" but found \"Patient\"")); assertThat(e.toString(), containsString("HTTP 400 Bad Request: Request has parameter codeSystem of type Patient but method expects type CodeSystem"));
} }
} }
@Test @ParameterizedTest
public void testDeltaAddInvalidFileType() throws IOException { @MethodSource("paramsProvider")
public void testDeltaAddInvalidFileType(String theFhirVersion) throws IOException {
try (FileWriter w = new FileWriter(myTextFileName, false)) { try (FileWriter w = new FileWriter(myTextFileName, false)) {
w.append("Help I'm a Bug"); w.append("Help I'm a Bug");
} }
@ -178,7 +231,7 @@ public class UploadTerminologyCommandTest extends BaseTest {
try { try {
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "ADD", "-m", "ADD",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -190,17 +243,16 @@ public class UploadTerminologyCommandTest extends BaseTest {
} }
} }
@Test @ParameterizedTest
public void testDeltaAddUsingCompressedFile() throws IOException { @MethodSource("paramsProvider")
public void testDeltaAddUsingCompressedFile(String theFhirVersion) throws IOException {
writeConceptAndHierarchyFiles();
writeArchiveFile(myConceptsFile, myHierarchyFile); writeArchiveFile(myConceptsFile, myHierarchyFile);
when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101"))); when(myTermLoaderSvc.loadDeltaAdd(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "ADD", "-m", "ADD",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -215,15 +267,13 @@ public class UploadTerminologyCommandTest extends BaseTest {
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100)); assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
} }
@Test @ParameterizedTest
public void testDeltaAddInvalidFileName() throws IOException { @MethodSource("paramsProvider")
public void testDeltaAddInvalidFileName(String theFhirVersion) throws IOException {
writeConceptAndHierarchyFiles();
try { try {
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "ADD", "-m", "ADD",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -235,15 +285,20 @@ public class UploadTerminologyCommandTest extends BaseTest {
} }
} }
@Test @ParameterizedTest
public void testDeltaRemove() throws IOException { @MethodSource("paramsProvider")
writeConceptAndHierarchyFiles(); public void testDeltaRemove(String theFhirVersion) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadDeltaRemove(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101"))); when(myTermLoaderSvc.loadDeltaRemove(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadDeltaRemove(eq("http://foo"), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
} else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "REMOVE", "-m", "REMOVE",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -257,21 +312,22 @@ public class UploadTerminologyCommandTest extends BaseTest {
assertEquals(1, listOfDescriptors.size()); assertEquals(1, listOfDescriptors.size());
assertEquals("file:/files.zip", listOfDescriptors.get(0).getFilename()); assertEquals("file:/files.zip", listOfDescriptors.get(0).getFilename());
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100)); assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
} }
@Test @ParameterizedTest
public void testSnapshot() throws IOException { @MethodSource("paramsProvider")
public void testSnapshot(String theFhirVersion) throws IOException {
if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
writeConceptAndHierarchyFiles(); } else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101"))); } else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "SNAPSHOT", "-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -287,17 +343,24 @@ public class UploadTerminologyCommandTest extends BaseTest {
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100)); assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
} }
@Test @ParameterizedTest
public void testPropertiesFile() throws IOException { @MethodSource("paramsProvider")
public void testPropertiesFile(String theFhirVersion) throws IOException {
try (FileWriter w = new FileWriter(myPropertiesFileName, false)) { try (FileWriter w = new FileWriter(myPropertiesFileName, false)) {
w.append("a=b\n"); w.append("a=b\n");
} }
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101"))); if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
} else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "SNAPSHOT", "-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -310,26 +373,24 @@ public class UploadTerminologyCommandTest extends BaseTest {
assertEquals(1, listOfDescriptors.size()); assertEquals(1, listOfDescriptors.size());
assertThat(listOfDescriptors.get(0).getFilename(), matchesPattern(".*\\.zip$")); assertThat(listOfDescriptors.get(0).getFilename(), matchesPattern(".*\\.zip$"));
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100)); assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
} }
/** @ParameterizedTest
* When transferring large files, we use a local file to store the binary instead of @MethodSource("paramsProvider")
* using HTTP to transfer a giant base 64 encoded attachment. Hopefully we can public void testSnapshotLargeFile(String theFhirVersion) throws IOException {
* replace this with a bulk data import at some point when that gets implemented.
*/
@Test
public void testSnapshotLargeFile() throws IOException {
UploadTerminologyCommand.setTransferSizeLimitForUnitTest(10); UploadTerminologyCommand.setTransferSizeLimitForUnitTest(10);
writeConceptAndHierarchyFiles(); if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101"))); } else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
when(myTermLoaderSvc.loadCustom(any(), anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
} else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
}
App.main(new String[]{ App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY, UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", "r4", "-v", theFhirVersion,
"-m", "SNAPSHOT", "-m", "SNAPSHOT",
"-t", "http://localhost:" + myPort, "-t", "http://localhost:" + myPort,
"-u", "http://foo", "-u", "http://foo",
@ -345,139 +406,51 @@ public class UploadTerminologyCommandTest extends BaseTest {
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100)); assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
} }
@Nested @ParameterizedTest
public class HeaderPassthroughOptionTests { @MethodSource("paramsProvider")
public void testUploadICD10UsingCompressedFile(String theFhirVersion) throws IOException {
@RegisterExtension if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) {
public final RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(myCtx); when(myTermLoaderSvc.loadIcd10cm(anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101")));
} else if (FHIR_VERSION_R4.equals(theFhirVersion)) {
private final String headerKey1 = "test-header-key-1"; when(myTermLoaderSvc.loadIcd10cm(anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.r4.model.IdType("CodeSystem/101")));
private final String headerValue1 = "test header value-1"; } else {
fail("Unknown FHIR Version param provided: " + theFhirVersion);
private final CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
private final UploadTerminologyCommand testedCommand =
new RequestCapturingUploadTerminologyCommand(myCapturingInterceptor);
@BeforeEach
public void before() {
when(myTermLoaderSvc.loadCustom(eq("http://foo"), anyList(), any()))
.thenReturn(new UploadStatistics(100, new IdType("CodeSystem/101")));
TerminologyUploaderProvider provider = new TerminologyUploaderProvider(myCtx, myTermLoaderSvc);
myRestfulServerExtension.registerProvider(provider);
} }
App.main(new String[]{
UploadTerminologyCommand.UPLOAD_TERMINOLOGY,
"-v", theFhirVersion,
"-t", "http://localhost:" + myPort,
"-u", myICD10URL,
"-d", myICD10FileName
});
@Test verify(myTermLoaderSvc, times(1)).loadIcd10cm(myDescriptorListCaptor.capture(), any());
public void oneHeader() throws Exception {
String[] args = new String[] {
"-v", "r4",
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myRestfulServerExtension.getPort(),
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName,
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\""
};
writeConceptAndHierarchyFiles(); List<ITermLoaderSvc.FileDescriptor> listOfDescriptors = myDescriptorListCaptor.getValue();
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true); assertEquals(1, listOfDescriptors.size());
testedCommand.run(commandLine); assertThat(listOfDescriptors.get(0).getFilename(), matchesPattern("^file:.*files.*\\.zip$"));
assertThat(IOUtils.toByteArray(listOfDescriptors.get(0).getInputStream()).length, greaterThan(100));
}
assertNotNull(myCapturingInterceptor.getLastRequest()); private synchronized void writeConceptAndHierarchyFiles() throws IOException {
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders(); if (!myConceptsFile.exists()) {
assertFalse(allHeaders.isEmpty()); try (FileWriter w = new FileWriter(myConceptsFile, false)) {
w.append("CODE,DISPLAY\n");
assertTrue(allHeaders.containsKey(headerKey1)); w.append("ANIMALS,Animals\n");
assertEquals(1, allHeaders.get(headerKey1).size()); w.append("CATS,Cats\n");
w.append("DOGS,Dogs\n");
assertThat(allHeaders.get(headerKey1), hasItems(headerValue1));
}
@Test
public void twoHeadersSameKey() throws Exception {
final String headerValue2 = "test header value-2";
String[] args = new String[] {
"-v", "r4",
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myRestfulServerExtension.getPort(),
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName,
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\"",
"-hp", "\"" + headerKey1 + ":" + headerValue2 + "\""
};
writeConceptAndHierarchyFiles();
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
testedCommand.run(commandLine);
assertNotNull(myCapturingInterceptor.getLastRequest());
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
assertFalse(allHeaders.isEmpty());
assertEquals(2, allHeaders.get(headerKey1).size());
assertTrue(allHeaders.containsKey(headerKey1));
assertEquals(2, allHeaders.get(headerKey1).size());
assertEquals(headerValue1, allHeaders.get(headerKey1).get(0));
assertEquals(headerValue2, allHeaders.get(headerKey1).get(1));
}
@Test
public void twoHeadersDifferentKeys() throws Exception {
final String headerKey2 = "test-header-key-2";
final String headerValue2 = "test header value-2";
String[] args = new String[] {
"-v", "r4",
"-m", "SNAPSHOT",
"-t", "http://localhost:" + myRestfulServerExtension.getPort(),
"-u", "http://foo",
"-d", myConceptsFileName,
"-d", myHierarchyFileName,
"-hp", "\"" + headerKey1 + ":" + headerValue1 + "\"",
"-hp", "\"" + headerKey2 + ":" + headerValue2 + "\""
};
writeConceptAndHierarchyFiles();
final CommandLine commandLine = new DefaultParser().parse(testedCommand.getOptions(), args, true);
testedCommand.run(commandLine);
assertNotNull(myCapturingInterceptor.getLastRequest());
Map<String, List<String>> allHeaders = myCapturingInterceptor.getLastRequest().getAllHeaders();
assertFalse(allHeaders.isEmpty());
assertTrue(allHeaders.containsKey(headerKey1));
assertEquals(1, allHeaders.get(headerKey1).size());
assertThat(allHeaders.get(headerKey1), hasItems(headerValue1));
assertTrue(allHeaders.containsKey(headerKey2));
assertEquals(1, allHeaders.get(headerKey2).size());
assertThat(allHeaders.get(headerKey2), hasItems(headerValue2));
}
private class RequestCapturingUploadTerminologyCommand extends UploadTerminologyCommand {
private CapturingInterceptor myCapturingInterceptor;
public RequestCapturingUploadTerminologyCommand(CapturingInterceptor theCapturingInterceptor) {
myCapturingInterceptor = theCapturingInterceptor;
} }
}
@Override if (!myHierarchyFile.exists()) {
protected IGenericClient newClient(CommandLine theCommandLine) throws ParseException { try (FileWriter w = new FileWriter(myHierarchyFile, false)) {
IGenericClient client = super.newClient(theCommandLine); w.append("PARENT,CHILD\n");
client.getInterceptorService().registerInterceptor(myCapturingInterceptor); w.append("ANIMALS,CATS\n");
return client; w.append("ANIMALS,DOGS\n");
} }
} }
} }
private void writeArchiveFile(File... theFiles) throws IOException { private void writeArchiveFile(File... theFiles) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream, Charsets.UTF_8); ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream, Charsets.UTF_8);
@ -485,11 +458,9 @@ public class UploadTerminologyCommandTest extends BaseTest {
for (File next : theFiles) { for (File next : theFiles) {
ZipEntry nextEntry = new ZipEntry(UploadTerminologyCommand.stripPath(next.getAbsolutePath())); ZipEntry nextEntry = new ZipEntry(UploadTerminologyCommand.stripPath(next.getAbsolutePath()));
zipOutputStream.putNextEntry(nextEntry); zipOutputStream.putNextEntry(nextEntry);
try (FileInputStream fileInputStream = new FileInputStream(next)) { try (FileInputStream fileInputStream = new FileInputStream(next)) {
IOUtils.copy(fileInputStream, zipOutputStream); IOUtils.copy(fileInputStream, zipOutputStream);
} }
} }
zipOutputStream.flush(); zipOutputStream.flush();
@ -502,54 +473,4 @@ public class UploadTerminologyCommandTest extends BaseTest {
fos.write(byteArrayOutputStream.toByteArray()); fos.write(byteArrayOutputStream.toByteArray());
} }
} }
private void writeConceptAndHierarchyFiles() throws IOException {
try (FileWriter w = new FileWriter(myConceptsFile, false)) {
w.append("CODE,DISPLAY\n");
w.append("ANIMALS,Animals\n");
w.append("CATS,Cats\n");
w.append("DOGS,Dogs\n");
}
try (FileWriter w = new FileWriter(myHierarchyFile, false)) {
w.append("PARENT,CHILD\n");
w.append("ANIMALS,CATS\n");
w.append("ANIMALS,DOGS\n");
}
}
@AfterEach
public void after() throws Exception {
JettyUtil.closeServer(myServer);
FileUtils.deleteQuietly(myConceptsFile);
FileUtils.deleteQuietly(myHierarchyFile);
FileUtils.deleteQuietly(myArchiveFile);
FileUtils.deleteQuietly(myCodeSystemFile);
FileUtils.deleteQuietly(myTextFile);
FileUtils.deleteQuietly(myPropertiesFile);
UploadTerminologyCommand.setTransferSizeLimitForUnitTest(-1);
}
@BeforeEach
public void before() throws Exception {
myServer = new Server(0);
TerminologyUploaderProvider provider = new TerminologyUploaderProvider(myCtx, myTermLoaderSvc);
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(myCtx);
servlet.registerProvider(provider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
myServer.setHandler(proxyHandler);
JettyUtil.startServer(myServer);
myPort = JettyUtil.getPortForStartedServer(myServer);
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
---
type: fix
issue: 2829
title: "Add DSTU3 Support To UploadTerminologyCommand."