From 86e4180238b43bd3e439b5f067d4ca47442cd8ab Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 08:29:54 +0000 Subject: [PATCH 01/23] Replace constructor with lombok annotation --- .../account/management/controllers/AuditController.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditController.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditController.java index 236c6fe69..c3ff7c600 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditController.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditController.java @@ -5,7 +5,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.AllArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -32,6 +32,7 @@ @ApiResponse(responseCode = "401", description = "Invalid access credential") @ApiResponse(responseCode = "403", description = "User has not been authorized") @IsAdmin +@AllArgsConstructor @SecurityRequirement(name = "bearerAuth") public class AuditController { @@ -40,11 +41,6 @@ public class AuditController { private static final String OK_ERROR_CODE = "200"; private static final String NOT_FOUND_ERROR_CODE = "404"; - @Autowired - public AuditController(AuditService auditService) { - this.auditService = auditService; - } - @ApiResponse(responseCode = OK_ERROR_CODE, description = "All audit logs returned as a page.") @Operation(summary = "Get all audit logs returned as a page") @GetMapping From b9b2e7dc2db7d6ee82786bfe12f1f9248846b412 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 08:33:53 +0000 Subject: [PATCH 02/23] Add delete method to clean up after audit functional test --- .../controllers/TestingSupportController.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java index c3262b43e..2c1d8e17f 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java @@ -4,8 +4,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; import org.apache.commons.lang3.tuple.Pair; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -20,6 +20,7 @@ import uk.gov.hmcts.reform.pip.account.management.model.AzureAccount; import uk.gov.hmcts.reform.pip.account.management.model.CreationEnum; import uk.gov.hmcts.reform.pip.account.management.service.AccountService; +import uk.gov.hmcts.reform.pip.account.management.service.AuditService; import uk.gov.hmcts.reform.pip.account.management.service.MediaApplicationService; import uk.gov.hmcts.reform.pip.model.authentication.roles.IsAdmin; @@ -31,6 +32,7 @@ @IsAdmin @SecurityRequirement(name = "bearerAuth") @Validated +@AllArgsConstructor @ConditionalOnProperty(prefix = "testingSupport", name = "enableApi", havingValue = "true") @SuppressWarnings("PMD.TestClassWithoutTestCases") public class TestingSupportController { @@ -41,14 +43,8 @@ public class TestingSupportController { private static final String BAD_REQUEST_CODE = "400"; private final AccountService accountService; - private final MediaApplicationService mediaApplicationService; - - @Autowired - public TestingSupportController(AccountService accountService, MediaApplicationService mediaApplicationService) { - this.accountService = accountService; - this.mediaApplicationService = mediaApplicationService; - } + private final AuditService auditService; @ApiResponse(responseCode = CREATED_CODE, description = "{PiUser}") @ApiResponse(responseCode = BAD_REQUEST_CODE, description = "Failed to create user account") @@ -80,4 +76,13 @@ public ResponseEntity deleteAccountsWithEmailPrefix(@PathVariable String public ResponseEntity deleteMediaApplicationsWithEmailPrefix(@PathVariable String emailPrefix) { return ResponseEntity.ok(mediaApplicationService.deleteAllApplicationsWithEmailPrefix(emailPrefix)); } + + @ApiResponse(responseCode = OK_CODE, + description = "Audit logs deleted with email starting with {emailPrefix}") + @Operation(summary = "Delete all audit logs created by user with email prefix") + @DeleteMapping("audit/{emailPrefix}") + @Transactional + public ResponseEntity deleteAuditLogsWithEmailPrefix(@PathVariable String emailPrefix) { + return ResponseEntity.ok(auditService.deleteAllLogsWithUserEmailPrefix(emailPrefix)); + } } From 8aff3eb1dd676cf45d9458775608d6421d698dc0 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 08:35:57 +0000 Subject: [PATCH 03/23] Add delete method to clean up after audit functional test --- .../management/database/AuditRepository.java | 7 +++++++ .../account/management/service/AuditService.java | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java index b1cb9d9a2..9b590b300 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java @@ -3,10 +3,12 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.query.Param; import org.springframework.transaction.annotation.Transactional; import uk.gov.hmcts.reform.pip.account.management.model.AuditLog; import java.time.LocalDateTime; +import java.util.List; import java.util.UUID; public interface AuditRepository extends JpaRepository { @@ -15,4 +17,9 @@ public interface AuditRepository extends JpaRepository { void deleteAllByTimestampBefore(LocalDateTime timestamp); Page findAllByOrderByTimestampDesc(Pageable pageable); + + List findAllByUserEmailStartingWithIgnoreCase(@Param("prefix") String prefix); + + void deleteByIdIn(List id); + } diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java index b9b37eee3..470be8b1a 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java @@ -10,6 +10,7 @@ import uk.gov.hmcts.reform.pip.account.management.model.AuditLog; import java.time.LocalDateTime; +import java.util.List; import java.util.UUID; /** @@ -61,4 +62,19 @@ public String deleteAuditLogs() { auditRepository.deleteAllByTimestampBefore(LocalDateTime.now().minusDays(90)); return "Audit logs that met the max retention period have been deleted"; } + + public String deleteAllLogsWithUserEmailPrefix(String prefix) { + List auditLogsToDelete = auditRepository + .findAllByUserEmailStartingWithIgnoreCase(prefix); + + if (!auditLogsToDelete.isEmpty()) { + + List auditLogIds = auditLogsToDelete.stream() + .map(AuditLog::getId) + .toList(); + auditRepository.deleteByIdIn(auditLogIds); + } + return String.format("%s audit log(s) deleted with user email starting with %s", + auditLogsToDelete.size(), prefix); + } } From dab2f881d5569e92a59d5afca5bd972e2f197e08 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 08:37:57 +0000 Subject: [PATCH 04/23] Replace constructor with lombok annotation --- .../pip/account/management/service/AuditService.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java index 470be8b1a..9eadcff69 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java @@ -1,7 +1,7 @@ package uk.gov.hmcts.reform.pip.account.management.service; +import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -18,16 +18,12 @@ */ @Slf4j @Service +@AllArgsConstructor public class AuditService { private static final String AUDIT_LOG_NOT_FOUND = "Audit log with id %s could not be found"; private final AuditRepository auditRepository; - @Autowired - public AuditService(AuditRepository auditRepository) { - this.auditRepository = auditRepository; - } - /** * Get all audit logs in a page object and descending order on timestamp. * From bc081cc498144582a454e66ecada483f830d0704 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 08:40:53 +0000 Subject: [PATCH 05/23] Add get method for audit functional tests --- .../management/utils/FunctionalTestBase.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java index 4595cdfa9..c991b61bd 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java @@ -2,9 +2,9 @@ import io.restassured.RestAssured; import io.restassured.response.Response; +import lombok.AllArgsConstructor; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.TestInstance; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.util.CollectionUtils; @@ -20,11 +20,11 @@ @SpringBootTest(classes = {Application.class, OAuthClient.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @TestInstance(TestInstance.Lifecycle.PER_CLASS) +@AllArgsConstructor public class FunctionalTestBase { protected static final String CONTENT_TYPE_VALUE = "application/json"; - @Autowired private OAuthClient authClient; protected String accessToken; @@ -47,6 +47,18 @@ protected Response doGetRequest(final String path, final Map add .thenReturn(); } + protected Response doGetRequestWithQueryParameters(final String path, final Map additionalHeaders, + final String pageNumber, final String pageSize) { + return given() + .relaxedHTTPSValidation() + .headers(getRequestHeaders(additionalHeaders)) + .queryParam("pageNumber", pageNumber) + .queryParam("pageSize", pageSize) + .when() + .get(path) + .thenReturn(); + } + protected Response doPostRequest(final String path, final Map additionalHeaders, final String body) { return given() From f57ebf657ab99ad9720de1cffa233cdc86fb36cc Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 08:42:53 +0000 Subject: [PATCH 06/23] Add get method for audit functional tests --- .../pip/account/management/utils/FunctionalTestBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java index c991b61bd..651008589 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java @@ -2,9 +2,9 @@ import io.restassured.RestAssured; import io.restassured.response.Response; -import lombok.AllArgsConstructor; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.TestInstance; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.util.CollectionUtils; @@ -20,11 +20,11 @@ @SpringBootTest(classes = {Application.class, OAuthClient.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @TestInstance(TestInstance.Lifecycle.PER_CLASS) -@AllArgsConstructor public class FunctionalTestBase { protected static final String CONTENT_TYPE_VALUE = "application/json"; + @Autowired private OAuthClient authClient; protected String accessToken; From 6dd6539c507c1a958d3ab394b43a87349c4d2069 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 08:44:40 +0000 Subject: [PATCH 07/23] Add functional tests for audit endpoints --- .../controllers/AuditCreationTest.java | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java new file mode 100644 index 000000000..953726118 --- /dev/null +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java @@ -0,0 +1,150 @@ +package uk.gov.hmcts.reform.pip.account.management.controllers; + +import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.HttpHeaders; +import io.restassured.response.Response; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import uk.gov.hmcts.reform.pip.account.management.model.AuditLog; +import uk.gov.hmcts.reform.pip.account.management.utils.FunctionalTestBase; +import uk.gov.hmcts.reform.pip.account.management.utils.OAuthClient; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; + +@ExtendWith(SpringExtension.class) +@ActiveProfiles(profiles = "functional") +@SpringBootTest(classes = {OAuthClient.class}) +class AuditCreationTest extends FunctionalTestBase { + private static final UUID USER_ID = UUID.randomUUID(); + private static final String TEST_EMAIL_PREFIX = String.format( + "pip-am-test-email-%s", ThreadLocalRandom.current().nextInt(1000, 9999)); + private static final String TEST_EMAIL = TEST_EMAIL_PREFIX + "@justice.gov.uk"; + private static final String ROLES = "SYSTEM_ADMIN"; + private static final String USER_PROVENANCE = "PI_AAD"; + private static final String ACTION = "PUBLICATION_UPLOAD"; + private static final String DETAILS = "Publication with artefact id %s successfully uploaded"; + private static final Integer PAGE_NUMBER = 0; + private static final Integer PAGE_SIZE = 2; + + private static final String AUDIT_URL = "/audit"; + private static final String GET_AUDIT_URL = "/audit/%s"; + private static final String TESTING_SUPPORT_APPLICATION_URL = "/testing-support/audit/"; + private static final String BEARER = "Bearer "; + + private Map bearer; + + @BeforeAll + public void startUp() { + bearer = Map.of(HttpHeaders.AUTHORIZATION, BEARER + accessToken); + } + + @AfterAll + public void teardown() { + doDeleteRequest(TESTING_SUPPORT_APPLICATION_URL + TEST_EMAIL_PREFIX, bearer); + } + + private AuditLog createAuditLog() { + + UUID artefactId = UUID.randomUUID(); + String responseBody = """ + { + "userId": "%s", + "userEmail": "%s", + "roles": "%s", + "userProvenance": "%s", + "action": "%s", + "details": "%s" + } + """.formatted(USER_ID, TEST_EMAIL, ROLES, USER_PROVENANCE, ACTION, String.format(DETAILS, artefactId)); + + Response response = doPostRequest(AUDIT_URL, bearer, responseBody); + + assertThat(response.getStatusCode()).isEqualTo(OK.value()); + + return response.getBody().as(AuditLog.class); + } + + @Test + void shouldBeAbleToCreateAndGetAnAuditRecord() { + AuditLog auditLog = createAuditLog(); + + Response getResponse = doGetRequest(String.format(GET_AUDIT_URL, auditLog.getId()), bearer); + assertThat(getResponse.getStatusCode()).isEqualTo(OK.value()); + + AuditLog retrievedAuditLog = getResponse.getBody().as(AuditLog.class); + assertThat(retrievedAuditLog.getId()).isEqualTo(auditLog.getId()); + assertThat(retrievedAuditLog.getUserEmail()).isEqualTo(auditLog.getUserEmail()); + } + + @Test + void shouldBeAbleToGetAllAuditLogsUsingDefaultDisplayParameters() { + AuditLog auditLog = createAuditLog(); + + Response getResponse = doGetRequest(String.format(AUDIT_URL), bearer); + + assertThat(getResponse.getStatusCode()).isEqualTo(OK.value()); + assertThat(getResponse.jsonPath().getInt("pageable.pageNumber")).isEqualTo(0); + assertThat(getResponse.jsonPath().getInt("pageable.pageSize")).isEqualTo(25); + + List retrievedAuditLogs = getResponse.jsonPath().getList("content", AuditLog.class); + + assertThat(retrievedAuditLogs).isNotNull(); + assertThat(retrievedAuditLogs.size()).isEqualTo(2); + assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + } + + @Test + void shouldBeAbleToGetAllAuditLogsUsingCustomDisplayParameters() { + AuditLog auditLog = createAuditLog(); + + Response getResponse = doGetRequestWithQueryParameters(String.format(AUDIT_URL), bearer, + PAGE_NUMBER.toString(), PAGE_SIZE.toString()); + + assertThat(getResponse.getStatusCode()).isEqualTo(OK.value()); + assertThat(getResponse.jsonPath().getInt("pageable.pageNumber")).isEqualTo(0); + assertThat(getResponse.jsonPath().getInt("pageable.pageSize")).isEqualTo(2); + assertThat(getResponse.jsonPath().getInt("totalPages")).isEqualTo(2); + assertThat(getResponse.jsonPath().getInt("totalElements")).isEqualTo(4); + + List retrievedAuditLogs = getResponse.jsonPath().getList("content", AuditLog.class); + + assertThat(retrievedAuditLogs).isNotNull(); + assertThat(retrievedAuditLogs.size()).isEqualTo(2); + assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + } + + @Test + void shouldReturnErrorWhenAuditRecordDoesNotExist() { + Response getResponse = doGetRequest(String.format(GET_AUDIT_URL, USER_ID), bearer); + + assertThat(getResponse.getStatusCode()).isEqualTo(NOT_FOUND.value()); + } + + @Test + void shouldReturnOkForDeleteAuditLogsIfAllInDate() { + AuditLog auditLog = createAuditLog(); + + Response response = doDeleteRequest(AUDIT_URL, bearer); + + assertThat(response.getStatusCode()).isEqualTo(OK.value()); + + Response getResponse = doGetRequest(String.format(AUDIT_URL), bearer); + + List retrievedAuditLogs = getResponse.jsonPath().getList("content", AuditLog.class); + + assertThat(retrievedAuditLogs).isNotNull(); + assertThat(retrievedAuditLogs.size()).isEqualTo(3); + assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + } +} From c605cbcf9232b8d69d967d82e6a0da4a5d3a8b91 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 09:39:52 +0000 Subject: [PATCH 08/23] Fix PMD issue --- .../reform/pip/account/management/utils/FunctionalTestBase.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java index efd0d4017..818fcf8a1 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java @@ -20,6 +20,7 @@ @SpringBootTest(classes = {Application.class, OAuthClient.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @TestInstance(TestInstance.Lifecycle.PER_CLASS) +@SuppressWarnings("PMD.TooManyMethods") public class FunctionalTestBase { protected static final String CONTENT_TYPE_VALUE = "application/json"; From 27825b8d607b191e6cb6c4c95166829d7a15545d Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 11:22:31 +0000 Subject: [PATCH 09/23] Add unit test for testing support delete audit method --- .../TestingSupportControllerTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java index b4b96da5a..7be1283bd 100644 --- a/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java @@ -8,10 +8,12 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import uk.gov.hmcts.reform.pip.account.management.model.AuditLog; import uk.gov.hmcts.reform.pip.account.management.model.AzureAccount; import uk.gov.hmcts.reform.pip.account.management.model.CreationEnum; import uk.gov.hmcts.reform.pip.account.management.model.PiUser; import uk.gov.hmcts.reform.pip.account.management.service.AccountService; +import uk.gov.hmcts.reform.pip.account.management.service.AuditService; import uk.gov.hmcts.reform.pip.account.management.service.MediaApplicationService; import static org.assertj.core.api.Assertions.assertThat; @@ -33,6 +35,9 @@ class TestingSupportControllerTest { @Mock private MediaApplicationService mediaApplicationService; + @Mock + private AuditService auditService; + @InjectMocks TestingSupportController testingSupportController; @@ -111,4 +116,23 @@ void testDeleteMediaApplicationsWithEmailPrefixReturnsOk() { .as(RESPONSE_BODY_MESSAGE) .isEqualTo(responseMessage); } + + @Test + void testDeleteAuditLogsWithEmailPrefixReturnsOk() { + AuditLog auditLog = new AuditLog(); + auditLog.setUserEmail(EMAIL_PREFIX); + + String responseMessage = "1 audit log(s) deleted with email starting with " + EMAIL_PREFIX; + when(auditService.deleteAllLogsWithUserEmailPrefix(EMAIL_PREFIX)).thenReturn(responseMessage); + + ResponseEntity response = testingSupportController.deleteAuditLogsWithEmailPrefix(EMAIL_PREFIX); + + assertThat(response.getStatusCode()) + .as(RESPONSE_STATUS_MESSAGE) + .isEqualTo(HttpStatus.OK); + + assertThat(response.getBody()) + .as(RESPONSE_BODY_MESSAGE) + .isEqualTo(responseMessage); + } } From 205d3d2100f6c3e10c218609e58118872668c7c9 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 12:50:44 +0000 Subject: [PATCH 10/23] Remove whitespace --- .../reform/pip/account/management/service/AuditService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java index 2ffe50aa4..99964f48d 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java @@ -104,7 +104,6 @@ public String deleteAllLogsWithUserEmailPrefix(String prefix) { .findAllByUserEmailStartingWithIgnoreCase(prefix); if (!auditLogsToDelete.isEmpty()) { - List auditLogIds = auditLogsToDelete.stream() .map(AuditLog::getId) .toList(); From ff77fa9108d8e86f9c74277433b1817c406d04b0 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 19 Dec 2024 12:52:26 +0000 Subject: [PATCH 11/23] Add unit test for functional test helper method --- .../account/management/service/AuditServiceTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java index da2671760..2772210ae 100644 --- a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java @@ -133,4 +133,16 @@ void deleteAuditLogs() { response, "Deletion response was not as expected"); verify(auditRepository, times(1)).deleteAllByTimestampBefore(any()); } + + @Test + void deleteAuditLogsByEmail() { + List auditLogs = List.of(auditLogExample); + when(auditRepository.findAllByUserEmailStartingWithIgnoreCase(EMAIL)).thenReturn(auditLogs); + + String response = auditService.deleteAllLogsWithUserEmailPrefix(EMAIL); + + assertEquals("1 audit log(s) deleted with user email starting with " + EMAIL, response, + "Deletion response was not as expected"); + verify(auditRepository, times(1)).deleteByIdIn(any()); + } } From a67f2b2bc50b230108be3a981580741669d1a65e Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Mon, 6 Jan 2025 17:00:53 +0000 Subject: [PATCH 12/23] Remove unused method --- .../reform/pip/account/management/database/AuditRepository.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java index a6a0a8388..491231497 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/database/AuditRepository.java @@ -17,8 +17,6 @@ public interface AuditRepository extends JpaRepository { @Transactional void deleteAllByTimestampBefore(LocalDateTime timestamp); - Page findAllByOrderByTimestampDesc(Pageable pageable); - List findAllByUserEmailStartingWithIgnoreCase(@Param("prefix") String prefix); void deleteByIdIn(List id); From 97c3089f69362042b737e581ba10589b9cdebfe0 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Mon, 6 Jan 2025 17:03:35 +0000 Subject: [PATCH 13/23] Filter returned audits for those created within the test only --- .../controllers/AuditCreationTest.java | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java index 953726118..075f7b790 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java @@ -39,8 +39,9 @@ class AuditCreationTest extends FunctionalTestBase { private static final String AUDIT_URL = "/audit"; private static final String GET_AUDIT_URL = "/audit/%s"; - private static final String TESTING_SUPPORT_APPLICATION_URL = "/testing-support/audit/"; + private static final String TESTING_SUPPORT_AUDIT_URL = "/testing-support/audit/"; private static final String BEARER = "Bearer "; + private static final String CONTENT = "content"; private Map bearer; @@ -50,9 +51,7 @@ public void startUp() { } @AfterAll - public void teardown() { - doDeleteRequest(TESTING_SUPPORT_APPLICATION_URL + TEST_EMAIL_PREFIX, bearer); - } + public void teardown() { doDeleteRequest(TESTING_SUPPORT_AUDIT_URL + TEST_EMAIL_PREFIX, bearer); } private AuditLog createAuditLog() { @@ -97,11 +96,16 @@ void shouldBeAbleToGetAllAuditLogsUsingDefaultDisplayParameters() { assertThat(getResponse.jsonPath().getInt("pageable.pageNumber")).isEqualTo(0); assertThat(getResponse.jsonPath().getInt("pageable.pageSize")).isEqualTo(25); - List retrievedAuditLogs = getResponse.jsonPath().getList("content", AuditLog.class); + List retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); + + List filteredAuditTestLogsOnly = retrievedAuditLogs + .stream() + .filter(log -> TEST_EMAIL.equals(log.getUserEmail())) + .toList(); - assertThat(retrievedAuditLogs).isNotNull(); - assertThat(retrievedAuditLogs.size()).isEqualTo(2); - assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + assertThat(filteredAuditTestLogsOnly).isNotNull(); + assertThat(filteredAuditTestLogsOnly.size()).isEqualTo(2); + assertThat(filteredAuditTestLogsOnly.getFirst().getId()).isEqualTo(auditLog.getId()); } @Test @@ -117,11 +121,16 @@ void shouldBeAbleToGetAllAuditLogsUsingCustomDisplayParameters() { assertThat(getResponse.jsonPath().getInt("totalPages")).isEqualTo(2); assertThat(getResponse.jsonPath().getInt("totalElements")).isEqualTo(4); - List retrievedAuditLogs = getResponse.jsonPath().getList("content", AuditLog.class); + List retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); - assertThat(retrievedAuditLogs).isNotNull(); - assertThat(retrievedAuditLogs.size()).isEqualTo(2); - assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + List filteredAuditTestLogsOnly = retrievedAuditLogs + .stream() + .filter(log -> TEST_EMAIL.equals(log.getUserEmail())) + .toList(); + + assertThat(filteredAuditTestLogsOnly).isNotNull(); + assertThat(filteredAuditTestLogsOnly.getFirst().getId()).isEqualTo(auditLog.getId()); + assertThat(filteredAuditTestLogsOnly.size()).isEqualTo(2); } @Test @@ -141,10 +150,15 @@ void shouldReturnOkForDeleteAuditLogsIfAllInDate() { Response getResponse = doGetRequest(String.format(AUDIT_URL), bearer); - List retrievedAuditLogs = getResponse.jsonPath().getList("content", AuditLog.class); + List retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); + + List filteredAuditTestLogsOnly = retrievedAuditLogs + .stream() + .filter(log -> TEST_EMAIL.equals(log.getUserEmail())) + .toList(); - assertThat(retrievedAuditLogs).isNotNull(); - assertThat(retrievedAuditLogs.size()).isEqualTo(3); - assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + assertThat(filteredAuditTestLogsOnly).isNotNull(); + assertThat(filteredAuditTestLogsOnly.size()).isEqualTo(3); + assertThat(filteredAuditTestLogsOnly.getFirst().getId()).isEqualTo(auditLog.getId()); } } From 6bab7ebb4f4f67d1c9e89d8253dafa8b72388b15 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Mon, 6 Jan 2025 17:04:11 +0000 Subject: [PATCH 14/23] Update error message to also apply to audit logs --- .../management/errorhandling/GlobalExceptionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/errorhandling/GlobalExceptionHandler.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/errorhandling/GlobalExceptionHandler.java index ef88cdae3..b95a8998e 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/errorhandling/GlobalExceptionHandler.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/errorhandling/GlobalExceptionHandler.java @@ -64,7 +64,7 @@ public ResponseEntity handle(ConstraintViolationException ex) @ExceptionHandler(NotFoundException.class) public ResponseEntity handle(NotFoundException ex) { - log.error(writeLog("404, Unable to find requested account / application")); + log.error(writeLog("404, Unable to find requested account / application / audit")); return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(generateExceptionResponse(ex.getMessage())); From a08bf94e3244880afae32fa424368bc2a5325475 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Mon, 6 Jan 2025 17:05:26 +0000 Subject: [PATCH 15/23] Add integration tests for testing support delete endpoint --- .../controllers/TestingSupportApiTest.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java index 64435dd9f..d2bbc317e 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java @@ -25,6 +25,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import uk.gov.hmcts.reform.pip.account.management.Application; import uk.gov.hmcts.reform.pip.account.management.config.ClientConfiguration; +import uk.gov.hmcts.reform.pip.account.management.model.AuditLog; import uk.gov.hmcts.reform.pip.account.management.model.AzureAccount; import uk.gov.hmcts.reform.pip.account.management.model.CreationEnum; import uk.gov.hmcts.reform.pip.account.management.model.MediaApplication; @@ -33,6 +34,7 @@ import uk.gov.hmcts.reform.pip.account.management.utils.IntegrationTestBase; import uk.gov.hmcts.reform.pip.model.account.Roles; import uk.gov.hmcts.reform.pip.model.account.UserProvenances; +import uk.gov.hmcts.reform.pip.model.enums.AuditAction; import java.io.InputStream; import java.util.ArrayList; @@ -48,6 +50,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static uk.gov.hmcts.reform.pip.model.enums.AuditAction.PUBLICATION_UPLOAD; @SpringBootTest(classes = {Application.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc @@ -62,6 +65,7 @@ class TestingSupportApiTest extends IntegrationTestBase { private static final String TESTING_SUPPORT_ACCOUNT_URL = TESTING_SUPPORT_BASE_URL + "account/"; private static final String TESTING_SUPPORT_APPLICATION_URL = TESTING_SUPPORT_BASE_URL + "application/"; private static final String TESTING_SUPPORT_CREATE_ACCOUNT_URL = TESTING_SUPPORT_BASE_URL + "account"; + private static final String TESTING_SUPPORT_AUDIT_URL = TESTING_SUPPORT_BASE_URL + "audit/"; private static final String ACCOUNT_URL = "/account/"; private static final String ACCOUNT_ADD_USER_URL = ACCOUNT_URL + "add/pi"; @@ -75,6 +79,7 @@ class TestingSupportApiTest extends IntegrationTestBase { private static final String EMAIL = EMAIL_PREFIX + "user123@test.com"; private static final String PASSWORD = "P@55word11"; private static final String ID = "1234"; + private static final UUID USER_ID = UUID.randomUUID(); private static final String PROVENANCE_USER_ID = UUID.randomUUID().toString(); private static final UserProvenances PROVENANCE = UserProvenances.PI_AAD; @@ -86,6 +91,10 @@ class TestingSupportApiTest extends IntegrationTestBase { private static final String EMPLOYER = "Test employer"; private static final MediaApplicationStatus PENDING_STATUS = MediaApplicationStatus.PENDING; + private static final String AUDIT_URL = "/audit"; + private static final AuditAction ACTION = PUBLICATION_UPLOAD; + private static final String DETAILS = "Publication successfully uploaded"; + private static final String UNAUTHORIZED_ROLE = "APPROLE_unknown.authorized"; private static final String UNAUTHORIZED_USERNAME = "unauthorized_isAuthorized"; @@ -282,6 +291,25 @@ void testTestingSupportDeleteApplicationsWithEmailPrefix() throws Exception { .andExpect(status().isNotFound()); } + @Test + void testTestingSupportDeleteAuditLogsWithEmailPrefix() throws Exception { + AuditLog auditLog = createAuditLog(); + + mockMvc.perform(get(AUDIT_URL + "/" + auditLog.getId())) + .andExpect(status().isOk()); + + MvcResult deleteResponse = mockMvc.perform(delete(TESTING_SUPPORT_AUDIT_URL + EMAIL_PREFIX)) + .andExpect(status().isOk()) + .andReturn(); + + assertThat(deleteResponse.getResponse().getContentAsString()) + .as("Audit Log delete response does not match") + .isEqualTo("1 audit log(s) deleted with user email starting with " + EMAIL_PREFIX); + + mockMvc.perform(get(AUDIT_URL + "/" + auditLog.getId())) + .andExpect(status().isNotFound()); + } + @Test @WithMockUser(username = UNAUTHORIZED_USERNAME, authorities = {UNAUTHORIZED_ROLE}) void testUnauthorisedTestingSupportDeleteAccounts() throws Exception { @@ -296,6 +324,13 @@ void testUnauthorisedTestingSupportDeleteApplications() throws Exception { .andExpect(status().isForbidden()); } + @Test + @WithMockUser(username = UNAUTHORIZED_USERNAME, authorities = {UNAUTHORIZED_ROLE}) + void testUnauthorisedTestingSupportDeleteAudits() throws Exception { + mockMvc.perform(delete(TESTING_SUPPORT_AUDIT_URL + EMAIL_PREFIX)) + .andExpect(status().isForbidden()); + } + private PiUser createUser() { PiUser user = new PiUser(); user.setEmail(EMAIL); @@ -318,7 +353,6 @@ private AzureAccount createAccount(String password) { return newAccount; } - @SuppressWarnings("PMD.SignatureDeclareThrowsException") private MediaApplication createApplication() throws Exception { MediaApplication application = new MediaApplication(); @@ -346,4 +380,28 @@ private MediaApplication createApplication() throws Exception { return OBJECT_MAPPER.readValue(mvcResult.getResponse().getContentAsString(), MediaApplication.class); } } + + private AuditLog createAuditLog() throws Exception { + AuditLog auditLog = new AuditLog(); + auditLog.setId(USER_ID); + auditLog.setUserId(ID); + auditLog.setUserEmail(EMAIL); + auditLog.setRoles(ROLE); + auditLog.setUserProvenance(PROVENANCE); + auditLog.setAction(ACTION); + auditLog.setDetails(DETAILS); + + MockHttpServletRequestBuilder postRequest = MockMvcRequestBuilders + .post(AUDIT_URL) + .content(OBJECT_MAPPER.writeValueAsString(auditLog)) + .header(ISSUER_HEADER, ISSUER_ID) + .contentType(MediaType.APPLICATION_JSON); + + MvcResult mvcResult = mockMvc.perform(postRequest) + .andExpect(status().isOk()) + .andReturn(); + + return OBJECT_MAPPER.readValue(mvcResult.getResponse().getContentAsString(), AuditLog.class); + } + } From 8ebaf695b6cf9f752a80f16fb3dee62819a7ac17 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Mon, 6 Jan 2025 17:18:18 +0000 Subject: [PATCH 16/23] Fix checkstyle and pmd fails --- .../pip/account/management/controllers/AuditCreationTest.java | 4 +++- .../account/management/controllers/TestingSupportApiTest.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java index 075f7b790..b5a89733e 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java @@ -51,7 +51,9 @@ public void startUp() { } @AfterAll - public void teardown() { doDeleteRequest(TESTING_SUPPORT_AUDIT_URL + TEST_EMAIL_PREFIX, bearer); } + public void teardown() { + doDeleteRequest(TESTING_SUPPORT_AUDIT_URL + TEST_EMAIL_PREFIX, bearer); + } private AuditLog createAuditLog() { diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java index d2bbc317e..3232b4657 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java @@ -57,7 +57,8 @@ @ActiveProfiles("integration") @AutoConfigureEmbeddedDatabase(type = AutoConfigureEmbeddedDatabase.DatabaseType.POSTGRES) @WithMockUser(username = "admin", authorities = {"APPROLE_api.request.admin"}) -@SuppressWarnings({"PMD.TooManyMethods", "PMD.ExcessiveImports", "PMD.UnitTestShouldIncludeAssert"}) +@SuppressWarnings({"PMD.TooManyMethods", "PMD.ExcessiveImports", "PMD.UnitTestShouldIncludeAssert", + "PMD.CouplingBetweenObjects"}) class TestingSupportApiTest extends IntegrationTestBase { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -381,6 +382,7 @@ private MediaApplication createApplication() throws Exception { } } + @SuppressWarnings("PMD.SignatureDeclareThrowsException") private AuditLog createAuditLog() throws Exception { AuditLog auditLog = new AuditLog(); auditLog.setId(USER_ID); From b28c0688f4696187e447bfd524854c8cab9dccb9 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Tue, 7 Jan 2025 11:08:20 +0000 Subject: [PATCH 17/23] test commits being picked up by jenkins --- .../pip/account/management/controllers/AuditCreationTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java index b5a89733e..a2b4efab6 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java @@ -163,4 +163,5 @@ void shouldReturnOkForDeleteAuditLogsIfAllInDate() { assertThat(filteredAuditTestLogsOnly.size()).isEqualTo(3); assertThat(filteredAuditTestLogsOnly.getFirst().getId()).isEqualTo(auditLog.getId()); } + } From 3ef2f98cb36a2e317ac8b3315b8fbd50f1d37049 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 9 Jan 2025 15:59:34 +0000 Subject: [PATCH 18/23] Update get request to include test generated email --- .../pip/account/management/utils/FunctionalTestBase.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java index e110b2c1b..7354a11da 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/utils/FunctionalTestBase.java @@ -52,12 +52,13 @@ protected Response doGetRequest(final String path, final Map add } protected Response doGetRequestWithQueryParameters(final String path, final Map additionalHeaders, - final String pageNumber, final String pageSize) { + final String pageNumber, final String pageSize, final String email) { return given() .relaxedHTTPSValidation() .headers(getRequestHeaders(additionalHeaders)) .queryParam("pageNumber", pageNumber) .queryParam("pageSize", pageSize) + .queryParam("email", email) .when() .get(path) .thenReturn(); From 3106714a8839fc6ffb36fa759deeac0389e6c63d Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 9 Jan 2025 16:01:29 +0000 Subject: [PATCH 19/23] Add helper functionality to update the timestamp on an audit log --- .../controllers/TestingSupportController.java | 10 ++++++++++ .../pip/account/management/service/AuditService.java | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java index 2c1d8e17f..a8d61b057 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportController.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -85,4 +86,13 @@ public ResponseEntity deleteMediaApplicationsWithEmailPrefix(@PathVariab public ResponseEntity deleteAuditLogsWithEmailPrefix(@PathVariable String emailPrefix) { return ResponseEntity.ok(auditService.deleteAllLogsWithUserEmailPrefix(emailPrefix)); } + + @ApiResponse(responseCode = OK_CODE, + description = "Audit log with id {auditId} updated") + @Operation(summary = "Update the timestamp of audit log with id") + @PutMapping("audit/{auditId}") + @Transactional + public ResponseEntity updateAuditLogTimestampWithId(@PathVariable String auditId) { + return ResponseEntity.ok(auditService.updateAuditTimestampWithAuditId(auditId)); + } } diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java index 99964f48d..720e26296 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuditService.java @@ -112,4 +112,15 @@ public String deleteAllLogsWithUserEmailPrefix(String prefix) { return String.format("%s audit log(s) deleted with user email starting with %s", auditLogsToDelete.size(), prefix); } + + public String updateAuditTimestampWithAuditId(String auditId) { + AuditLog auditLogToUpdate = getAuditLogById(UUID.fromString(auditId)); + + LocalDateTime expired = LocalDateTime.now().minusDays(200); + + auditLogToUpdate.setTimestamp(expired); + auditRepository.save(auditLogToUpdate); + + return String.format("1 audit log(s) updated with timestamp %s", expired); + } } From 6a2faaddbbab6cdb836ee5a93738652871481acb Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 9 Jan 2025 16:02:50 +0000 Subject: [PATCH 20/23] Add tests for helper functionality --- .../controllers/TestingSupportApiTest.java | 21 ++++++++++++++++++- .../management/service/AuditServiceTest.java | 10 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java index 3232b4657..09e28115b 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java @@ -37,6 +37,7 @@ import uk.gov.hmcts.reform.pip.model.enums.AuditAction; import java.io.InputStream; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -49,6 +50,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static uk.gov.hmcts.reform.pip.model.enums.AuditAction.PUBLICATION_UPLOAD; @@ -305,12 +307,29 @@ void testTestingSupportDeleteAuditLogsWithEmailPrefix() throws Exception { assertThat(deleteResponse.getResponse().getContentAsString()) .as("Audit Log delete response does not match") - .isEqualTo("1 audit log(s) deleted with user email starting with " + EMAIL_PREFIX); + .isEqualTo("2 audit log(s) deleted with user email starting with " + EMAIL_PREFIX); mockMvc.perform(get(AUDIT_URL + "/" + auditLog.getId())) .andExpect(status().isNotFound()); } + @Test + void testTestingSupportUpdateAuditLogTimestampWithId() throws Exception { + AuditLog auditLog = createAuditLog(); + LocalDate expiredDate = auditLog.getTimestamp().minusDays(200).toLocalDate(); + + mockMvc.perform(get(AUDIT_URL + "/" + auditLog.getId())) + .andExpect(status().isOk()); + + MvcResult updateAudit = mockMvc.perform(put(TESTING_SUPPORT_AUDIT_URL + auditLog.getId())) + .andExpect(status().isOk()) + .andReturn(); + + assertThat(updateAudit.getResponse().getContentAsString()) + .as("Audit Log update response does not match") + .contains("1 audit log(s) updated with timestamp " + expiredDate); + } + @Test @WithMockUser(username = UNAUTHORIZED_USERNAME, authorities = {UNAUTHORIZED_ROLE}) void testUnauthorisedTestingSupportDeleteAccounts() throws Exception { diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java index 2772210ae..d0ebdf8f7 100644 --- a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuditServiceTest.java @@ -145,4 +145,14 @@ void deleteAuditLogsByEmail() { "Deletion response was not as expected"); verify(auditRepository, times(1)).deleteByIdIn(any()); } + + @Test + void updateAuditTimestampByAuditId() { + when(auditRepository.findById(ID)).thenReturn(Optional.of(auditLogExample)); + + String response = auditService.updateAuditTimestampWithAuditId(ID.toString()); + + assertEquals("1 audit log(s) updated with timestamp " + auditLogExample.getTimestamp(), response, + "Update response was not as expected"); + } } From d40d85f24221564938d3485df3f105e702dbf906 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 9 Jan 2025 16:16:03 +0000 Subject: [PATCH 21/23] Add tests for helper functions --- .../TestingSupportControllerTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java index 7be1283bd..4d8dc2dc4 100644 --- a/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportControllerTest.java @@ -16,6 +16,8 @@ import uk.gov.hmcts.reform.pip.account.management.service.AuditService; import uk.gov.hmcts.reform.pip.account.management.service.MediaApplicationService; +import java.util.UUID; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; @@ -135,4 +137,24 @@ void testDeleteAuditLogsWithEmailPrefixReturnsOk() { .as(RESPONSE_BODY_MESSAGE) .isEqualTo(responseMessage); } + + @Test + void testUpdateAuditLogTimestampWithIdReturnsOk() { + AuditLog auditLog = new AuditLog(); + UUID auditId = UUID.randomUUID(); + auditLog.setId(auditId); + + String responseMessage = "1 audit log(s) updated with timestamp "; + when(auditService.updateAuditTimestampWithAuditId(auditId.toString())).thenReturn(responseMessage); + + ResponseEntity response = testingSupportController.updateAuditLogTimestampWithId(auditId.toString()); + + assertThat(response.getStatusCode()) + .as(RESPONSE_STATUS_MESSAGE) + .isEqualTo(HttpStatus.OK); + + assertThat(response.getBody()) + .as(RESPONSE_BODY_MESSAGE) + .contains(responseMessage); + } } From 81f2b7076da853d776c28d928130db5cab483766 Mon Sep 17 00:00:00 2001 From: Natasha Alker Date: Thu, 9 Jan 2025 16:17:49 +0000 Subject: [PATCH 22/23] Add functional test for deletion of out of date audits --- .../controllers/AuditCreationTest.java | 68 +++++++++++-------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java index a2b4efab6..bc4794bbf 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/AuditCreationTest.java @@ -76,6 +76,12 @@ private AuditLog createAuditLog() { return response.getBody().as(AuditLog.class); } + private void deleteAuditLog() { + Response response = doDeleteRequest(AUDIT_URL, bearer); + + assertThat(response.getStatusCode()).isEqualTo(OK.value()); + } + @Test void shouldBeAbleToCreateAndGetAnAuditRecord() { AuditLog auditLog = createAuditLog(); @@ -92,7 +98,8 @@ void shouldBeAbleToCreateAndGetAnAuditRecord() { void shouldBeAbleToGetAllAuditLogsUsingDefaultDisplayParameters() { AuditLog auditLog = createAuditLog(); - Response getResponse = doGetRequest(String.format(AUDIT_URL), bearer); + Response getResponse = doGetRequestWithQueryParameters(String.format(AUDIT_URL), bearer, + "", "", TEST_EMAIL_PREFIX); assertThat(getResponse.getStatusCode()).isEqualTo(OK.value()); assertThat(getResponse.jsonPath().getInt("pageable.pageNumber")).isEqualTo(0); @@ -100,14 +107,9 @@ void shouldBeAbleToGetAllAuditLogsUsingDefaultDisplayParameters() { List retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); - List filteredAuditTestLogsOnly = retrievedAuditLogs - .stream() - .filter(log -> TEST_EMAIL.equals(log.getUserEmail())) - .toList(); - - assertThat(filteredAuditTestLogsOnly).isNotNull(); - assertThat(filteredAuditTestLogsOnly.size()).isEqualTo(2); - assertThat(filteredAuditTestLogsOnly.getFirst().getId()).isEqualTo(auditLog.getId()); + assertThat(retrievedAuditLogs).isNotNull(); + assertThat(retrievedAuditLogs.size()).isEqualTo(2); + assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); } @Test @@ -115,7 +117,7 @@ void shouldBeAbleToGetAllAuditLogsUsingCustomDisplayParameters() { AuditLog auditLog = createAuditLog(); Response getResponse = doGetRequestWithQueryParameters(String.format(AUDIT_URL), bearer, - PAGE_NUMBER.toString(), PAGE_SIZE.toString()); + PAGE_NUMBER.toString(), PAGE_SIZE.toString(), TEST_EMAIL_PREFIX); assertThat(getResponse.getStatusCode()).isEqualTo(OK.value()); assertThat(getResponse.jsonPath().getInt("pageable.pageNumber")).isEqualTo(0); @@ -125,14 +127,9 @@ void shouldBeAbleToGetAllAuditLogsUsingCustomDisplayParameters() { List retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); - List filteredAuditTestLogsOnly = retrievedAuditLogs - .stream() - .filter(log -> TEST_EMAIL.equals(log.getUserEmail())) - .toList(); - - assertThat(filteredAuditTestLogsOnly).isNotNull(); - assertThat(filteredAuditTestLogsOnly.getFirst().getId()).isEqualTo(auditLog.getId()); - assertThat(filteredAuditTestLogsOnly.size()).isEqualTo(2); + assertThat(retrievedAuditLogs).isNotNull(); + assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + assertThat(retrievedAuditLogs.size()).isEqualTo(2); } @Test @@ -146,22 +143,37 @@ void shouldReturnErrorWhenAuditRecordDoesNotExist() { void shouldReturnOkForDeleteAuditLogsIfAllInDate() { AuditLog auditLog = createAuditLog(); - Response response = doDeleteRequest(AUDIT_URL, bearer); + deleteAuditLog(); - assertThat(response.getStatusCode()).isEqualTo(OK.value()); + Response getResponse = doGetRequestWithQueryParameters(String.format(AUDIT_URL), bearer, + "", "", TEST_EMAIL_PREFIX); - Response getResponse = doGetRequest(String.format(AUDIT_URL), bearer); + List retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); + assertThat(retrievedAuditLogs).isNotNull(); + assertThat(retrievedAuditLogs.getFirst().getId()).isEqualTo(auditLog.getId()); + assertThat(retrievedAuditLogs.size()).isEqualTo(3); + } + + @Test + void shouldBeAbleToDeleteAnOutOfDateAudit() { + Response getResponse = doGetRequestWithQueryParameters(String.format(AUDIT_URL), bearer, + "", "", TEST_EMAIL_PREFIX); List retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); + assertThat(retrievedAuditLogs.size()).isEqualTo(4); + + AuditLog auditLog = createAuditLog(); + doPutRequest(TESTING_SUPPORT_AUDIT_URL + auditLog.getId(), bearer); + + getResponse = doGetRequestWithQueryParameters(String.format(AUDIT_URL), bearer, "", "", TEST_EMAIL_PREFIX); + retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); + assertThat(retrievedAuditLogs.size()).isEqualTo(5); - List filteredAuditTestLogsOnly = retrievedAuditLogs - .stream() - .filter(log -> TEST_EMAIL.equals(log.getUserEmail())) - .toList(); + deleteAuditLog(); - assertThat(filteredAuditTestLogsOnly).isNotNull(); - assertThat(filteredAuditTestLogsOnly.size()).isEqualTo(3); - assertThat(filteredAuditTestLogsOnly.getFirst().getId()).isEqualTo(auditLog.getId()); + getResponse = doGetRequestWithQueryParameters(String.format(AUDIT_URL), bearer, "", "", TEST_EMAIL_PREFIX); + retrievedAuditLogs = getResponse.jsonPath().getList(CONTENT, AuditLog.class); + assertThat(retrievedAuditLogs.size()).isEqualTo(4); } } From d863bb5fb6058ec90344bc279e7b242d3a2e2a4e Mon Sep 17 00:00:00 2001 From: ChrisS1512 <87066931+ChrisS1512@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:59:12 +0000 Subject: [PATCH 23/23] PUB-2576 - Fixed test --- .../account/management/controllers/TestingSupportApiTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java index 9f316a1f0..0299bfff9 100644 --- a/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/TestingSupportApiTest.java @@ -82,7 +82,6 @@ class TestingSupportApiTest extends IntegrationTestBase { private static final String EMAIL = EMAIL_PREFIX + "user123@test.com"; private static final String PASSWORD = "P@55word11"; private static final String ID = "1234"; - private static final UUID USER_ID = UUID.randomUUID(); private static final String PROVENANCE_USER_ID = UUID.randomUUID().toString(); private static final UserProvenances PROVENANCE = UserProvenances.PI_AAD; @@ -404,7 +403,6 @@ private MediaApplication createApplication() throws Exception { @SuppressWarnings("PMD.SignatureDeclareThrowsException") private AuditLog createAuditLog() throws Exception { AuditLog auditLog = new AuditLog(); - auditLog.setId(USER_ID); auditLog.setUserId(ID); auditLog.setUserEmail(EMAIL); auditLog.setRoles(ROLE);