From 8b081f79d3b5533018aca3cf5f428ab2d9fe8044 Mon Sep 17 00:00:00 2001 From: krishna-patel-ch Date: Tue, 19 Mar 2024 15:16:16 +0000 Subject: [PATCH 1/2] IDVA6-494: Ported over service layer and rest layer again --- .../AssociationsListForCompanyController.java | 53 ++ .../service/AssociationsService.java | 16 + ...ociationsListForCompanyControllerTest.java | 338 +++++++++ ...ociationsListForCompanyControllerTest.java | 642 ++++++++++++++++++ .../integration/AssociationsServiceTest.java | 408 +++++++++++ .../service/AssociationsServiceTest.java | 374 ++++++++++ 6 files changed, 1831 insertions(+) create mode 100644 src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java create mode 100644 src/test/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyControllerTest.java create mode 100644 src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsListForCompanyControllerTest.java create mode 100644 src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsServiceTest.java diff --git a/src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java b/src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java new file mode 100644 index 00000000..569f2df9 --- /dev/null +++ b/src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java @@ -0,0 +1,53 @@ +package uk.gov.companieshouse.accounts.association.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; +import uk.gov.companieshouse.accounts.association.AccountsAssociationServiceApplication; +import uk.gov.companieshouse.accounts.association.exceptions.BadRequestRuntimeException; +import uk.gov.companieshouse.accounts.association.service.AssociationsService; +import uk.gov.companieshouse.accounts.association.service.CompanyService; +import uk.gov.companieshouse.api.accounts.associations.api.AssociationsListForCompanyInterface; +import uk.gov.companieshouse.api.accounts.associations.model.AssociationsList; +import uk.gov.companieshouse.logging.Logger; +import uk.gov.companieshouse.logging.LoggerFactory; + +@RestController +public class AssociationsListForCompanyController implements AssociationsListForCompanyInterface { + + private final AssociationsService associationsService; + private final CompanyService companyService; + + private static final Logger LOG = LoggerFactory.getLogger( AccountsAssociationServiceApplication.applicationNameSpace ); + + public AssociationsListForCompanyController(AssociationsService associationsService, CompanyService companyService) { + this.associationsService = associationsService; + this.companyService = companyService; + } + + @Override + public ResponseEntity getAssociationsForCompany( final String companyNumber, final String xRequestId, final Boolean includeRemoved, final Integer pageIndex, final Integer itemsPerPage ) { + + LOG.debug( String.format( "%s: Attempting to fetch users that are associated with company %s. includeRemoved=%b, itemsPerPage=%d, and pageIndex=%d.", xRequestId, companyNumber, includeRemoved, itemsPerPage, pageIndex ) ); + + if ( pageIndex < 0 ){ + LOG.error( "pageIndex was less then 0" ); + throw new BadRequestRuntimeException( "Please check the request and try again" ); + } + + if ( itemsPerPage <= 0 ){ + LOG.error( "itemsPerPage was less then 0" ); + throw new BadRequestRuntimeException( "Please check the request and try again" ); + } + + final var companyProfile = companyService.fetchCompanyProfile( companyNumber ); + + final var associationsList = associationsService.fetchAssociatedUsers( companyNumber, companyProfile, includeRemoved, itemsPerPage, pageIndex ); + final var associationsListIsEmpty = associationsList.getItems().isEmpty(); + + LOG.debug( associationsListIsEmpty ? String.format( "%s: Could not find any associations", xRequestId ) : String.format( "%s: Successfully fetched associations", xRequestId ) ); + + return new ResponseEntity<>( associationsList, HttpStatus.OK ); + } + +} \ No newline at end of file diff --git a/src/main/java/uk/gov/companieshouse/accounts/association/service/AssociationsService.java b/src/main/java/uk/gov/companieshouse/accounts/association/service/AssociationsService.java index ac0180cb..d1e4d20b 100644 --- a/src/main/java/uk/gov/companieshouse/accounts/association/service/AssociationsService.java +++ b/src/main/java/uk/gov/companieshouse/accounts/association/service/AssociationsService.java @@ -1,9 +1,12 @@ package uk.gov.companieshouse.accounts.association.service; import jakarta.validation.constraints.NotNull; +import java.util.HashSet; +import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import uk.gov.companieshouse.accounts.association.mapper.AssociationMapper; @@ -12,6 +15,7 @@ import uk.gov.companieshouse.accounts.association.models.AssociationDao; import uk.gov.companieshouse.accounts.association.repositories.AssociationsRepository; import uk.gov.companieshouse.api.accounts.associations.model.Association; +import uk.gov.companieshouse.api.accounts.associations.model.Association.StatusEnum; import uk.gov.companieshouse.api.accounts.associations.model.AssociationsList; import uk.gov.companieshouse.api.accounts.user.model.User; @@ -19,6 +23,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import uk.gov.companieshouse.api.company.CompanyDetails; @Service public class AssociationsService { @@ -62,5 +67,16 @@ public AssociationsList fetchAssociationsForUserStatusAndCompany( return associationsListUserMapper.daoToDto(results, user); } + public AssociationsList fetchAssociatedUsers( final String companyNumber, final CompanyDetails companyDetails, final boolean includeRemoved, final int itemsPerPage, final int pageIndex ){ + final Pageable pageable = PageRequest.of( pageIndex, itemsPerPage ); + + final var statuses = new HashSet<>( Set.of( StatusEnum.CONFIRMED.getValue(), StatusEnum.AWAITING_APPROVAL.getValue() ) ); + if ( includeRemoved ) + statuses.add( StatusEnum.REMOVED.getValue() ); + + final var associations = associationsRepository.fetchAssociatedUsers( companyNumber, statuses, pageable ); + + return associationsListCompanyMapper.daoToDto( associations, companyDetails ); + } } \ No newline at end of file diff --git a/src/test/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyControllerTest.java b/src/test/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyControllerTest.java new file mode 100644 index 00000000..bf3bb512 --- /dev/null +++ b/src/test/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyControllerTest.java @@ -0,0 +1,338 @@ +package uk.gov.companieshouse.accounts.association.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MockMvc; +import uk.gov.companieshouse.accounts.association.configuration.InterceptorConfig; +import uk.gov.companieshouse.accounts.association.exceptions.NotFoundRuntimeException; +import uk.gov.companieshouse.accounts.association.service.AssociationsService; +import uk.gov.companieshouse.accounts.association.service.CompanyService; +import uk.gov.companieshouse.api.accounts.associations.model.Association; +import uk.gov.companieshouse.api.accounts.associations.model.Association.ApprovalRouteEnum; +import uk.gov.companieshouse.api.accounts.associations.model.Association.StatusEnum; +import uk.gov.companieshouse.api.accounts.associations.model.AssociationLinks; +import uk.gov.companieshouse.api.accounts.associations.model.AssociationsList; +import uk.gov.companieshouse.api.accounts.associations.model.AssociationsListLinks; +import uk.gov.companieshouse.api.accounts.associations.model.Invitation; +import uk.gov.companieshouse.api.company.CompanyDetails; + +@AutoConfigureMockMvc +@WebMvcTest(AssociationsListForCompanyController.class) +@ExtendWith(MockitoExtension.class) +@Tag("unit-test") +public class AssociationsListForCompanyControllerTest { + + @Value("${internal.api.url}") + private String internalApiUrl; + + @Autowired + public MockMvc mockMvc; + + @MockBean + AssociationsService associationsService; + + @MockBean + CompanyService companyService; + + @InjectMocks + AssociationsListForCompanyController associationsListForCompanyController; + + @MockBean + InterceptorConfig interceptorConfig; + + private static final String DEFAULT_KIND = "association"; + private static final String DEFAULT_DISPLAY_NAME = "Not provided"; + + private final LocalDateTime now = LocalDateTime.now(); + + private Association associationOne; + private Association associationTwo; + + + @BeforeEach + public void setup() { + + final var invitationOne = + new Invitation().invitedBy( "666" ) + .invitedAt( now.plusDays(4).toString() ); + + associationOne = + new Association().etag("a") + .id("1") + .userId("111") + .userEmail("bruce.wayne@gotham.city") + .displayName("Batman") + .companyNumber("111111") + .companyName("Wayne Enterprises") + .status(StatusEnum.CONFIRMED) + .createdAt( LocalDateTime.now().atOffset( ZoneOffset.UTC ) ) + .approvedAt( now.plusDays(1).atOffset( ZoneOffset.UTC ) ) + .removedAt( now.plusDays(2).atOffset( ZoneOffset.UTC ) ) + .kind( DEFAULT_KIND ) + .approvalRoute(ApprovalRouteEnum.AUTH_CODE) + .approvalExpiryAt( now.plusDays(3).toString() ) + .invitations( List.of( invitationOne ) ) + .links( new AssociationLinks().self( "/1" ) ); + + final var invitationTwo = + new Invitation().invitedBy( "666" ) + .invitedAt( now.plusDays(8).toString() ); + + associationTwo = + new Association().etag("b") + .id("2") + .userId("222") + .userEmail("the.joker@gotham.city") + .displayName(DEFAULT_DISPLAY_NAME) + .companyNumber("111111") + .companyName("Wayne Enterprises") + .status(StatusEnum.REMOVED) + .createdAt( LocalDateTime.now().atOffset( ZoneOffset.UTC ) ) + .approvedAt( now.plusDays(5).atOffset( ZoneOffset.UTC ) ) + .removedAt( now.plusDays(6).atOffset( ZoneOffset.UTC ) ) + .kind( DEFAULT_KIND ) + .approvalRoute(ApprovalRouteEnum.AUTH_CODE) + .approvalExpiryAt( now.plusDays(7).toString() ) + .invitations( List.of( invitationTwo ) ) + .links( new AssociationLinks().self( "/2" ) ); + + Mockito.doNothing().when(interceptorConfig).addInterceptors( any() ); + } + + @Test + void getAssociationsForCompanyWithMalformedCompanyNumberReturnsBadRequest() throws Exception { + mockMvc.perform( get( "/associations/companies/{company_number}", "$$$$$$" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isBadRequest()); + } + + @Test + void getAssociationsForCompanyWithNonexistentCompanyReturnsNotFound() throws Exception { + Mockito.doThrow( new NotFoundRuntimeException( "accounts-association-api", "Not found" ) ).when( companyService ).fetchCompanyProfile( any() ); + + mockMvc.perform( get( "/associations/companies/{company_number}", "919191" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isNotFound()) + .andReturn() + .getResponse(); + } + + @Test + void getAssociationsForCompanyWithoutXRequestIdReturnsBadRequest() throws Exception { + mockMvc.perform( get( "/associations/companies/{company_number}", "111111" ) ) + .andExpect(status().isBadRequest()); + } + + @Test + void getAssociationsForCompanyWithoutQueryParamsUsesDefaults() throws Exception { + final var expectedAssociationsList = new AssociationsList(); + expectedAssociationsList.setTotalResults( 1 ); + expectedAssociationsList.setTotalPages( 1 ); + expectedAssociationsList.setPageNumber( 0 ); + expectedAssociationsList.setItemsPerPage( 15 ); + expectedAssociationsList.setLinks( new AssociationsListLinks().self(String.format("%s/associations", internalApiUrl)).next("") ); + expectedAssociationsList.setItems(List.of( associationOne )); + Mockito.doReturn(expectedAssociationsList).when(associationsService).fetchAssociatedUsers( any(), any(), eq( false ), eq( 15 ), eq( 0 ) ); + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + Mockito.doReturn( companyDetails ).when( companyService ).fetchCompanyProfile( any() ); + + mockMvc.perform( get( "/associations/companies/{company_number}", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()); + + + Mockito.verify( associationsService ).fetchAssociatedUsers( eq( "111111" ), eq( companyDetails ), eq( false ), eq( 15 ), eq( 0 ) ); + } + + @Test + void getAssociationsForCompanyWithIncludeRemovedFalseAppliesFilter() throws Exception { + final var expectedAssociationsList = new AssociationsList(); + expectedAssociationsList.setTotalResults( 1 ); + expectedAssociationsList.setTotalPages( 1 ); + expectedAssociationsList.setPageNumber( 0 ); + expectedAssociationsList.setItemsPerPage( 15 ); + expectedAssociationsList.setLinks( new AssociationsListLinks().self(String.format("%s/associations", internalApiUrl)).next("") ); + expectedAssociationsList.setItems(List.of( associationOne )); + Mockito.doReturn(expectedAssociationsList).when(associationsService).fetchAssociatedUsers( any(), any(), eq( false ), eq( 15 ), eq( 0 ) ); + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + Mockito.doReturn( companyDetails ).when( companyService ).fetchCompanyProfile( any() ); + + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=false", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()); + + Mockito.verify( associationsService ).fetchAssociatedUsers( eq( "111111" ), eq( companyDetails ), eq( false ), eq( 15 ), eq( 0 ) ); + } + + @Test + void getAssociationsForCompanyWithIncludeRemovedTrueDoesNotApplyFilter() throws Exception { + final var expectedAssociationsList = new AssociationsList(); + expectedAssociationsList.setTotalResults( 2 ); + expectedAssociationsList.setTotalPages( 1 ); + expectedAssociationsList.setPageNumber( 0 ); + expectedAssociationsList.setItemsPerPage( 15 ); + expectedAssociationsList.setLinks( new AssociationsListLinks().self(String.format("%s/associations", internalApiUrl)).next("") ); + expectedAssociationsList.setItems(List.of( associationOne, associationTwo )); + Mockito.doReturn(expectedAssociationsList).when(associationsService).fetchAssociatedUsers( any(), any(), eq( true ), eq( 15 ), eq( 0 ) ); + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + Mockito.doReturn( companyDetails ).when( companyService ).fetchCompanyProfile( any() ); + + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()); + + Mockito.verify( associationsService ).fetchAssociatedUsers( eq( "111111" ), eq( companyDetails ), eq( true ), eq( 15 ), eq( 0 ) ); + } + + @Test + void getAssociationsForCompanyPaginatesCorrectly() throws Exception { + final var expectedAssociationsList = new AssociationsList(); + expectedAssociationsList.setTotalResults( 2 ); + expectedAssociationsList.setTotalPages( 2 ); + expectedAssociationsList.setPageNumber( 1 ); + expectedAssociationsList.setItemsPerPage( 1 ); + expectedAssociationsList.setLinks( new AssociationsListLinks().self(String.format("%s/associations", internalApiUrl)).next("") ); + expectedAssociationsList.setItems(List.of( associationTwo )); + Mockito.doReturn(expectedAssociationsList).when(associationsService).fetchAssociatedUsers( any(), any(), eq( true ), eq( 1 ), eq( 1 ) ); + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + Mockito.doReturn( companyDetails ).when( companyService ).fetchCompanyProfile( any() ); + + final var response = + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=1&page_index=1", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()) + .andReturn() + .getResponse(); + + final var objectMapper = new ObjectMapper(); + objectMapper.registerModule( new JavaTimeModule() ); + final AssociationsList associationsList = objectMapper.readValue( response.getContentAsByteArray(), AssociationsList.class ); + final var links = associationsList.getLinks(); + + final var items = + associationsList.getItems() + .stream() + .map( Association::getId ) + .toList(); + + Assertions.assertTrue( items.contains( "2" ) ); + Assertions.assertEquals( String.format("%s/associations", internalApiUrl), links.getSelf() ); + Assertions.assertEquals( String.format( "" ), links.getNext() ); + Assertions.assertEquals( 1, associationsList.getPageNumber() ); + Assertions.assertEquals( 1, associationsList.getItemsPerPage() ); + Assertions.assertEquals( 2, associationsList.getTotalResults() ); + Assertions.assertEquals( 2, associationsList.getTotalPages() ); + } + + + + + + + + + + + private String reduceTimestampResolution( String timestamp ){ + return timestamp.substring( 0, timestamp.indexOf( ":" ) ); + } + + private String localDateTimeToNormalisedString( LocalDateTime localDateTime ){ + final var timestamp = localDateTime.toString(); + return reduceTimestampResolution( timestamp ); + } + + @Test + void getAssociationsForCompanyDoesMappingCorrectly() throws Exception { + + final var expectedAssociationsList = new AssociationsList(); + expectedAssociationsList.setTotalResults( 2 ); + expectedAssociationsList.setTotalPages( 1 ); + expectedAssociationsList.setPageNumber( 0 ); + expectedAssociationsList.setItemsPerPage( 2 ); + expectedAssociationsList.setLinks( new AssociationsListLinks().self(String.format("%s/associations", internalApiUrl)).next("") ); + expectedAssociationsList.setItems(List.of( associationOne, associationTwo )); + Mockito.doReturn(expectedAssociationsList).when(associationsService).fetchAssociatedUsers( any(), any(), eq( true ), eq( 2 ), eq( 0 ) ); + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + Mockito.doReturn( companyDetails ).when( companyService ).fetchCompanyProfile( any() ); + + final var response = + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=2&page_index=0", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()) + .andReturn() + .getResponse(); + + final var objectMapper = new ObjectMapper(); + objectMapper.registerModule( new JavaTimeModule() ); + final AssociationsList associationsList = objectMapper.readValue( response.getContentAsByteArray(), AssociationsList.class ); + + final var associations = associationsList.getItems(); + final var associationOne = associations.getFirst(); + final var invitationsOne = associationOne.getInvitations(); + + Assertions.assertEquals( "a", associationOne.getEtag() ); + Assertions.assertEquals( "1", associationOne.getId() ); + Assertions.assertEquals( "111", associationOne.getUserId() ); + Assertions.assertEquals( "bruce.wayne@gotham.city", associationOne.getUserEmail() ); + Assertions.assertEquals( "Batman", associationOne.getDisplayName() ); + Assertions.assertEquals( "111111", associationOne.getCompanyNumber() ); + Assertions.assertEquals( "Wayne Enterprises", associationOne.getCompanyName() ); + Assertions.assertEquals( StatusEnum.CONFIRMED, associationOne.getStatus() ); + Assertions.assertNotNull( associationOne.getCreatedAt() ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(1) ), localDateTimeToNormalisedString( associationOne.getApprovedAt().toLocalDateTime() ) ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(2) ), localDateTimeToNormalisedString( associationOne.getRemovedAt().toLocalDateTime() ) ); + Assertions.assertEquals( DEFAULT_KIND, associationOne.getKind() ); + Assertions.assertEquals( ApprovalRouteEnum.AUTH_CODE, associationOne.getApprovalRoute() ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(3) ), reduceTimestampResolution( associationOne.getApprovalExpiryAt() ) ); + Assertions.assertEquals( 1, invitationsOne.size() ); + Assertions.assertEquals( "666", invitationsOne.get(0).getInvitedBy() ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(4) ), reduceTimestampResolution( invitationsOne.get(0).getInvitedAt() ) ); + Assertions.assertEquals( "/1", associationOne.getLinks().getSelf() ); + + final var associationTwo = associations.get( 1 ); + Assertions.assertEquals( "222", associationTwo.getUserId() ); + Assertions.assertEquals( DEFAULT_DISPLAY_NAME, associationTwo.getDisplayName() ); + Assertions.assertEquals( "Wayne Enterprises", associationTwo.getCompanyName() ); + } + + @Test + void getAssociationsForCompanyWithUnacceptablePaginationParametersShouldReturnBadRequest() throws Exception { + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=1&page_index=-1", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isBadRequest()); + + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=0&page_index=0", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isBadRequest()); + } + + +} \ No newline at end of file diff --git a/src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsListForCompanyControllerTest.java b/src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsListForCompanyControllerTest.java new file mode 100644 index 00000000..953bfd35 --- /dev/null +++ b/src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsListForCompanyControllerTest.java @@ -0,0 +1,642 @@ +package uk.gov.companieshouse.accounts.association.integration; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.google.api.client.http.HttpHeaders; +import com.google.api.client.http.HttpResponseException.Builder; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.test.web.servlet.MockMvc; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import uk.gov.companieshouse.accounts.association.configuration.InterceptorConfig; +import uk.gov.companieshouse.accounts.association.models.AssociationDao; +import uk.gov.companieshouse.accounts.association.models.InvitationDao; +import uk.gov.companieshouse.accounts.association.repositories.AssociationsRepository; +import uk.gov.companieshouse.accounts.association.rest.AccountsUserEndpoint; +import uk.gov.companieshouse.accounts.association.rest.CompanyProfileEndpoint; +import uk.gov.companieshouse.api.InternalApiClient; +import uk.gov.companieshouse.api.accounts.associations.model.Association.ApprovalRouteEnum; +import uk.gov.companieshouse.api.accounts.associations.model.Association.StatusEnum; +import uk.gov.companieshouse.api.accounts.associations.model.AssociationsList; +import uk.gov.companieshouse.api.accounts.user.model.User; +import uk.gov.companieshouse.api.company.CompanyDetails; +import uk.gov.companieshouse.api.error.ApiErrorResponseException; +import uk.gov.companieshouse.api.handler.exception.URIValidationException; +import uk.gov.companieshouse.api.model.ApiResponse; +import uk.gov.companieshouse.api.sdk.ApiClientService; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@AutoConfigureMockMvc +@SpringBootTest +@Testcontainers +@ExtendWith(MockitoExtension.class) +@Tag("integration-test") +public class AssociationsListForCompanyControllerTest { + + @Value("${internal.api.url}") + private String internalApiUrl; + + @Container + @ServiceConnection + static MongoDBContainer container = new MongoDBContainer("mongo:5"); + + @Autowired + MongoTemplate mongoTemplate; + + @Autowired + public MockMvc mockMvc; + + @MockBean + ApiClientService apiClientService; + + @MockBean + InternalApiClient internalApiClient; + + @MockBean + CompanyProfileEndpoint companyProfileEndpoint; + + @MockBean + AccountsUserEndpoint accountsUserEndpoint; + + @Autowired + AssociationsRepository associationsRepository; + + @MockBean + InterceptorConfig interceptorConfig; + + private static final String DEFAULT_KIND = "association"; + private static final String DEFAULT_DISPLAY_NAME = "Not provided"; + + private final LocalDateTime now = LocalDateTime.now(); + + private ApiResponse toCompanyDetailsApiResponse( final String companyNumber, final String companyName ){ + final var companyDetails = new CompanyDetails(); + companyDetails.setCompanyNumber( companyNumber ); + companyDetails.setCompanyName( companyName ); + return new ApiResponse<>( 200, Map.of(), companyDetails ); + } + + private ApiResponse toGetUserDetailsApiResponse( final String email, final String displayName ){ + final var user = new User().email( email ).displayName( displayName ); + return new ApiResponse<>( 200, Map.of(), user ); + } + + @BeforeEach + public void setup() throws ApiErrorResponseException, URIValidationException { + + final var invitationOne = new InvitationDao(); + invitationOne.setInvitedBy("666"); + invitationOne.setInvitedAt(now.plusDays(4)); + + final var associationOne = new AssociationDao(); + associationOne.setCompanyNumber("111111"); + associationOne.setUserId("111"); + associationOne.setUserEmail("bruce.wayne@gotham.city"); + associationOne.setStatus(StatusEnum.CONFIRMED.getValue()); + associationOne.setId("1"); + associationOne.setApprovedAt(now.plusDays(1)); + associationOne.setRemovedAt(now.plusDays(2)); + associationOne.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationOne.setApprovalExpiryAt(now.plusDays(3)); + associationOne.setInvitations( List.of( invitationOne ) ); + associationOne.setEtag( "a" ); + + final var invitationTwo = new InvitationDao(); + invitationTwo.setInvitedBy("666"); + invitationTwo.setInvitedAt( now.plusDays(8) ); + + final var associationTwo = new AssociationDao(); + associationTwo.setCompanyNumber("111111"); + associationTwo.setUserId("222"); + associationTwo.setUserEmail("the.joker@gotham.city"); + associationTwo.setStatus(StatusEnum.CONFIRMED.getValue()); + associationTwo.setId("2"); + associationTwo.setApprovedAt( now.plusDays(5) ); + associationTwo.setRemovedAt( now.plusDays(6) ); + associationTwo.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationTwo.setApprovalExpiryAt( now.plusDays(7) ); + associationTwo.setInvitations( List.of( invitationTwo ) ); + associationTwo.setEtag("b"); + + final var invitationThree = new InvitationDao(); + invitationThree.setInvitedBy("666"); + invitationThree.setInvitedAt( now.plusDays(12) ); + + final var associationThree = new AssociationDao(); + associationThree.setCompanyNumber("111111"); + associationThree.setUserId("333"); + associationThree.setUserEmail("harley.quinn@gotham.city"); + associationThree.setStatus(StatusEnum.CONFIRMED.getValue()); + associationThree.setId("3"); + associationThree.setApprovedAt( now.plusDays(9) ); + associationThree.setRemovedAt( now.plusDays(10) ); + associationThree.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationThree.setApprovalExpiryAt( now.plusDays(11) ); + associationThree.setInvitations( List.of( invitationThree ) ); + associationThree.setEtag("c"); + + final var invitationFour = new InvitationDao(); + invitationFour.setInvitedBy("666"); + invitationFour.setInvitedAt( now.plusDays(16) ); + + final var associationFour = new AssociationDao(); + associationFour.setCompanyNumber("111111"); + associationFour.setUserId("444"); + associationFour.setUserEmail("robin@gotham.city"); + associationFour.setStatus(StatusEnum.CONFIRMED.getValue()); + associationFour.setId("4"); + associationFour.setApprovedAt( now.plusDays(13) ); + associationFour.setRemovedAt( now.plusDays(14) ); + associationFour.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationFour.setApprovalExpiryAt( now.plusDays(15) ); + associationFour.setInvitations( List.of( invitationFour ) ); + associationFour.setEtag("d"); + + final var invitationFive = new InvitationDao(); + invitationFive.setInvitedBy("666"); + invitationFive.setInvitedAt( now.plusDays(20) ); + + final var associationFive = new AssociationDao(); + associationFive.setCompanyNumber("111111"); + associationFive.setUserId("555"); + associationFive.setUserEmail("barbara.gordon@gotham.city"); + associationFive.setStatus(StatusEnum.CONFIRMED.getValue()); + associationFive.setId("5"); + associationFive.setApprovedAt( now.plusDays(17) ); + associationFive.setRemovedAt( now.plusDays(18) ); + associationFive.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFive.setApprovalExpiryAt( now.plusDays(19) ); + associationFive.setInvitations( List.of( invitationFive ) ); + associationFive.setEtag("e"); + + final var invitationSix = new InvitationDao(); + invitationSix.setInvitedBy("5555"); + invitationSix.setInvitedAt( now.plusDays(24) ); + + final var associationSix = new AssociationDao(); + associationSix.setCompanyNumber("111111"); + associationSix.setUserId("666"); + associationSix.setUserEmail("homer.simpson@springfield.com"); + associationSix.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationSix.setId("6"); + associationSix.setApprovedAt( now.plusDays(21) ); + associationSix.setRemovedAt( now.plusDays(22) ); + associationSix.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSix.setApprovalExpiryAt( now.plusDays(23) ); + associationSix.setInvitations( List.of( invitationSix ) ); + associationSix.setEtag("f"); + + final var invitationSeven = new InvitationDao(); + invitationSeven.setInvitedBy("5555"); + invitationSeven.setInvitedAt( now.plusDays(28) ); + + final var associationSeven = new AssociationDao(); + associationSeven.setCompanyNumber("111111"); + associationSeven.setUserId("777"); + associationSeven.setUserEmail("marge.simpson@springfield.com"); + associationSeven.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationSeven.setId("7"); + associationSeven.setApprovedAt( now.plusDays(25) ); + associationSeven.setRemovedAt( now.plusDays(26) ); + associationSeven.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSeven.setApprovalExpiryAt( now.plusDays(27) ); + associationSeven.setInvitations( List.of( invitationSeven ) ); + associationSeven.setEtag("g"); + + final var invitationEight = new InvitationDao(); + invitationEight.setInvitedBy("5555"); + invitationEight.setInvitedAt( now.plusDays(32) ); + + final var associationEight = new AssociationDao(); + associationEight.setCompanyNumber("111111"); + associationEight.setUserId("888"); + associationEight.setUserEmail("bart.simpson@springfield.com"); + associationEight.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationEight.setId("8"); + associationEight.setApprovedAt( now.plusDays(29) ); + associationEight.setRemovedAt( now.plusDays(30) ); + associationEight.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationEight.setApprovalExpiryAt( now.plusDays(31) ); + associationEight.setInvitations( List.of( invitationEight ) ); + associationEight.setEtag("h"); + + final var invitationNine = new InvitationDao(); + invitationNine.setInvitedBy("5555"); + invitationNine.setInvitedAt( now.plusDays(36) ); + + final var associationNine = new AssociationDao(); + associationNine.setCompanyNumber("111111"); + associationNine.setUserId("999"); + associationNine.setUserEmail("lisa.simpson@springfield.com"); + associationNine.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationNine.setId("9"); + associationNine.setApprovedAt( now.plusDays(33) ); + associationNine.setRemovedAt( now.plusDays(34) ); + associationNine.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationNine.setApprovalExpiryAt( now.plusDays(35) ); + associationNine.setInvitations( List.of( invitationNine ) ); + associationNine.setEtag("i"); + + final var invitationTen = new InvitationDao(); + invitationTen.setInvitedBy("5555"); + invitationTen.setInvitedAt( now.plusDays(40) ); + + final var associationTen = new AssociationDao(); + associationTen.setCompanyNumber("111111"); + associationTen.setUserId("1111"); + associationTen.setUserEmail("maggie.simpson@springfield.com"); + associationTen.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationTen.setId("10"); + associationTen.setApprovedAt( now.plusDays(37) ); + associationTen.setRemovedAt( now.plusDays(38) ); + associationTen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationTen.setApprovalExpiryAt( now.plusDays(39) ); + associationTen.setInvitations( List.of( invitationTen ) ); + associationTen.setEtag("j"); + + final var invitationEleven = new InvitationDao(); + invitationEleven.setInvitedBy("5555"); + invitationEleven.setInvitedAt( now.plusDays(44) ); + + final var associationEleven = new AssociationDao(); + associationEleven.setCompanyNumber("111111"); + associationEleven.setUserId("2222"); + associationEleven.setUserEmail("crusty.the.clown@springfield.com"); + associationEleven.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationEleven.setId("11"); + associationEleven.setApprovedAt( now.plusDays(41) ); + associationEleven.setRemovedAt( now.plusDays(42) ); + associationEleven.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationEleven.setApprovalExpiryAt( now.plusDays(43) ); + associationEleven.setInvitations( List.of( invitationEleven ) ); + associationEleven.setEtag("k"); + + final var invitationTwelve = new InvitationDao(); + invitationTwelve.setInvitedBy("5555"); + invitationTwelve.setInvitedAt( now.plusDays(48) ); + + final var associationTwelve = new AssociationDao(); + associationTwelve.setCompanyNumber("111111"); + associationTwelve.setUserId("3333"); + associationTwelve.setUserEmail("itchy@springfield.com"); + associationTwelve.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationTwelve.setId("12"); + associationTwelve.setApprovedAt( now.plusDays(45) ); + associationTwelve.setRemovedAt( now.plusDays(46) ); + associationTwelve.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationTwelve.setApprovalExpiryAt( now.plusDays(47) ); + associationTwelve.setInvitations( List.of( invitationTwelve ) ); + associationTwelve.setEtag("l"); + + final var invitationThirteen = new InvitationDao(); + invitationThirteen.setInvitedBy("5555"); + invitationThirteen.setInvitedAt( now.plusDays(52) ); + + final var associationThirteen = new AssociationDao(); + associationThirteen.setCompanyNumber("111111"); + associationThirteen.setUserId("4444"); + associationThirteen.setUserEmail("scratchy@springfield.com"); + associationThirteen.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationThirteen.setId("13"); + associationThirteen.setApprovedAt( now.plusDays(49) ); + associationThirteen.setRemovedAt( now.plusDays(50) ); + associationThirteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationThirteen.setApprovalExpiryAt( now.plusDays(51) ); + associationThirteen.setInvitations( List.of( invitationThirteen ) ); + associationThirteen.setEtag("m"); + + final var invitationFourteen = new InvitationDao(); + invitationFourteen.setInvitedBy("111"); + invitationFourteen.setInvitedAt( now.plusDays(56) ); + + final var associationFourteen = new AssociationDao(); + associationFourteen.setCompanyNumber("111111"); + associationFourteen.setUserId("5555"); + associationFourteen.setUserEmail("ross@friends.com"); + associationFourteen.setStatus(StatusEnum.REMOVED.getValue()); + associationFourteen.setId("14"); + associationFourteen.setApprovedAt( now.plusDays(53) ); + associationFourteen.setRemovedAt( now.plusDays(54) ); + associationFourteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFourteen.setApprovalExpiryAt( now.plusDays(55) ); + associationFourteen.setInvitations( List.of( invitationFourteen ) ); + associationFourteen.setEtag("n"); + + final var invitationFifteen = new InvitationDao(); + invitationFifteen.setInvitedBy("111"); + invitationFifteen.setInvitedAt( now.plusDays(60) ); + + final var associationFifteen = new AssociationDao(); + associationFifteen.setCompanyNumber("111111"); + associationFifteen.setUserId("6666"); + associationFifteen.setUserEmail("rachel@friends.com"); + associationFifteen.setStatus(StatusEnum.REMOVED.getValue()); + associationFifteen.setId("15"); + associationFifteen.setApprovedAt( now.plusDays(57) ); + associationFifteen.setRemovedAt( now.plusDays(58) ); + associationFifteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFifteen.setApprovalExpiryAt( now.plusDays(59) ); + associationFifteen.setInvitations( List.of( invitationFifteen ) ); + associationFifteen.setEtag("o"); + + final var invitationSixteen = new InvitationDao(); + invitationSixteen.setInvitedBy("111"); + invitationSixteen.setInvitedAt( now.plusDays(64) ); + + final var associationSixteen = new AssociationDao(); + associationSixteen.setCompanyNumber("111111"); + associationSixteen.setUserId("7777"); + associationSixteen.setUserEmail("chandler@friends.com"); + associationSixteen.setStatus(StatusEnum.REMOVED.getValue()); + associationSixteen.setId("16"); + associationSixteen.setApprovedAt( now.plusDays(61) ); + associationSixteen.setRemovedAt( now.plusDays(62) ); + associationSixteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSixteen.setApprovalExpiryAt( now.plusDays(63) ); + associationSixteen.setInvitations( List.of( invitationSixteen ) ); + associationSixteen.setEtag("p"); + + final var invitationSeventeen = new InvitationDao(); + invitationSeventeen.setInvitedBy("111"); + invitationSeventeen.setInvitedAt( now.plusDays(68) ); + + final var associationSeventeen = new AssociationDao(); + associationSeventeen.setCompanyNumber("222222"); + associationSeventeen.setUserId("8888"); + associationSeventeen.setUserEmail("mr.blobby@nightmare.com"); + associationSeventeen.setStatus(StatusEnum.CONFIRMED.getValue()); + associationSeventeen.setId("17"); + associationSeventeen.setApprovedAt( now.plusDays(65) ); + associationSeventeen.setRemovedAt( now.plusDays(66) ); + associationSeventeen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSeventeen.setApprovalExpiryAt( now.plusDays(67) ); + associationSeventeen.setInvitations( List.of( invitationSeventeen ) ); + associationSeventeen.setEtag("q"); + + associationsRepository.insert( List.of( associationOne, associationTwo, associationThree, associationFour, + associationFive, associationSix, associationSeven, associationEight, associationNine, associationTen, + associationEleven, associationTwelve, associationThirteen, associationFourteen, associationFifteen, + associationSixteen, associationSeventeen) ); + + Mockito.doReturn( toCompanyDetailsApiResponse( "111111", "Wayne Enterprises" ) ).when( companyProfileEndpoint ).fetchCompanyProfile( eq( "111111" ) ); + Mockito.doThrow( new ApiErrorResponseException( new Builder( 404, "Not Found", new HttpHeaders() ) ) ).when( companyProfileEndpoint ).fetchCompanyProfile( eq( "919191" ) ); + + Mockito.doReturn( toGetUserDetailsApiResponse( "bruce.wayne@gotham.city", "Batman" ) ).when( accountsUserEndpoint ).getUserDetails( eq( "111" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "the.joker@gotham.city", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "222" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "harley.quinn@gotham.city", "Harleen Quinzel" ) ).when( accountsUserEndpoint ).getUserDetails( eq( "333" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "robin@gotham.city", "Boy Wonder" ) ).when( accountsUserEndpoint ).getUserDetails( eq( "444" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "barbara.gordon@gotham.city", "Batwoman" ) ).when( accountsUserEndpoint ).getUserDetails( eq( "555" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "homer.simpson@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "666" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "marge.simpson@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "777" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "bart.simpson@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "888" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "lisa.simpson@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "999" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "maggie.simpson@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "1111" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "crusty.the.clown@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "2222" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "itchy@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "3333" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "scratchy@springfield.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "4444" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "ross@friends.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "5555" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "rachel@friends.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "6666" ) ); + Mockito.doReturn( toGetUserDetailsApiResponse( "chandler@friends.com", null ) ).when( accountsUserEndpoint ).getUserDetails( eq( "7777" ) ); + Mockito.doThrow( new ApiErrorResponseException( new Builder( 404, "Not Found", new HttpHeaders() ) ) ).when( accountsUserEndpoint ).getUserDetails( eq( "9191" ) ); + + Mockito.doNothing().when(interceptorConfig).addInterceptors( any() ); + } + + @Test + void getAssociationsForCompanyWithMalformedCompanyNumberReturnsBadRequest() throws Exception { + mockMvc.perform( get( "/associations/companies/{company_number}", "$$$$$$" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isBadRequest()); + } + + @Test + void getAssociationsForCompanyWithNonexistentCompanyReturnsNotFound() throws Exception { + mockMvc.perform( get( "/associations/companies/{company_number}", "919191" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isNotFound()) + .andReturn() + .getResponse(); + } + + @Test + void getAssociationsForCompanyWithoutXRequestIdReturnsBadRequest() throws Exception { + mockMvc.perform( get( "/associations/companies/{company_number}", "111111" ) ) + .andExpect(status().isBadRequest()); + } + + @Test + void getAssociationsForCompanyWithoutQueryParamsUsesDefaults() throws Exception { + final var response = + mockMvc.perform( get( "/associations/companies/{company_number}", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()) + .andReturn() + .getResponse(); + + final var objectMapper = new ObjectMapper(); + objectMapper.registerModule( new JavaTimeModule() ); + final AssociationsList associationsList = objectMapper.readValue( response.getContentAsByteArray(), AssociationsList.class ); + final var links = associationsList.getLinks(); + + final var items = + associationsList.getItems() + .stream() + .map( uk.gov.companieshouse.api.accounts.associations.model.Association::getId ) + .toList(); + + Assertions.assertTrue( items.containsAll( List.of ( "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13" ) ) ); + Assertions.assertEquals( "/associations/companies/111111?page_index=0&items_per_page=15", links.getSelf() ); + Assertions.assertEquals( "", links.getNext() ); + Assertions.assertEquals( 0, associationsList.getPageNumber() ); + Assertions.assertEquals( 15, associationsList.getItemsPerPage() ); + Assertions.assertEquals( 13, associationsList.getTotalResults() ); + Assertions.assertEquals( 1, associationsList.getTotalPages() ); + } + + @Test + void getAssociationsForCompanyWithIncludeRemovedFalseAppliesFilter() throws Exception { + final var response = + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=false", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()) + .andReturn() + .getResponse(); + + final var objectMapper = new ObjectMapper(); + objectMapper.registerModule( new JavaTimeModule() ); + final AssociationsList associationsList = objectMapper.readValue( response.getContentAsByteArray(), AssociationsList.class ); + final var links = associationsList.getLinks(); + + final var items = + associationsList.getItems() + .stream() + .map( uk.gov.companieshouse.api.accounts.associations.model.Association::getId ) + .toList(); + + Assertions.assertTrue( items.containsAll( List.of ( "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13" ) ) ); + Assertions.assertEquals( "/associations/companies/111111?page_index=0&items_per_page=15", links.getSelf() ); + Assertions.assertEquals( "", links.getNext() ); + Assertions.assertEquals( 0, associationsList.getPageNumber() ); + Assertions.assertEquals( 15, associationsList.getItemsPerPage() ); + Assertions.assertEquals( 13, associationsList.getTotalResults() ); + Assertions.assertEquals( 1, associationsList.getTotalPages() ); + } + + @Test + void getAssociationsForCompanyWithIncludeRemovedTrueDoesNotApplyFilter() throws Exception { + final var response = + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()) + .andReturn() + .getResponse(); + + final var objectMapper = new ObjectMapper(); + objectMapper.registerModule( new JavaTimeModule() ); + final AssociationsList associationsList = objectMapper.readValue( response.getContentAsByteArray(), AssociationsList.class ); + final var links = associationsList.getLinks(); + + final var items = + associationsList.getItems() + .stream() + .map( uk.gov.companieshouse.api.accounts.associations.model.Association::getId ) + .toList(); + + Assertions.assertTrue( items.containsAll( List.of ( "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" ) ) ); + Assertions.assertEquals( "/associations/companies/111111?page_index=0&items_per_page=15", links.getSelf() ); + Assertions.assertEquals( "/associations/companies/111111?page_index=1&items_per_page=15", links.getNext() ); + Assertions.assertEquals( 0, associationsList.getPageNumber() ); + Assertions.assertEquals( 15, associationsList.getItemsPerPage() ); + Assertions.assertEquals( 16, associationsList.getTotalResults() ); + Assertions.assertEquals( 2, associationsList.getTotalPages() ); + } + + @Test + void getAssociationsForCompanyPaginatesCorrectly() throws Exception { + final var response = + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=3&page_index=2", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()) + .andReturn() + .getResponse(); + + final var objectMapper = new ObjectMapper(); + objectMapper.registerModule( new JavaTimeModule() ); + final AssociationsList associationsList = objectMapper.readValue( response.getContentAsByteArray(), AssociationsList.class ); + final var links = associationsList.getLinks(); + + final var items = + associationsList.getItems() + .stream() + .map( uk.gov.companieshouse.api.accounts.associations.model.Association::getId ) + .toList(); + + Assertions.assertTrue( items.containsAll( List.of ( "7", "8", "9" ) ) ); + Assertions.assertEquals( "/associations/companies/111111?page_index=2&items_per_page=3", links.getSelf() ); + Assertions.assertEquals( "/associations/companies/111111?page_index=3&items_per_page=3", links.getNext() ); + Assertions.assertEquals( 2, associationsList.getPageNumber() ); + Assertions.assertEquals( 3, associationsList.getItemsPerPage() ); + Assertions.assertEquals( 16, associationsList.getTotalResults() ); + Assertions.assertEquals( 6, associationsList.getTotalPages() ); + } + + @Test + void getAssociationsForCompanyWhereAccountsUserEndpointCannotFindUserReturnsNotFound() throws Exception { + Mockito.doReturn( toCompanyDetailsApiResponse( "222222", "Nightmare" ) ).when( companyProfileEndpoint ).fetchCompanyProfile( eq( "222222" ) ); + Mockito.doThrow( new ApiErrorResponseException( new Builder( 404, "Not Found", new HttpHeaders() ) ) ).when( accountsUserEndpoint ).getUserDetails( eq( "8888" ) ); + + mockMvc.perform( get( "/associations/companies/{company_number}", "222222" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isNotFound()); + } + + @Test + void getAssociationsForCompanyWhereCompanyProfileEndpointCannotFindCompanyReturnsNotFound() throws Exception { + Mockito.doReturn( toGetUserDetailsApiResponse( "mr.blobby@nightmare.com", "Mr Blobby" ) ).when( accountsUserEndpoint ).getUserDetails( eq( "8888" ) ); + Mockito.doThrow( new ApiErrorResponseException( new Builder( 404, "Not Found", new HttpHeaders() ) ) ).when( companyProfileEndpoint ).fetchCompanyProfile( eq( "222222" ) ); + + mockMvc.perform( get( "/associations/companies/{company_number}", "222222" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isNotFound()); + } + + private String reduceTimestampResolution( String timestamp ){ + return timestamp.substring( 0, timestamp.indexOf( ":" ) ); + } + + private String localDateTimeToNormalisedString( LocalDateTime localDateTime ){ + final var timestamp = localDateTime.toString(); + return reduceTimestampResolution( timestamp ); + } + + @Test + void getAssociationsForCompanyDoesMappingCorrectly() throws Exception { + + final var response = + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=2&page_index=0", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isOk()) + .andReturn() + .getResponse(); + + final var objectMapper = new ObjectMapper(); + objectMapper.registerModule( new JavaTimeModule() ); + final AssociationsList associationsList = objectMapper.readValue( response.getContentAsByteArray(), AssociationsList.class ); + + final var associations = associationsList.getItems(); + final var associationOne = associations.getFirst(); + final var invitationsOne = associationOne.getInvitations(); + + Assertions.assertEquals( "a", associationOne.getEtag() ); + Assertions.assertEquals( "1", associationOne.getId() ); + Assertions.assertEquals( "111", associationOne.getUserId() ); + Assertions.assertEquals( "bruce.wayne@gotham.city", associationOne.getUserEmail() ); + Assertions.assertEquals( "Batman", associationOne.getDisplayName() ); + Assertions.assertEquals( "111111", associationOne.getCompanyNumber() ); + Assertions.assertEquals( "Wayne Enterprises", associationOne.getCompanyName() ); + Assertions.assertEquals( StatusEnum.CONFIRMED, associationOne.getStatus() ); + Assertions.assertNotNull( associationOne.getCreatedAt() ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(1) ), localDateTimeToNormalisedString( associationOne.getApprovedAt().toLocalDateTime() ) ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(2) ), localDateTimeToNormalisedString( associationOne.getRemovedAt().toLocalDateTime() ) ); + Assertions.assertEquals( DEFAULT_KIND, associationOne.getKind() ); + Assertions.assertEquals( ApprovalRouteEnum.AUTH_CODE, associationOne.getApprovalRoute() ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(3) ), reduceTimestampResolution( associationOne.getApprovalExpiryAt() ) ); + Assertions.assertEquals( 1, invitationsOne.size() ); + Assertions.assertEquals( "homer.simpson@springfield.com", invitationsOne.get(0).getInvitedBy() ); + Assertions.assertEquals( localDateTimeToNormalisedString( now.plusDays(4) ), reduceTimestampResolution( invitationsOne.get(0).getInvitedAt() ) ); + Assertions.assertEquals( "/associations/1", associationOne.getLinks().getSelf() ); + + final var associationTwo = associations.get( 1 ); + Assertions.assertEquals( "222", associationTwo.getUserId() ); + Assertions.assertEquals( DEFAULT_DISPLAY_NAME, associationTwo.getDisplayName() ); + Assertions.assertEquals( "Wayne Enterprises", associationTwo.getCompanyName() ); + } + + @Test + void getAssociationsForCompanyWithUnacceptablePaginationParametersShouldReturnBadRequest() throws Exception { + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=1&page_index=-1", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isBadRequest()); + + mockMvc.perform( get( "/associations/companies/{company_number}?include_removed=true&items_per_page=0&page_index=0", "111111" ).header("X-Request-Id", "theId123") ) + .andExpect(status().isBadRequest()); + } + + @AfterEach + public void after() { + mongoTemplate.dropCollection(AssociationDao.class); + } + +} \ No newline at end of file diff --git a/src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsServiceTest.java b/src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsServiceTest.java new file mode 100644 index 00000000..c5df4649 --- /dev/null +++ b/src/test/java/uk/gov/companieshouse/accounts/association/integration/AssociationsServiceTest.java @@ -0,0 +1,408 @@ +package uk.gov.companieshouse.accounts.association.integration; + +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; + +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatcher; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.data.domain.Page; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import uk.gov.companieshouse.accounts.association.mapper.AssociationsListCompanyMapper; +import uk.gov.companieshouse.accounts.association.models.AssociationDao; +import uk.gov.companieshouse.accounts.association.models.InvitationDao; +import uk.gov.companieshouse.accounts.association.repositories.AssociationsRepository; +import uk.gov.companieshouse.accounts.association.service.AssociationsService; +import uk.gov.companieshouse.api.InternalApiClient; +import uk.gov.companieshouse.api.accounts.associations.model.Association.ApprovalRouteEnum; +import uk.gov.companieshouse.api.accounts.associations.model.Association.StatusEnum; +import uk.gov.companieshouse.api.company.CompanyDetails; +import uk.gov.companieshouse.api.sdk.ApiClientService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mockito; + +@SpringBootTest +@ExtendWith(MockitoExtension.class) +@Testcontainers +@Tag("integration-test") +public class AssociationsServiceTest { + + @Container + @ServiceConnection + static MongoDBContainer container = new MongoDBContainer("mongo:5"); + + @Autowired + MongoTemplate mongoTemplate; + + @Autowired + AssociationsRepository associationsRepository; + + @MockBean + ApiClientService apiClientService; + + @MockBean + InternalApiClient internalApiClient; + + @MockBean + AssociationsListCompanyMapper associationsListCompanyMapper; + + @Autowired + private AssociationsService associationsService; + + @BeforeEach + public void setup() { + final var now = LocalDateTime.now(); + + final var invitationOne = new InvitationDao(); + invitationOne.setInvitedBy("666"); + invitationOne.setInvitedAt(now.plusDays(4)); + + final var associationOne = new AssociationDao(); + associationOne.setCompanyNumber("111111"); + associationOne.setUserId("111"); + associationOne.setStatus( StatusEnum.CONFIRMED.getValue() ); + associationOne.setUserEmail("bruce.wayne@gotham.city"); + associationOne.setId("1"); + associationOne.setApprovedAt(now.plusDays(1)); + associationOne.setRemovedAt(now.plusDays(2)); + associationOne.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationOne.setApprovalExpiryAt(now.plusDays(3)); + associationOne.setInvitations( List.of( invitationOne ) ); + associationOne.setEtag( "a" ); + + final var invitationTwo = new InvitationDao(); + invitationTwo.setInvitedBy("666"); + invitationTwo.setInvitedAt( now.plusDays(8) ); + + final var associationTwo = new AssociationDao(); + associationTwo.setCompanyNumber("222222"); + associationTwo.setUserId("111"); + associationTwo.setStatus( StatusEnum.CONFIRMED.getValue() ); + associationTwo.setCompanyNumber("111111"); + associationTwo.setUserId("222"); + associationTwo.setUserEmail("the.joker@gotham.city"); + associationTwo.setId("2"); + associationTwo.setApprovedAt( now.plusDays(5) ); + associationTwo.setRemovedAt( now.plusDays(6) ); + associationTwo.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationTwo.setApprovalExpiryAt( now.plusDays(7) ); + associationTwo.setInvitations( List.of( invitationTwo ) ); + associationTwo.setEtag("b"); + + final var invitationThree = new InvitationDao(); + invitationThree.setInvitedBy("666"); + invitationThree.setInvitedAt( now.plusDays(12) ); + + final var associationThree = new AssociationDao(); + associationThree.setCompanyNumber("111111"); + associationThree.setUserId("222"); + associationThree.setStatus( StatusEnum.CONFIRMED.getValue() ); + associationThree.setUserId("333"); + associationThree.setUserEmail("harley.quinn@gotham.city"); + associationThree.setId("3"); + associationThree.setApprovedAt( now.plusDays(9) ); + associationThree.setRemovedAt( now.plusDays(10) ); + associationThree.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationThree.setApprovalExpiryAt( now.plusDays(11) ); + associationThree.setInvitations( List.of( invitationThree ) ); + associationThree.setEtag("c"); + + final var invitationFour = new InvitationDao(); + invitationFour.setInvitedBy("666"); + invitationFour.setInvitedAt( now.plusDays(16) ); + + final var associationFour = new AssociationDao(); + associationFour.setCompanyNumber("111111"); + associationFour.setUserId("444"); + associationFour.setUserEmail("robin@gotham.city"); + associationFour.setStatus(StatusEnum.CONFIRMED.getValue()); + associationFour.setId("4"); + associationFour.setApprovedAt( now.plusDays(13) ); + associationFour.setRemovedAt( now.plusDays(14) ); + associationFour.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationFour.setApprovalExpiryAt( now.plusDays(15) ); + associationFour.setInvitations( List.of( invitationFour ) ); + associationFour.setEtag("d"); + + final var invitationFive = new InvitationDao(); + invitationFive.setInvitedBy("666"); + invitationFive.setInvitedAt( now.plusDays(20) ); + + final var associationFive = new AssociationDao(); + associationFive.setCompanyNumber("111111"); + associationFive.setUserId("555"); + associationFive.setUserEmail("barbara.gordon@gotham.city"); + associationFive.setStatus(StatusEnum.CONFIRMED.getValue()); + associationFive.setId("5"); + associationFive.setApprovedAt( now.plusDays(17) ); + associationFive.setRemovedAt( now.plusDays(18) ); + associationFive.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFive.setApprovalExpiryAt( now.plusDays(19) ); + associationFive.setInvitations( List.of( invitationFive ) ); + associationFive.setEtag("e"); + + final var invitationSix = new InvitationDao(); + invitationSix.setInvitedBy("5555"); + invitationSix.setInvitedAt( now.plusDays(24) ); + + final var associationSix = new AssociationDao(); + associationSix.setCompanyNumber("111111"); + associationSix.setUserId("666"); + associationSix.setUserEmail("homer.simpson@springfield.com"); + associationSix.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationSix.setId("6"); + associationSix.setApprovedAt( now.plusDays(21) ); + associationSix.setRemovedAt( now.plusDays(22) ); + associationSix.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSix.setApprovalExpiryAt( now.plusDays(23) ); + associationSix.setInvitations( List.of( invitationSix ) ); + associationSix.setEtag("f"); + + final var invitationSeven = new InvitationDao(); + invitationSeven.setInvitedBy("5555"); + invitationSeven.setInvitedAt( now.plusDays(28) ); + + final var associationSeven = new AssociationDao(); + associationSeven.setCompanyNumber("111111"); + associationSeven.setUserId("777"); + associationSeven.setUserEmail("marge.simpson@springfield.com"); + associationSeven.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationSeven.setId("7"); + associationSeven.setApprovedAt( now.plusDays(25) ); + associationSeven.setRemovedAt( now.plusDays(26) ); + associationSeven.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSeven.setApprovalExpiryAt( now.plusDays(27) ); + associationSeven.setInvitations( List.of( invitationSeven ) ); + associationSeven.setEtag("g"); + + final var invitationEight = new InvitationDao(); + invitationEight.setInvitedBy("5555"); + invitationEight.setInvitedAt( now.plusDays(32) ); + + final var associationEight = new AssociationDao(); + associationEight.setCompanyNumber("111111"); + associationEight.setUserId("888"); + associationEight.setUserEmail("bart.simpson@springfield.com"); + associationEight.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationEight.setId("8"); + associationEight.setApprovedAt( now.plusDays(29) ); + associationEight.setRemovedAt( now.plusDays(30) ); + associationEight.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationEight.setApprovalExpiryAt( now.plusDays(31) ); + associationEight.setInvitations( List.of( invitationEight ) ); + associationEight.setEtag("h"); + + final var invitationNine = new InvitationDao(); + invitationNine.setInvitedBy("5555"); + invitationNine.setInvitedAt( now.plusDays(36) ); + + final var associationNine = new AssociationDao(); + associationNine.setCompanyNumber("111111"); + associationNine.setUserId("999"); + associationNine.setUserEmail("lisa.simpson@springfield.com"); + associationNine.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationNine.setId("9"); + associationNine.setApprovedAt( now.plusDays(33) ); + associationNine.setRemovedAt( now.plusDays(34) ); + associationNine.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationNine.setApprovalExpiryAt( now.plusDays(35) ); + associationNine.setInvitations( List.of( invitationNine ) ); + associationNine.setEtag("i"); + + final var invitationTen = new InvitationDao(); + invitationTen.setInvitedBy("5555"); + invitationTen.setInvitedAt( now.plusDays(40) ); + + final var associationTen = new AssociationDao(); + associationTen.setCompanyNumber("111111"); + associationTen.setUserId("1111"); + associationTen.setUserEmail("maggie.simpson@springfield.com"); + associationTen.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationTen.setId("10"); + associationTen.setApprovedAt( now.plusDays(37) ); + associationTen.setRemovedAt( now.plusDays(38) ); + associationTen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationTen.setApprovalExpiryAt( now.plusDays(39) ); + associationTen.setInvitations( List.of( invitationTen ) ); + associationTen.setEtag("j"); + + final var invitationEleven = new InvitationDao(); + invitationEleven.setInvitedBy("5555"); + invitationEleven.setInvitedAt( now.plusDays(44) ); + + final var associationEleven = new AssociationDao(); + associationEleven.setCompanyNumber("111111"); + associationEleven.setUserId("2222"); + associationEleven.setUserEmail("crusty.the.clown@springfield.com"); + associationEleven.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationEleven.setId("11"); + associationEleven.setApprovedAt( now.plusDays(41) ); + associationEleven.setRemovedAt( now.plusDays(42) ); + associationEleven.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationEleven.setApprovalExpiryAt( now.plusDays(43) ); + associationEleven.setInvitations( List.of( invitationEleven ) ); + associationEleven.setEtag("k"); + + final var invitationTwelve = new InvitationDao(); + invitationTwelve.setInvitedBy("5555"); + invitationTwelve.setInvitedAt( now.plusDays(48) ); + + final var associationTwelve = new AssociationDao(); + associationTwelve.setCompanyNumber("111111"); + associationTwelve.setUserId("3333"); + associationTwelve.setUserEmail("itchy@springfield.com"); + associationTwelve.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationTwelve.setId("12"); + associationTwelve.setApprovedAt( now.plusDays(45) ); + associationTwelve.setRemovedAt( now.plusDays(46) ); + associationTwelve.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationTwelve.setApprovalExpiryAt( now.plusDays(47) ); + associationTwelve.setInvitations( List.of( invitationTwelve ) ); + associationTwelve.setEtag("l"); + + final var invitationThirteen = new InvitationDao(); + invitationThirteen.setInvitedBy("5555"); + invitationThirteen.setInvitedAt( now.plusDays(52) ); + + final var associationThirteen = new AssociationDao(); + associationThirteen.setCompanyNumber("111111"); + associationThirteen.setUserId("4444"); + associationThirteen.setUserEmail("scratchy@springfield.com"); + associationThirteen.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationThirteen.setId("13"); + associationThirteen.setApprovedAt( now.plusDays(49) ); + associationThirteen.setRemovedAt( now.plusDays(50) ); + associationThirteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationThirteen.setApprovalExpiryAt( now.plusDays(51) ); + associationThirteen.setInvitations( List.of( invitationThirteen ) ); + associationThirteen.setEtag("m"); + + final var invitationFourteen = new InvitationDao(); + invitationFourteen.setInvitedBy("111"); + invitationFourteen.setInvitedAt( now.plusDays(56) ); + + final var associationFourteen = new AssociationDao(); + associationFourteen.setCompanyNumber("111111"); + associationFourteen.setUserId("5555"); + associationFourteen.setUserEmail("ross@friends.com"); + associationFourteen.setStatus(StatusEnum.REMOVED.getValue()); + associationFourteen.setId("14"); + associationFourteen.setApprovedAt( now.plusDays(53) ); + associationFourteen.setRemovedAt( now.plusDays(54) ); + associationFourteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFourteen.setApprovalExpiryAt( now.plusDays(55) ); + associationFourteen.setInvitations( List.of( invitationFourteen ) ); + associationFourteen.setEtag("n"); + + final var invitationFifteen = new InvitationDao(); + invitationFifteen.setInvitedBy("111"); + invitationFifteen.setInvitedAt( now.plusDays(60) ); + + final var associationFifteen = new AssociationDao(); + associationFifteen.setCompanyNumber("111111"); + associationFifteen.setUserId("6666"); + associationFifteen.setUserEmail("rachel@friends.com"); + associationFifteen.setStatus(StatusEnum.REMOVED.getValue()); + associationFifteen.setId("15"); + associationFifteen.setApprovedAt( now.plusDays(57) ); + associationFifteen.setRemovedAt( now.plusDays(58) ); + associationFifteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFifteen.setApprovalExpiryAt( now.plusDays(59) ); + associationFifteen.setInvitations( List.of( invitationFifteen ) ); + associationFifteen.setEtag("o"); + + final var invitationSixteen = new InvitationDao(); + invitationSixteen.setInvitedBy("111"); + invitationSixteen.setInvitedAt( now.plusDays(64) ); + + final var associationSixteen = new AssociationDao(); + associationSixteen.setCompanyNumber("111111"); + associationSixteen.setUserId("7777"); + associationSixteen.setUserEmail("chandler@friends.com"); + associationSixteen.setStatus(StatusEnum.REMOVED.getValue()); + associationSixteen.setId("16"); + associationSixteen.setApprovedAt( now.plusDays(61) ); + associationSixteen.setRemovedAt( now.plusDays(62) ); + associationSixteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSixteen.setApprovalExpiryAt( now.plusDays(63) ); + associationSixteen.setInvitations( List.of( invitationSixteen ) ); + associationSixteen.setEtag("p"); + + associationsRepository.insert( List.of( associationOne, associationTwo, associationThree, associationFour, + associationFive, associationSix, associationSeven, associationEight, associationNine, associationTen, + associationEleven, associationTwelve, associationThirteen, associationFourteen, associationFifteen, + associationSixteen ) ); + } + + @Test + void fetchAssociatedUsersWithNullInputsReturnsNull(){ + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + Assertions.assertNull( associationsService.fetchAssociatedUsers( null, companyDetails,true, 15, 0 ) ); + Assertions.assertNull( associationsService.fetchAssociatedUsers( "111111", null,true, 15, 0 ) ); + } + + private ArgumentMatcher> associationsPageMatches( int totalElements, int totalPages, int numElementsOnPage, List expectedAssociationIds ){ + return page -> { + final var associationIds = + page.getContent() + .stream() + .map( AssociationDao::getId ) + .toList(); + + return page.getTotalElements() == totalElements && + page.getTotalPages() == totalPages && + associationIds.size() == numElementsOnPage && + associationIds.containsAll( expectedAssociationIds ); + }; + } + + @Test + void fetchAssociatedUsersWithIncludeRemovedTrueDoesNotApplyFilter(){ + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + associationsService.fetchAssociatedUsers( "111111", companyDetails, true, 20, 0 ); + final var expectedAssociationIds = List.of( "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16" ); + Mockito.verify( associationsListCompanyMapper ).daoToDto( argThat( associationsPageMatches(16, 1, 16, expectedAssociationIds ) ), eq( companyDetails ) ); + } + + @Test + void fetchAssociatedUsersWithIncludeRemovedFalseAppliesFilter(){ + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + associationsService.fetchAssociatedUsers( "111111", companyDetails, false, 20, 0 ); + final var expectedAssociationIds = List.of( "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13" ); + Mockito.verify( associationsListCompanyMapper ).daoToDto( argThat( associationsPageMatches(13, 1, 13, expectedAssociationIds ) ), eq( companyDetails ) ); + } + + @Test + void fetchAssociatedUsersAppliesPaginationCorrectly() { + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + associationsService.fetchAssociatedUsers("111111", companyDetails, true, 15, 1); + Mockito.verify(associationsListCompanyMapper).daoToDto(argThat(associationsPageMatches(16, 2, 1, List.of("16"))), eq(companyDetails)); + } + + @AfterEach + public void after() { + mongoTemplate.dropCollection(AssociationDao.class); + } + +} diff --git a/src/test/java/uk/gov/companieshouse/accounts/association/service/AssociationsServiceTest.java b/src/test/java/uk/gov/companieshouse/accounts/association/service/AssociationsServiceTest.java index cc976322..b37957cc 100644 --- a/src/test/java/uk/gov/companieshouse/accounts/association/service/AssociationsServiceTest.java +++ b/src/test/java/uk/gov/companieshouse/accounts/association/service/AssociationsServiceTest.java @@ -1,24 +1,32 @@ package uk.gov.companieshouse.accounts.association.service; +import java.time.LocalDateTime; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatcher; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import uk.gov.companieshouse.accounts.association.mapper.AssociationMapper; import uk.gov.companieshouse.accounts.association.mapper.AssociationsListCompanyMapper; import uk.gov.companieshouse.accounts.association.mapper.AssociationsListUserMapper; import uk.gov.companieshouse.accounts.association.models.AssociationDao; +import uk.gov.companieshouse.accounts.association.models.InvitationDao; import uk.gov.companieshouse.accounts.association.repositories.AssociationsRepository; import uk.gov.companieshouse.api.accounts.associations.model.Association; +import uk.gov.companieshouse.api.accounts.associations.model.Association.ApprovalRouteEnum; +import uk.gov.companieshouse.api.accounts.associations.model.Association.StatusEnum; import uk.gov.companieshouse.api.accounts.associations.model.AssociationsList; import uk.gov.companieshouse.api.accounts.user.model.User; +import uk.gov.companieshouse.api.company.CompanyDetails; import uk.gov.companieshouse.api.error.ApiErrorResponseException; import uk.gov.companieshouse.api.handler.exception.URIValidationException; @@ -26,6 +34,9 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -48,9 +59,300 @@ class AssociationsServiceTest { @Mock AssociationMapper associationMapper; + private AssociationDao associationOne; + private AssociationDao associationTwo; + private AssociationDao associationThree; + private AssociationDao associationFour; + private AssociationDao associationFive; + private AssociationDao associationSix; + private AssociationDao associationSeven; + private AssociationDao associationEight; + private AssociationDao associationNine; + private AssociationDao associationTen; + private AssociationDao associationEleven; + private AssociationDao associationTwelve; + private AssociationDao associationThirteen; + private AssociationDao associationFourteen; + private AssociationDao associationFifteen; + private AssociationDao associationSixteen; @BeforeEach public void setup() { + + final var now = LocalDateTime.now(); + + final var invitationOne = new InvitationDao(); + invitationOne.setInvitedBy("666"); + invitationOne.setInvitedAt(now.plusDays(4)); + + associationOne = new AssociationDao(); + associationOne.setCompanyNumber("111111"); + associationOne.setUserId("111"); + associationOne.setUserEmail("bruce.wayne@gotham.city"); + associationOne.setStatus(StatusEnum.CONFIRMED.getValue()); + associationOne.setId("1"); + associationOne.setApprovedAt(now.plusDays(1)); + associationOne.setRemovedAt(now.plusDays(2)); + associationOne.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationOne.setApprovalExpiryAt(now.plusDays(3)); + associationOne.setInvitations( List.of( invitationOne ) ); + associationOne.setEtag( "a" ); + + final var invitationTwo = new InvitationDao(); + invitationTwo.setInvitedBy("666"); + invitationTwo.setInvitedAt( now.plusDays(8) ); + + associationTwo = new AssociationDao(); + associationTwo.setCompanyNumber("111111"); + associationTwo.setUserId("222"); + associationTwo.setUserEmail("the.joker@gotham.city"); + associationTwo.setStatus(StatusEnum.CONFIRMED.getValue()); + associationTwo.setId("2"); + associationTwo.setApprovedAt( now.plusDays(5) ); + associationTwo.setRemovedAt( now.plusDays(6) ); + associationTwo.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationTwo.setApprovalExpiryAt( now.plusDays(7) ); + associationTwo.setInvitations( List.of( invitationTwo ) ); + associationTwo.setEtag("b"); + + final var invitationThree = new InvitationDao(); + invitationThree.setInvitedBy("666"); + invitationThree.setInvitedAt( now.plusDays(12) ); + + associationThree = new AssociationDao(); + associationThree.setCompanyNumber("111111"); + associationThree.setUserId("333"); + associationThree.setUserEmail("harley.quinn@gotham.city"); + associationThree.setStatus(StatusEnum.CONFIRMED.getValue()); + associationThree.setId("3"); + associationThree.setApprovedAt( now.plusDays(9) ); + associationThree.setRemovedAt( now.plusDays(10) ); + associationThree.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationThree.setApprovalExpiryAt( now.plusDays(11) ); + associationThree.setInvitations( List.of( invitationThree ) ); + associationThree.setEtag("c"); + + final var invitationFour = new InvitationDao(); + invitationFour.setInvitedBy("666"); + invitationFour.setInvitedAt( now.plusDays(16) ); + + associationFour = new AssociationDao(); + associationFour.setCompanyNumber("111111"); + associationFour.setUserId("444"); + associationFour.setUserEmail("robin@gotham.city"); + associationFour.setStatus(StatusEnum.CONFIRMED.getValue()); + associationFour.setId("4"); + associationFour.setApprovedAt( now.plusDays(13) ); + associationFour.setRemovedAt( now.plusDays(14) ); + associationFour.setApprovalRoute(ApprovalRouteEnum.AUTH_CODE); + associationFour.setApprovalExpiryAt( now.plusDays(15) ); + associationFour.setInvitations( List.of( invitationFour ) ); + associationFour.setEtag("d"); + + final var invitationFive = new InvitationDao(); + invitationFive.setInvitedBy("666"); + invitationFive.setInvitedAt( now.plusDays(20) ); + + associationFive = new AssociationDao(); + associationFive.setCompanyNumber("111111"); + associationFive.setUserId("555"); + associationFive.setUserEmail("barbara.gordon@gotham.city"); + associationFive.setStatus(StatusEnum.CONFIRMED.getValue()); + associationFive.setId("5"); + associationFive.setApprovedAt( now.plusDays(17) ); + associationFive.setRemovedAt( now.plusDays(18) ); + associationFive.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFive.setApprovalExpiryAt( now.plusDays(19) ); + associationFive.setInvitations( List.of( invitationFive ) ); + associationFive.setEtag("e"); + + final var invitationSix = new InvitationDao(); + invitationSix.setInvitedBy("5555"); + invitationSix.setInvitedAt( now.plusDays(24) ); + + associationSix = new AssociationDao(); + associationSix.setCompanyNumber("111111"); + associationSix.setUserId("666"); + associationSix.setUserEmail("homer.simpson@springfield.com"); + associationSix.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationSix.setId("6"); + associationSix.setApprovedAt( now.plusDays(21) ); + associationSix.setRemovedAt( now.plusDays(22) ); + associationSix.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSix.setApprovalExpiryAt( now.plusDays(23) ); + associationSix.setInvitations( List.of( invitationSix ) ); + associationSix.setEtag("f"); + + final var invitationSeven = new InvitationDao(); + invitationSeven.setInvitedBy("5555"); + invitationSeven.setInvitedAt( now.plusDays(28) ); + + associationSeven = new AssociationDao(); + associationSeven.setCompanyNumber("111111"); + associationSeven.setUserId("777"); + associationSeven.setUserEmail("marge.simpson@springfield.com"); + associationSeven.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationSeven.setId("7"); + associationSeven.setApprovedAt( now.plusDays(25) ); + associationSeven.setRemovedAt( now.plusDays(26) ); + associationSeven.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSeven.setApprovalExpiryAt( now.plusDays(27) ); + associationSeven.setInvitations( List.of( invitationSeven ) ); + associationSeven.setEtag("g"); + + final var invitationEight = new InvitationDao(); + invitationEight.setInvitedBy("5555"); + invitationEight.setInvitedAt( now.plusDays(32) ); + + associationEight = new AssociationDao(); + associationEight.setCompanyNumber("111111"); + associationEight.setUserId("888"); + associationEight.setUserEmail("bart.simpson@springfield.com"); + associationEight.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationEight.setId("8"); + associationEight.setApprovedAt( now.plusDays(29) ); + associationEight.setRemovedAt( now.plusDays(30) ); + associationEight.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationEight.setApprovalExpiryAt( now.plusDays(31) ); + associationEight.setInvitations( List.of( invitationEight ) ); + associationEight.setEtag("h"); + + final var invitationNine = new InvitationDao(); + invitationNine.setInvitedBy("5555"); + invitationNine.setInvitedAt( now.plusDays(36) ); + + associationNine = new AssociationDao(); + associationNine.setCompanyNumber("111111"); + associationNine.setUserId("999"); + associationNine.setUserEmail("lisa.simpson@springfield.com"); + associationNine.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationNine.setId("9"); + associationNine.setApprovedAt( now.plusDays(33) ); + associationNine.setRemovedAt( now.plusDays(34) ); + associationNine.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationNine.setApprovalExpiryAt( now.plusDays(35) ); + associationNine.setInvitations( List.of( invitationNine ) ); + associationNine.setEtag("i"); + + final var invitationTen = new InvitationDao(); + invitationTen.setInvitedBy("5555"); + invitationTen.setInvitedAt( now.plusDays(40) ); + + associationTen = new AssociationDao(); + associationTen.setCompanyNumber("111111"); + associationTen.setUserId("1111"); + associationTen.setUserEmail("maggie.simpson@springfield.com"); + associationTen.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationTen.setId("10"); + associationTen.setApprovedAt( now.plusDays(37) ); + associationTen.setRemovedAt( now.plusDays(38) ); + associationTen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationTen.setApprovalExpiryAt( now.plusDays(39) ); + associationTen.setInvitations( List.of( invitationTen ) ); + associationTen.setEtag("j"); + + final var invitationEleven = new InvitationDao(); + invitationEleven.setInvitedBy("5555"); + invitationEleven.setInvitedAt( now.plusDays(44) ); + + associationEleven = new AssociationDao(); + associationEleven.setCompanyNumber("111111"); + associationEleven.setUserId("2222"); + associationEleven.setUserEmail("crusty.the.clown@springfield.com"); + associationEleven.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationEleven.setId("11"); + associationEleven.setApprovedAt( now.plusDays(41) ); + associationEleven.setRemovedAt( now.plusDays(42) ); + associationEleven.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationEleven.setApprovalExpiryAt( now.plusDays(43) ); + associationEleven.setInvitations( List.of( invitationEleven ) ); + associationEleven.setEtag("k"); + + final var invitationTwelve = new InvitationDao(); + invitationTwelve.setInvitedBy("5555"); + invitationTwelve.setInvitedAt( now.plusDays(48) ); + + associationTwelve = new AssociationDao(); + associationTwelve.setCompanyNumber("111111"); + associationTwelve.setUserId("3333"); + associationTwelve.setUserEmail("itchy@springfield.com"); + associationTwelve.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationTwelve.setId("12"); + associationTwelve.setApprovedAt( now.plusDays(45) ); + associationTwelve.setRemovedAt( now.plusDays(46) ); + associationTwelve.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationTwelve.setApprovalExpiryAt( now.plusDays(47) ); + associationTwelve.setInvitations( List.of( invitationTwelve ) ); + associationTwelve.setEtag("l"); + + final var invitationThirteen = new InvitationDao(); + invitationThirteen.setInvitedBy("5555"); + invitationThirteen.setInvitedAt( now.plusDays(52) ); + + associationThirteen = new AssociationDao(); + associationThirteen.setCompanyNumber("111111"); + associationThirteen.setUserId("4444"); + associationThirteen.setUserEmail("scratchy@springfield.com"); + associationThirteen.setStatus(StatusEnum.AWAITING_APPROVAL.getValue()); + associationThirteen.setId("13"); + associationThirteen.setApprovedAt( now.plusDays(49) ); + associationThirteen.setRemovedAt( now.plusDays(50) ); + associationThirteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationThirteen.setApprovalExpiryAt( now.plusDays(51) ); + associationThirteen.setInvitations( List.of( invitationThirteen ) ); + associationThirteen.setEtag("m"); + + final var invitationFourteen = new InvitationDao(); + invitationFourteen.setInvitedBy("111"); + invitationFourteen.setInvitedAt( now.plusDays(56) ); + + associationFourteen = new AssociationDao(); + associationFourteen.setCompanyNumber("111111"); + associationFourteen.setUserId("5555"); + associationFourteen.setUserEmail("ross@friends.com"); + associationFourteen.setStatus(StatusEnum.REMOVED.getValue()); + associationFourteen.setId("14"); + associationFourteen.setApprovedAt( now.plusDays(53) ); + associationFourteen.setRemovedAt( now.plusDays(54) ); + associationFourteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFourteen.setApprovalExpiryAt( now.plusDays(55) ); + associationFourteen.setInvitations( List.of( invitationFourteen ) ); + associationFourteen.setEtag("n"); + + final var invitationFifteen = new InvitationDao(); + invitationFifteen.setInvitedBy("111"); + invitationFifteen.setInvitedAt( now.plusDays(60) ); + + associationFifteen = new AssociationDao(); + associationFifteen.setCompanyNumber("111111"); + associationFifteen.setUserId("6666"); + associationFifteen.setUserEmail("rachel@friends.com"); + associationFifteen.setStatus(StatusEnum.REMOVED.getValue()); + associationFifteen.setId("15"); + associationFifteen.setApprovedAt( now.plusDays(57) ); + associationFifteen.setRemovedAt( now.plusDays(58) ); + associationFifteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationFifteen.setApprovalExpiryAt( now.plusDays(59) ); + associationFifteen.setInvitations( List.of( invitationFifteen ) ); + associationFifteen.setEtag("o"); + + final var invitationSixteen = new InvitationDao(); + invitationSixteen.setInvitedBy("111"); + invitationSixteen.setInvitedAt( now.plusDays(64) ); + + associationSixteen = new AssociationDao(); + associationSixteen.setCompanyNumber("111111"); + associationSixteen.setUserId("7777"); + associationSixteen.setUserEmail("chandler@friends.com"); + associationSixteen.setStatus(StatusEnum.REMOVED.getValue()); + associationSixteen.setId("16"); + associationSixteen.setApprovedAt( now.plusDays(61) ); + associationSixteen.setRemovedAt( now.plusDays(62) ); + associationSixteen.setApprovalRoute(ApprovalRouteEnum.INVITATION); + associationSixteen.setApprovalExpiryAt( now.plusDays(63) ); + associationSixteen.setInvitations( List.of( invitationSixteen ) ); + associationSixteen.setEtag("p"); + associationsService = new AssociationsService( associationsRepository, associationsListUserMapper, @@ -94,5 +396,77 @@ void fetchAssociationsForUserUsesStatusConfirmedAsDefaultWhenStatusNotProvided() } + @Test + void fetchAssociatedUsersWithNullInputsReturnsNull(){ + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + Assertions.assertNull( associationsService.fetchAssociatedUsers( null, companyDetails,true, 15, 0 ) ); + Assertions.assertNull( associationsService.fetchAssociatedUsers( "111111", null,true, 15, 0 ) ); + } + + private ArgumentMatcher> associationsPageMatches( int totalElements, int totalPages, int numElementsOnPage, List expectedAssociationIds ){ + return page -> { + final var associationIds = + page.getContent() + .stream() + .map( AssociationDao::getId ) + .toList(); + + return page.getTotalElements() == totalElements && + page.getTotalPages() == totalPages && + associationIds.size() == numElementsOnPage && + associationIds.containsAll( expectedAssociationIds ); + }; + } + + @Test + void fetchAssociatedUsersWithIncludeRemovedTrueDoesNotApplyFilter(){ + final var content = List.of( associationOne, associationTwo, associationThree, associationFour, associationFive, associationSix, associationSeven, associationEight, associationNine, associationTen, associationEleven, associationTwelve, associationThirteen, associationFourteen, associationFifteen, associationSixteen ); + final var pageRequest = PageRequest.of(0, 20); + final var page = new PageImpl<>(content, pageRequest, content.size()); + + Mockito.doReturn( page ).when( associationsRepository ).fetchAssociatedUsers( any(), any(), any() ); + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + associationsService.fetchAssociatedUsers( "111111", companyDetails, true, 20, 0 ); + final var expectedAssociationIds = List.of( "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16" ); + Mockito.verify( associationsListCompanyMapper ).daoToDto( argThat( associationsPageMatches(16, 1, 16, expectedAssociationIds ) ), eq( companyDetails ) ); + } + + @Test + void fetchAssociatedUsersWithIncludeRemovedFalseAppliesFilter(){ + + final var content = List.of( associationOne, associationTwo, associationThree, associationFour, associationFive, associationSix, associationSeven, associationEight, associationNine, associationTen, associationEleven, associationTwelve, associationThirteen ); + final var pageRequest = PageRequest.of(0, 20); + final var page = new PageImpl<>(content, pageRequest, content.size()); + + Mockito.doReturn( page ).when( associationsRepository ).fetchAssociatedUsers( any(), any(), any() ); + + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + associationsService.fetchAssociatedUsers( "111111", companyDetails, false, 20, 0 ); + final var expectedAssociationIds = List.of( "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13" ); + Mockito.verify( associationsListCompanyMapper ).daoToDto( argThat( associationsPageMatches(13, 1, 13, expectedAssociationIds ) ), eq( companyDetails ) ); + } + + @Test + void fetchAssociatedUsersAppliesPaginationCorrectly() { + final var content = List.of(associationSixteen); + final var pageRequest = PageRequest.of( 1, 15 ); + final var page = new PageImpl<>( content, pageRequest, 16 ); + + Mockito.doReturn( page ).when( associationsRepository ).fetchAssociatedUsers( any(), any(), any() ); + + final var companyDetails = + new CompanyDetails().companyNumber("111111").companyName("Wayne Enterprises"); + + associationsService.fetchAssociatedUsers("111111", companyDetails, true, 15, 1); + Mockito.verify(associationsListCompanyMapper).daoToDto(argThat(associationsPageMatches(16, 2, 1, List.of("16"))), eq(companyDetails)); + } } \ No newline at end of file From ad91c336c9d4133c5452a165a7af3dc2aebd5460 Mon Sep 17 00:00:00 2001 From: krishna-patel-ch Date: Wed, 20 Mar 2024 12:36:24 +0000 Subject: [PATCH 2/2] Review comment changes --- .../AssociationsListForCompanyController.java | 4 ++-- .../controller/UserCompanyAssociations.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java b/src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java index 569f2df9..dcb1cd49 100644 --- a/src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java +++ b/src/main/java/uk/gov/companieshouse/accounts/association/controller/AssociationsListForCompanyController.java @@ -28,7 +28,7 @@ public AssociationsListForCompanyController(AssociationsService associationsServ @Override public ResponseEntity getAssociationsForCompany( final String companyNumber, final String xRequestId, final Boolean includeRemoved, final Integer pageIndex, final Integer itemsPerPage ) { - LOG.debug( String.format( "%s: Attempting to fetch users that are associated with company %s. includeRemoved=%b, itemsPerPage=%d, and pageIndex=%d.", xRequestId, companyNumber, includeRemoved, itemsPerPage, pageIndex ) ); + LOG.info( String.format( "%s: Attempting to fetch users that are associated with company %s. includeRemoved=%b, itemsPerPage=%d, and pageIndex=%d.", xRequestId, companyNumber, includeRemoved, itemsPerPage, pageIndex ) ); if ( pageIndex < 0 ){ LOG.error( "pageIndex was less then 0" ); @@ -45,7 +45,7 @@ public ResponseEntity getAssociationsForCompany( final String final var associationsList = associationsService.fetchAssociatedUsers( companyNumber, companyProfile, includeRemoved, itemsPerPage, pageIndex ); final var associationsListIsEmpty = associationsList.getItems().isEmpty(); - LOG.debug( associationsListIsEmpty ? String.format( "%s: Could not find any associations", xRequestId ) : String.format( "%s: Successfully fetched associations", xRequestId ) ); + LOG.info( associationsListIsEmpty ? String.format( "%s: Could not find any associations", xRequestId ) : String.format( "%s: Successfully fetched associations", xRequestId ) ); return new ResponseEntity<>( associationsList, HttpStatus.OK ); } diff --git a/src/main/java/uk/gov/companieshouse/accounts/association/controller/UserCompanyAssociations.java b/src/main/java/uk/gov/companieshouse/accounts/association/controller/UserCompanyAssociations.java index 96f7b13b..7578ca40 100644 --- a/src/main/java/uk/gov/companieshouse/accounts/association/controller/UserCompanyAssociations.java +++ b/src/main/java/uk/gov/companieshouse/accounts/association/controller/UserCompanyAssociations.java @@ -53,6 +53,16 @@ public ResponseEntity fetchAssociationsBy( LOG.infoContext(xRequestId, "Trying to fetch associations data for user in session :".concat(ericIdentity), null); + if ( pageIndex < 0 ){ + LOG.error( "pageIndex was less then 0" ); + throw new BadRequestRuntimeException( "Please check the request and try again" ); + } + + if ( itemsPerPage <= 0 ){ + LOG.error( "itemsPerPage was less then 0" ); + throw new BadRequestRuntimeException( "Please check the request and try again" ); + } + final var user = usersService.fetchUserDetails(ericIdentity); Optional.ofNullable(user).orElseThrow(() -> new BadRequestRuntimeException("Eric id is not valid"));//NOSONAR or else throw will be caught by controller advice final AssociationsList associationsList = associationsService