Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
public class QueueUtils {

/**
* Utility method for parsing a date from a string into a Date. TODO: This will need review and
* testing related to handling of timezones and other date formats
* Utility method for parsing a date from a string into a Date
*
* @param dateVal the date value ot parse
* @return the resulting date object
* @deprecated as of 3.1.0, as this only accepts yyyy-MM-dd HH:mm:ss in the server's default
* timezone. REST date parameters now use ConversionUtil.convert(String, Date.class).
*/
@Deprecated
public static Date parseDate(String dateVal) {

Check warning on line 37 in api/src/main/java/org/openmrs/module/queue/utils/QueueUtils.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not forget to remove this deprecated code someday.

See more on https://sonarcloud.io/project/issues?id=openmrs_openmrs-module-queue&issues=AaAownpkkY5_Ufzfi91k&open=AaAownpkkY5_Ufzfi91k&pullRequest=121
try {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateVal);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.openmrs.module.queue.web.resources.parser;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

Expand All @@ -19,7 +20,8 @@
import org.openmrs.Provider;
import org.openmrs.module.queue.api.QueueServicesWrapper;
import org.openmrs.module.queue.api.search.QueueEntrySearchCriteria;
import org.openmrs.module.queue.utils.QueueUtils;
import org.openmrs.module.webservices.rest.web.ConversionUtil;
import org.openmrs.module.webservices.rest.web.response.ConversionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

Expand Down Expand Up @@ -153,32 +155,32 @@ public QueueEntrySearchCriteria constructFromRequest(Map<String, String[]> param
}
case SEARCH_PARAM_STARTED_ON_OR_AFTER: {
String date = parameterMap.get(SEARCH_PARAM_STARTED_ON_OR_AFTER)[0];
criteria.setStartedOnOrAfter(QueueUtils.parseDate(date));
criteria.setStartedOnOrAfter(parseDate(parameterName, date));
break;
}
case SEARCH_PARAM_STARTED_ON_OR_BEFORE: {
String date = parameterMap.get(SEARCH_PARAM_STARTED_ON_OR_BEFORE)[0];
criteria.setStartedOnOrBefore(QueueUtils.parseDate(date));
criteria.setStartedOnOrBefore(parseDate(parameterName, date));
break;
}
case SEARCH_PARAM_STARTED_ON: {
String date = parameterMap.get(SEARCH_PARAM_STARTED_ON)[0];
criteria.setStartedOn(QueueUtils.parseDate(date));
criteria.setStartedOn(parseDate(parameterName, date));
break;
}
case SEARCH_PARAM_ENDED_ON_OR_AFTER: {
String date = parameterMap.get(SEARCH_PARAM_ENDED_ON_OR_AFTER)[0];
criteria.setEndedOnOrAfter(QueueUtils.parseDate(date));
criteria.setEndedOnOrAfter(parseDate(parameterName, date));
break;
}
case SEARCH_PARAM_ENDED_ON_OR_BEFORE: {
String date = parameterMap.get(SEARCH_PARAM_ENDED_ON_OR_BEFORE)[0];
criteria.setEndedOnOrBefore(QueueUtils.parseDate(date));
criteria.setEndedOnOrBefore(parseDate(parameterName, date));
break;
}
case SEARCH_PARAM_ENDED_ON: {
String date = parameterMap.get(SEARCH_PARAM_ENDED_ON)[0];
criteria.setEndedOn(QueueUtils.parseDate(date));
criteria.setEndedOn(parseDate(parameterName, date));
break;
}
case SEARCH_PARAM_IS_ENDED: {
Expand All @@ -197,6 +199,18 @@ public QueueEntrySearchCriteria constructFromRequest(Map<String, String[]> param
return criteria;
}

private Date parseDate(String parameterName, String value) {
if (StringUtils.isBlank(value)) {
throw new ConversionException("The " + parameterName + " parameter is blank");
}
try {
return (Date) ConversionUtil.convert(value, Date.class);
}
catch (ConversionException e) {
throw new ConversionException("Unable to parse the " + parameterName + " parameter: " + value, e);
}
Comment thread
UjjawalPrabhat marked this conversation as resolved.
Resolved
}

private Boolean parseBoolean(String value) {
if (StringUtils.isBlank(value)) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_ENDED_ON;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_ENDED_ON_OR_AFTER;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_ENDED_ON_OR_BEFORE;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_HAS_VISIT;
Expand All @@ -34,15 +37,20 @@
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_QUEUE;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_QUEUE_COMING_FROM;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_SERVICE;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_STARTED_ON;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_STARTED_ON_OR_AFTER;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_STARTED_ON_OR_BEFORE;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_STATUS;
import static org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser.SEARCH_PARAM_VISIT;

import javax.servlet.http.HttpServletRequest;

import java.time.Instant;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -63,6 +71,7 @@
import org.openmrs.api.LocationService;
import org.openmrs.api.PatientService;
import org.openmrs.api.context.Context;
import org.openmrs.messagesource.MessageSourceService;
import org.openmrs.module.queue.api.QueueEntryService;
import org.openmrs.module.queue.api.QueueRoomService;
import org.openmrs.module.queue.api.QueueService;
Expand All @@ -71,20 +80,26 @@
import org.openmrs.module.queue.api.search.QueueEntrySearchCriteria;
import org.openmrs.module.queue.model.Queue;
import org.openmrs.module.queue.model.QueueEntry;
import org.openmrs.module.queue.utils.QueueUtils;
import org.openmrs.module.queue.web.resources.parser.QueueEntrySearchCriteriaParser;
import org.openmrs.module.webservices.rest.web.RequestContext;
import org.openmrs.module.webservices.rest.web.RestUtil;
import org.openmrs.module.webservices.rest.web.api.RestService;
import org.openmrs.module.webservices.rest.web.representation.CustomRepresentation;
import org.openmrs.module.webservices.rest.web.representation.DefaultRepresentation;
import org.openmrs.module.webservices.rest.web.representation.FullRepresentation;
import org.openmrs.module.webservices.rest.web.representation.RefRepresentation;
import org.openmrs.module.webservices.rest.web.response.ConversionException;

@ExtendWith(MockitoExtension.class)
public class QueueEntryResourceTest extends BaseQueueResourceTest<QueueEntry, QueueEntryResource> {

private static final String QUEUE_ENTRY_UUID = "6hje567a-fca0-11e5-9e59-08002719a7";

// An instant expressed with an offset, so the expectation holds whatever timezone the tests run in
private static final String DATE_WITH_OFFSET = "2023-09-10T16:42:13.000+05:30";

private static final Date EXPECTED_DATE = Date.from(Instant.parse("2023-09-10T11:12:13Z"));

private QueueEntryResource resource;

private QueueEntry queueEntry;
Expand Down Expand Up @@ -136,6 +151,11 @@ public void prepareMocks() {
//By pass authentication
getContext().when(Context::isAuthenticated).thenReturn(true);

// ConversionUtil looks for a Date converter before parsing; finding none raises an APIException
// that it swallows, and building that exception localizes its message. Both are needed.
getContext().when(() -> Context.getService(RestService.class)).thenReturn(mock(RestService.class));
getContext().when(Context::getMessageSourceService).thenReturn(mock(MessageSourceService.class));

getContext().when(() -> Context.getRegisteredComponents(QueueServicesWrapper.class))
.thenReturn(Collections.singletonList(queueServicesWrapper));

Expand Down Expand Up @@ -354,42 +374,90 @@ public void shouldSearchQueueEntriesByQueueComingFrom() {

@Test
public void shouldSearchQueueEntriesByStartedOnOrAfter() {
String dateStr = "2023-09-10 11:12:13";
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_AFTER, new String[] { dateStr });
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_AFTER, new String[] { DATE_WITH_OFFSET });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
assertThat(criteria.getStartedOnOrAfter(), equalTo(QueueUtils.parseDate(dateStr)));
assertThat(criteria.getStartedOnOrAfter(), equalTo(EXPECTED_DATE));
}

@Test
public void shouldSearchQueueEntriesByStartedOnOrBefore() {
String dateStr = "2023-09-10 11:12:13";
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_BEFORE, new String[] { dateStr });
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_BEFORE, new String[] { DATE_WITH_OFFSET });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
assertThat(criteria.getStartedOnOrBefore(), equalTo(EXPECTED_DATE));
}

@Test
public void shouldSearchQueueEntriesByStartedOn() {
parameterMap.put(SEARCH_PARAM_STARTED_ON, new String[] { DATE_WITH_OFFSET });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
assertThat(criteria.getStartedOnOrBefore(), equalTo(QueueUtils.parseDate(dateStr)));
assertThat(criteria.getStartedOn(), equalTo(EXPECTED_DATE));
}

@Test
public void shouldSearchQueueEntriesByEndedOnOrAfter() {
String dateStr = "2023-09-10 11:12:13";
parameterMap.put(SEARCH_PARAM_ENDED_ON_OR_AFTER, new String[] { dateStr });
parameterMap.put(SEARCH_PARAM_ENDED_ON_OR_AFTER, new String[] { DATE_WITH_OFFSET });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
assertThat(criteria.getEndedOnOrAfter(), equalTo(QueueUtils.parseDate(dateStr)));
assertThat(criteria.getEndedOnOrAfter(), equalTo(EXPECTED_DATE));
}

@Test
public void shouldSearchQueueEntriesByEndedOnOrBefore() {
String dateStr = "2023-09-10 11:12:13";
parameterMap.put(SEARCH_PARAM_ENDED_ON_OR_BEFORE, new String[] { dateStr });
parameterMap.put(SEARCH_PARAM_ENDED_ON_OR_BEFORE, new String[] { DATE_WITH_OFFSET });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
assertThat(criteria.getEndedOnOrBefore(), equalTo(QueueUtils.parseDate(dateStr)));
assertThat(criteria.getEndedOnOrBefore(), equalTo(EXPECTED_DATE));
}
Comment thread
UjjawalPrabhat marked this conversation as resolved.
Resolved

@Test
public void shouldSearchQueueEntriesByEndedOn() {
parameterMap.put(SEARCH_PARAM_ENDED_ON, new String[] { DATE_WITH_OFFSET });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
assertThat(criteria.getEndedOn(), equalTo(EXPECTED_DATE));
}

@Test
public void shouldSearchQueueEntriesByDateWithAUtcDesignator() {
// The shape Date.toISOString() produces, which is what the O3 service queues app sends
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_AFTER, new String[] { "2023-09-10T11:12:13.000Z" });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
assertThat(criteria.getStartedOnOrAfter(), equalTo(EXPECTED_DATE));
}

@Test
public void shouldSearchQueueEntriesByDateWithoutATimezone() {
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_AFTER, new String[] { "2023-09-10 11:12:13" });
resource.doSearch(requestContext);
verify(queueEntryService).getQueueEntries(queueEntryArgumentCaptor.capture());
QueueEntrySearchCriteria criteria = queueEntryArgumentCaptor.getValue();
Date expected = new GregorianCalendar(2023, Calendar.SEPTEMBER, 10, 11, 12, 13).getTime();
assertThat(criteria.getStartedOnOrAfter(), equalTo(expected));
}

@Test
public void shouldFailToSearchQueueEntriesByAnUnparseableDate() {
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_AFTER, new String[] { "not-a-date" });
ConversionException e = assertThrows(ConversionException.class, () -> resource.doSearch(requestContext));
assertThat(e.getMessage(), containsString(SEARCH_PARAM_STARTED_ON_OR_AFTER));
}

@Test
public void shouldFailToSearchQueueEntriesByABlankDate() {
parameterMap.put(SEARCH_PARAM_STARTED_ON_OR_AFTER, new String[] { "" });
ConversionException e = assertThrows(ConversionException.class, () -> resource.doSearch(requestContext));
assertThat(e.getMessage(), containsString(SEARCH_PARAM_STARTED_ON_OR_AFTER));
}

@Test
Expand Down