Skip to content

Commit

Permalink
REL pagination unit tests ✅
Browse files Browse the repository at this point in the history
  • Loading branch information
ndegwamartin committed Nov 21, 2024
1 parent 90d064e commit fd5df53
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ private List<String> getRelChunkStrategyIds(

int endIndex =
Math.min(
startIndex + SyncAccessDecisionConstants.REL_LOCATION_CHUNK_SIZE,
startIndex + getRelLocationChunkSize(),
syncStrategyIdsMap
.get(Constants.SyncStrategy.RELATED_ENTITY_LOCATION)
.size());
Expand Down Expand Up @@ -283,18 +283,21 @@ public String postProcess(RequestDetailsReader request, HttpResponse response)
return resultContent;
}

// int count = getQueryParamValue("_count", request);

private String getQueryParamValue(
String key, RequestDetailsReader requestDetailsReader, String defaultValue) {
String[] countRaw = requestDetailsReader.getParameters().get(key);
String[] countRaw = requestDetailsReader.getParameters().getOrDefault(key, new String[] {});
return countRaw.length > 0 ? countRaw[0] : defaultValue;
}

private int getQueryParamIntValue(
String key, RequestDetailsReader requestDetailsReader, int defaultValue) {
String[] countRaw = requestDetailsReader.getParameters().getOrDefault(key, new String[] {});
return countRaw.length > 0 ? Integer.parseInt(countRaw[0]) : defaultValue;
return Integer.parseInt(
getQueryParamValue(key, requestDetailsReader, String.valueOf(defaultValue)));
}

@VisibleForTesting
protected int getRelLocationChunkSize() {
return SyncAccessDecisionConstants.REL_LOCATION_CHUNK_SIZE;
}

