diff --git a/build.gradle b/build.gradle index a46e1265ae6..8d9eb03c118 100644 --- a/build.gradle +++ b/build.gradle @@ -515,6 +515,8 @@ dependencies { testImplementation group: 'org.jeasy', name: 'easy-random-core', version: '5.0.0' + testImplementation 'com.atlassian.oai:swagger-request-validator-core:2.46.0' + compileJava.dependsOn = openApiGenerateTaskList } diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImplTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImplTest.java index afa2035c001..95014f790ec 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImplTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImplTest.java @@ -29,7 +29,7 @@ import static uk.gov.hmcts.darts.common.enums.SecurityRoleEnum.JUDICIARY; import static uk.gov.hmcts.darts.common.enums.SecurityRoleEnum.REQUESTER; import static uk.gov.hmcts.darts.hearings.exception.HearingApiError.HEARING_NOT_FOUND; -import static uk.gov.hmcts.darts.transcriptions.exception.TranscriptionApiError.TRANSCRIPTION_NOT_FOUND; +import static uk.gov.hmcts.darts.transcriptions.exception.TranscriptionApiError.BAD_REQUEST_TRANSCRIPTION_ID; class AuthorisationImplTest extends IntegrationBase { @@ -222,8 +222,8 @@ void authoriseByTranscriptionIdShouldThrowTranscriptionApiErrorTranscriptionNotF -1L, Set.of(JUDICIARY)) ); - assertEquals(TRANSCRIPTION_NOT_FOUND.getTitle(), exception.getMessage()); - assertEquals(TRANSCRIPTION_NOT_FOUND, exception.getError()); + assertEquals(BAD_REQUEST_TRANSCRIPTION_ID.getTitle(), exception.getMessage()); + assertEquals(BAD_REQUEST_TRANSCRIPTION_ID, exception.getError()); } @Test diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerDownloadTranscriptIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerDownloadTranscriptIntTest.java index 37894f955a8..db3bffff7d8 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerDownloadTranscriptIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerDownloadTranscriptIntTest.java @@ -54,6 +54,7 @@ import static uk.gov.hmcts.darts.audit.api.AuditActivity.DOWNLOAD_TRANSCRIPTION; import static uk.gov.hmcts.darts.common.enums.ExternalLocationTypeEnum.UNSTRUCTURED; import static uk.gov.hmcts.darts.common.enums.ObjectRecordStatusEnum.STORED; +import static uk.gov.hmcts.darts.test.common.TestUtils.getContentsFromFile; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.APPROVED; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.COMPLETE; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.WITH_TRANSCRIBER; @@ -163,7 +164,7 @@ void downloadTranscript_shouldReturn401Error_whenUserNotFound() throws Exception } @Test - void downloadTranscriptShouldReturnNotFoundError() throws Exception { + void downloadTranscript_ShouldReturnNotFoundError() throws Exception { MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(URL_TEMPLATE, transcriptionId) .header( "accept", @@ -185,7 +186,7 @@ void downloadTranscriptShouldReturnNotFoundError() throws Exception { } @Test - void downloadTranscriptShouldReturnOkWithMicrosoftWordNew() throws Exception { + void downloadTranscript_ShouldReturnOk_WithMicrosoftWordNew() throws Exception { final String fileName = "Test Document.docx"; final String fileType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; final int fileSize = 11_937; @@ -257,7 +258,7 @@ void downloadTranscriptShouldReturnOkWithMicrosoftWordNew() throws Exception { @Test @SuppressWarnings("PMD.CloseResource") - void downloadTranscriptShouldReturnOkWithMicrosoftWordOld() throws Exception { + void downloadTranscript_ShouldReturnOk_WithMicrosoftWordOld() throws Exception { final String fileName = "Test Document.doc"; final String fileType = "application/msword"; final int fileSize = 22_528; @@ -319,4 +320,23 @@ void downloadTranscriptShouldReturnOkWithMicrosoftWordOld() throws Exception { verifyNoMoreInteractions(mockAuditApi, mockDataManagementFacade, mockFileBasedDownloadResponseMetaData); } + @Test + void downloadTranscript_ShouldReturnBadRequest_WhenNegativeTranscriptionIdUsed() throws Exception { + MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/transcriptions/-123/document") + .header( + "accept", + "application/msword", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ); + MvcResult mvcResult = mockMvc.perform(requestBuilder) + .andExpect(status().isBadRequest()) + .andReturn(); + + String actualResponse = mvcResult.getResponse().getContentAsString(); + + String expectedResponse = getContentsFromFile("tests/transcriptions/transcription/expectedResponseBadRequest.json"); + JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); + + verifyNoInteractions(mockAuditApi); + } } \ No newline at end of file diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerGetTranscriptionTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerGetTranscriptionTest.java index ca64989e2e9..4dd1849813d 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerGetTranscriptionTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerGetTranscriptionTest.java @@ -287,8 +287,33 @@ void getTranscriptionNotFoundWhenIsCurrentFalse() throws Exception { } @Test - void getTranscriptionNotFound() throws Exception { + void getTranscription_ShouldReturnBadRequest_WhenNegativeTranscriptionId() throws Exception { MockHttpServletRequestBuilder requestBuilder = get(ENDPOINT_URL_TRANSCRIPTION, -999); + MvcResult response = mockMvc.perform(requestBuilder).andExpect(status().isBadRequest()).andReturn(); + String actualResponse = response.getResponse().getContentAsString(); + String expectedResponse = getContentsFromFile("tests/transcriptions/transcription/expectedResponseBadRequest.json"); + JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); + } + + @Test + void getTranscription_ShouldReturnNotFound_WhenTranscriptDoesNotExist() throws Exception { + TranscriptionEntity transcriptionEntity = transactionalUtil.executeInTransaction(() -> { + HearingEntity hearingEntity = dartsDatabase.getHearingRepository().findAll().getFirst(); + TranscriptionEntity transcription = dartsDatabase.getTranscriptionStub().createTranscription(hearingEntity); + transcription.setStartTime(SOME_DATE_TIME); + transcription.setEndTime(SOME_DATE_TIME); + transcription = dartsDatabase.save(transcription); + UserAccountEntity userAccount = dartsDatabase.getUserAccountRepository().findById(transcription.getCreatedById()).orElseThrow(); + + addTranscriptionWorkflow(transcription, userAccount, "comment1", TranscriptionStatusEnum.REQUESTED); + addTranscriptionWorkflow(transcription, userAccount, "comment2", TranscriptionStatusEnum.APPROVED); + transcription.getCourtroom().getCourthouse().getCourthouseName(); + transcription.getRequestedBy().getUserName(); + return transcription; + }); + dartsDatabase.updateCreatedBy(transcriptionEntity, OffsetDateTime.of(2023, 6, 20, 10, 0, 0, 0, ZoneOffset.UTC)); + + MockHttpServletRequestBuilder requestBuilder = get(ENDPOINT_URL_TRANSCRIPTION, transcriptionEntity.getId() + 1); MvcResult response = mockMvc.perform(requestBuilder).andExpect(status().isNotFound()).andReturn(); String actualResponse = response.getResponse().getContentAsString(); String expectedResponse = getContentsFromFile("tests/transcriptions/transcription/expectedResponseNotFound.json"); diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionUnfulfilledIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionUnfulfilledIntTest.java index 850be5273ac..ff662ec8146 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionUnfulfilledIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionUnfulfilledIntTest.java @@ -40,6 +40,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static uk.gov.hmcts.darts.audit.api.AuditActivity.UNFULFILLED_TRANSCRIPTION; +import static uk.gov.hmcts.darts.test.common.TestUtils.getContentsFromFile; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.CLOSED; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.UNFULFILLED; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.WITH_TRANSCRIBER; @@ -168,12 +169,11 @@ void updateTranscription_ShouldReturnTranscriptionUnprocessableEntityError_Where } @Test - void updateTranscription_ShouldReturnTranscriptionNotFoundError() throws Exception { + void updateTranscription_ShouldReturnTranscriptionNotFoundError_WhenTranscriptionDoesNotExist() throws Exception { UpdateTranscriptionRequest updateTranscription = new UpdateTranscriptionRequest(); updateTranscription.setTranscriptionStatusId(UNFULFILLED.getId()); - MockHttpServletRequestBuilder requestBuilder = patch(URI.create( - String.format("/transcriptions/%d", -1))) + String.format("/transcriptions/%d", transcriptionId + 1))) .header("Content-Type", "application/json") .content(objectMapper.writeValueAsString(updateTranscription)); MvcResult mvcResult = mockMvc.perform(requestBuilder) @@ -189,6 +189,27 @@ void updateTranscription_ShouldReturnTranscriptionNotFoundError() throws Excepti verifyNoInteractions(mockAuditApi); } + @Test + void updateTranscription_ShouldReturnTranscriptionBadRequestError_WhenNegativeTranscriptionIdUsed() throws Exception { + UpdateTranscriptionRequest updateTranscription = new UpdateTranscriptionRequest(); + updateTranscription.setTranscriptionStatusId(UNFULFILLED.getId()); + + MockHttpServletRequestBuilder requestBuilder = patch(URI.create( + String.format("/transcriptions/%d", -1))) + .header("Content-Type", "application/json") + .content(objectMapper.writeValueAsString(updateTranscription)); + MvcResult mvcResult = mockMvc.perform(requestBuilder) + .andExpect(status().isBadRequest()) + .andReturn(); + + String actualJson = mvcResult.getResponse().getContentAsString(); + String expectedJson = getContentsFromFile("tests/transcriptions/transcription/expectedResponseBadRequest.json"); + + JSONAssert.assertEquals(expectedJson, actualJson, JSONCompareMode.NON_EXTENSIBLE); + verifyNoInteractions(notificationApi); + verifyNoInteractions(mockAuditApi); + } + @Test void updateTranscription_ShouldReturnTranscriptionWorkflowActionInvalidError() throws Exception { UpdateTranscriptionRequest updateTranscription = new UpdateTranscriptionRequest(); diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionWithTranscriberIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionWithTranscriberIntTest.java index 7e48f1e6a72..eb05aeb2558 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionWithTranscriberIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/transcriptions/controller/TranscriptionControllerUpdateTranscriptionWithTranscriberIntTest.java @@ -36,6 +36,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static uk.gov.hmcts.darts.audit.api.AuditActivity.ACCEPT_TRANSCRIPTION; +import static uk.gov.hmcts.darts.test.common.TestUtils.getContentsFromFile; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.APPROVED; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.COMPLETE; import static uk.gov.hmcts.darts.transcriptions.enums.TranscriptionStatusEnum.WITH_TRANSCRIBER; @@ -133,7 +134,7 @@ void updateTranscriptionWithTranscriberWithoutComment() throws Exception { } @Test - void updateTranscriptionShouldReturnTranscriptionNotFoundError() throws Exception { + void updateTranscription_ShouldReturnBadRequest_WhenInvalidTranscriptionId() throws Exception { UpdateTranscriptionRequest updateTranscription = new UpdateTranscriptionRequest(); updateTranscription.setTranscriptionStatusId(WITH_TRANSCRIBER.getId()); @@ -141,14 +142,33 @@ void updateTranscriptionShouldReturnTranscriptionNotFoundError() throws Exceptio String.format("/transcriptions/%d", -1))) .header("Content-Type", "application/json") .content(objectMapper.writeValueAsString(updateTranscription)); + MvcResult mvcResult = mockMvc.perform(requestBuilder) + .andExpect(status().isBadRequest()) + .andReturn(); + + String actualJson = mvcResult.getResponse().getContentAsString(); + String expectedJson = getContentsFromFile("tests/transcriptions/transcription/expectedResponseBadRequest.json"); + JSONAssert.assertEquals(expectedJson, actualJson, JSONCompareMode.NON_EXTENSIBLE); + + verifyNoInteractions(mockAuditApi); + } + + @Test + void updateTranscription_ShouldReturnNotFound_WhenTranscriptionDoesNotExist() throws Exception { + UpdateTranscriptionRequest updateTranscription = new UpdateTranscriptionRequest(); + updateTranscription.setTranscriptionStatusId(WITH_TRANSCRIBER.getId()); + + MockHttpServletRequestBuilder requestBuilder = patch(URI.create( + String.format("/transcriptions/%d", transcriptionId + 1))) + .header("Content-Type", "application/json") + .content(objectMapper.writeValueAsString(updateTranscription)); MvcResult mvcResult = mockMvc.perform(requestBuilder) .andExpect(status().isNotFound()) .andReturn(); String actualJson = mvcResult.getResponse().getContentAsString(); - String expectedJson = """ - {"type":"TRANSCRIPTION_101","title":"The requested transcription cannot be found","status":404} - """; + String expectedJson = getContentsFromFile("tests/transcriptions/transcription/expectedResponseNotFound.json"); + JSONAssert.assertEquals(expectedJson, actualJson, JSONCompareMode.NON_EXTENSIBLE); verifyNoInteractions(mockAuditApi); diff --git a/src/integrationTest/resources/tests/transcriptions/transcription/expectedResponseBadRequest.json b/src/integrationTest/resources/tests/transcriptions/transcription/expectedResponseBadRequest.json new file mode 100644 index 00000000000..643e0cd7fdf --- /dev/null +++ b/src/integrationTest/resources/tests/transcriptions/transcription/expectedResponseBadRequest.json @@ -0,0 +1 @@ +{"type":"TRANSCRIPTION_124","title":"Invalid transcription id","status":400} \ No newline at end of file diff --git a/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImpl.java b/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImpl.java index 8dc6e254d5d..3c1f89772fc 100644 --- a/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImpl.java +++ b/src/main/java/uk/gov/hmcts/darts/authorisation/component/impl/AuthorisationImpl.java @@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; +import org.apache.coyote.BadRequestException; import org.springframework.stereotype.Component; import uk.gov.hmcts.darts.audio.entity.MediaRequestEntity; import uk.gov.hmcts.darts.authorisation.api.AuthorisationApi; @@ -22,6 +23,8 @@ import uk.gov.hmcts.darts.common.repository.MediaRequestRepository; import uk.gov.hmcts.darts.common.repository.TranscriptionRepository; import uk.gov.hmcts.darts.common.repository.TransformedMediaRepository; +import uk.gov.hmcts.darts.util.DataUtil; +import uk.gov.hmcts.darts.util.ValidationConstants; import java.util.Collections; import java.util.List; @@ -36,6 +39,7 @@ import static uk.gov.hmcts.darts.audio.exception.AudioRequestsApiError.TRANSFORMED_MEDIA_NOT_FOUND; import static uk.gov.hmcts.darts.cases.exception.CaseApiError.CASE_NOT_FOUND; import static uk.gov.hmcts.darts.hearings.exception.HearingApiError.HEARING_NOT_FOUND; +import static uk.gov.hmcts.darts.transcriptions.exception.TranscriptionApiError.BAD_REQUEST_TRANSCRIPTION_ID; import static uk.gov.hmcts.darts.transcriptions.exception.TranscriptionApiError.TRANSCRIPTION_NOT_FOUND; @Component @@ -115,6 +119,9 @@ public void authoriseByMediaId(Long mediaId, Set securityRoles @SuppressWarnings({"PMD.ExceptionAsFlowControl"}) public void authoriseByTranscriptionId(Long transcriptionId, Set securityRoles) { try { + if (!DataUtil.isWithinBounds(transcriptionId, 1L, ValidationConstants.MaxValues.MAX_LONG_VALUE)) { + throw new BadRequestException(); + } final List courthouses = getCourthousesFromTranscription(transcriptionId); if (CollectionUtils.isEmpty(courthouses)) { throw new EntityNotFoundException(); @@ -123,6 +130,9 @@ public void authoriseByTranscriptionId(Long transcriptionId, Set m.getMessage().contains("Numeric instance is lower than the required " + + "minimum (minimum: 1, found: -123)"))); + } + + @Test + void openApi_ShouldReturnError_WhenAboveMaximumTranscriptionIdUsed() { + String maxTranscriptionId = ValidationConstants.MaxValues.MAX_LONG_VALUE.toString(); + String exceededTranscriptionId = maxTranscriptionId + "99"; + Request request = SimpleRequest.Builder + .get("/transcriptions/" + exceededTranscriptionId + "/document") + .build(); + + ValidationReport report = VALIDATOR.validateRequest(request); + + String expectedSubstring = "Numeric instance is greater than the required maximum (maximum: " + + maxTranscriptionId + ", found: " + exceededTranscriptionId + ")"; + + assertTrue( + report.getMessages().stream().anyMatch(m -> m.getMessage().equals(expectedSubstring)) + ); + } + + @Test + void openApi_ShouldReturnNoError_WhenValidTranscriptionIdUsed() { + Request request = SimpleRequest.Builder + .get("/transcriptions/1000/document") + .build(); + + ValidationReport report = VALIDATOR.validateRequest(request); + + assertTrue(report.getMessages().isEmpty(), "Expected no validation errors for a valid transcription_id"); + } +} diff --git a/src/test/java/uk/gov/hmcts/darts/util/DataUtilTest.java b/src/test/java/uk/gov/hmcts/darts/util/DataUtilTest.java index 5b59d80a7b4..3ad580dc05c 100644 --- a/src/test/java/uk/gov/hmcts/darts/util/DataUtilTest.java +++ b/src/test/java/uk/gov/hmcts/darts/util/DataUtilTest.java @@ -295,4 +295,35 @@ void toBooleanWithDefaultValue_shouldDefaultToValueSpecified() { assertThat(DataUtil.toBoolean(true)).isTrue(); assertThat(DataUtil.toBoolean(false)).isFalse(); } + + @Test + void isWithinBounds_shouldReturnTrue_WhenValueIsWithinBounds() { + assertThat(DataUtil.isWithinBounds(5L, 1L, 10L)).isTrue(); + } + + @Test + void isWithinBounds_shouldReturnFalse_WhenValueIsBelowMin() { + assertThat(DataUtil.isWithinBounds(0L, 1L, 10L)).isFalse(); + } + + @Test + void isWithinBounds_shouldReturnFalse_WhenValueIsAboveMax() { + assertThat(DataUtil.isWithinBounds(11L, 1L, 10L)).isFalse(); + } + + @Test + void isWithinBounds_shouldReturnTrue_WhenValueIsEqualToMin() { + assertThat(DataUtil.isWithinBounds(1L, 1L, 10L)).isTrue(); + } + + @Test + void isWithinBounds_shouldReturnTrue_WhenValueIsEqualToMax() { + assertThat(DataUtil.isWithinBounds(10L, 1L, 10L)).isTrue(); + } + + @Test + void isWithinBounds_shouldReturnFalseWhenValueIsNull() { + assertThat(DataUtil.isWithinBounds(null, 1L, 10L)).isFalse(); + } + }