From a439c33702f2791c3b8054f0223a63c891a1c1f3 Mon Sep 17 00:00:00 2001 From: Phil Payne Date: Thu, 4 Jan 2024 10:42:45 +0000 Subject: [PATCH] story(ccls-1814) linked cases Includes CCLS-1815 --- caab-api/open-api-specification.yml | 145 +++++++++ .../ApplicationControllerIntegrationTest.java | 11 + .../api/controller/ApplicationController.java | 160 +++++++++- .../caab/api/mapper/ApplicationMapper.java | 14 +- .../caab/api/service/ApplicationService.java | 96 ++++++ .../ccms/caab/api/advice/AuditAdviceTest.java | 78 +++++ .../controller/ApplicationControllerTest.java | 72 +++++ .../api/mapper/ApplicationMapperTest.java | 53 ++++ .../api/service/ApplicationServiceTest.java | 281 ++++++++++++++++-- 9 files changed, 857 insertions(+), 53 deletions(-) create mode 100644 caab-service/src/test/java/uk/gov/laa/ccms/caab/api/advice/AuditAdviceTest.java diff --git a/caab-api/open-api-specification.yml b/caab-api/open-api-specification.yml index 39ddec9..465108e 100644 --- a/caab-api/open-api-specification.yml +++ b/caab-api/open-api-specification.yml @@ -257,6 +257,149 @@ paths: description: 'Not found' '500': description: 'Internal server error' + /applications/{id}/linked-cases: + get: + tags: + - applications + summary: 'Get an application''s linked cases' + operationId: 'getApplicationLinkedCases' + parameters: + - name: 'id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + example: '1234567890' + responses: + '200': + description: 'Successful operation' + content: + application/json: + schema: + type: 'array' + items: + $ref: "#/components/schemas/linkedCase" + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '404': + description: 'Not found' + '500': + description: 'Internal server error' + post: + tags: + - applications + summary: 'Add a linked case to an application' + operationId: 'addApplicationLinkedCase' + parameters: + - name: 'id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + - name: 'Caab-User-Login-Id' + in: header + required: true + schema: + type: 'string' + example: 'MARILYN@DESORANDCO.CO.UK' + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/linkedCase" + responses: + '201': + description: 'Case added successfully' + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '404': + description: 'Not found' + '500': + description: 'Internal server error' + /applications/{id}/linked-cases/{linked-case-id}: + delete: + tags: + - applications + summary: 'Remove a linked case from an application' + operationId: 'removeApplicationLinkedCase' + parameters: + - name: 'id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + - name: 'linked-case-id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + - name: 'Caab-User-Login-Id' + in: header + required: true + schema: + type: 'string' + example: 'MARILYN@DESORANDCO.CO.UK' + responses: + '204': + description: 'No Content' + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '404': + description: 'Not found' + '500': + description: 'Internal server error' + patch: + tags: + - applications + summary: 'Update a linked case of an application' + operationId: 'updateApplicationLinkedCase' + parameters: + - name: 'id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + - name: 'linked-case-id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + - name: 'Caab-User-Login-Id' + in: header + required: true + schema: + type: 'string' + example: 'MARILYN@DESORANDCO.CO.UK' + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/linkedCase" + responses: + '200': + description: 'Case updated successfully' + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '404': + description: 'Not found' + '500': + description: 'Internal server error' components: schemas: intDisplayValue: @@ -501,6 +644,8 @@ components: linkedCase: type: 'object' properties: + id: + type: 'integer' lsc_case_reference: type: 'string' relation_to_case: diff --git a/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/ApplicationControllerIntegrationTest.java b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/ApplicationControllerIntegrationTest.java index 7abae91..0985a7c 100644 --- a/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/ApplicationControllerIntegrationTest.java +++ b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/ApplicationControllerIntegrationTest.java @@ -32,6 +32,7 @@ import uk.gov.laa.ccms.caab.api.entity.AuditTrail; import uk.gov.laa.ccms.caab.api.service.ApplicationService; import uk.gov.laa.ccms.caab.model.ApplicationDetail; +import uk.gov.laa.ccms.caab.model.LinkedCase; import uk.gov.laa.ccms.data.api.AbstractIntegrationTest; @SpringBootTest(classes = CaabApiApplication.class) @@ -161,6 +162,15 @@ public void testCreateApplication(String fileInput, String auditTrailMethod, Lis assertAuditTrail(savedApplicationDetails, auditTrailMethod, auditUser); setAuditPropertiesToNull(savedApplicationDetails, auditTrailsToNull); + + //null out the id's as they are generated by the database + //theses will always be different + if (savedApplicationDetails.getLinkedCases() != null){ + for (LinkedCase linkedCase : savedApplicationDetails.getLinkedCases()){ + linkedCase.setId(null); + } + } + assertEquals(applicationDetail, savedApplicationDetails); } @@ -258,4 +268,5 @@ private static void nullifyFieldRecursive(Object object, String[] fields, int in } } } + } diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/controller/ApplicationController.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/controller/ApplicationController.java index f9ffaea..bcae6c5 100644 --- a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/controller/ApplicationController.java +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/controller/ApplicationController.java @@ -2,6 +2,7 @@ import java.net.URI; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -14,6 +15,7 @@ import uk.gov.laa.ccms.caab.model.ApplicationDetail; import uk.gov.laa.ccms.caab.model.ApplicationProviderDetails; import uk.gov.laa.ccms.caab.model.ApplicationType; +import uk.gov.laa.ccms.caab.model.LinkedCase; /** * Represents the main controller handling application-related requests. @@ -27,6 +29,14 @@ public class ApplicationController implements ApplicationsApi { private final ApplicationService applicationService; + + /** + * Creates a new application and returns the URI of the created resource. + * + * @param caabUserLoginId the user login ID used for audit trail + * @param applicationDetail the details of the application to be created + * @return a ResponseEntity with the location header set to the URI of the created application + */ @Override public ResponseEntity createApplication( final String caabUserLoginId, @@ -45,6 +55,13 @@ public ResponseEntity createApplication( return new ResponseEntity<>(headers, HttpStatus.CREATED); } + + /** + * Retrieves the details of a specific application. + * + * @param applicationId the unique identifier of the application + * @return a ResponseEntity containing the details of the application + */ @Override public ResponseEntity getApplication( final Long applicationId) { @@ -54,6 +71,14 @@ public ResponseEntity getApplication( return new ResponseEntity<>(application, HttpStatus.OK); } + //correspondence address + + /** + * Retrieves the correspondence address for a specific application. + * + * @param applicationId the unique identifier of the application + * @return a ResponseEntity containing the correspondence address of the application + */ @Override public ResponseEntity
getApplicationCorrespondenceAddress( final Long applicationId) { @@ -63,57 +88,160 @@ public ResponseEntity
getApplicationCorrespondenceAddress( return new ResponseEntity<>(correspondenceAddress, HttpStatus.OK); } + /** + * Updates the correspondence address of a specific application. + * + * @param applicationId the unique identifier of the application + * @param caabUserLoginId the user login ID used for audit trail + * @param address the new correspondence address + * @return a ResponseEntity with no content + */ + @Override + public ResponseEntity putApplicationCorrespondenceAddress( + final Long applicationId, + final String caabUserLoginId, + final Address address) { + applicationService.putCorrespondenceAddress(applicationId, address); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + //provider details + + /** + * Retrieves the provider details for a specific application. + * + * @param applicationId the unique identifier of the application + * @return a ResponseEntity containing the provider details of the application + */ @Override public ResponseEntity getApplicationProviderDetails( final Long applicationId) { - ApplicationProviderDetails applicationProviderDetails = applicationService.getApplicationProviderDetails(applicationId); return new ResponseEntity<>(applicationProviderDetails, HttpStatus.OK); } + /** + * Updates the provider details of a specific application. + * + * @param applicationId the unique identifier of the application + * @param caabUserLoginId the user login ID used for audit trail + * @param applicationProviderDetails the new provider details + * @return a ResponseEntity with no content + */ + @Override + public ResponseEntity putApplicationProviderDetails( + final Long applicationId, + final String caabUserLoginId, + final ApplicationProviderDetails applicationProviderDetails) { + applicationService.putProviderDetails(applicationId, applicationProviderDetails); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + //application type + + /** + * Retrieves the type of a specific application. + * + * @param applicationId the unique identifier of the application + * @return a ResponseEntity containing the type of the application + */ @Override public ResponseEntity getApplicationType( final Long applicationId) { - ApplicationType applicationType = applicationService.getApplicationType(applicationId); return new ResponseEntity<>(applicationType, HttpStatus.OK); } + /** + * Updates the type of a specific application. + * + * @param applicationId the unique identifier of the application + * @param caabUserLoginId the user login ID used for audit trail + * @param applicationType the new type of the application + * @return a ResponseEntity with no content + */ @Override - public ResponseEntity putApplicationCorrespondenceAddress( + public ResponseEntity putApplicationType( final Long applicationId, final String caabUserLoginId, - final Address address) { - - applicationService.putCorrespondenceAddress(applicationId, address); + final ApplicationType applicationType) { + applicationService.putApplicationType(applicationId, applicationType); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } - @Override - public ResponseEntity putApplicationProviderDetails( - final Long applicationId, - final String caabUserLoginId, - final ApplicationProviderDetails applicationProviderDetails) { + //Linked Cases - applicationService.putProviderDetails(applicationId, applicationProviderDetails); + /** + * Retrieves all linked cases for a specific application. + * + * @param applicationId the unique identifier of the application + * @return a ResponseEntity containing a list of linked cases + */ + @Override + public ResponseEntity> getApplicationLinkedCases(final Long applicationId) { + List linkedCases = applicationService.getLinkedCasesForApplication(applicationId); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); + return new ResponseEntity<>(linkedCases, HttpStatus.OK); } + /** + * Adds a linked case to a specific application. + * + * @param applicationId the unique identifier of the application + * @param caabUserLoginId the user login ID used for audit trail + * @param linkedCase the linked case to be added + * @return a ResponseEntity indicating the case was successfully created + */ @Override - public ResponseEntity putApplicationType( + public ResponseEntity addApplicationLinkedCase( final Long applicationId, final String caabUserLoginId, - final ApplicationType applicationType) { + final LinkedCase linkedCase) { + applicationService.createLinkedCaseForApplication(applicationId, linkedCase); - applicationService.putApplicationType(applicationId, applicationType); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + /** + * Updates a linked case of a specific application. + * + * @param applicationId the unique identifier of the application + * @param linkedCaseId the unique identifier of the linked case + * @param caabUserLoginId the user login ID used for audit trail + * @param linkedCase the updated linked case + * @return a ResponseEntity with no content + */ + @Override + public ResponseEntity updateApplicationLinkedCase( + final Long applicationId, final Long linkedCaseId, + final String caabUserLoginId, + final LinkedCase linkedCase) { + applicationService.updateLinkedCaseForApplication(applicationId, linkedCaseId, linkedCase); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } + /** + * Removes a linked case from a specific application. + * + * @param applicationId the unique identifier of the application + * @param linkedCaseId the unique identifier of the linked case + * @param caabUserLoginId the user login ID used for audit trail + * @return a ResponseEntity indicating the case was successfully removed + */ + @Override + public ResponseEntity removeApplicationLinkedCase( + final Long applicationId, + final Long linkedCaseId, + final String caabUserLoginId) { + applicationService.removeLinkedCaseFromApplication(applicationId, linkedCaseId); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } } diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapper.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapper.java index efaf601..d031069 100644 --- a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapper.java +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapper.java @@ -1,5 +1,6 @@ package uk.gov.laa.ccms.caab.api.mapper; +import java.util.List; import lombok.Generated; import org.mapstruct.AfterMapping; import org.mapstruct.InheritInverseConfiguration; @@ -170,13 +171,17 @@ uk.gov.laa.ccms.caab.model.ScopeLimitation toScopeLimitationModel( @Mapping(target = "address", source = "address", qualifiedByName = "toAddressModel") uk.gov.laa.ccms.caab.model.Opponent toOpponentModel(Opponent opponent); + List toLinkedCaseList(List linkedCases); + + List toLinkedCaseModelList(List linkedCases); + @Mapping(target = "auditTrail", ignore = true) @Mapping(target = "clientSurname", source = "client.surname") @Mapping(target = "clientReference", source = "client.reference") @Mapping(target = "clientFirstName", source = "client.firstName") LinkedCase toLinkedCase(uk.gov.laa.ccms.caab.model.LinkedCase linkedCase); - @InheritInverseConfiguration + @InheritInverseConfiguration(name = "toLinkedCase") uk.gov.laa.ccms.caab.model.LinkedCase toLinkedCaseModel(LinkedCase linkedCase); @Named("toAddress") @@ -274,7 +279,8 @@ void updateAddress( @MappingTarget Address address, uk.gov.laa.ccms.caab.model.Address addressModel); - - - + @Mapping(target = "auditTrail", ignore = true) + void updateLinkedCase( + @MappingTarget LinkedCase linkedCase, + uk.gov.laa.ccms.caab.model.LinkedCase linkedCaseModel); } diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/service/ApplicationService.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/service/ApplicationService.java index 86f81ae..8155acb 100644 --- a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/service/ApplicationService.java +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/service/ApplicationService.java @@ -1,6 +1,7 @@ package uk.gov.laa.ccms.caab.api.service; import jakarta.transaction.Transactional; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -12,6 +13,7 @@ import uk.gov.laa.ccms.caab.model.ApplicationDetail; import uk.gov.laa.ccms.caab.model.ApplicationProviderDetails; import uk.gov.laa.ccms.caab.model.ApplicationType; +import uk.gov.laa.ccms.caab.model.LinkedCase; /** * Service responsible for handling application-related operations. @@ -69,6 +71,100 @@ public ApplicationDetail getApplication(final Long applicationId) { HttpStatus.NOT_FOUND)); } + /** + * Gets an application's linked cases. + * + * @param id the TDS id for the application. + * @return the application's linked cases. + */ + @Transactional + public List getLinkedCasesForApplication(final Long id) { + return applicationRepository.findById(id) + .map(Application::getLinkedCases) + .map(applicationMapper::toLinkedCaseModelList) + .orElseThrow(() -> new CaabApiException( + String.format("Linked cases for application with id %s not found", id), + HttpStatus.NOT_FOUND)); + } + + /** + * Creates and associates a new linked case with a specified application. + * If the application is not found, a CaabApiException is thrown. + * + * @param id The unique identifier of the application. + * @param linkedCase The LinkedCase object containing the details of the case to be linked. + * @throws CaabApiException If the application with the specified ID is not found. + */ + @Transactional + public void createLinkedCaseForApplication(final Long id, final LinkedCase linkedCase) { + Application application = applicationRepository.findById(id) + .orElseThrow(() -> new CaabApiException( + String.format("Application with id %s not found", id), HttpStatus.NOT_FOUND)); + + uk.gov.laa.ccms.caab.api.entity.LinkedCase linkedCaseEntity = + applicationMapper.toLinkedCase(linkedCase); + application.getLinkedCases().add(linkedCaseEntity); + linkedCaseEntity.setApplication(application); + applicationRepository.save(application); + } + + /** + * Removes a linked case from the specified application. + * If either the application or the linked case is not found, a CaabApiException is thrown. + * + * @param id The unique identifier of the application. + * @param linkedCaseId The unique identifier of the linked case to be removed. + * @throws CaabApiException If the application or the linked case with the specified IDs are + * not found. + */ + @Transactional + public void removeLinkedCaseFromApplication(final Long id, final Long linkedCaseId) { + Application application = applicationRepository.findById(id) + .orElseThrow(() -> new CaabApiException( + String.format("Application with id %s not found", id), HttpStatus.NOT_FOUND)); + + uk.gov.laa.ccms.caab.api.entity.LinkedCase linkedCaseEntity = + application.getLinkedCases().stream() + .filter(linkedCase -> linkedCase.getId().equals(linkedCaseId)) + .findFirst() + .orElseThrow(() -> new CaabApiException( + String.format("Linked case with id %s not found", linkedCaseId), HttpStatus.NOT_FOUND)); + + application.getLinkedCases().remove(linkedCaseEntity); + applicationRepository.save(application); + } + + /** + * Updates a linked case of a specified application. + * If either the application or the linked case is not found, a CaabApiException is thrown. + * + * @param id The unique identifier of the application. + * @param linkedCaseId The unique identifier of the linked case to be updated. + * @param linkedCaseModel The LinkedCase object containing the details of the case to be updated. + * @throws CaabApiException If the application or the linked case with the specified IDs are not + * found. + */ + @Transactional + public void updateLinkedCaseForApplication( + final Long id, final Long linkedCaseId, + final LinkedCase linkedCaseModel) { + Application application = applicationRepository.findById(id) + .orElseThrow(() -> new CaabApiException( + String.format("Application with id %s not found", id), HttpStatus.NOT_FOUND)); + + uk.gov.laa.ccms.caab.api.entity.LinkedCase linkedCaseEntity = + application.getLinkedCases().stream() + .filter(linkedCase -> linkedCase.getId().equals(linkedCaseId)) + .findFirst() + .orElseThrow(() -> new CaabApiException( + String.format("Linked case with id %s not found", linkedCaseId), HttpStatus.NOT_FOUND)); + + applicationMapper.updateLinkedCase(linkedCaseEntity, linkedCaseModel); + applicationRepository.save(application); + } + + + /** * Gets an application's correspondence address. * diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/advice/AuditAdviceTest.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/advice/AuditAdviceTest.java new file mode 100644 index 0000000..4a8db4a --- /dev/null +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/advice/AuditAdviceTest.java @@ -0,0 +1,78 @@ +package uk.gov.laa.ccms.caab.api.advice; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import uk.gov.laa.ccms.caab.api.audit.AuditorAwareImpl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(SpringExtension.class) +class AuditAdviceTest { + + @Mock + private AuditorAwareImpl auditorAware; + + @InjectMocks + private AuditAdvice auditAdvice; + + private MockMvc mockMvc; + + @BeforeEach + public void setup() { + // Setup MockMvc with the AuditAdvice + mockMvc = MockMvcBuilders.standaloneSetup(new MockController()) + .setControllerAdvice(auditAdvice) + .build(); + } + + @AfterEach + public void tearDown() { + // Reset currentUserHolder after each test + AuditorAwareImpl.currentUserHolder.remove(); + } + + @Test + void setCurrentUserHolderIfAvailable() throws Exception { + String caabUserLoginId = "testUser"; + + mockMvc.perform(get("/test") + .header("Caab-User-Login-Id", caabUserLoginId)) + .andDo(print()) + .andExpect(status().isOk()); + + assertEquals(caabUserLoginId, AuditorAwareImpl.currentUserHolder.get()); + } + + @Test + void currentUserHolderIsNullWhenCaabUserLoginIdNotProvided() throws Exception { + mockMvc.perform(get("/test")) // No Caab-User-Login-Id header + .andDo(print()) + .andExpect(status().isOk()); + + // Assert that currentUserHolder is null or unchanged + assertNull(AuditorAwareImpl.currentUserHolder.get()); + } + + // Mock controller for testing purposes + @RestController + private static class MockController { + @GetMapping("/test") + public void testEndpoint() { + // Test endpoint for AuditAdvice + } + } +} diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/controller/ApplicationControllerTest.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/controller/ApplicationControllerTest.java index 8c17e48..d0745b3 100644 --- a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/controller/ApplicationControllerTest.java +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/controller/ApplicationControllerTest.java @@ -3,7 +3,9 @@ import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @@ -12,6 +14,8 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -29,6 +33,7 @@ import uk.gov.laa.ccms.caab.model.ApplicationType; import uk.gov.laa.ccms.caab.model.Client; import uk.gov.laa.ccms.caab.model.IntDisplayValue; +import uk.gov.laa.ccms.caab.model.LinkedCase; import uk.gov.laa.ccms.caab.model.StringDisplayValue; @ExtendWith(SpringExtension.class) @@ -174,4 +179,71 @@ public void putApplicationCorrespondenceAddress() throws Exception { verify(applicationService).putCorrespondenceAddress(id, address); } + @Test + public void getApplicationLinkedCases_returnsLinkedCases() throws Exception { + Long id = 1L; + List linkedCases = Arrays.asList(new LinkedCase(), new LinkedCase()); // Assuming some mock linked cases + + when(applicationService.getLinkedCasesForApplication(id)).thenReturn(linkedCases); + + this.mockMvc.perform(get("/applications/{id}/linked-cases", id)) + .andExpect(status().isOk()); + + verify(applicationService).getLinkedCasesForApplication(id); + } + + @Test + public void addApplicationLinkedCase_isCreated() throws Exception { + Long id = 1L; + String caabUserLoginId = "userLoginId"; + LinkedCase linkedCase = new LinkedCase(); // Set up linked case details as required + + doNothing().when(applicationService).createLinkedCaseForApplication(id, linkedCase); + + this.mockMvc.perform(post("/applications/{id}/linked-cases", id) + .header("Caab-User-Login-Id", caabUserLoginId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(linkedCase))) + .andExpect(status().isCreated()); + + verify(applicationService).createLinkedCaseForApplication(id, linkedCase); + } + + @Test + public void updateApplicationLinkedCase_noContent() throws Exception { + Long id = 1L; + Long linkedCaseId = 2L; + String caabUserLoginId = "userLoginId"; + LinkedCase linkedCase = new LinkedCase(); // Set up updated linked case details as required + + doNothing().when(applicationService).updateLinkedCaseForApplication(id, linkedCaseId, linkedCase); + + this.mockMvc.perform(patch("/applications/{id}/linked-cases/{linkedCaseId}", id, linkedCaseId) + .header("Caab-User-Login-Id", caabUserLoginId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(linkedCase))) + .andExpect(status().isNoContent()); + + verify(applicationService).updateLinkedCaseForApplication(id, linkedCaseId, linkedCase); + } + + @Test + public void removeApplicationLinkedCase_noContent() throws Exception { + Long id = 1L; + Long linkedCaseId = 2L; + String caabUserLoginId = "userLoginId"; + + doNothing().when(applicationService).removeLinkedCaseFromApplication(id, linkedCaseId); + + this.mockMvc.perform(delete("/applications/{id}/linked-cases/{linkedCaseId}", id, linkedCaseId) + .header("Caab-User-Login-Id", caabUserLoginId)) + .andExpect(status().isNoContent()); + + verify(applicationService).removeLinkedCaseFromApplication(id, linkedCaseId); + } + + + + + } \ No newline at end of file diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapperTest.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapperTest.java index 74be2c0..bacdb92 100644 --- a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapperTest.java +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/mapper/ApplicationMapperTest.java @@ -14,6 +14,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import uk.gov.laa.ccms.caab.api.entity.Address; @@ -1148,6 +1149,58 @@ public void testToProviderDetails() { assertEquals("ProviderCase123", result.getProviderCaseReference()); } + @Test + void updateAddress_updatesFieldsWhenModelIsNotNull() { + Address address = buildAddress(); + uk.gov.laa.ccms.caab.model.Address addressModel = new uk.gov.laa.ccms.caab.model.Address(); + + addressModel.setPostcode("TestPostcode"); + addressModel.setHouseNameOrNumber("123"); + + mapper.updateAddress(address, addressModel); + + assertEquals("TestPostcode", address.getPostCode()); + assertEquals("123", address.getHouseNameNumber()); + } + + @Test + void updateAddress_doesNothingWhenModelIsNull() { + ApplicationMapper mapper = new ApplicationMapperImpl(); // Replace with your actual mapper instantiation + + Address address = buildAddress(); + + mapper.updateAddress(address, null); + + // Assert that all fields remain unchanged + assertEquals("InitialPostcode", address.getPostCode()); + assertEquals("InitialHouseNameNumber", address.getHouseNameNumber()); + assertTrue(address.getNoFixedAbode()); + assertEquals("InitialAddressLine1", address.getAddressLine1()); + assertEquals("InitialAddressLine2", address.getAddressLine2()); + assertEquals("InitialCity", address.getCity()); + assertEquals("InitialCounty", address.getCounty()); + assertEquals("InitialCountry", address.getCountry()); + assertEquals("InitialCareOf", address.getCareOf()); + assertEquals("InitialPreferredAddress", address.getPreferredAddress()); + } + + @NotNull + private static Address buildAddress() { + Address address = new Address(); + address.setPostCode("InitialPostcode"); + address.setHouseNameNumber("InitialHouseNameNumber"); + address.setNoFixedAbode(true); + address.setAddressLine1("InitialAddressLine1"); + address.setAddressLine2("InitialAddressLine2"); + address.setCity("InitialCity"); + address.setCounty("InitialCounty"); + address.setCountry("InitialCountry"); + address.setCareOf("InitialCareOf"); + address.setPreferredAddress("InitialPreferredAddress"); + return address; + } + + private AuditDetail buildAuditDetail() { AuditDetail auditDetail = new AuditDetail(); auditDetail.setCreated(createdAt); diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/service/ApplicationServiceTest.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/service/ApplicationServiceTest.java index 8112954..7a34126 100644 --- a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/service/ApplicationServiceTest.java +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/service/ApplicationServiceTest.java @@ -1,5 +1,8 @@ package uk.gov.laa.ccms.caab.api.service; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -17,18 +20,17 @@ import uk.gov.laa.ccms.caab.api.repository.ApplicationRepository; import uk.gov.laa.ccms.caab.model.ApplicationProviderDetails; import uk.gov.laa.ccms.caab.model.ApplicationType; +import uk.gov.laa.ccms.caab.model.LinkedCase; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class ApplicationServiceTest { - - private static final String CAAB_USER_LOGIN_ID = "testUser"; - private static final String OLD_USER = "oldUser"; - @Mock private ApplicationRepository applicationRepository; @@ -252,8 +254,249 @@ void patchProviderDetails_whenNotExists_throwsException() { assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); } + @Test + void getLinkedCasesForApplication_whenExists_returnsLinkedCases() { + Long id = 1L; + List expectedLinkedCases = Arrays.asList(new LinkedCase(), new LinkedCase()); // Assuming some mock linked cases + Application application = new Application(); + application.setLinkedCases(new ArrayList<>()); // Set linked cases in the application + + when(applicationRepository.findById(id)).thenReturn(Optional.of(application)); + when(applicationMapper.toLinkedCaseModelList(any())).thenReturn(expectedLinkedCases); + + List result = applicationService.getLinkedCasesForApplication(id); + + verify(applicationRepository).findById(id); + verify(applicationMapper).toLinkedCaseModelList(application.getLinkedCases()); + + assertEquals(expectedLinkedCases, result); + } + + @Test + void getLinkedCasesForApplication_whenNotExists_throwsException() { + Long id = 1L; + + when(applicationRepository.findById(id)).thenReturn(Optional.empty()); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> { + applicationService.getLinkedCasesForApplication(id); + }); + + verify(applicationRepository).findById(id); + + assertEquals("Linked cases for application with id " + id + " not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + @Test + void getApplicationCorrespondenceAddress_whenExists_returnsAddress() { + Long id = 1L; + uk.gov.laa.ccms.caab.model.Address expectedAddress = new uk.gov.laa.ccms.caab.model.Address(); // Mock address + Application application = new Application(); + application.setCorrespondenceAddress(new Address()); // Set a mock address in the application + + when(applicationRepository.findById(id)).thenReturn(Optional.of(application)); + when(applicationMapper.toAddressModel(any())).thenReturn(expectedAddress); + + uk.gov.laa.ccms.caab.model.Address result = applicationService.getApplicationCorrespondenceAddress(id); + + verify(applicationRepository).findById(id); + verify(applicationMapper).toAddressModel(application.getCorrespondenceAddress()); + + assertEquals(expectedAddress, result); + } + + @Test + void getApplicationCorrespondenceAddress_whenNotExists_throwsException() { + Long id = 1L; + + when(applicationRepository.findById(id)).thenReturn(Optional.empty()); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> { + applicationService.getApplicationCorrespondenceAddress(id); + }); + + verify(applicationRepository).findById(id); + + assertEquals("Correspondence address for application with id " + id + " not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + @Test + void putCorrespondenceAddress_whenExists_updatesAddress() { + Long id = 1L; + uk.gov.laa.ccms.caab.model.Address newAddress = new uk.gov.laa.ccms.caab.model.Address(); // Mock new address + Application application = new Application(); + + when(applicationRepository.findById(id)).thenReturn(Optional.of(application)); + + applicationService.putCorrespondenceAddress(id, newAddress); + + verify(applicationRepository).findById(id); + verify(applicationMapper).addCorrespondenceAddressToApplication(application, newAddress); + verify(applicationRepository).save(application); + } + + @Test + void putCorrespondenceAddress_whenNotExists_throwsException() { + Long id = 1L; + uk.gov.laa.ccms.caab.model.Address newAddress = new uk.gov.laa.ccms.caab.model.Address(); + + when(applicationRepository.findById(id)).thenReturn(Optional.empty()); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> { + applicationService.putCorrespondenceAddress(id, newAddress); + }); + + verify(applicationRepository).findById(id); + + assertEquals("Application with id " + id + " not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + + @Test + void createLinkedCaseForApplication_whenApplicationExists_createsLinkedCase() { + Long applicationId = 1L; + LinkedCase linkedCase = new LinkedCase(); + Application application = new Application(); + application.setLinkedCases(new ArrayList<>()); + + uk.gov.laa.ccms.caab.api.entity.LinkedCase linkedCaseEntity = new uk.gov.laa.ccms.caab.api.entity.LinkedCase(); + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.of(application)); + when(applicationMapper.toLinkedCase(linkedCase)).thenReturn(linkedCaseEntity); + + applicationService.createLinkedCaseForApplication(applicationId, linkedCase); + + verify(applicationRepository).findById(applicationId); + verify(applicationMapper).toLinkedCase(linkedCase); + verify(applicationRepository).save(application); + assertTrue(application.getLinkedCases().contains(linkedCaseEntity)); + } + + @Test + void createLinkedCaseForApplication_whenApplicationNotExists_throwsException() { + Long applicationId = 1L; + LinkedCase linkedCase = new LinkedCase(); + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.empty()); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> + applicationService.createLinkedCaseForApplication(applicationId, linkedCase)); + + assertEquals("Application with id 1 not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + @Test + void removeLinkedCaseFromApplication_whenApplicationNotExists_throwsException() { + Long applicationId = 1L; + Long linkedCaseId = 2L; + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.empty()); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> + applicationService.removeLinkedCaseFromApplication(applicationId, linkedCaseId)); + + assertEquals("Application with id 1 not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + + @Test + void removeLinkedCaseFromApplication_whenCaseExists_removesLinkedCase() { + Long applicationId = 1L; + Long linkedCaseId = 2L; + Application application = new Application(); + uk.gov.laa.ccms.caab.api.entity.LinkedCase linkedCaseEntity = new uk.gov.laa.ccms.caab.api.entity.LinkedCase(); + linkedCaseEntity.setId(linkedCaseId); + application.setLinkedCases(new ArrayList<>(Arrays.asList(linkedCaseEntity))); + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.of(application)); + + applicationService.removeLinkedCaseFromApplication(applicationId, linkedCaseId); + + verify(applicationRepository).findById(applicationId); + verify(applicationRepository).save(application); + assertFalse(application.getLinkedCases().contains(linkedCaseEntity)); + } + + @Test + void removeLinkedCaseFromApplication_whenCaseNotExists_throwsException() { + Long applicationId = 1L; + Long linkedCaseId = 2L; + Application application = new Application(); + application.setLinkedCases(new ArrayList<>()); + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.of(application)); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> + applicationService.removeLinkedCaseFromApplication(applicationId, linkedCaseId)); + + assertEquals("Linked case with id 2 not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + @Test + void updateLinkedCaseForApplication_whenApplicationNotExists_throwsException() { + Long applicationId = 1L; + Long linkedCaseId = 2L; + LinkedCase linkedCaseModel = new LinkedCase(); + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.empty()); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> + applicationService.updateLinkedCaseForApplication(applicationId, linkedCaseId, linkedCaseModel)); + + assertEquals("Application with id 1 not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + @Test + void updateLinkedCaseForApplication_whenCaseExists_updatesLinkedCase() { + Long applicationId = 1L; + Long linkedCaseId = 2L; + LinkedCase linkedCaseModel = new LinkedCase(); + Application application = new Application(); + application.setLinkedCases(new ArrayList<>()); + + uk.gov.laa.ccms.caab.api.entity.LinkedCase linkedCaseEntity = new uk.gov.laa.ccms.caab.api.entity.LinkedCase(); + linkedCaseEntity.setId(linkedCaseId); + application.setLinkedCases(new ArrayList<>(Arrays.asList(linkedCaseEntity))); + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.of(application)); + + applicationService.updateLinkedCaseForApplication(applicationId, linkedCaseId, linkedCaseModel); + + verify(applicationRepository).findById(applicationId); + verify(applicationMapper).updateLinkedCase(linkedCaseEntity, linkedCaseModel); + verify(applicationRepository).save(application); + } + + @Test + void updateLinkedCaseForApplication_whenCaseNotExists_throwsException() { + Long applicationId = 1L; + Long linkedCaseId = 2L; + LinkedCase linkedCaseModel = new LinkedCase(); + Application application = new Application(); + application.setLinkedCases(new ArrayList<>()); + + when(applicationRepository.findById(applicationId)).thenReturn(Optional.of(application)); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> + applicationService.updateLinkedCaseForApplication(applicationId, linkedCaseId, linkedCaseModel)); + + assertEquals("Linked case with id 2 not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + + + + /** - * Helper method to setup the mocking behaviour of applicationMapper and applicationRepository. + * Helper method to set up the mocking behaviour of applicationMapper and applicationRepository. */ private void mockMapperAndRepository(ApplicationDetail applicationDetail, Application application) { when(applicationMapper.toApplication(applicationDetail)).thenReturn(application); @@ -268,24 +511,6 @@ private void verifyInteractionsWithMocks(ApplicationDetail applicationDetail, Ap verify(applicationRepository).save(application); } - /** - * Helper method to verify that AuditTrail is set on the Application, Address, and CostStructure. - */ - private void verifyAuditTrailSetOnEntities(Application application) { - assertAuditTrailSet(CAAB_USER_LOGIN_ID, application.getAuditTrail()); - assertAuditTrailSet(CAAB_USER_LOGIN_ID, application.getCorrespondenceAddress().getAuditTrail()); - assertAuditTrailSet(CAAB_USER_LOGIN_ID, application.getCosts().getAuditTrail()); - } - - /** - * Helper method to assert that AuditTrail is correctly set on individual entity. - */ - private void assertAuditTrailSet(String userId, AuditTrail auditTrail) { - assert auditTrail != null; - assert userId.equals(auditTrail.getCreatedBy()); - assert userId.equals(auditTrail.getLastSavedBy()); - } - /** * Helper method to create an Application with existing Address and CostStructure. */ @@ -299,15 +524,5 @@ private Application createApplicationWithExistingAddressAndCosts() { return application; } - - /** - * Helper method to create a new AuditTrail object. - */ - private AuditTrail createAuditTrail() { - AuditTrail auditTrail = new AuditTrail(); - auditTrail.setCreatedBy(OLD_USER); - auditTrail.setLastSavedBy(OLD_USER); - return auditTrail; - } }