package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.transaction.PlatformTransactionManager;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.TestDstu1Config;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Location;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.TestUtil;
public class FhirSystemDaoDstu1Test extends BaseJpaTest {
private static AnnotationConfigApplicationContext ourCtx;
private static EntityManager ourEntityManager;
private static FhirContext ourFhirContext;
private static IFhirResourceDao<Location> ourLocationDao;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu1Test.class);
private static IFhirResourceDao<Observation> ourObservationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirSystemDao<List<IResource>, MetaDt> ourSystemDao;
private static PlatformTransactionManager ourTxManager;
private static ISearchParamPresenceSvc ourSearchParamPresenceSvc;
private static ISearchCoordinatorSvc ourSearchCoordinatorSvc;
@Before
public void before() {
super.purgeDatabase(ourEntityManager, ourTxManager, ourSearchParamPresenceSvc, ourSearchCoordinatorSvc);
}
@Override
protected FhirContext getContext() {
return ourFhirContext;
}
@Test
public void testGetResourceCounts() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testGetResourceCountsO01");
ourObservationDao.create(obs, mySrd);
Map<String, Long> oldCounts = ourSystemDao.getResourceCounts();
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testGetResourceCountsP01");
patient.addName().addFamily("Tester").addGiven("Joe");
ourPatientDao.create(patient, mySrd);
Map<String, Long> newCounts = ourSystemDao.getResourceCounts();
if (oldCounts.containsKey("Patient")) {
assertEquals(oldCounts.get("Patient") + 1, (long) newCounts.get("Patient"));
} else {
assertEquals(1L, (long) newCounts.get("Patient"));
}
assertEquals((long) oldCounts.get("Observation"), (long) newCounts.get("Observation"));
}
@Test
public void testHistory() throws Exception {
Date start = new Date();
Thread.sleep(10);
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testHistory");
patient.addName().addFamily("Tester").addGiven("Joe");
IIdType pid = ourPatientDao.create(patient, mySrd).getId().toVersionless();
Thread.sleep(10);
patient.addName().addFamily("A");
patient.setId(pid);
IIdType newpid = ourPatientDao.update(patient, mySrd).getId();
Thread.sleep(10);
patient.addName().addFamily("B");
patient.setId(pid);
IIdType newpid2 = ourPatientDao.update(patient, mySrd).getId();
Thread.sleep(10);
patient.addName().addFamily("C");
patient.setId(pid);
IIdType newpid3 = ourPatientDao.update(patient, mySrd).getId();
IBundleProvider values = ourSystemDao.history(start, null, mySrd);
assertEquals(4, values.size().intValue());
List<IBaseResource> res = values.getResources(0, 4);
assertEquals(newpid3, res.get(0).getIdElement());
assertEquals(newpid2, res.get(1).getIdElement());
assertEquals(newpid, res.get(2).getIdElement());
assertEquals(pid.toUnqualifiedVersionless(), res.get(3).getIdElement().toUnqualifiedVersionless());
Location loc = new Location();
loc.getAddress().addLine("AAA");
IIdType lid = ourLocationDao.create(loc, mySrd).getId();
Location loc2 = new Location();
loc2.getAddress().addLine("AAA");
ourLocationDao.create(loc2, mySrd).getId();
Thread.sleep(2000);
values = ourLocationDao.history(start, null, mySrd);
assertEquals(2, values.size().intValue());
values = ourLocationDao.history(lid.toUnqualifiedVersionless(), start, null, mySrd);
assertEquals(1, values.size().intValue());
}
@Test
public void testPersistWithSimpleLink() {
Patient patient = new Patient();
patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01"));
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
patient.addName().addFamily("Tester").addGiven("Joe");
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01"));
ourSystemDao.transaction(mySrd, Arrays.asList((IResource) patient, obs));
String patientId = (patient.getId().getIdPart());
String obsId = (obs.getId().getIdPart());
// assertThat(patientId, greaterThan(0L));
// assertEquals(patientVersion, 1L);
// assertThat(obsId, greaterThan(patientId));
// assertEquals(obsVersion, 1L);
// Try to search
IBundleProvider obsResults = ourObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_NAME, new IdentifierDt("urn:system", "testPersistWithSimpleLinkO01")));
assertEquals(1, obsResults.size().intValue());
IBundleProvider patResults = ourPatientDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01")));
assertEquals(1, obsResults.size().intValue());
IIdType foundPatientId = patResults.getResources(0, 1).get(0).getIdElement();
ResourceReferenceDt subject = obs.getSubject();
assertEquals(foundPatientId.getIdPart(), subject.getReference().getIdPart());
// Update
patient = (Patient) patResults.getResources(0, 1).get(0);
obs = (Observation) obsResults.getResources(0, 1).get(0);
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02");
ourSystemDao.transaction(mySrd, Arrays.asList((IResource) patient, obs));
String patientId2 = (patient.getId().getIdPart());
String patientVersion2 = (patient.getId().getVersionIdPart());
String obsId2 = (obs.getId().getIdPart());
String obsVersion2 = (obs.getId().getVersionIdPart());
assertEquals(patientId, patientId2);
assertEquals(patientVersion2, "2");
assertEquals(obsId, obsId2);
assertEquals(obsVersion2, "2");
}
@Test
public void testPersistWithUnknownId() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/999998888888"));
try {
ourSystemDao.transaction(mySrd, Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/999998888888 not found, specified in path: Observation.subject"));
}
obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/1.2.3.4"));
try {
ourSystemDao.transaction(mySrd, Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/1.2.3.4 not found, specified in path: Observation.subject"));
}
}
@Test
public void testTagOperationss() throws Exception {
TagList preSystemTl = ourSystemDao.getAllTags(mySrd);
TagList tl1 = new TagList();
tl1.addTag("testGetAllTagsScheme1", "testGetAllTagsTerm1", "testGetAllTagsLabel1");
Patient p1 = new Patient();
p1.addIdentifier().setSystem("foo").setValue("testGetAllTags01");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, tl1);
ourPatientDao.create(p1, mySrd);
TagList tl2 = new TagList();
tl2.addTag("testGetAllTagsScheme2", "testGetAllTagsTerm2", "testGetAllTagsLabel2");
Observation o1 = new Observation();
o1.getName().setText("testGetAllTags02");
ResourceMetadataKeyEnum.TAG_LIST.put(o1, tl2);
IIdType o1id = ourObservationDao.create(o1, mySrd).getId();
assertTrue(o1id.getVersionIdPart() != null);
TagList postSystemTl = ourSystemDao.getAllTags(mySrd);
assertEquals(preSystemTl.size() + 2, postSystemTl.size());
assertEquals("testGetAllTagsLabel1", postSystemTl.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel());
TagList tags = ourPatientDao.getAllResourceTags(mySrd);
assertEquals("testGetAllTagsLabel1", tags.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel());
assertNull(tags.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
TagList tags2 = ourObservationDao.getTags(o1id, mySrd);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel());
o1.setId(o1id);
IIdType o1id2 = ourObservationDao.update(o1, mySrd).getId();
assertTrue(o1id2.getVersionIdPart() != null);
tags2 = ourObservationDao.getTags(o1id, mySrd);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel());
tags2 = ourObservationDao.getTags(o1id2, mySrd);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
/*
* Remove a tag from a version
*/
ourObservationDao.removeTag(o1id2, TagTypeEnum.TAG, "testGetAllTagsScheme2", "testGetAllTagsTerm2", mySrd);
tags2 = ourObservationDao.getTags(o1id2, mySrd);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
tags2 = ourObservationDao.getTags(o1id, mySrd);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
/*
* Add a tag
*/
ourObservationDao.addTag(o1id2, TagTypeEnum.TAG, "testGetAllTagsScheme3", "testGetAllTagsTerm3", "testGetAllTagsLabel3");
tags2 = ourObservationDao.getTags(o1id2, mySrd);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
assertNotNull(tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3"));
assertEquals("testGetAllTagsLabel3", tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3").getLabel());
tags2 = ourObservationDao.getTags(o1id, mySrd);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
}
@Test(expected = InvalidRequestException.class)
public void testTransactionFailsWithDuplicateIds() {
Patient patient1 = new Patient();
patient1.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient1.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
Patient patient2 = new Patient();
patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
ourSystemDao.transaction(mySrd, Arrays.asList((IResource) patient1, patient2));
}
@Test
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = FhirSystemDaoDstu1Test.class.getResourceAsStream("/bundle-dstu1.xml");
Bundle bundle = ourFhirContext.newXmlParser().parseBundle(new InputStreamReader(bundleRes));
List<IResource> res = bundle.toListOfResources();
ourSystemDao.transaction(mySrd, res);
Patient p1 = (Patient) res.get(0);
String id = p1.getId().getValue();
ourLog.info("ID: {}", id);
assertThat(id, not(equalToIgnoringCase("74635")));
assertThat(id, not(equalToIgnoringCase("")));
}
/**
* Issue #55. Note that this is the incorrect way to do this but we'll leave it since people may depend on it.
*/
@Test
public void testTransactionWithCidIds() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.setId("cid:patient1");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01");
res.add(p1);
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds02");
o1.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o1);
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds03");
o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o2);
ourSystemDao.transaction(mySrd, res);
assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
}
@Test
public void testTransactionWithCidIds2() throws Exception {
String resource = "/dstu1_bundle.xml";
String bundleStr = loadClasspath(resource);
Bundle bundle = ourFhirContext.newXmlParser().parseBundle(bundleStr);
List<IResource> res = new ArrayList<IResource>();
for (BundleEntry next : bundle.getEntries()) {
res.add(next.getResource());
}
List<IResource> response = ourSystemDao.transaction(mySrd, res);
String encodeResourceToString = ourFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(response.get(0));
ourLog.info(encodeResourceToString);
assertThat(encodeResourceToString, not(containsString("smsp")));
}
/**
* This is the correct way to do this, not {@link #testTransactionWithCidIds()}
*/
@Test
public void testTransactionWithCidIdsUnqualified() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.setId("cid:patient1");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified01");
res.add(p1);
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified02");
o1.setSubject(new ResourceReferenceDt("cid:patient1"));
res.add(o1);
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIdsUnqualified03");
o2.setSubject(new ResourceReferenceDt("cid:patient1"));
res.add(o2);
ourSystemDao.transaction(mySrd, res);
assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
}
@Test
public void testTransactionWithDelete() throws Exception {
/*
* Create 3
*/
List<IResource> res;
res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p1);
Patient p2 = new Patient();
p2.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p2);
Patient p3 = new Patient();
p3.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p3);
ourSystemDao.transaction(mySrd, res);
/*
* Verify
*/
IBundleProvider results = ourPatientDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete")));
assertEquals(3, results.size().intValue());
/*
* Now delete 2
*/
res = new ArrayList<IResource>();
List<IBaseResource> existing = results.getResources(0, 3);
p1 = new Patient();
p1.setId(existing.get(0).getIdElement());
ResourceMetadataKeyEnum.DELETED_AT.put(p1, InstantDt.withCurrentTime());
res.add(p1);
p2 = new Patient();
p2.setId(existing.get(1).getIdElement());
ResourceMetadataKeyEnum.DELETED_AT.put(p2, InstantDt.withCurrentTime());
res.add(p2);
ourSystemDao.transaction(mySrd, res);
/*
* Verify
*/
IBundleProvider results2 = ourPatientDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete")));
assertEquals(1, results2.size().intValue());
List<IBaseResource> existing2 = results2.getResources(0, 1);
assertEquals(existing2.get(0).getIdElement(), existing.get(2).getIdElement());
}
@AfterClass
public static void afterClassClearContext() {
ourCtx.close();
TestUtil.clearAllStaticFieldsForUnitTest();
}
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
ourCtx = new AnnotationConfigApplicationContext(TestDstu1Config.class);
ourFhirContext = ourCtx.getBean("myFhirContextDstu1", FhirContext.class);
ourPatientDao = ourCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
ourLocationDao = ourCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class);
ourSystemDao = ourCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class);
ourEntityManager = ourCtx.getBean(EntityManager.class);
ourTxManager = ourCtx.getBean(PlatformTransactionManager.class);
ourSearchParamPresenceSvc = ourCtx.getBean(ISearchParamPresenceSvc.class);
ourSearchCoordinatorSvc = ourCtx.getBean(ISearchCoordinatorSvc.class);
}
}