private IBaseResource processRelatedEntityLocationSyncStrategy(
Expand All @@ -313,7 +316,7 @@ private IBaseResource processRelatedEntityLocationSyncStrategy(
if (syncStrategyIdsMap
.getOrDefault(Constants.SyncStrategy.RELATED_ENTITY_LOCATION, List.of())
.size()
<= SyncAccessDecisionConstants.REL_LOCATION_CHUNK_SIZE) {
<= getRelLocationChunkSize()) {
return responseResource;
}

Expand All @@ -333,12 +336,12 @@ private IBaseResource processRelatedEntityLocationSyncStrategy(
+ "?"
+ getRequestParametersString(request.getParameters());

for (int startIndex = SyncAccessDecisionConstants.REL_LOCATION_CHUNK_SIZE;
for (int startIndex = getRelLocationChunkSize();
startIndex
< syncStrategyIdsMap
.get(Constants.SyncStrategy.RELATED_ENTITY_LOCATION)
.size();
startIndex += SyncAccessDecisionConstants.REL_LOCATION_CHUNK_SIZE) {
startIndex += getRelLocationChunkSize()) {

List<String> syncLocationIds =
getRelChunkStrategyIds(startIndex, syncStrategyIdsMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ public static String replaceAddQueryParamValue(String url, String paramName, Str
Map<String, String> queryMap = new HashMap<>();

for (String param : queryParams) {
if (param.isEmpty()) continue;
String[] pair = param.split("=");
queryMap.put(pair[0], pair.length > 1 ? pair[1] : "");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,4 +451,16 @@ public void testAccessDeniedWhenSingleRoleMissingForTypeBundleResources() throws

assertThat(canAccess, equalTo(false));
}

@Test
public void testGenerateSyncStrategyIdsCacheKey() {
String testUserId = "my-test-user-id";
Map<String, String[]> strategyIdMap =
Map.of(Constants.SyncStrategy.CARE_TEAM, new String[] {"id-1, id-2,id-3"});
String cacheKey =
PermissionAccessChecker.generateSyncStrategyIdsCacheKey(
testUserId, Constants.SyncStrategy.CARE_TEAM, strategyIdMap);

Assert.assertEquals(testUserId, cacheKey);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand All @@ -19,7 +20,9 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Encounter;
import org.hl7.fhir.r4.model.ListResource;
import org.hl7.fhir.r4.model.Meta;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Assert;
Expand All @@ -39,10 +42,13 @@
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.gclient.IQuery;
import ca.uhn.fhir.rest.gclient.ITransaction;
import ca.uhn.fhir.rest.gclient.ITransactionTyped;
import ca.uhn.fhir.rest.gclient.IUntypedQuery;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;

@RunWith(MockitoJUnitRunner.class)
Expand Down Expand Up @@ -1071,4 +1077,145 @@ private SyncAccessDecision createSyncAccessDecisionTestInstance(String syncStrat
accessDecision.setSkippedResourcesConfig(skippedDataFilterConfig);
return accessDecision;
}

@Test
public void testPostProcessWithRELSyncStrategyWorksCorrectly() throws IOException {

relatedEntityLocationIds.add("relocationid1");
relatedEntityLocationIds.add("relocationid2");
relatedEntityLocationIds.add("relocationid3");

testInstance =
Mockito.spy(
createSyncAccessDecisionTestInstance(
Constants.SyncStrategy.RELATED_ENTITY_LOCATION));

FhirContext fhirR4Context = mock(FhirContext.class);
IGenericClient iGenericClient = mock(IGenericClient.class);
ITransaction iTransaction = mock(ITransaction.class);
ITransactionTyped<Bundle> iClientExecutable = mock(ITransactionTyped.class);

Mockito.when(iGenericClient.transaction()).thenReturn(iTransaction);
Mockito.when(iTransaction.withBundle(any(Bundle.class))).thenReturn(iClientExecutable);
Mockito.when(testInstance.getRelLocationChunkSize()).thenReturn(2);

Bundle resultBundle = new Bundle();
resultBundle.setType(Bundle.BundleType.BATCHRESPONSE);
resultBundle.setId("bundle-result-id");

Mockito.when(iClientExecutable.execute()).thenReturn(resultBundle);

testInstance.setFhirR4Context(fhirR4Context);

RequestDetailsReader requestDetailsSpy = Mockito.mock(RequestDetailsReader.class);

Map<String, String[]> params = new HashMap<>();
params.put(Constants.PAGINATION_PAGE_SIZE, new String[] {"2"});
params.put(
Constants.SYNC_LOCATIONS_SEARCH_PARAM, new String[] {"location1d", "location2d"});
String fhirServerBase = "http://test:8080/fhir";

Mockito.when(requestDetailsSpy.getParameters()).thenReturn(params);
Mockito.when(requestDetailsSpy.getFhirServerBase()).thenReturn(fhirServerBase);
Mockito.when(requestDetailsSpy.getRequestPath()).thenReturn("Encounter");

StringBuilder queryParamStringBuilder = new StringBuilder();
params.forEach(
(key, value) ->
queryParamStringBuilder
.append("&")
.append(key)
.append("=")
.append(String.join(",", value)));

Mockito.when(requestDetailsSpy.getCompleteUrl())
.thenReturn(fhirServerBase + "/Encounter?" + queryParamStringBuilder.toString());

Encounter encounter = new Encounter();
encounter.setId("encounter-1");

Encounter encounter2 = new Encounter();
encounter2.setId("encounter-2");

Bundle bundle = new Bundle();
bundle.setTotal(3);
bundle.setType(Bundle.BundleType.SEARCHSET);
bundle.setMeta(new Meta().setLastUpdated(new Date()));

Bundle.BundleEntryComponent bundleEntryComponent = new Bundle.BundleEntryComponent();
bundleEntryComponent.setResource(encounter);

Bundle.BundleEntryComponent bundleEntryComponent2 = new Bundle.BundleEntryComponent();
bundleEntryComponent2.setResource(encounter);

bundle.setEntry(List.of(bundleEntryComponent, bundleEntryComponent2));

HttpResponse fhirResponseMock =
Mockito.mock(HttpResponse.class, Answers.RETURNS_DEEP_STUBS);

TestUtil.setUpFhirResponseMock(
fhirResponseMock,
FhirContext.forR4().newJsonParser().encodeResourceToString(bundle));

IUntypedQuery searchClient = Mockito.mock(IUntypedQuery.class);
IQuery searchClientIQuery = Mockito.mock(IQuery.class);
Mockito.when(iGenericClient.search()).thenReturn(searchClient);

// First batch
Mockito.when(searchClient.byUrl("Encounter?&_count=2")).thenReturn(searchClientIQuery);
Mockito.when(searchClientIQuery.usingStyle(SearchStyleEnum.POST))
.thenReturn(searchClientIQuery);
Mockito.when(searchClientIQuery.execute()).thenReturn(bundle);

// Second batch
Bundle bundle2 = new Bundle();
bundle2.setTotal(3);
bundle2.setType(Bundle.BundleType.SEARCHSET);

Encounter encounter3 = new Encounter();
encounter3.setId("encounter-3");

Bundle.BundleEntryComponent bundleEntryComponent3 = new Bundle.BundleEntryComponent();
bundleEntryComponent3.setResource(encounter3);

bundle2.setEntry(List.of(bundleEntryComponent3));

IQuery searchClientIQuery2 = Mockito.mock(IQuery.class);
Mockito.when(
searchClient.byUrl(
"Encounter?&_count=2&_tag=https://smartregister.org/related-entity-location-tag-id%7Crelocationid3,"))
.thenReturn(searchClientIQuery2);
Mockito.when(searchClientIQuery2.usingStyle(SearchStyleEnum.POST))
.thenReturn(searchClientIQuery2);
Mockito.when(searchClientIQuery2.execute()).thenReturn(bundle2);

testInstance.setFhirR4Client(iGenericClient);
testInstance.setFhirR4Context(FhirContext.forR4());
String resultContent = testInstance.postProcess(requestDetailsSpy, fhirResponseMock);

// Verify correct request to HAPI FHIR server

ArgumentCaptor<String> searchUrlCaptor = ArgumentCaptor.forClass(String.class);
Mockito.verify(searchClient).byUrl(searchUrlCaptor.capture());

String capturedSearchUrl = searchUrlCaptor.getValue();
Assert.assertNotNull(capturedSearchUrl);
Assert.assertEquals(
"Encounter?&_count=2&_tag=https://smartregister.org/related-entity-location-tag-id%7Crelocationid3,",
capturedSearchUrl);

// Verify returned result content from the server request, has pagination links
Assert.assertNotNull(resultContent);
Bundle resultContentBundle =
(Bundle) FhirContext.forR4Cached().newJsonParser().parseResource(resultContent);
Assert.assertNotNull(resultContentBundle.getMeta().getLastUpdated());
Assert.assertEquals(2, resultContentBundle.getLink().size());
Assert.assertEquals(2, resultContentBundle.getEntry().size());
Assert.assertEquals(
"http://test:8080/fhir/Encounter?&_count=2&_syncLocations=location1d,location2d",
resultContentBundle.getLink(Bundle.LINK_SELF).getUrl());
Assert.assertEquals(
"http://test:8080/fhir/Encounter?_count=2&_sLPage=2&_syncLocations=location1d,location2d",
resultContentBundle.getLink(Bundle.LINK_NEXT).getUrl());
}
}

0 comments on commit fd5df53

Please sign in to comment.