diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/wataskmanagementapi/controllers/PostTaskCompleteByIdControllerReplicaTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/wataskmanagementapi/controllers/PostTaskCompleteByIdControllerReplicaTest.java new file mode 100644 index 0000000000..dabf80b0c6 --- /dev/null +++ b/src/integrationTest/java/uk/gov/hmcts/reform/wataskmanagementapi/controllers/PostTaskCompleteByIdControllerReplicaTest.java @@ -0,0 +1,329 @@ +package uk.gov.hmcts.reform.wataskmanagementapi.controllers; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import uk.gov.hmcts.reform.authorisation.ServiceAuthorisationApi; +import uk.gov.hmcts.reform.authorisation.generators.AuthTokenGenerator; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.access.AccessControlService; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.access.entities.AccessControlResponse; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.idam.IdamService; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.idam.entities.Token; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.idam.entities.UserInfo; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.restrict.ClientAccessControlService; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.role.entities.RoleAssignment; +import uk.gov.hmcts.reform.wataskmanagementapi.auth.role.entities.response.RoleAssignmentResource; +import uk.gov.hmcts.reform.wataskmanagementapi.clients.CamundaServiceApi; +import uk.gov.hmcts.reform.wataskmanagementapi.clients.IdamWebApi; +import uk.gov.hmcts.reform.wataskmanagementapi.clients.RoleAssignmentServiceApi; +import uk.gov.hmcts.reform.wataskmanagementapi.config.LaunchDarklyFeatureFlagProvider; +import uk.gov.hmcts.reform.wataskmanagementapi.config.features.FeatureFlag; +import uk.gov.hmcts.reform.wataskmanagementapi.controllers.request.CompleteTaskRequest; +import uk.gov.hmcts.reform.wataskmanagementapi.domain.enums.TestRolesWithGrantType; +import uk.gov.hmcts.reform.wataskmanagementapi.entity.ReportableTaskResource; +import uk.gov.hmcts.reform.wataskmanagementapi.entity.TaskHistoryResource; +import uk.gov.hmcts.reform.wataskmanagementapi.entity.TaskResource; +import uk.gov.hmcts.reform.wataskmanagementapi.entity.TaskRoleResource; +import uk.gov.hmcts.reform.wataskmanagementapi.enums.TaskAction; +import uk.gov.hmcts.reform.wataskmanagementapi.services.CFTTaskDatabaseService; +import uk.gov.hmcts.reform.wataskmanagementapi.services.ReplicaBaseTest; +import uk.gov.hmcts.reform.wataskmanagementapi.utils.ServiceMocks; +import uk.gov.hmcts.reform.wataskmanagementapi.utils.TaskTestUtils; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.within; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static uk.gov.hmcts.reform.wataskmanagementapi.cft.enums.CFTTaskState.COMPLETED; +import static uk.gov.hmcts.reform.wataskmanagementapi.cft.enums.CFTTaskState.UNASSIGNED; +import static uk.gov.hmcts.reform.wataskmanagementapi.config.SecurityConfiguration.AUTHORIZATION; +import static uk.gov.hmcts.reform.wataskmanagementapi.config.SecurityConfiguration.SERVICE_AUTHORIZATION; +import static uk.gov.hmcts.reform.wataskmanagementapi.utils.ServiceMocks.IDAM_AUTHORIZATION_TOKEN; +import static uk.gov.hmcts.reform.wataskmanagementapi.utils.ServiceMocks.IDAM_OTHER_USER_ID; +import static uk.gov.hmcts.reform.wataskmanagementapi.utils.ServiceMocks.IDAM_USER_EMAIL; +import static uk.gov.hmcts.reform.wataskmanagementapi.utils.ServiceMocks.IDAM_USER_ID; +import static uk.gov.hmcts.reform.wataskmanagementapi.utils.ServiceMocks.SERVICE_AUTHORIZATION_TOKEN; + +@ActiveProfiles("replica") +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +@Slf4j +public class PostTaskCompleteByIdControllerReplicaTest extends ReplicaBaseTest { + + private static final String ENDPOINT_PATH = "/task/%s/complete"; + private static String ENDPOINT_BEING_TESTED; + + @MockitoBean + LaunchDarklyFeatureFlagProvider launchDarklyFeatureFlagProvider; + + @MockitoBean + private AuthTokenGenerator authTokenGenerator; + + @MockitoBean + private IdamWebApi idamWebApi; + @MockitoBean + private CamundaServiceApi camundaServiceApi; + @MockitoBean + private RoleAssignmentServiceApi roleAssignmentServiceApi; + @MockitoBean + private ServiceAuthorisationApi serviceAuthorisationApi; + @Autowired + private CFTTaskDatabaseService cftTaskDatabaseService; + @MockitoBean + private IdamService idamService; + @MockitoBean + private AccessControlService accessControlService; + @MockitoBean + private ClientAccessControlService clientAccessControlService; + + @Mock + private UserInfo mockedUserInfo; + + private ServiceMocks mockServices; + + TaskTestUtils taskTestUtils; + + @BeforeAll + void init() { + taskTestUtils = new TaskTestUtils(cftTaskDatabaseService,"replica"); + } + + @Test + void should_update_reportable_task_values_when_complete_api_invoked() throws Exception { + + final String taskId = UUID.randomUUID().toString(); + + when(clientAccessControlService.hasPrivilegedAccess(eq(SERVICE_AUTHORIZATION_TOKEN), any())) + .thenReturn(false); + + lenient().when(launchDarklyFeatureFlagProvider.getBooleanValue(eq(FeatureFlag.WA_COMPLETION_PROCESS_UPDATE), + anyString(), anyString())).thenReturn(false); + when(authTokenGenerator.generate()) + .thenReturn(IDAM_AUTHORIZATION_TOKEN); + lenient().when(mockedUserInfo.getUid()) + .thenReturn(IDAM_USER_ID); + lenient().when(mockedUserInfo.getEmail()) + .thenReturn(IDAM_USER_EMAIL); + + mockServices = new ServiceMocks( + idamWebApi, + serviceAuthorisationApi, + camundaServiceApi, + roleAssignmentServiceApi + ); + + mockServices.mockUserInfo(); + + RoleAssignmentRequest roleAssignmentRequest = RoleAssignmentRequest.builder() + .testRolesWithGrantType(TestRolesWithGrantType.STANDARD_TRIBUNAL_CASE_WORKER_PUBLIC) + .roleAssignmentAttribute( + RoleAssignmentAttribute.builder() + .jurisdiction("IA") + .caseType("Asylum") + .caseId("completeCaseId1") + .build() + ) + .build(); + + List roleAssignments = new ArrayList<>(); + + createRoleAssignment(roleAssignments, roleAssignmentRequest); + + final RoleAssignmentResource accessControlResponse = new RoleAssignmentResource(roleAssignments); + + + + TaskRoleResource taskRoleResource = new TaskRoleResource( + TestRolesWithGrantType.STANDARD_TRIBUNAL_CASE_WORKER_PUBLIC.getRoleName(), + true, true, true, false, false, false, + new String[]{}, 1, false, + TestRolesWithGrantType.STANDARD_TRIBUNAL_CASE_WORKER_PUBLIC.getRoleCategory().name() + ); + + taskRoleResource.setComplete(true); + + when(idamService.getUserInfo(IDAM_AUTHORIZATION_TOKEN)).thenReturn(mockedUserInfo); + when(roleAssignmentServiceApi.getRolesForUser( + any(), any(), any() + )).thenReturn(accessControlResponse); + when(accessControlService.getRoles(IDAM_AUTHORIZATION_TOKEN)) + .thenReturn(new AccessControlResponse(mockedUserInfo, roleAssignments)); + + lenient().when(mockedUserInfo.getUid()) + .thenReturn(IDAM_OTHER_USER_ID); + when(idamWebApi.token(any())).thenReturn(new Token(IDAM_AUTHORIZATION_TOKEN, "scope")); + when(serviceAuthorisationApi.serviceToken(any())).thenReturn(SERVICE_AUTHORIZATION_TOKEN); + + doNothing().when(camundaServiceApi).assignTask(any(), any(), any()); + doNothing().when(camundaServiceApi).addLocalVariablesToTask(any(), any(), any()); + + taskTestUtils.insertDummyTaskInDb("IA", "Asylum", "completeCaseId1", + taskId,UNASSIGNED, taskRoleResource,null, IDAM_USER_ID); + + ENDPOINT_BEING_TESTED = String.format(ENDPOINT_PATH, taskId); + + CompleteTaskRequest request = new CompleteTaskRequest(null); + mockMvc.perform( + post(ENDPOINT_BEING_TESTED) + .header(AUTHORIZATION, IDAM_AUTHORIZATION_TOKEN) + .header(SERVICE_AUTHORIZATION, SERVICE_AUTHORIZATION_TOKEN) + .contentType(APPLICATION_JSON_VALUE) + .content(asJsonString(request)) + ).andExpectAll( + status().isNoContent() + ); + + await() + .pollDelay(5, SECONDS) + .atMost(30, SECONDS) + .untilAsserted(() -> { + List reportableTaskList2 + = miReportingServiceForTest.findByReportingTaskId(taskId); + assertEquals(1, reportableTaskList2.size()); + }); + + Optional taskResourcePostComplete = cftTaskDatabaseService.findByIdOnly(taskId); + + assertTrue(taskResourcePostComplete.isPresent()); + assertEquals(COMPLETED, taskResourcePostComplete.get().getState()); + assertEquals(IDAM_USER_ID, taskResourcePostComplete.get().getAssignee()); + assertNotNull(taskResourcePostComplete.get().getLastUpdatedTimestamp()); + assertEquals(IDAM_OTHER_USER_ID, taskResourcePostComplete.get().getLastUpdatedUser()); + assertEquals(TaskAction.COMPLETED.getValue(), taskResourcePostComplete.get().getLastUpdatedAction()); + + await() + .pollDelay(3, SECONDS) + .atMost(30, SECONDS) + .untilAsserted(() -> { + + List taskHistoryResourceList + = miReportingServiceForTest.findByTaskId(taskId); + + assertEquals(2, taskHistoryResourceList.size()); + assertEquals("COMPLETED", taskHistoryResourceList.get(1).getState()); + assertEquals(IDAM_USER_ID, taskHistoryResourceList.get(1).getAssignee()); + assertEquals(IDAM_OTHER_USER_ID, taskHistoryResourceList.get(1).getUpdatedBy()); + assertEquals("Complete", taskHistoryResourceList.get(1).getUpdateAction()); + + OffsetDateTime expected = OffsetDateTime.now(); + + assertThat(taskHistoryResourceList.get(1).getUpdated()) + .isCloseTo(expected, within(1, ChronoUnit.MINUTES)); + + assertThat(taskHistoryResourceList.get(1).getCreated()) + .isCloseTo(expected, within(1, ChronoUnit.MINUTES)); + + assertThat(taskHistoryResourceList.get(1).getDueDateTime()) + .isCloseTo(expected.plusDays(1), within(1, ChronoUnit.MINUTES)); + }); + + await() + .pollDelay(3, SECONDS) + .atMost(30, SECONDS) + .untilAsserted(() -> { + + List reportableTaskList + = miReportingServiceForTest.findByReportingTaskId(taskId); + + assertEquals(1, reportableTaskList.size()); + assertEquals("COMPLETED", reportableTaskList.get(0).getState()); + assertNotNull(reportableTaskList.get(0).getAssignee()); + assertEquals(IDAM_USER_ID, reportableTaskList.get(0).getAssignee()); + assertNotNull(reportableTaskList.get(0).getUpdatedBy()); + assertEquals(IDAM_OTHER_USER_ID, reportableTaskList.get(0).getUpdatedBy()); + + OffsetDateTime expected = OffsetDateTime.now(); + + assertThat(reportableTaskList.get(0).getUpdated()) + .isCloseTo(expected, within(1, ChronoUnit.MINUTES)); + assertEquals("Complete", reportableTaskList.get(0).getUpdateAction()); + + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + + assertEquals(today, reportableTaskList.get(0).getCompletedDate() + .toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); + assertThat(reportableTaskList.get(0).getCompletedDateTime().toLocalDate()) + .isEqualTo(expected.toLocalDate()); + assertEquals(today, reportableTaskList.get(0).getCreatedDate() + .toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); + + assertThat(reportableTaskList.get(0).getDueDate() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate()) + .isEqualTo(LocalDate.now().plusDays(1)); + + assertEquals(today, reportableTaskList.get(0).getLastUpdatedDate() + .toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); + assertEquals("COMPLETED", reportableTaskList.get(0).getFinalStateLabel()); + assertEquals(today, reportableTaskList.get(0).getFirstAssignedDate() + .toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); + assertThat(reportableTaskList.get(0).getFirstAssignedDateTime()) + .isCloseTo(expected, within(1, ChronoUnit.MINUTES)); + Assertions.assertNull(reportableTaskList.get(0).getWaitTimeDays()); + Assertions.assertNull(reportableTaskList.get(0).getWaitTime()); + assertEquals(0, reportableTaskList.get(0).getHandlingTimeDays()); + + long seconds = 0; + LocalTime time = null; + + String processingTime = reportableTaskList.get(0).getProcessingTime(); + time = LocalTime.parse(processingTime); + seconds = Duration.between(LocalTime.MIDNIGHT, time).getSeconds(); + assertTrue(seconds < 60, + String.format("Processing time %s exceeds 1 minute limit", processingTime)); + + String handlingTime = reportableTaskList.get(0).getHandlingTime(); + time = LocalTime.parse(handlingTime); + seconds = Duration.between(LocalTime.MIDNIGHT, time).getSeconds(); + assertTrue(seconds < 60, + String.format("Handling time %s exceeds 1 minute limit", processingTime)); + + assertEquals(0, reportableTaskList.get(0).getProcessingTimeDays()); + assertEquals("Yes", reportableTaskList.get(0).getIsWithinSla()); + assertEquals(0, reportableTaskList.get(0).getNumberOfReassignments()); + assertEquals(-1, reportableTaskList.get(0).getDueDateToCompletedDiffDays()); + + String diffTime = reportableTaskList.get(0).getDueDateToCompletedDiffTime(); + if (diffTime.contains("day")) { + int days = Integer.parseInt(diffTime.split(" ")[0]); + assertTrue(days <= 1, + String.format("Expected diff <= 1 day, but was %s", diffTime)); + } else { + time = LocalTime.parse(diffTime); + assertTrue(time.isBefore(LocalTime.MIDNIGHT.minus(1, ChronoUnit.MILLIS)), + String.format("Expected time < 24h, but was %s", time)); + } + }); + + } + +} diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/wataskmanagementapi/utils/TaskTestUtils.java b/src/integrationTest/java/uk/gov/hmcts/reform/wataskmanagementapi/utils/TaskTestUtils.java index d8ca5a2863..d16c545b8f 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/wataskmanagementapi/utils/TaskTestUtils.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/wataskmanagementapi/utils/TaskTestUtils.java @@ -20,6 +20,7 @@ import uk.gov.hmcts.reform.wataskmanagementapi.domain.camunda.PermissionsDmnEvaluationResponse; import uk.gov.hmcts.reform.wataskmanagementapi.domain.camunda.SecurityClassification; import uk.gov.hmcts.reform.wataskmanagementapi.domain.enums.TestRolesWithGrantType; +import uk.gov.hmcts.reform.wataskmanagementapi.entity.NoteResource; import uk.gov.hmcts.reform.wataskmanagementapi.entity.TaskResource; import uk.gov.hmcts.reform.wataskmanagementapi.entity.TaskRoleResource; import uk.gov.hmcts.reform.wataskmanagementapi.services.CFTTaskDatabaseService; @@ -29,6 +30,7 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; @@ -42,8 +44,16 @@ public class TaskTestUtils { private final CFTTaskDatabaseService cftTaskDatabaseService; + private final String profile; + public TaskTestUtils(CFTTaskDatabaseService cftTaskDatabaseService) { this.cftTaskDatabaseService = cftTaskDatabaseService; + this.profile = "primary"; + } + + public TaskTestUtils(CFTTaskDatabaseService cftTaskDatabaseService, String profile) { + this.cftTaskDatabaseService = cftTaskDatabaseService; + this.profile = profile; } public String createTaskAndRoleAssignments(CFTTaskState cftTaskState, String caseId,OffsetDateTime dueDateTime, @@ -98,7 +108,7 @@ public void insertDummyTaskInDb(String jurisdiction, if (null != dueDateTime) { taskResource.setDueDateTime(dueDateTime); } else { - taskResource.setDueDateTime(OffsetDateTime.now()); + taskResource.setDueDateTime(OffsetDateTime.now().plusDays(1)); } taskResource.setJurisdiction(jurisdiction); taskResource.setCaseTypeId(caseType); @@ -111,7 +121,13 @@ public void insertDummyTaskInDb(String jurisdiction, if (null != assignee) { taskResource.setAssignee(assignee); } - + if ("replica".equals(profile)) { + taskResource.setLastUpdatedAction("Configure"); + taskResource.setLastUpdatedTimestamp(OffsetDateTime.now()); + addMissingParameters(taskResource,true); + taskResource.setPriorityDate(OffsetDateTime.now().plusDays(3).withHour(10).withMinute(0).withSecond(0) + .withNano(0)); + } taskRoleResource.setTaskId(taskId); Set taskRoleResourceSet = Set.of(taskRoleResource); taskResource.setTaskRoleResources(taskRoleResourceSet); @@ -348,4 +364,41 @@ public RoleAssignment buildRoleAssignment(String actorId, String roleName, List< .endTime(OffsetDateTime.now().plusYears(1)) .build(); } + + private void addMissingParameters(TaskResource taskResource, boolean required) { + taskResource.setDescription(required + ? "[Decide an application](/case/WA/WaCaseType/" + + "${[CASE_REFERENCE]}/trigger/decideAnApplication)" + : null); + List notesList = new ArrayList<>(); + final NoteResource noteResource = new NoteResource( + "someCode", + "noteTypeVal", + "userVal", + "someContent" + ); + notesList.add(noteResource); + taskResource.setNotes(required ? notesList : null); + taskResource.setRegion(required ? "Wales" : null); + taskResource.setLocationName(required ? "Cardiff" : null); + taskResource.setAdditionalProperties(required ? Map.of( + "key1", "value1", + "key2", "value2", + "key3", "value3", + "key4", "value4" + ) : null); + taskResource.setReconfigureRequestTime(required + ? OffsetDateTime.now().plusDays(1).withHour(10) + .withMinute(0).withSecond(0).withNano(0) + : null); + taskResource.setLastReconfigurationTime(required + ? OffsetDateTime.now().plusDays(1).withHour(10) + .withMinute(0).withSecond(0).withNano(0) + : null); + taskResource.setNextHearingId(required ? "W-CA-1234" : null); + taskResource.setNextHearingDate(required + ? OffsetDateTime.now().plusDays(2).withHour(10).withMinute(0) + .withSecond(0).withNano(0) + : null); + } }