package ca.uhn.fhir.jpa.term;
import static org.hamcrest.Matchers.containsInRelativeOrder;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.TestUtil;
@RunWith(MockitoJUnitRunner.class)
public class TerminologyLoaderSvcTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TerminologyLoaderSvcTest.class);
private TerminologyLoaderSvc mySvc;
@Mock
private IHapiTerminologySvc myTermSvc;
@Captor
private ArgumentCaptor<TermCodeSystemVersion> myCsvCaptor;
@Before
public void before() {
mySvc = new TerminologyLoaderSvc();
mySvc.setTermSvcForUnitTests(myTermSvc);
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Test
public void testLoadLoinc() throws Exception {
ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
ZipOutputStream zos1 = new ZipOutputStream(bos1);
addEntry(zos1, "/loinc/", "loinc.csv");
zos1.close();
ourLog.info("ZIP file has {} bytes", bos1.toByteArray().length);
ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
ZipOutputStream zos2 = new ZipOutputStream(bos2);
addEntry(zos2, "/loinc/", "LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV");
zos2.close();
ourLog.info("ZIP file has {} bytes", bos2.toByteArray().length);
RequestDetails details = mock(RequestDetails.class);
mySvc.loadLoinc(list(bos1.toByteArray(), bos2.toByteArray()), details);
verify(myTermSvc, times(1)).storeNewCodeSystemVersion(mySystemCaptor.capture(), myCsvCaptor.capture(), any(RequestDetails.class));
TermCodeSystemVersion ver = myCsvCaptor.getValue();
TermConcept code = ver.getConcepts().iterator().next();
assertEquals("10013-1", code.getCode());
}
@Captor
private ArgumentCaptor<String> mySystemCaptor;
/**
* This is just for trying stuff, it won't run without
* local files external to the git repo
*/
@Ignore
@Test
public void testLoadSnomedCtAgainstRealFile() throws Exception {
byte[] bytes = IOUtils.toByteArray(new FileInputStream("/Users/james/Downloads/SnomedCT_Release_INT_20160131_Full.zip"));
RequestDetails details = mock(RequestDetails.class);
mySvc.loadSnomedCt(list(bytes), details);
}
@Test
public void testLoadSnomedCt() throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(bos);
addEntry(zos, "/sct/", "sct2_Concept_Full_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_Concept_Full-en_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_Description_Full-en_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_Identifier_Full_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_Relationship_Full_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_TextDefinition_Full-en_INT_20160131.txt");
zos.close();
ourLog.info("ZIP file has {} bytes", bos.toByteArray().length);
RequestDetails details = mock(RequestDetails.class);
mySvc.loadSnomedCt(list(bos.toByteArray()), details);
verify(myTermSvc).storeNewCodeSystemVersion(any(String.class), myCsvCaptor.capture(), any(RequestDetails.class));
TermCodeSystemVersion csv = myCsvCaptor.getValue();
TreeSet<String> allCodes = toCodes(csv, true);
ourLog.info(allCodes.toString());
assertThat(allCodes, containsInRelativeOrder("116680003"));
assertThat(allCodes, not(containsInRelativeOrder("207527008")));
allCodes = toCodes(csv, false);
ourLog.info(allCodes.toString());
assertThat(allCodes, hasItem("126816002"));
}
private List<byte[]> list(byte[]... theByteArray) {
return new ArrayList<byte[]>(Arrays.asList(theByteArray));
}
private TreeSet<String> toCodes(TermCodeSystemVersion theCsv, boolean theAddChildren) {
TreeSet<String> retVal = new TreeSet<String>();
for (TermConcept next : theCsv.getConcepts()) {
toCodes(retVal, next, theAddChildren);
}
return retVal;
}
private void toCodes(TreeSet<String> theCodes, TermConcept theConcept, boolean theAddChildren) {
theCodes.add(theConcept.getCode());
if (theAddChildren) {
for (TermConceptParentChildLink next : theConcept.getChildren()) {
toCodes(theCodes, next.getChild(), theAddChildren);
}
}
}
@Test
public void testLoadSnomedCtBadInput() throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(bos);
addEntry(zos, "/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
zos.close();
ourLog.info("ZIP file has {} bytes", bos.toByteArray().length);
RequestDetails details = mock(RequestDetails.class);
try {
mySvc.loadSnomedCt(Collections.singletonList(bos.toByteArray()), details);
fail();
} catch (InvalidRequestException e) {
assertEquals("Invalid input zip file, expected zip to contain the following name fragments: [Terminology/sct2_Description_Full-en, Terminology/sct2_Relationship_Full, Terminology/sct2_Concept_Full_] but found: []", e.getMessage());
}
}
private void addEntry(ZipOutputStream zos, String theClasspathPrefix, String theFileName) throws IOException {
ourLog.info("Adding {} to test zip", theFileName);
zos.putNextEntry(new ZipEntry("SnomedCT_Release_INT_20160131_Full/Terminology/" + theFileName));
byte[] byteArray = IOUtils.toByteArray(getClass().getResourceAsStream(theClasspathPrefix + theFileName));
Validate.notNull(byteArray);
zos.write(byteArray);
zos.closeEntry();
}
}