/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.module.sync; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Set; import java.util.TreeSet; import junit.framework.Assert; import org.junit.Test; import org.openmrs.Concept; import org.openmrs.Encounter; import org.openmrs.Location; import org.openmrs.Obs; import org.openmrs.Patient; import org.openmrs.PatientIdentifier; import org.openmrs.PatientIdentifierType; import org.openmrs.PatientProgram; import org.openmrs.Person; import org.openmrs.PersonName; import org.openmrs.Program; import org.openmrs.ProgramWorkflow; import org.openmrs.ProgramWorkflowState; import org.openmrs.User; import org.openmrs.api.ConceptService; import org.openmrs.api.context.Context; import org.openmrs.util.OpenmrsUtil; import org.springframework.test.annotation.NotTransactional; /** * Tests creating various pieces of data via synchronization */ public class SyncPatientTest extends SyncBaseTest { @Override public String getInitialDataset() { try { return "org/openmrs/module/sync/include/" + new TestUtil().getTestDatasetFilename("syncCreateTest"); } catch (Exception e) { throw new RuntimeException(e); } } @Test @NotTransactional public void shouldEnrollInProgram() throws Exception { runSyncTest(new SyncTestHelper() { int numberEnrolledBefore = 0; Date dateEnrolled = new Date(System.currentTimeMillis() - 100000); Date dateCompleted = new Date(System.currentTimeMillis() - 10000); Program hivProgram = null; public void runOnChild() { User creator = Context.getAuthenticatedUser(); Patient p = Context.getPatientService().getPatient(2); numberEnrolledBefore = Context.getProgramWorkflowService().getPatientPrograms(p).size(); hivProgram = Context.getProgramWorkflowService().getProgram("HIV PROGRAM"); Context.getProgramWorkflowService().enrollPatientInProgram(p, hivProgram, dateEnrolled, dateCompleted, creator); } public void runOnParent() { int compare = 0; Patient p = Context.getPatientService().getPatient(2); assertEquals("Enrollment failed", numberEnrolledBefore + 1, Context.getProgramWorkflowService().getPatientPrograms(p).size()); for (PatientProgram pp : Context.getProgramWorkflowService().getPatientPrograms(p)) { if (pp.getProgram().equals(hivProgram)) { compare = OpenmrsUtil.compare( pp.getDateEnrolled(), dateEnrolled); assertEquals("Failed to change date", compare, 0); compare = OpenmrsUtil.compare( pp.getDateCompleted(), dateCompleted); assertEquals("Failed to change date", compare, 0); } } } }); } @Test @NotTransactional public void shouldEnrollInProgramAndState() throws Exception { runSyncTest(new SyncTestHelper() { int numberEnrolledBefore = 0; Date dateEnrolled = new Date(); Date dateCompleted = null; Program hivProgram = null; ProgramWorkflow txStat = null; ProgramWorkflowState curedState = null; public void runOnChild() { hivProgram = Context.getProgramWorkflowService().getProgramByName("HIV PROGRAM"); txStat = hivProgram.getWorkflowByName("TREATMENT STATUS"); curedState = txStat.getStateByName("PATIENT CURED"); Patient p = Context.getPatientService().getPatient(2); numberEnrolledBefore = Context.getProgramWorkflowService().getPatientPrograms(p).size(); Context.getProgramWorkflowService().enrollPatientInProgram(p, hivProgram, dateEnrolled,dateCompleted, Context.getAuthenticatedUser()); PatientProgram pp = null; for (PatientProgram ppLoop : Context.getProgramWorkflowService().getPatientPrograms(p)) { if (ppLoop.getProgram().equals(hivProgram)) { pp = ppLoop; break; } } Context.getProgramWorkflowService().changeToState(pp, txStat, curedState, dateEnrolled); } public void runOnParent() { int compare = 0; Patient p = Context.getPatientService().getPatient(2); assertEquals("Enrollment failed", numberEnrolledBefore + 1, Context.getProgramWorkflowService().getPatientPrograms(p).size()); for (PatientProgram pp : Context.getProgramWorkflowService().getPatientPrograms(p)) { if (pp.getProgram().equals(hivProgram)) { compare = OpenmrsUtil.compare( pp.getDateEnrolled(), dateEnrolled); assertEquals("Failed to change date", compare, 0); assertNotNull("Failed to change date", pp.getDateCompleted()); assertEquals("Wrong state", pp.getCurrentState(txStat).getState(), curedState); } } } }); } @Test @NotTransactional public void shouldChangeState() throws Exception { runSyncTest(new SyncTestHelper() { Program hivProgram; ProgramWorkflow txStat; ProgramWorkflowState curedState; public void runOnChild() { hivProgram = Context.getProgramWorkflowService().getProgram("HIV PROGRAM"); txStat = hivProgram.getWorkflowByName("TREATMENT STATUS"); curedState = txStat.getStateByName("PATIENT CURED"); Patient p = Context.getPatientService().getPatient(3); Collection<PatientProgram> temp = Context.getProgramWorkflowService().getPatientPrograms(p); assertEquals("Before test, patient record does not have the expected number of program enrollments", temp.size(), 1); PatientProgram pp = temp.iterator().next(); assertNotSame("Before test, patient record not in expected state", pp.getCurrentState(txStat), curedState); Context.getProgramWorkflowService().changeToState(pp, txStat, curedState, new Date()); } public void runOnParent() { Patient p = Context.getPatientService().getPatient(3); PatientProgram pp = Context.getProgramWorkflowService().getPatientPrograms(p).iterator().next(); assertEquals("State not set", pp.getCurrentState(txStat).getState(), curedState); } }); } @Test @NotTransactional public void shouldCreateEncounterAndObs() throws Exception { runSyncTest(new SyncTestHelper() { int numEncountersSoFar = 0; Date dateOfNewEncounter = new Date(); Date anotherDate = new Date(System.currentTimeMillis() - 20000l); public void runOnChild() { ConceptService cs = Context.getConceptService(); Concept weight = cs.getConceptByName("WEIGHT"); Concept reason = cs.getConceptByName("REASON ORDER STOPPED"); Concept other = cs.getConceptByName("OTHER NON-CODED"); Location loc = Context.getLocationService().getLocation("Someplace"); User u = Context.getUserService().getUser(1); Patient p = Context.getPatientService().getPatient(2); numEncountersSoFar = Context.getEncounterService().getEncountersByPatient(p).size(); Encounter enc = new Encounter(); enc.setPatient(p); enc.setLocation(loc); enc.setProvider(u); enc.setEncounterDatetime(dateOfNewEncounter); Obs o1 = new Obs(); o1.setConcept(weight); o1.setValueNumeric(74.0); o1.setObsDatetime(dateOfNewEncounter); Obs o2 = new Obs(); o2.setConcept(reason); o2.setValueCoded(other); o2.setObsDatetime(dateOfNewEncounter); enc.addObs(o1); enc.addObs(o2); Context.getEncounterService().saveEncounter(enc); Obs noEnc = new Obs(); noEnc.setConcept(weight); noEnc.setValueNumeric(12.3); noEnc.setObsDatetime(anotherDate); noEnc.setPerson(p); noEnc.setLocation(loc); Context.getObsService().saveObs(noEnc,null); } public void runOnParent() { ConceptService cs = Context.getConceptService(); Concept weight = cs.getConceptByName("WEIGHT"); Concept reason = cs.getConceptByName("REASON ORDER STOPPED"); Concept other = cs.getConceptByName("OTHER NON-CODED"); Location loc = Context.getLocationService().getLocation("Someplace"); Patient p = Context.getPatientService().getPatient(2); List<Encounter> encs = Context.getEncounterService().getEncountersByPatient(p); assertEquals("Should now have one more encounter than before", numEncountersSoFar + 1, encs.size()); Encounter lookAt = null; for (Encounter e : encs) { if (OpenmrsUtil.compare(e.getEncounterDatetime(), dateOfNewEncounter) == 0) { lookAt = e; break; } } assertEquals(lookAt.getLocation(), loc); //reload lookAt int lookAtId = lookAt.getEncounterId(); Context.evictFromSession(lookAt); lookAt = Context.getEncounterService().getEncounter(lookAtId); assertEquals("Should have two obs", 2,lookAt.getObs().size()); for (Obs o : lookAt.getObs()) { if (o.getConcept().equals(weight)) { assertEquals("Weight should be 74.0", o.getValueNumeric(), (Double)74.0); } else { assertEquals("Reason should be OTHER NON-CODED", o.getValueCoded(), other); } } boolean found = false; for (Obs o : Context.getObsService().getObservationsByPerson(p)) { if ( (OpenmrsUtil.compare(o.getObsDatetime(), anotherDate) == 0) && o.getConcept().equals(weight) && o.getValueNumeric().equals(12.3)) found = true; } assertTrue("Cannot find newly created encounter-less obs", found); } }); } /** * Fails due to known bug: see ticket #934 * * @throws Exception */ @Test @NotTransactional public void shouldEditEncounter() throws Exception { runSyncTest(new SyncTestHelper() { Date d1 = ymd.parse("1978-01-01"); Date d2 = ymd.parse("1978-12-31"); public void runOnChild(){ Patient p = Context.getPatientService().getPatient(2); Collection<Encounter> encs = Context.getEncounterService().getEncountersByPatient(p); assertEquals(encs.size(), 1); Encounter e = encs.iterator().next(); e.setEncounterDatetime(d2); Context.getEncounterService().saveEncounter(e); } public void runOnParent() { Patient p = Context.getPatientService().getPatient(2); Collection<Encounter> encs = Context.getEncounterService().getEncounters(p, d1, d2); assertEquals(encs.size(), 1); Encounter e = encs.iterator().next(); int compare = OpenmrsUtil.compare(e.getEncounterDatetime(), d2); assertEquals("Failed to change date", compare, 0); } }); } @Test @NotTransactional public void shouldEditObs() throws Exception { runSyncTest(new SyncTestHelper() { Date d = ymd.parse("1978-04-11"); Concept weight = null; int obsCount = 0; public void runOnChild(){ weight = Context.getConceptService().getConceptByName("WEIGHT"); Patient p = Context.getPatientService().getPatient(2); Obs obs = null; for (Obs o : Context.getObsService().getObservationsByPersonAndConcept(p, weight)) { if (OpenmrsUtil.compare(o.getObsDatetime(), d) == 0) { obs = o; } } obsCount = obs.getEncounter().getObs().size(); assertNotNull("Before test, could not find expected obs", obs); Context.getObsService().voidObs(obs, "Data entry error"); assertEquals(obsCount - 1,obs.getEncounter().getObs().size() ); obsCount = obs.getEncounter().getObs().size(); Obs newObs = new Obs(); newObs.setPerson(obs.getPerson()); newObs.setConcept(obs.getConcept()); newObs.setObsDatetime(obs.getObsDatetime()); newObs.setLocation(obs.getLocation()); newObs.setCreator(Context.getAuthenticatedUser()); newObs.setDateCreated(new Date()); newObs.setValueNumeric(99.9); newObs.setEncounter(obs.getEncounter()); newObs = Context.getObsService().saveObs(newObs, null); obsCount++; int encId = newObs.getEncounter().getEncounterId(); Context.evictFromSession(newObs.getEncounter()); assertEquals(obsCount,Context.getEncounterService().getEncounter(encId).getObs().size()); } public void runOnParent() { int encId = 0; Patient p = Context.getPatientService().getPatient(2); Obs obs = null; for (Obs o : Context.getObsService().getObservationsByPersonAndConcept(p, weight)) if (OpenmrsUtil.compare(o.getObsDatetime(),d)==0) { obs = o; break; } assertNotNull(obs); assertEquals( (Double)99.9, obs.getValueNumeric()); encId = obs.getEncounter().getEncounterId(); Context.evictFromSession(obs.getEncounter()); assertEquals(obsCount,Context.getEncounterService().getEncounter(encId).getObs().size()); } }); } @Test @NotTransactional public void shouldCreatePatient() throws Exception { runSyncTest(new SyncTestHelper() { public void runOnChild() { Location loc = Context.getLocationService().getLocation("Someplace"); PatientIdentifierType pit = Context.getPatientService().getPatientIdentifierType(2); if (pit.getUuid() == null) throw new RuntimeException("pit.uuid is null! " + pit); else log.info("pit.uuid = " + pit.getUuid() + " , pit = " + pit); Patient p = new Patient(); p.addName(new PersonName("Darius", "Graham", "Jazayeri")); p.addIdentifier(new PatientIdentifier("999", pit, loc)); p.setGender("m"); p.setBirthdate(new Date()); Context.getPatientService().savePatient(p); List<PatientIdentifier> ids = Context.getPatientService().getPatientIdentifiers("999", pit); assertNotNull(ids); if (ids.size() != 1) assertFalse("Can't find patient we just created. ids.size()==" + ids.size(), true); log.info("Patients at end " + Context.getPatientService().findPatients("Darius", false).size()); } public void runOnParent() { log.info("Patients at beginning " + Context.getPatientService().findPatients("Darius", false).size()); Location loc = Context.getLocationService().getLocation("Someplace"); PatientIdentifierType pit = Context.getPatientService().getPatientIdentifierType(2); PersonName name = new PersonName("Darius", "Graham", "Jazayeri"); PatientIdentifier id = new PatientIdentifier("999", pit, loc); List<PatientIdentifier> ids = Context.getPatientService().getPatientIdentifiers("999", pit); assertNotNull(ids); if (ids.size() != 1) assertFalse("Should only find one patient, not " + ids.size(), true); // check the name Patient p = ids.get(0).getPatient(); assertEquals(p.getPersonName().toString(), name.toString()); // check the identifier PatientIdentifier firstpid = p.getIdentifiers().iterator().next(); assertEquals(firstpid.getIdentifier(), id.getIdentifier()); assertEquals(firstpid.getIdentifierType(), id.getIdentifierType()); } }); } @Test @NotTransactional public void shouldCreatePatientFromExistingUser() throws Exception { runSyncTest(new SyncTestHelper() { String uuid = null; public void runOnChild() { Location loc = Context.getLocationService().getLocation("Someplace"); PatientIdentifierType pit = Context.getPatientService().getPatientIdentifierType(2); ArrayList<PatientIdentifierType> pits = new ArrayList<PatientIdentifierType>(); pits.add(pit); if (pit.getUuid() == null) throw new RuntimeException("pit.uuid is null! " + pit); else log.info("pit.uuid = " + pit.getUuid() + " , pit = " + pit); Person person = Context.getPersonService().getPerson(5); Context.clearSession(); // so that this Person doesn't cause hibernate to think the new Patient is in the cache already (only needed until #725 is fixed) Patient p = new Patient(person); p.setCreator(Context.getUserService().getUser(1)); p.setDateCreated(Context.getUserService().getUser(1).getDateCreated()); p.addIdentifier(new PatientIdentifier("999", pit, loc)); Context.getPatientService().savePatient(p); Assert.assertEquals(1, p.getIdentifiers().size()); Assert.assertEquals("999", p.getPatientIdentifier().getIdentifier()); List<PatientIdentifier> ids = Context.getPatientService().getPatientIdentifiers("999",pits, null, null, null); assertNotNull(ids); this.uuid = p.getUuid(); if (ids.size() != 1) assertFalse("Can't find patient we just created. ids.size()==" + ids.size(), true); log.info("Patients at end " + Context.getPatientService().getPatients("Stub").size()); } public void runOnParent() { //check by pat identifier Location loc = Context.getLocationService().getLocation("Someplace"); PatientIdentifierType pit = Context.getPatientService().getPatientIdentifierType(2); ArrayList<PatientIdentifierType> pits = new ArrayList<PatientIdentifierType>(); pits.add(pit); PatientIdentifier id = new PatientIdentifier("999", pit, loc); List<PatientIdentifier> ids = Context.getPatientService().getPatientIdentifiers("999",pits, null, null, null); assertNotNull(ids); if (ids.size() != 1) assertFalse("Should only find one patient, not " + ids.size(), true); // fetch by uuid Patient p = Context.getPatientService().getPatientByUuid(this.uuid); assertNotNull(p); //fetch by name assertEquals(1,Context.getPatientService().getPatients("Stub").size()); } }); } @Test @NotTransactional public void shouldEditPatient() throws Exception { runSyncTest(new SyncTestHelper() { PatientIdentifierType pit; public void runOnChild() { pit = Context.getPatientService().getPatientIdentifierType(2); Location loc = Context.getLocationService().getLocation("Someplace"); Patient p = Context.getPatientService().getPatient(2); p.setGender("F"); p.removeName(p.getPersonName()); p.addName(new PersonName("Peter", null, "Parker")); p.addIdentifier(new PatientIdentifier("super123", pit, loc)); Context.getPatientService().savePatient(p); } public void runOnParent() { Patient p = Context.getPatientService().getPatient(2); assertEquals("Gender didn't change", p.getGender(), "F"); assertEquals("Name should be Peter Parker", p.getPersonName().toString(), "Peter Parker"); boolean found = false; for (PatientIdentifier id : p.getIdentifiers()) if (id.getIdentifier().equals("super123") && id.getIdentifierType().equals(pit)) found = true; assertTrue("Couldn't find new ID", found); } }); } @Test @NotTransactional public void shouldEditPatientIdentifiers() throws Exception { runSyncTest(new SyncTestHelper() { PatientIdentifierType pit; public void runOnChild() { pit = Context.getPatientService().getPatientIdentifierType(2); Location loc = Context.getLocationService().getLocation("Someplace"); Patient p = Context.getPatientService().getPatient(2); p.setGender("F"); p.removeName(p.getPersonName()); p.addName(new PersonName("Peter", null, "Parker")); p.addIdentifier(new PatientIdentifier("super123", pit, loc)); // don't save here, in real-world situations savePatient is only called once per transaction //Context.getPatientService().savePatient(p); /* patient 2 has two existing IDs: * "ID1234" with uuid of '6b920848-1b90-102b-8082-d8cf852a43d2' - this should be removed * "ID1234-2" with uuid of 'e333cc28-6fef-11df-83c8-3679bc4524e5' - this should be voided */ Set<PatientIdentifier> pis = p.getIdentifiers(); PatientIdentifier piToDelete = null; PatientIdentifier piToVoid = null; for(PatientIdentifier pi : pis) { if ("ID1234".equals(pi.getIdentifier())) { piToDelete = pi; } else if ("ID1234-2".equals(pi.getIdentifier())) { piToVoid = pi; }; } //whack ID1234 by removing it from the patient p.removeIdentifier(piToDelete); //SyncUtil.deleteOpenmrsObject(piToDelete); //change ID1234-2 to void and save it via syncUtil to test resorting the treeset piToVoid.setVoided(true); piToVoid.setVoidReason("testing sync"); //SyncUtil.updateOpenmrsObject(piToVoid, "org.openmrs.PatientIdentifier", piToVoid.getUuid()); Context.getPatientService().savePatient(p); } public void runOnParent() { Patient p = Context.getPatientService().getPatient(2); assertEquals("Gender didn't change", p.getGender(), "F"); assertEquals("Name should be Peter Parker", p.getPersonName().toString(), "Peter Parker"); boolean foundNew = false; boolean foundOld = false; for (PatientIdentifier id : p.getIdentifiers()) { if (id.getIdentifier().equals("super123") && id.getIdentifierType().equals(pit)) foundNew = true; else if (id.getIdentifier().equals("ID1234") && id.getUuid().equals("6b920848-1b90-102b-8082-d8cf852a43d2")) foundOld = true; } assertTrue("Couldn't find new ID", foundNew); assertFalse("Still found old ID that should have been removed.", foundOld); } }); } @Test @NotTransactional public void shouldEditPatientName() throws Exception { runSyncTest(new SyncTestHelper() { int numberBefore; public void runOnChild() { Patient p = Context.getPatientService().getPatient(2); numberBefore = p.getNames().size(); p.getPersonName().setGivenName("Superman"); Context.getPatientService().savePatient(p); } public void runOnParent() { Patient p = Context.getPatientService().getPatient(2); assertEquals("Should not have added a new name", numberBefore, p.getNames().size()); assertEquals("Name should be Superman", "Superman", p.getPersonName().getGivenName()); } }); } @Test @NotTransactional public void shouldMergePatients() throws Exception { runSyncTest(new SyncTestHelper() { Set<PatientIdentifier> pis = null; int p1AddressCount = 0; int p1EncounterCount = 0; int p1ObsCount = 0; int p2AddressCount = 0; int p2EncounterCount = 0; int p2IdentifiersCount = 0; int p2ObsCount = 0; public void runOnChild() { Patient p1 = Context.getPatientService().getPatient(2); Patient p2 = Context.getPatientService().getPatient(3); p1AddressCount = p1.getAddresses().size(); p1EncounterCount = Context.getEncounterService().getEncountersByPatient(p1).size(); p1ObsCount = Context.getObsService().getObservationsByPerson(p1).size(); p2AddressCount = p2.getAddresses().size(); p2EncounterCount = Context.getEncounterService().getEncountersByPatient(p2).size(); p2ObsCount = Context.getObsService().getObservationsByPerson(p2).size(); pis = new TreeSet<PatientIdentifier>(); pis.addAll(p1.getIdentifiers()); pis.addAll(p2.getIdentifiers()); try { Context.getPatientService().mergePatients(p2, p1); } catch (Exception e) { throw new RuntimeException(e); } } public void runOnParent() { Patient p1 = Context.getPatientService().getPatient(2); Patient p2 = Context.getPatientService().getPatient(3); Set<PatientIdentifier> pis2 = p2.getIdentifiers(); for(PatientIdentifier pi : pis) { boolean matched = false; for (PatientIdentifier pi2 : pis2) { if (pi.getIdentifier().equalsIgnoreCase(pi2.getIdentifier())) { matched = true; break; } } if (!matched) { assertEquals("patient identifier not found after merge: " + pi.toString(), false); } } assertEquals("Patient not voided after merge",true, p1.isVoided()); assertEquals("Encounters count wrong",p1EncounterCount+p2EncounterCount, Context.getEncounterService().getEncountersByPatient(p2).size()); assertEquals("Address count wrong",p1AddressCount+p2AddressCount, p2.getAddresses().size()); assertEquals("Obs count wrong",p1ObsCount+p2ObsCount, Context.getObsService().getObservationsByPerson(p2).size()); } }); } }