/** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. * * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS * graphic logo is a trademark of OpenMRS Inc. */ package org.openmrs.module.radiology.order; import static org.hamcrest.collection.IsEmptyCollection.empty; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsCollectionContaining.hasItem; import static org.hamcrest.core.IsNot.not; import static org.hamcrest.core.IsNull.nullValue; 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.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import org.hamcrest.Matchers; import org.hibernate.cfg.Environment; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openmrs.Encounter; import org.openmrs.Order; import org.openmrs.Order.Urgency; import org.openmrs.Patient; import org.openmrs.Provider; import org.openmrs.api.AdministrationService; import org.openmrs.api.ConceptService; import org.openmrs.api.EncounterService; import org.openmrs.api.PatientService; import org.openmrs.api.ProviderService; import org.openmrs.api.context.Context; import org.openmrs.module.radiology.study.RadiologyStudy; import org.openmrs.parameter.EncounterSearchCriteriaBuilder; import org.openmrs.test.BaseModuleContextSensitiveTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; /** * Tests {@link RadiologyOrderService} */ public class RadiologyOrderServiceComponentTest extends BaseModuleContextSensitiveTest { private static final String TEST_DATASET = "org/openmrs/module/radiology/include/RadiologyOrderServiceComponentTestDataset.xml"; private static final int PATIENT_ID_WITH_ONLY_ONE_NON_RADIOLOGY_ORDER = 70011; private static final int PATIENT_ID_WITH_TWO_RADIOLOGY_ORDERS = 70021; private static final int PATIENT_ID_WITH_ONE_VOIDED_AND_TWO_NON_VOIDED_RADIOLOGY_ORDERS = 70023; private static final int EXISTING_RADIOLOGY_ORDER_ID = 2001; private static final String EXISTING_RADIOLOGY_ORDER_UUID = "44f24d7e-ebbd-4500-bfba-1db19561ca04"; private static final int NON_EXISTING_RADIOLOGY_ORDER_ID = 99999; private static final String NON_EXISTING_RADIOLOGY_ORDER_UUID = "99999999-ebbd-4500-bfba-1db19561ca04"; private static final String RADIOLOGY_ORDER_UUID_OF_VOIDED = "56816dbe-59aa-4d4d-a943-3016009e9ae1"; private static final int CONCEPT_ID_FOR_FRACTURE = 178; private static final String EXISTING_RADIOLOGY_ORDER_ACCESSION_NUMBER = "1"; private static final int PROVIDER_ID_WITH_TWO_ASSIGNED_RADIOLOGY_ORDERS = 2; @Autowired private PatientService patientService; @Autowired private ConceptService conceptService; @Autowired @Qualifier("adminService") private AdministrationService administrationService; @Autowired private EncounterService encounterService; @Autowired private ProviderService providerService; @Autowired private RadiologyOrderService radiologyOrderService; /** * Overriding following method is necessary to enable MVCC which is disabled by default in DB h2 * used for the component tests. This prevents following exception: * org.hibernate.exception.GenericJDBCException: could not load an entity: * [org.openmrs.GlobalProperty#order.nextOrderNumberSeed] due to "Timeout trying to lock table " * GLOBAL_PROPERTY"; SQL statement:" which occurs in all tests touching methods that call * orderService.saveOrder() */ @Override public Properties getRuntimeProperties() { Properties result = super.getRuntimeProperties(); String url = result.getProperty(Environment.URL); if (url.contains("jdbc:h2:") && !url.contains(";MVCC=TRUE")) { result.setProperty(Environment.URL, url + ";MVCC=TRUE"); } return result; } @Before public void setUp() throws Exception { // We need to commit the global property nextAccessionNumberSeed otherwise it will not be visible in the // HibernateRadiologyOrderDAO since the RadiologyOrderServiceImpl.getNextAccessionNumberSeedSequenceValue() opens a // new transaction. if (!Context.isSessionOpen()) { Context.openSession(); } executeDataSet(TEST_DATASET); getConnection().commit(); Context.clearSession(); } @After public void tearDown() throws Exception { // We need to delete all data we committed otherwise this will influence other test classes and break isolation. this.deleteAllData(); } @Test public void shouldCreateNewRadiologyOrderAndStudyGivenRadiologyOrder() throws Exception { RadiologyOrder radiologyOrder = getUnsavedRadiologyOrder(); radiologyOrder = radiologyOrderService.placeRadiologyOrder(radiologyOrder); assertNotNull(radiologyOrder); assertNotNull(radiologyOrder.getOrderId()); assertNotNull(radiologyOrder.getAccessionNumber()); assertNotNull(radiologyOrder.getStudy()); assertNotNull(radiologyOrder.getStudy() .getStudyId()); assertNotNull(radiologyOrder.getEncounter()); } /** * Convenience method to get a RadiologyOrder object with all required values filled in but * which is not yet saved in the database * * @return RadiologyOrder object that can be saved to the database */ public RadiologyOrder getUnsavedRadiologyOrder() { RadiologyOrder radiologyOrder = new RadiologyOrder(); radiologyOrder.setPatient(patientService.getPatient(PATIENT_ID_WITH_ONLY_ONE_NON_RADIOLOGY_ORDER)); radiologyOrder.setOrderer(providerService.getProviderByIdentifier("1")); radiologyOrder.setConcept(conceptService.getConcept(CONCEPT_ID_FOR_FRACTURE)); radiologyOrder.setInstructions("CT ABDOMEN PANCREAS WITH IV CONTRAST"); Calendar calendar = Calendar.getInstance(); calendar.set(2015, Calendar.FEBRUARY, 4, 14, 35, 0); radiologyOrder.setScheduledDate(calendar.getTime()); radiologyOrder.setUrgency(Order.Urgency.ON_SCHEDULED_DATE); RadiologyStudy radiologyStudy = new RadiologyStudy(); radiologyOrder.setStudy(radiologyStudy); return radiologyOrder; } @Test public void shouldCreateRadiologyOrderEncounterWhenSavingARadiologyOrder() throws Exception { RadiologyOrder radiologyOrder = getUnsavedRadiologyOrder(); EncounterSearchCriteriaBuilder encounterSearchCriteria = new EncounterSearchCriteriaBuilder().setPatient(radiologyOrder.getPatient()) .setProviders(Arrays.asList(radiologyOrder.getOrderer())); List<Encounter> matchingEncounters = encounterService.getEncounters(encounterSearchCriteria.createEncounterSearchCriteria()); assertThat(matchingEncounters, is(empty())); assertThat(radiologyOrder.getEncounter(), is(nullValue())); radiologyOrder = radiologyOrderService.placeRadiologyOrder(radiologyOrder); assertThat(radiologyOrder.getEncounter(), is(not(nullValue()))); matchingEncounters = encounterService.getEncounters(encounterSearchCriteria.createEncounterSearchCriteria()); assertThat(matchingEncounters, hasItem(radiologyOrder.getEncounter())); assertThat(matchingEncounters.size(), is(1)); } @Test public void shouldSetTheRadiologyOrderAccessionNumberWhenSavingARadiologyOrder() throws Exception { RadiologyOrder radiologyOrder = getUnsavedRadiologyOrder(); radiologyOrder.setAccessionNumber(null); radiologyOrder = radiologyOrderService.placeRadiologyOrder(radiologyOrder); assertNotNull(radiologyOrder); assertNotNull(radiologyOrder.getAccessionNumber()); } @Test public void shouldAlwaysReturnAUniqueAccessionNumberWhenCalledMultipleTimes() throws Exception { int N = 50; final Set<String> uniqueAccessionNumbers = new HashSet<String>(N); List<Thread> threads = new ArrayList<Thread>(); for (int i = 0; i < N; i++) { threads.add(new Thread(new Runnable() { @Override public void run() { try { Context.openSession(); uniqueAccessionNumbers .add(((AccessionNumberGenerator) radiologyOrderService).getNewAccessionNumber()); } finally { Context.closeSession(); } } })); } for (int i = 0; i < N; ++i) { threads.get(i) .start(); } for (int i = 0; i < N; ++i) { threads.get(i) .join(); } // since we used a set we should have the size as N indicating that there were no duplicates Assert.assertEquals(N, uniqueAccessionNumbers.size()); } @Test public void shouldCreateDiscontinuationOrderWhichDiscontinuesGivenRadiologyOrderThatIsNotInProgressOrCompleted() throws Exception { RadiologyOrder radiologyOrder = radiologyOrderService.getRadiologyOrder(EXISTING_RADIOLOGY_ORDER_ID); radiologyOrder.getStudy() .setPerformedStatus(null); String discontinueReason = "Wrong Procedure"; Order discontinuationOrder = radiologyOrderService.discontinueRadiologyOrder(radiologyOrder, radiologyOrder.getOrderer(), discontinueReason); assertNotNull(discontinuationOrder); assertThat(discontinuationOrder.getAction(), is(Order.Action.DISCONTINUE)); assertThat(discontinuationOrder.getPreviousOrder(), is((Order) radiologyOrder)); assertThat(radiologyOrder.isActive(), is(false)); } @Test public void shouldCreateRadiologyOrderEncounter() throws Exception { RadiologyOrder radiologyOrder = radiologyOrderService.getRadiologyOrder(EXISTING_RADIOLOGY_ORDER_ID); radiologyOrder.getStudy() .setPerformedStatus(null); String discontinueReason = "Wrong Procedure"; EncounterSearchCriteriaBuilder encounterSearchCriteria = new EncounterSearchCriteriaBuilder().setPatient(radiologyOrder.getPatient()) .setProviders(Arrays.asList(radiologyOrder.getOrderer())); List<Encounter> matchingEncounters = encounterService.getEncounters(encounterSearchCriteria.createEncounterSearchCriteria()); assertThat(matchingEncounters, hasItem(radiologyOrder.getEncounter())); assertThat(matchingEncounters.size(), is(1)); Order discontinuationOrder = radiologyOrderService.discontinueRadiologyOrder(radiologyOrder, radiologyOrder.getOrderer(), discontinueReason); assertThat(discontinuationOrder.getEncounter(), is(not(nullValue()))); matchingEncounters = encounterService.getEncounters(encounterSearchCriteria.createEncounterSearchCriteria()); assertThat(matchingEncounters, hasItem(radiologyOrder.getEncounter())); assertThat(matchingEncounters, hasItem(discontinuationOrder.getEncounter())); } @Test public void shouldReturnRadiologyOrderMatchingGivenOrderId() { RadiologyOrder radiologyOrder = radiologyOrderService.getRadiologyOrder(EXISTING_RADIOLOGY_ORDER_ID); assertNotNull(radiologyOrder); assertThat(radiologyOrder.getOrderId(), is(EXISTING_RADIOLOGY_ORDER_ID)); } @Test public void shouldReturnNullIfNoMatchIsFoundGivenOrderId() { assertNull(radiologyOrderService.getRadiologyOrder(NON_EXISTING_RADIOLOGY_ORDER_ID)); } @Test public void shouldReturnRadiologyOrderMatchingGivenUuid() throws Exception { RadiologyOrder radiologyOrder = radiologyOrderService.getRadiologyOrderByUuid(EXISTING_RADIOLOGY_ORDER_UUID); assertNotNull(radiologyOrder); assertThat(radiologyOrder.getUuid(), is(EXISTING_RADIOLOGY_ORDER_UUID)); } @Test public void shouldReturnNullIfNoMatchIsFoundForGivenUuid() throws Exception { assertNull(radiologyOrderService.getRadiologyOrderByUuid(NON_EXISTING_RADIOLOGY_ORDER_UUID)); } @Test public void shouldReturnAllRadiologyOrdersForGivenPatientIfPatientIsSpecified() throws Exception { Patient patient = patientService.getPatient(PATIENT_ID_WITH_TWO_RADIOLOGY_ORDERS); RadiologyOrderSearchCriteria radiologyOrderSearchCriteria = new RadiologyOrderSearchCriteria.Builder().withPatient(patient) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteria); assertThat(radiologyOrders.size(), is(2)); for (RadiologyOrder radiologyOrder : radiologyOrders) { assertThat(radiologyOrder.getPatient(), is(patient)); } } @Test public void shouldReturnAllRadiologyOrdersIncludingVoidedMatchingTheSearchQueryIfIncludeVoidedIsSet() throws Exception { Patient patient = patientService.getPatient(PATIENT_ID_WITH_ONE_VOIDED_AND_TWO_NON_VOIDED_RADIOLOGY_ORDERS); RadiologyOrderSearchCriteria radiologyOrderSearchCriteria = new RadiologyOrderSearchCriteria.Builder().withPatient(patient) .includeVoided() .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteria); assertThat(radiologyOrders.size(), is(3)); assertThat(radiologyOrders, hasItem(Matchers.<RadiologyOrder> hasProperty("uuid", is(RADIOLOGY_ORDER_UUID_OF_VOIDED)))); assertThat(radiologyOrders, hasItem(Matchers.<RadiologyOrder> hasProperty("voided", is(true)))); } @Test public void shouldReturnAllRadiologyOrdersForGivenUrgency() throws Exception { RadiologyOrderSearchCriteria radiologyOrderSearchCriteria = new RadiologyOrderSearchCriteria.Builder().withUrgency(Urgency.STAT) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteria); assertThat(radiologyOrders.size(), is(5)); for (RadiologyOrder radiologyOrder : radiologyOrders) { assertThat(radiologyOrder.getUrgency(), is(Urgency.STAT)); } } @Test public void shouldReturnAllRadiologyOrdersWithEffectiveOrderStartDateInGivenDateRangeIfToDateAndFromDateAreSpecified() throws Exception { Patient patient = patientService.getPatient(70024); DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date fromDate = format.parse("2016-02-02"); Date toDate = format.parse("2016-04-04"); RadiologyOrderSearchCriteria radiologyOrderSearchCriteriaDateRange = new RadiologyOrderSearchCriteria.Builder().includeVoided() .withPatient(patient) .fromEffectiveStartDate(fromDate) .toEffectiveStartDate(toDate) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteriaDateRange); assertThat(radiologyOrders.size(), is(3)); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(2009))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20012))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20015))); for (RadiologyOrder radiologyOrder : radiologyOrders) { if (radiologyOrder.getUrgency() .equals(Urgency.ON_SCHEDULED_DATE)) { assertTrue(radiologyOrder.getScheduledDate() .compareTo(fromDate) >= 0); assertTrue(radiologyOrder.getScheduledDate() .compareTo(toDate) <= 0); } else { assertTrue(radiologyOrder.getDateActivated() .compareTo(fromDate) >= 0); assertTrue(radiologyOrder.getDateActivated() .compareTo(toDate) <= 0); } } } @Test public void shouldReturnAllRadiologyOrdersWithEffectiveOrderStartDateAfterOrEqualToFromDateIfOnlyFromDateIsSpecified() throws Exception { Patient patient = patientService.getPatient(70024); DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date fromDate = format.parse("2016-03-03"); RadiologyOrderSearchCriteria radiologyOrderSearchCriteriaDateRange = new RadiologyOrderSearchCriteria.Builder().includeVoided() .withPatient(patient) .fromEffectiveStartDate(fromDate) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteriaDateRange); assertThat(radiologyOrders.size(), is(6)); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(2009))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20010))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20012))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20013))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20015))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20016))); for (RadiologyOrder radiologyOrder : radiologyOrders) { if (radiologyOrder.getUrgency() .equals(Urgency.ON_SCHEDULED_DATE)) { assertTrue(radiologyOrder.getScheduledDate() .compareTo(fromDate) >= 0); } else { assertTrue(radiologyOrder.getDateActivated() .compareTo(fromDate) >= 0); } } } @Test public void shouldReturnAllRadiologyOrdersWithEffectiveOrderStartDateBeforeOrEqualToToDateIfOnlyToDateIsSpecified() throws Exception { Patient patient = patientService.getPatient(70024); DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date toDate = format.parse("2016-03-03"); RadiologyOrderSearchCriteria radiologyOrderSearchCriteriaDateRange = new RadiologyOrderSearchCriteria.Builder().includeVoided() .withPatient(patient) .toEffectiveStartDate(toDate) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteriaDateRange); assertThat(radiologyOrders.size(), is(6)); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(2008))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(2009))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20011))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20012))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20014))); assertThat(radiologyOrders, hasItem(radiologyOrderService.getRadiologyOrder(20015))); for (RadiologyOrder radiologyOrder : radiologyOrders) { if (radiologyOrder.getUrgency() .equals(Urgency.ON_SCHEDULED_DATE)) { assertTrue(radiologyOrder.getScheduledDate() .compareTo(toDate) <= 0); } else { assertTrue(radiologyOrder.getDateActivated() .compareTo(toDate) <= 0); } } } @Test public void shouldReturnEmptyListIfFromDateAfterToDate() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date fromDate = format.parse("2016-06-30"); Date toDate = format.parse("2016-05-29"); RadiologyOrderSearchCriteria radiologyOrderSearchCriteria = new RadiologyOrderSearchCriteria.Builder().fromEffectiveStartDate(fromDate) .toEffectiveStartDate(toDate) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteria); assertTrue(radiologyOrders.isEmpty()); } @Test public void shouldReturnEmptySearchResultIfNoEffectiveOrderStartIsInDateRange() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); RadiologyOrderSearchCriteria radiologyOrderSearchCriteriaDateRange = new RadiologyOrderSearchCriteria.Builder().fromEffectiveStartDate(format.parse("2016-06-06")) .toEffectiveStartDate(format.parse("2016-07-07")) .build(); List<RadiologyOrder> radiologyOrdersWithDateRange = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteriaDateRange); assertTrue(radiologyOrdersWithDateRange.isEmpty()); } @Test public void shouldReturnAllRadiologyOrdersForGivenAccessionNumberIfAccessionNumberIsSpecified() throws Exception { RadiologyOrderSearchCriteria radiologyOrderSearchCriteria = new RadiologyOrderSearchCriteria.Builder().withAccessionNumber(EXISTING_RADIOLOGY_ORDER_ACCESSION_NUMBER) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteria); assertThat(radiologyOrders.size(), is(1)); assertThat(radiologyOrders.get(0) .getAccessionNumber(), is(EXISTING_RADIOLOGY_ORDER_ACCESSION_NUMBER)); } @Test public void shouldReturnAllRadiologyOrdersForGivenOrderer() throws Exception { Provider orderer = providerService.getProvider(PROVIDER_ID_WITH_TWO_ASSIGNED_RADIOLOGY_ORDERS); RadiologyOrderSearchCriteria radiologyOrderSearchCriteria = new RadiologyOrderSearchCriteria.Builder().withOrderer(orderer) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteria); assertThat(radiologyOrders.size(), is(2)); for (RadiologyOrder radiologyOrder : radiologyOrders) { assertThat(radiologyOrder.getOrderer(), is(orderer)); } } @Test public void shouldReturnAllRadiologyOrdersForGivenUrgencyAndOrderer() throws Exception { Provider orderer = providerService.getProvider(PROVIDER_ID_WITH_TWO_ASSIGNED_RADIOLOGY_ORDERS); RadiologyOrderSearchCriteria radiologyOrderSearchCriteria = new RadiologyOrderSearchCriteria.Builder().withOrderer(orderer) .withUrgency(Urgency.STAT) .build(); List<RadiologyOrder> radiologyOrders = radiologyOrderService.getRadiologyOrders(radiologyOrderSearchCriteria); assertThat(radiologyOrders.size(), is(1)); assertThat(radiologyOrders.get(0) .getOrderer(), is(orderer)); assertThat(radiologyOrders.get(0) .getUrgency(), is(Urgency.STAT)); assertThat(radiologyOrders.get(0) .getOrderId(), is(2006)); } }