From de2a2768139a90814a5c5c3ec31c678ace0613b4 Mon Sep 17 00:00:00 2001 From: cgi-jhjsimpson Date: Tue, 30 Jun 2026 14:33:09 +0100 Subject: [PATCH 1/3] Timezone fix. --- ...CaseControllerAdminGetCaseByIdIntTest.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/integrationTest/java/uk/gov/hmcts/darts/cases/controller/CaseControllerAdminGetCaseByIdIntTest.java b/src/integrationTest/java/uk/gov/hmcts/darts/cases/controller/CaseControllerAdminGetCaseByIdIntTest.java index 200b726b8cd..68b663c33c6 100644 --- a/src/integrationTest/java/uk/gov/hmcts/darts/cases/controller/CaseControllerAdminGetCaseByIdIntTest.java +++ b/src/integrationTest/java/uk/gov/hmcts/darts/cases/controller/CaseControllerAdminGetCaseByIdIntTest.java @@ -134,8 +134,8 @@ void adminGetCaseById_WithCaseOpenAndReportingRestrictions() throws Exception { String actualResponse = mvcResult.getResponse().getContentAsString(); String expectedResponse = getContentsFromFile( "tests/cases/CaseControllerAdminGetCaseByIdTest/testCaseOpen/expectedResponse.json"); - expectedResponse = expectedResponse.replace("", courtCase.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); - expectedResponse = expectedResponse.replace("", courtCase.getLastModifiedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); + expectedResponse = expectedResponse.replace("", formatAsUtc(courtCase.getCreatedDateTime())); + expectedResponse = expectedResponse.replace("", formatAsUtc(courtCase.getLastModifiedDateTime())); JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); } @@ -176,8 +176,8 @@ void adminGetCaseById_WithCaseClosedAndReportingRestrictions() throws Exception String actualResponse = mvcResult.getResponse().getContentAsString(); String expectedResponse = getContentsFromFile( "tests/cases/CaseControllerAdminGetCaseByIdTest/testCaseClosed/expectedResponse.json"); - expectedResponse = expectedResponse.replace("", courtCase.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); - expectedResponse = expectedResponse.replace("", courtCase.getLastModifiedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); + expectedResponse = expectedResponse.replace("", formatAsUtc(courtCase.getCreatedDateTime())); + expectedResponse = expectedResponse.replace("", formatAsUtc(courtCase.getLastModifiedDateTime())); JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); } @@ -213,8 +213,8 @@ void adminGetCaseById_IsAnonymised() throws Exception { String expectedResponse = getContentsFromFile( "tests/cases/CaseControllerAdminGetCaseByIdTest/testIsAnonymised/expectedResponse.json"); expectedResponse = expectedResponse - .replace("", courtCase.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) - .replace("", courtCase.getLastModifiedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) + .replace("", formatAsUtc(courtCase.getCreatedDateTime())) + .replace("", formatAsUtc(courtCase.getLastModifiedDateTime())) .replace("", String.valueOf(anonymisedBy.getId())); JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); } @@ -248,8 +248,8 @@ void adminGetCaseById_IsDeleted() throws Exception { String expectedResponse = getContentsFromFile( "tests/cases/CaseControllerAdminGetCaseByIdTest/expectedResponse_isDeleted.json"); expectedResponse = expectedResponse - .replace("", courtCase.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) - .replace("", courtCase.getLastModifiedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) + .replace("", formatAsUtc(courtCase.getCreatedDateTime())) + .replace("", formatAsUtc(courtCase.getLastModifiedDateTime())) .replace("", String.valueOf(deletedBy.getId())); JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); } @@ -299,8 +299,8 @@ void adminGetCaseById_WithRetentionAndAdditionalCaseDetails() throws Exception { String expectedResponse = getContentsFromFile( "tests/cases/CaseControllerAdminGetCaseByIdTest/expectedResponse_withRetentionAndAdditionalCaseDetails.json"); expectedResponse = expectedResponse - .replace("", courtCase.getCreatedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)) - .replace("", courtCase.getLastModifiedDateTime().format(DateTimeFormatter.ISO_DATE_TIME)); + .replace("", formatAsUtc(courtCase.getCreatedDateTime())) + .replace("", formatAsUtc(courtCase.getLastModifiedDateTime())); JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.NON_EXTENSIBLE); } @@ -328,4 +328,8 @@ private List createEventsWithDifferentTimestamps(List Date: Wed, 1 Jul 2026 16:40:17 +0100 Subject: [PATCH 2/3] Added some minor validation and tests. --- .../resources/openapi/transcriptions.yaml | 4 ++ .../TranscriptionOpenApiContractTest.java | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/main/resources/openapi/transcriptions.yaml b/src/main/resources/openapi/transcriptions.yaml index cd0e4bd0c28..bf84eef063e 100644 --- a/src/main/resources/openapi/transcriptions.yaml +++ b/src/main/resources/openapi/transcriptions.yaml @@ -456,17 +456,21 @@ paths: schema: type: integer format: int64 + description: Transcription ID. Validated by the application for min and max range. requestBody: + required: true content: multipart/form-data: schema: required: - transcript type: object + additionalProperties: false properties: transcript: type: string format: binary + description: Transcript file. Validated by the application for file extension, content type, and maximum size. responses: '200': description: OK diff --git a/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java b/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java index af7b89ab3f8..2ace8a520d5 100644 --- a/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java +++ b/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java @@ -4,7 +4,9 @@ import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.SimpleRequest; import com.atlassian.oai.validator.report.ValidationReport; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import uk.gov.hmcts.darts.util.ValidationConstants; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -59,4 +61,67 @@ void openApi_ShouldReturnNoError_WhenValidTranscriptionIdUsed() { assertTrue(report.getMessages().isEmpty(), "Expected no validation errors for a valid transcription_id"); } + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + class TranscriptionsTranscriptionIdDocumentPost { + + @Test + void openApi_ShouldReturnNoError_WhenValidTranscriptionIdUsed() { + String boundary = "test-boundary"; + Request request = SimpleRequest.Builder + .post("/transcriptions/1/document") + .withContentType("multipart/form-data; boundary=" + boundary) + .withBody(multipartTranscriptBody(boundary)) + .build(); + + ValidationReport report = VALIDATOR.validateRequest(request); + + assertTrue(report.getMessages().isEmpty(), "Expected no validation errors for a valid transcript upload request"); + } + + @Test + void openApi_ShouldReturnError_WhenUnsupportedContentTypeUsed() { + Request request = SimpleRequest.Builder + .post("/transcriptions/1/document") + .withContentType("application/json") + .withBody("{\"transcript\":\"Transcript content\"}") + .build(); + + ValidationReport report = VALIDATOR.validateRequest(request); + + assertHasMessageContaining(report, "does not match any allowed types"); + } + + @Test + void openApi_ShouldReturnError_WhenRequestBodyIsMissing() { + Request request = SimpleRequest.Builder + .post("/transcriptions/1/document") + .withContentType("multipart/form-data") + .build(); + + ValidationReport report = VALIDATOR.validateRequest(request); + + assertHasMessageContaining(report, "A request body is required but none found"); + } + + private String multipartTranscriptBody(String boundary) { + return String.join("\r\n", + "--" + boundary, + "Content-Disposition: form-data; name=\"transcript\"; filename=\"transcript.txt\"", + "Content-Type: text/plain", + "", + "Transcript content", + "--" + boundary + "--", + ""); + } + } + + private void assertHasMessageContaining(ValidationReport report, String expectedSubstring) { + assertTrue( + report.getMessages().stream() + .anyMatch(message -> message.getMessage().contains(expectedSubstring)), + () -> "Expected validation message containing '%s' but got %s".formatted(expectedSubstring, report.getMessages()) + ); + } } From 21094dddf700da670d17f98c95dc924e77a8d815 Mon Sep 17 00:00:00 2001 From: cgi-jhjsimpson Date: Thu, 2 Jul 2026 10:27:40 +0100 Subject: [PATCH 3/3] Test transcription_id in the URL path for NaN. --- .../openapi/TranscriptionOpenApiContractTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java b/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java index 2ace8a520d5..e8a87e29daa 100644 --- a/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java +++ b/src/test/java/uk/gov/hmcts/darts/openapi/TranscriptionOpenApiContractTest.java @@ -80,6 +80,17 @@ void openApi_ShouldReturnNoError_WhenValidTranscriptionIdUsed() { assertTrue(report.getMessages().isEmpty(), "Expected no validation errors for a valid transcript upload request"); } + @Test + void openApi_ShouldReturnError_WhenTranscriptionIdIsNotNumeric() { + Request request = SimpleRequest.Builder + .get("/transcriptions/not-a-number/document") + .build(); + + ValidationReport report = VALIDATOR.validateRequest(request); + + assertHasMessageContaining(report, "Instance type (string) does not match any allowed primitive type"); + } + @Test void openApi_ShouldReturnError_WhenUnsupportedContentTypeUsed() { Request request = SimpleRequest.Builder