diff --git a/docs/superpowers/plans/2026-05-16-amp504-raw-payload-implementation.md b/docs/superpowers/plans/2026-05-16-amp504-raw-payload-implementation.md index 221d4d1f14..f4f7b17f38 100644 --- a/docs/superpowers/plans/2026-05-16-amp504-raw-payload-implementation.md +++ b/docs/superpowers/plans/2026-05-16-amp504-raw-payload-implementation.md @@ -1,4 +1,4 @@ -# AMP-504: PCR rawPayload Forwarding — Implementation Plan (Design 2) +# AMP-504: PCR rawPayload Forwarding — Implementation Plan (Design) > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. diff --git a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessor.java b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessor.java index 3aad215465..26ff4481e3 100644 --- a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessor.java +++ b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessor.java @@ -12,6 +12,7 @@ import uk.gov.justice.core.courts.prisonCourtRegisterDocument.PrisonCourtRegisterDefendant; import uk.gov.justice.core.courts.prisonCourtRegisterDocument.PrisonCourtRegisterHearingVenue; import uk.gov.justice.services.common.converter.JsonObjectToObjectConverter; +import uk.gov.justice.services.common.converter.ObjectToJsonObjectConverter; import uk.gov.justice.services.common.util.UtcClock; import uk.gov.justice.services.core.annotation.Handles; import uk.gov.justice.services.core.annotation.ServiceComponent; @@ -111,6 +112,9 @@ public class PrisonCourtRegisterEventProcessor { @Inject private HearingResultsDocumentSubscriptionClient hearingResultsDocumentSubscriptionClient; + @Inject + private ObjectToJsonObjectConverter objectToJsonObjectConverter; + @SuppressWarnings("squid:S1160") @Handles("progression.event.prison-court-register-recorded") public void generatePrisonCourtRegister(final JsonEnvelope envelope) { @@ -231,9 +235,12 @@ public void sendPrisonCourtRegisterV2(final JsonEnvelope envelope) throws Inter ? emailRecipients.get(0).getEmail() : ""; Instant createdAt = envelope.metadata().createdAt().orElse(ZonedDateTime.now()).toInstant(); - PcrEventPayload pcrEventPayload = hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(prisonCourtRegisterGenerated, emailRecipient, createdAt); - final UUID fileId = prisonCourtRegisterGenerated.getFileId(); + final String rawPayload = fileService.retrievePayload(fileId) + .map(JsonObject::toString) + .orElseGet(() -> objectToJsonObjectConverter.convert(prisonCourtRegisterGenerated).toString()); + PcrEventPayload pcrEventPayload = hearingResultsDocumentSubscriptionPCRMapper + .mapPcrForhearingResultsDocument(prisonCourtRegisterGenerated, emailRecipient, createdAt, rawPayload); final String prisonCourtRegisterId = envelope.payloadAsJsonObject().containsKey("id") ? envelope.payloadAsJsonObject().getString("id") : fileId.toString(); diff --git a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/FileService.java b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/FileService.java index 1a1b68db00..aec16a1dab 100644 --- a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/FileService.java +++ b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/FileService.java @@ -2,14 +2,19 @@ import static javax.json.Json.createObjectBuilder; +import uk.gov.justice.services.fileservice.api.FileRetriever; import uk.gov.justice.services.fileservice.api.FileServiceException; import uk.gov.justice.services.fileservice.api.FileStorer; import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.StringReader; import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.UUID; import javax.inject.Inject; +import javax.json.Json; import javax.json.JsonObject; import org.slf4j.Logger; @@ -23,6 +28,9 @@ public class FileService { @Inject private FileStorer fileStorer; + @Inject + private FileRetriever fileRetriever; + public UUID storePayload(final JsonObject payload, final String fileName, final String templateName) { try { final byte[] jsonPayloadInBytes = payload.toString().getBytes(StandardCharsets.UTF_8); @@ -42,4 +50,21 @@ public UUID storePayload(final JsonObject payload, final String fileName, final throw new RuntimeException(fileServiceException.getMessage()); } } + + public Optional retrievePayload(final UUID fileId) { + try { + return fileRetriever.retrieve(fileId).map(ref -> { + try (InputStream stream = ref.getContentStream()) { + final String json = new String(stream.readAllBytes(), StandardCharsets.UTF_8); + return Json.createReader(new StringReader(json)).readObject(); + } catch (java.io.IOException e) { + LOGGER.error("Failed to read content stream for fileId {}", fileId, e); + throw new RuntimeException(e); + } + }); + } catch (FileServiceException e) { + LOGGER.error("Failed to retrieve payload from file service for fileId {}", fileId, e); + throw new RuntimeException(e); + } + } } diff --git a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/dto/PcrEventPayload.java b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/dto/PcrEventPayload.java index 28b7b57718..d26424e3e4 100644 --- a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/dto/PcrEventPayload.java +++ b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/dto/PcrEventPayload.java @@ -1,5 +1,6 @@ package uk.gov.moj.cpp.progression.service.amp.dto; +import com.fasterxml.jackson.annotation.JsonRawValue; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -24,5 +25,7 @@ public class PcrEventPayload { private UUID materialId; private Instant timestamp; private PcrEventPayloadDefendant defendant; + @JsonRawValue + private String rawPayload; } diff --git a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapper.java b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapper.java index 23cb0ad6a3..123b3bab8c 100644 --- a/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapper.java +++ b/progression-event/progression-event-processor/src/main/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapper.java @@ -17,14 +17,19 @@ @Slf4j public class HearingResultsDocumentSubscriptionPCRMapper { - public PcrEventPayload mapPcrForhearingResultsDocument(PrisonCourtRegisterGeneratedV2 pcrIn, String prisonEmail, Instant createdAt) { + public PcrEventPayload mapPcrForhearingResultsDocument( + final PrisonCourtRegisterGeneratedV2 pcrIn, + final String prisonEmail, + final Instant createdAt, + final String rawPayload) { return PcrEventPayload.builder() .eventType(PcrEventType.PRISON_COURT_REGISTER_GENERATED) .eventId(pcrIn.getId()) .hearingId(pcrIn.getHearingId()) .materialId(pcrIn.getMaterialId()) - .timestamp(Instant.now()) + .timestamp(createdAt) .defendant(mapDefendant(pcrIn, prisonEmail)) + .rawPayload(rawPayload) .build(); } diff --git a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessorTest.java b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessorTest.java index 88a62d3156..ec322d9710 100644 --- a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessorTest.java +++ b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/processor/PrisonCourtRegisterEventProcessorTest.java @@ -10,6 +10,7 @@ import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.justice.services.common.converter.jackson.ObjectMapperProducer; import uk.gov.justice.core.courts.PrisonCourtRegisterGenerated; import uk.gov.justice.core.courts.PrisonCourtRegisterGeneratedV2; import uk.gov.justice.core.courts.PrisonCourtRegisterRecorded; @@ -49,6 +50,8 @@ import static java.util.Collections.singletonList; import static java.util.UUID.randomUUID; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -69,7 +72,8 @@ public class PrisonCourtRegisterEventProcessorTest { private PrisonCourtRegisterEventProcessor prisonCourtRegisterEventProcessor; private final ObjectMapper objectMapper = new ObjectMapperProducer().objectMapper(); - private final ObjectToJsonObjectConverter objectToJsonObjectConverter = new ObjectToJsonObjectConverter(objectMapper); + @Spy + private ObjectToJsonObjectConverter objectToJsonObjectConverter = new ObjectToJsonObjectConverter(new ObjectMapperProducer().objectMapper()); @Mock private SystemDocGeneratorService systemDocGeneratorService; @@ -227,7 +231,8 @@ public void shouldSendPrisonCourtRegisterV2() throws InterruptedException { .materialId(randomUUID()) .eventId(randomUUID()) .build(); - when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class))).thenReturn(pcrEventPayload); + when(fileService.retrievePayload(any(UUID.class))).thenReturn(Optional.empty()); + when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class), any())).thenReturn(pcrEventPayload); when(applicationParameters.getHearingResultsDocumentSubscriptionUrl()).thenReturn("http://amp-url"); when(hearingResultsDocumentSubscriptionClient.post("http://amp-url", pcrEventPayload)).thenReturn(Response.ok().build()); when(applicationParameters.getHearingResultsDocumentSubscriptionRetryTimes()).thenReturn("3"); @@ -236,7 +241,7 @@ public void shouldSendPrisonCourtRegisterV2() throws InterruptedException { prisonCourtRegisterEventProcessor.sendPrisonCourtRegisterV2(requestMessage); verify(hearingResultsDocumentSubscriptionClient).post("http://amp-url", pcrEventPayload); - verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class)); + verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class), any()); } @Test @@ -265,7 +270,8 @@ public void shouldSendPrisonCourtRegisterV2WhenRecipientsHaveNoEmailAddress() th .build(); // Recipients exist but don't have emailAddress1, so filterEmailRecipients returns empty list // resulting in empty string for emailRecipient - when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq(""), any(Instant.class))).thenReturn(pcrEventPayload); + when(fileService.retrievePayload(any(UUID.class))).thenReturn(Optional.empty()); + when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq(""), any(Instant.class), any())).thenReturn(pcrEventPayload); when(applicationParameters.getHearingResultsDocumentSubscriptionUrl()).thenReturn("http://hrds-address"); when(hearingResultsDocumentSubscriptionClient.post("http://hrds-address", pcrEventPayload)).thenReturn(Response.ok().build()); when(applicationParameters.getHearingResultsDocumentSubscriptionRetryTimes()).thenReturn("3"); @@ -274,7 +280,7 @@ public void shouldSendPrisonCourtRegisterV2WhenRecipientsHaveNoEmailAddress() th prisonCourtRegisterEventProcessor.sendPrisonCourtRegisterV2(requestMessage); verify(hearingResultsDocumentSubscriptionClient).post("http://hrds-address", pcrEventPayload); - verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq(""), any(Instant.class)); + verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq(""), any(Instant.class), any()); } @Test @@ -301,7 +307,8 @@ public void shouldSendPrisonCourtRegisterV2WithMissingIdUsesFileId() throws Inte .materialId(randomUUID()) .eventId(randomUUID()) .build(); - when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class))).thenReturn(pcrEventPayload); + when(fileService.retrievePayload(any(UUID.class))).thenReturn(Optional.empty()); + when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class), any())).thenReturn(pcrEventPayload); when(applicationParameters.getHearingResultsDocumentSubscriptionUrl()).thenReturn("http://hrds-address"); when(hearingResultsDocumentSubscriptionClient.post("http://hrds-address", pcrEventPayload)).thenReturn(Response.ok().build()); when(applicationParameters.getHearingResultsDocumentSubscriptionRetryTimes()).thenReturn("3"); @@ -310,7 +317,7 @@ public void shouldSendPrisonCourtRegisterV2WithMissingIdUsesFileId() throws Inte prisonCourtRegisterEventProcessor.sendPrisonCourtRegisterV2(requestMessage); verify(hearingResultsDocumentSubscriptionClient).post("http://hrds-address", pcrEventPayload); - verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class)); + verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class), any()); } @Test @@ -337,7 +344,8 @@ public void shouldSendPrisonCourtRegisterV2WithMissingCreatedAtUsesCurrentTime() .materialId(randomUUID()) .eventId(randomUUID()) .build(); - when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class))).thenReturn(pcrEventPayload); + when(fileService.retrievePayload(any(UUID.class))).thenReturn(Optional.empty()); + when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class), any())).thenReturn(pcrEventPayload); when(applicationParameters.getHearingResultsDocumentSubscriptionUrl()).thenReturn("http://hrds-address"); when(hearingResultsDocumentSubscriptionClient.post("http://hrds-address", pcrEventPayload)).thenReturn(Response.ok().build()); when(applicationParameters.getHearingResultsDocumentSubscriptionRetryTimes()).thenReturn("3"); @@ -346,7 +354,7 @@ public void shouldSendPrisonCourtRegisterV2WithMissingCreatedAtUsesCurrentTime() prisonCourtRegisterEventProcessor.sendPrisonCourtRegisterV2(requestMessage); verify(hearingResultsDocumentSubscriptionClient).post("http://hrds-address", pcrEventPayload); - verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class)); + verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument(any(PrisonCourtRegisterGeneratedV2.class), eq("test@hmcst.net"), any(Instant.class), any()); } @Test @@ -376,4 +384,84 @@ public void shouldSendPrisonCourtRegisterWithDefendantHasNoDateOfBirth() { assertThat(notificationJsonObjectCaptor.getValue().getString("notificationId"), is(notNullValue())); } + @Test + public void shouldPassRawPayloadFromFileServiceToMapper() throws InterruptedException { + final UUID fileId = randomUUID(); + final JsonObject sourcePayloadJson = Json.createObjectBuilder() + .add("courtHouse", "Southwark Crown Court").build(); + + final PrisonCourtRegisterGeneratedV2 prisonCourtRegisterGeneratedV2 = + PrisonCourtRegisterGeneratedV2.prisonCourtRegisterGeneratedV2() + .withId(randomUUID()) + .withFileId(fileId) + .withMaterialId(randomUUID()) + .withHearingId(randomUUID()) + .withCourtCentreId(randomUUID()) + .withRecipients(singletonList(new PrisonCourtRegisterRecipient.Builder() + .withEmailAddress1("prison@example.com") + .withEmailTemplateName("templateName").build())) + .withDefendant(PrisonCourtRegisterDefendant.prisonCourtRegisterDefendant() + .withName("Test Defendant").build()) + .build(); + + final JsonEnvelope requestMessage = envelopeFrom( + MetadataBuilderFactory.metadataWithRandomUUID("progression.event.prison-court-register-generated-v2"), + objectToJsonObjectConverter.convert(prisonCourtRegisterGeneratedV2)); + + when(applicationParameters.getHearingResultsDocumentSubscriptionUrl()).thenReturn("http://hrds/notifications"); + when(applicationParameters.getHearingResultsDocumentSubscriptionRetryTimes()).thenReturn("3"); + when(applicationParameters.getHearingResultsDocumentSubscriptionRetryInterval()).thenReturn("1000"); + when(fileService.retrievePayload(fileId)).thenReturn(Optional.of(sourcePayloadJson)); + when(hearingResultsDocumentSubscriptionClient.post(anyString(), any())) + .thenReturn(Response.ok().build()); + when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument( + any(), anyString(), any(), any())).thenReturn(PcrEventPayload.builder().build()); + + prisonCourtRegisterEventProcessor.sendPrisonCourtRegisterV2(requestMessage); + + final ArgumentCaptor rawPayloadCaptor = ArgumentCaptor.forClass(String.class); + verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument( + any(), anyString(), any(), rawPayloadCaptor.capture()); + assertThat(rawPayloadCaptor.getValue(), containsString("Southwark Crown Court")); + } + + @Test + public void shouldFallBackToV2EventJsonWhenFileServiceReturnsEmpty() throws InterruptedException { + final UUID fileId = randomUUID(); + + final PrisonCourtRegisterGeneratedV2 prisonCourtRegisterGeneratedV2 = + PrisonCourtRegisterGeneratedV2.prisonCourtRegisterGeneratedV2() + .withId(randomUUID()) + .withFileId(fileId) + .withMaterialId(randomUUID()) + .withHearingId(randomUUID()) + .withCourtCentreId(randomUUID()) + .withRecipients(singletonList(new PrisonCourtRegisterRecipient.Builder() + .withEmailAddress1("prison@example.com") + .withEmailTemplateName("templateName").build())) + .withDefendant(PrisonCourtRegisterDefendant.prisonCourtRegisterDefendant() + .withName("Test Defendant").build()) + .build(); + + final JsonEnvelope requestMessage = envelopeFrom( + MetadataBuilderFactory.metadataWithRandomUUID("progression.event.prison-court-register-generated-v2"), + objectToJsonObjectConverter.convert(prisonCourtRegisterGeneratedV2)); + + when(applicationParameters.getHearingResultsDocumentSubscriptionUrl()).thenReturn("http://hrds/notifications"); + when(applicationParameters.getHearingResultsDocumentSubscriptionRetryTimes()).thenReturn("3"); + when(applicationParameters.getHearingResultsDocumentSubscriptionRetryInterval()).thenReturn("1000"); + when(fileService.retrievePayload(fileId)).thenReturn(Optional.empty()); + when(hearingResultsDocumentSubscriptionClient.post(anyString(), any())) + .thenReturn(Response.ok().build()); + when(hearingResultsDocumentSubscriptionPCRMapper.mapPcrForhearingResultsDocument( + any(), anyString(), any(), any())).thenReturn(PcrEventPayload.builder().build()); + + prisonCourtRegisterEventProcessor.sendPrisonCourtRegisterV2(requestMessage); + + final ArgumentCaptor rawPayloadCaptor = ArgumentCaptor.forClass(String.class); + verify(hearingResultsDocumentSubscriptionPCRMapper).mapPcrForhearingResultsDocument( + any(), anyString(), any(), rawPayloadCaptor.capture()); + assertThat(rawPayloadCaptor.getValue(), is(notNullValue())); + } + } \ No newline at end of file diff --git a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/FileServiceTest.java b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/FileServiceTest.java index cb9ea23c3c..1e29efa7c1 100644 --- a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/FileServiceTest.java +++ b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/FileServiceTest.java @@ -1,19 +1,27 @@ package uk.gov.moj.cpp.progression.service; +import static java.util.UUID.randomUUID; import static javax.json.Json.createObjectBuilder; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import uk.gov.justice.services.core.sender.Sender; +import uk.gov.justice.services.fileservice.api.FileRetriever; import uk.gov.justice.services.fileservice.api.FileServiceException; import uk.gov.justice.services.fileservice.api.FileStorer; +import uk.gov.justice.services.fileservice.domain.FileReference; +import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Optional; import java.util.UUID; +import javax.json.Json; import javax.json.JsonObject; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -30,6 +38,8 @@ public class FileServiceTest { private FileService fileService; @Mock private FileStorer fileStorer; + @Mock + private FileRetriever fileRetriever; @Test public void shouldStorePayloadIntoFileService() throws FileServiceException { @@ -60,4 +70,31 @@ public void shouldThrowExceptionWhenFileServiceFailedToStore() throws FileServic } + @Test + void retrievePayloadShouldReturnParsedJsonObject() throws FileServiceException { + final UUID fileId = randomUUID(); + final String json = "{\"courtHouse\":\"Southwark Crown Court\",\"registerDate\":\"2024-10-01\"}"; + final FileReference fileRef = new FileReference( + fileId, + Json.createObjectBuilder().build(), + new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8))); + when(fileRetriever.retrieve(fileId)).thenReturn(Optional.of(fileRef)); + + final Optional result = fileService.retrievePayload(fileId); + + assertTrue(result.isPresent()); + assertThat(result.get().getString("courtHouse"), equalTo("Southwark Crown Court")); + assertThat(result.get().getString("registerDate"), equalTo("2024-10-01")); + } + + @Test + void retrievePayloadShouldReturnEmptyWhenFileNotFound() throws FileServiceException { + final UUID fileId = randomUUID(); + when(fileRetriever.retrieve(fileId)).thenReturn(Optional.empty()); + + final Optional result = fileService.retrievePayload(fileId); + + assertTrue(result.isEmpty()); + } + } \ No newline at end of file diff --git a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapperTest.java b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapperTest.java index f71b9c2a73..2093498c66 100644 --- a/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapperTest.java +++ b/progression-event/progression-event-processor/src/test/java/uk/gov/moj/cpp/progression/service/amp/mappers/HearingResultsDocumentSubscriptionPCRMapperTest.java @@ -19,8 +19,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; import static org.junit.jupiter.api.Assertions.assertNull; import static uk.gov.moj.cpp.progression.service.amp.dto.PcrEventType.PRISON_COURT_REGISTER_GENERATED; @@ -49,26 +47,47 @@ class HearingResultsDocumentSubscriptionPCRMapperTest { @Test void mapperShouldCreateAmpPayload() { - Instant createdAt = Instant.now(); - PcrEventPayload payload = mapper.mapPcrForhearingResultsDocument(pcr, "wandsworth@example.com", createdAt); + final Instant createdAt = Instant.parse("2024-10-01T10:00:00Z"); + final PcrEventPayload payload = mapper.mapPcrForhearingResultsDocument(pcr, "wandsworth@example.com", createdAt, null); assertThat(payload.getEventId(), equalTo(pcr.getId())); assertThat(payload.getMaterialId(), equalTo(pcr.getMaterialId())); assertThat(payload.getHearingId(), equalTo(pcr.getHearingId())); assertThat(payload.getEventType(), equalTo(PRISON_COURT_REGISTER_GENERATED)); - assertThat(payload.getTimestamp(), is(notNullValue())); + assertThat(payload.getTimestamp(), equalTo(createdAt)); assertDefendant(payload.getDefendant()); } @Test void mapperShouldBeNullSafe() { - PrisonCourtRegisterGeneratedV2 emptyPcr = PrisonCourtRegisterGeneratedV2.prisonCourtRegisterGeneratedV2() + final PrisonCourtRegisterGeneratedV2 emptyPcr = PrisonCourtRegisterGeneratedV2.prisonCourtRegisterGeneratedV2() .build(); - PcrEventPayload payload = mapper.mapPcrForhearingResultsDocument(emptyPcr, null, null); + final PcrEventPayload payload = mapper.mapPcrForhearingResultsDocument(emptyPcr, null, null, null); assertNull(payload.getEventId()); } + @Test + void mapperShouldIncludeRawPayload() { + final Instant createdAt = Instant.parse("2024-10-01T10:00:00Z"); + final String rawPayload = "{\"courtHouse\":\"Southwark Crown Court\"}"; + + final PcrEventPayload payload = mapper.mapPcrForhearingResultsDocument( + pcr, "wandsworth@example.com", createdAt, rawPayload); + + assertThat(payload.getRawPayload(), equalTo(rawPayload)); + } + + @Test + void mapperShouldUseCreatedAtNotNow() { + final Instant createdAt = Instant.parse("2024-10-01T10:00:00Z"); + + final PcrEventPayload payload = mapper.mapPcrForhearingResultsDocument( + pcr, "wandsworth@example.com", createdAt, null); + + assertThat(payload.getTimestamp(), equalTo(createdAt)); + } + private void assertDefendant(PcrEventPayloadDefendant defendant) { assertThat(defendant.getMasterDefendantId(), equalTo(UUID.fromString("d78e8cac-991c-43fa-86a7-8fc6b857308a"))); assertThat(defendant.getName(), equalTo("Defendant Name"));