diff --git a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/ServiceBusQueueTest.java b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/ServiceBusQueueTest.java index 66c532ac..f3033f01 100644 --- a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/ServiceBusQueueTest.java +++ b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/ServiceBusQueueTest.java @@ -1,5 +1,6 @@ package uk.gov.hmcts.cp.subscription.http; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -8,6 +9,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestClient; +import java.util.UUID; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -18,8 +21,8 @@ @Slf4j class ServiceBusQueueTest { private static final String AUTHORIZATION = "Authorization"; + private static final String CORRELATION_ID_KEY = "X-Correlation-Id"; - private String testClientId = "11111111-2222-3333-4444-555555555555"; private String baseUrl = System.getProperty("app.baseUrl", "http://localhost:8082"); private RestClient restClient = RestClient.create(); @@ -34,41 +37,41 @@ void beforeEach() { } } + @Test + void post_notification_without_correlation_id_should_have_one_generated_in_response() { + final String postUrl = baseUrl + "/notifications"; + ResponseEntity postResponse = restClient.post() + .uri(postUrl) + .contentType(MediaType.APPLICATION_JSON) + .body(notificationBody()) + .retrieve() + .toEntity(String.class); + assertThat(postResponse.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); + String generatedCorrelationId = postResponse.getHeaders().getFirst(CORRELATION_ID_KEY); + assertThat(generatedCorrelationId).isNotNull(); + log.info("filter generated correlationId:{}", generatedCorrelationId); + } + @Test void post_notification() { final String postUrl = baseUrl + "/notifications"; + String correlationId = UUID.randomUUID().toString(); ResponseEntity postResponse = restClient.post() .uri(postUrl) + .header(CORRELATION_ID_KEY, correlationId) .contentType(MediaType.APPLICATION_JSON) .body(notificationBody()) .retrieve() .toEntity(String.class); assertThat(postResponse.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); + assertThat(postResponse.getHeaders().getFirst(CORRELATION_ID_KEY)).isEqualTo(correlationId); log.info("postResponse:{}", postResponse.getBody()); } + @SneakyThrows private String notificationBody() { - return "{\n" + - " \"eventId\": \"3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n" + - " \"materialId\": \"123e4567-e89b-12d3-a456-426614174000\",\n" + - " \"eventType\": \"PRISON_COURT_REGISTER_GENERATED\",\n" + - " \"timestamp\": \"2024-01-15T10:30:00Z\",\n" + - " \"defendant\": {\n" + - " \"masterDefendantId\": \"8b8f1c3a-9a41-4f0f-b8a0-1c23d9e8a111\",\n" + - " \"name\": \"John Doe\",\n" + - " \"dateOfBirth\": \"1990-05-15\",\n" + - " \"custodyEstablishmentDetails\": {\n" + - " \"emailAddress\": \"prison@moj.gov.uk\"\n" + - " },\n" + - " \"cases\": [\n" + - " {\n" + - " \"urn\": \"CT98KRYCAP\"\n" + - " },\n" + - " {\n" + - " \"urn\": \"AB75123123\"\n" + - " }\n" + - " ]\n" + - " }\n" + - "}"; + return new String(getClass().getClassLoader() + .getResourceAsStream("files/notification-body.json") + .readAllBytes()); } } \ No newline at end of file diff --git a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/SubscriptionApiTest.java b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/SubscriptionApiTest.java index 67ef6d5a..ccd1000e 100644 --- a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/SubscriptionApiTest.java +++ b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/SubscriptionApiTest.java @@ -1,6 +1,7 @@ package uk.gov.hmcts.cp.subscription.http; import com.fasterxml.jackson.databind.JsonNode; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -9,6 +10,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestClient; +import uk.gov.hmcts.cp.subscription.http.util.JwtHelper; +import uk.gov.hmcts.cp.subscription.http.util.JsonMapper; import java.util.UUID; @@ -24,6 +27,7 @@ @Slf4j class SubscriptionApiTest { private static final String AUTHORIZATION = "Authorization"; + private static final String CORRELATION_ID_KEY = "X-Correlation-Id"; private String testClientId = "11111111-2222-3333-4444-555555555555"; private String bearerToken = JwtHelper.bearerTokenWithAzp(testClientId); @@ -43,48 +47,78 @@ void beforeEach() { } + @Test + void create_subscription_without_correlation_id_should_have_one_generated_in_response() { + String clientId = UUID.randomUUID().toString(); + String token = JwtHelper.bearerTokenWithAzp(clientId); + + ResponseEntity response = restClient.post() + .uri("http://localhost:8090/client-subscriptions") + .header(AUTHORIZATION, token) + .contentType(MediaType.APPLICATION_JSON) + .body(subscriptionRequestBody()) + .retrieve() + .toEntity(String.class); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + String generatedCorrelationId = response.getHeaders().getFirst(CORRELATION_ID_KEY); + assertThat(generatedCorrelationId).isNotNull(); + log.info("generated correlationId:{}", generatedCorrelationId); + } + @Test void round_trip_subscription_should_work_ok() throws InterruptedException { + String correlationId = UUID.randomUUID().toString(); // To maker this idempotent we catch the 409 use the subscriptionId in the response. // i.e. From 409 Conflict: "{"error":"invalid_request","message":"subscription already exist with 215767e1-3da3-470e-b8aa-f5da1d79a064"} try { - UUID subscriptionId = createSubscription(); - getSubscription(subscriptionId); + UUID subscriptionId = createSubscription(correlationId); + getSubscription(subscriptionId, correlationId); } catch (HttpClientErrorException e) { log.info("Subscription already exists ... trying to parse subscriptionId from:{}", e.getMessage()); JsonNode jsonNode = new JsonMapper().toJsonNode(e.getResponseBodyAsString()); String message = String.valueOf(jsonNode.get("message")); String subscriptionIdString = message.replaceAll("subscription already exist with ", "").replaceAll("\"", ""); UUID subscriptionId = UUID.fromString(subscriptionIdString); - getSubscription(subscriptionId); + getSubscription(subscriptionId, correlationId); } } - private UUID createSubscription() { + private UUID createSubscription(String correlationId) { final String postUrl = baseUrl + "/client-subscriptions"; - final String body = "{\"notificationEndpoint\":{\"callbackUrl\":\"https://my-callback-url\"},\"eventTypes\":[\"PRISON_COURT_REGISTER_GENERATED\"]}"; ResponseEntity postResult = restClient.post() .uri(postUrl) .header(AUTHORIZATION, bearerToken) + .header(CORRELATION_ID_KEY, correlationId) .contentType(MediaType.APPLICATION_JSON) - .body(body) + .body(subscriptionRequestBody()) .retrieve() .toEntity(String.class); assertThat(postResult.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(postResult.getHeaders().getFirst(CORRELATION_ID_KEY)).isEqualTo(correlationId); JsonNode jsonNode = new JsonMapper().toJsonNode(postResult.getBody()); String subscriptiuonIdString = String.valueOf(jsonNode.get("clientSubscriptionId")).replaceAll("\"", ""); return UUID.fromString(subscriptiuonIdString); } - private void getSubscription(UUID subscriptionId) { + @SneakyThrows + private String subscriptionRequestBody() { + try (var stream = getClass().getClassLoader().getResourceAsStream("files/subscription-request.json")) { + return new String(stream.readAllBytes()); + } + } + + private void getSubscription(UUID subscriptionId, String correlationId) { final String getUrl = String.format("%s/client-subscriptions/%s", baseUrl, subscriptionId); ResponseEntity getResult = RestClient.builder().baseUrl(getUrl) .defaultHeader(AUTHORIZATION, bearerToken) + .defaultHeader(CORRELATION_ID_KEY, correlationId) .build() .get() .retrieve() .toEntity(String.class); assertThat(getResult.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(getResult.getBody()).contains("clientSubscriptionId\":\"" + subscriptionId); + assertThat(getResult.getHeaders().getFirst(CORRELATION_ID_KEY)).isEqualTo(correlationId); } } \ No newline at end of file diff --git a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/JsonMapper.java b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/util/JsonMapper.java similarity index 77% rename from apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/JsonMapper.java rename to apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/util/JsonMapper.java index 544c7070..3a458920 100644 --- a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/JsonMapper.java +++ b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/util/JsonMapper.java @@ -1,14 +1,12 @@ -package uk.gov.hmcts.cp.subscription.http; +package uk.gov.hmcts.cp.subscription.http.util; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; -import org.springframework.stereotype.Service; -@Service public class JsonMapper { - private ObjectMapper objectMapper = new ObjectMapper(); + private final ObjectMapper objectMapper = new ObjectMapper(); @SneakyThrows public String toJson(final Object object) { @@ -24,4 +22,4 @@ public T fromJson(final String json, final Class clazz) { public JsonNode toJsonNode(final String json) { return objectMapper.readTree(json); } -} +} \ No newline at end of file diff --git a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/JwtHelper.java b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/util/JwtHelper.java similarity index 81% rename from apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/JwtHelper.java rename to apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/util/JwtHelper.java index 02fbf233..5adf4051 100644 --- a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/JwtHelper.java +++ b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/util/JwtHelper.java @@ -1,4 +1,4 @@ -package uk.gov.hmcts.cp.subscription.http; +package uk.gov.hmcts.cp.subscription.http.util; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -7,13 +7,13 @@ import java.util.Base64; @NoArgsConstructor(access = AccessLevel.PRIVATE) -final class JwtHelper { +public final class JwtHelper { - static String bearerTokenWithAzp(final String clientId) { + public static String bearerTokenWithAzp(final String clientId) { final String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; final String payload = "{\"azp\":\"" + clientId + "\"}"; final String headerB64 = Base64.getUrlEncoder().withoutPadding().encodeToString(header.getBytes(StandardCharsets.UTF_8)); final String payloadB64 = Base64.getUrlEncoder().withoutPadding().encodeToString(payload.getBytes(StandardCharsets.UTF_8)); return "Bearer " + headerB64 + "." + payloadB64 + ".sig"; } -} +} \ No newline at end of file diff --git a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/wiremock/MaterialServiceTest.java b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/wiremock/MaterialServiceTest.java index 9f7b871d..6ab49a80 100644 --- a/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/wiremock/MaterialServiceTest.java +++ b/apiTest/src/test/java/uk/gov/hmcts/cp/subscription/http/wiremock/MaterialServiceTest.java @@ -16,27 +16,32 @@ @Slf4j class MaterialServiceTest { private final String baseUrl = "http://localhost:8090"; + private final String CORRELATION_ID_KEY = "X-Correlation-Id"; private final RestClient restClient = RestClient.create(); - @Test void material_metadata() { UUID materialId = UUID.randomUUID(); + String correlationId = UUID.randomUUID().toString(); ResponseEntity response = restClient .get() .uri(metaDataUrl(materialId)) + .header(CORRELATION_ID_KEY, correlationId) .retrieve() .toEntity(String.class); log.info("material metadata:{}", response.getBody()); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getHeaders().getFirst(CORRELATION_ID_KEY)).isEqualTo(correlationId); } @Test void material_metadata_timeout() { UUID timeoutId = UUID.fromString("11111111-1111-1111-1111-111111111112"); + String correlationId = UUID.randomUUID().toString(); ResponseEntity response = restClient .get() .uri(metaDataUrl(timeoutId)) + .header(CORRELATION_ID_KEY, correlationId) .retrieve() .toEntity(String.class); log.info("material metadata timeout:{}", response.getBody()); diff --git a/apiTest/src/test/resources/files/notification-body.json b/apiTest/src/test/resources/files/notification-body.json new file mode 100644 index 00000000..5b6f19b1 --- /dev/null +++ b/apiTest/src/test/resources/files/notification-body.json @@ -0,0 +1,22 @@ +{ + "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "materialId": "123e4567-e89b-12d3-a456-426614174000", + "eventType": "PRISON_COURT_REGISTER_GENERATED", + "timestamp": "2024-01-15T10:30:00Z", + "defendant": { + "masterDefendantId": "8b8f1c3a-9a41-4f0f-b8a0-1c23d9e8a111", + "name": "John Doe", + "dateOfBirth": "1990-05-15", + "custodyEstablishmentDetails": { + "emailAddress": "prison@moj.gov.uk" + }, + "cases": [ + { + "urn": "CT98KRYCAP" + }, + { + "urn": "AB75123123" + } + ] + } +} diff --git a/apiTest/src/test/resources/files/subscription-created.json b/apiTest/src/test/resources/files/subscription-created.json new file mode 100644 index 00000000..cbe39008 --- /dev/null +++ b/apiTest/src/test/resources/files/subscription-created.json @@ -0,0 +1,3 @@ +{ + "clientSubscriptionId": "{{randomValue type='UUID'}}" +} \ No newline at end of file diff --git a/apiTest/src/test/resources/files/subscription-get.json b/apiTest/src/test/resources/files/subscription-get.json new file mode 100644 index 00000000..7b157717 --- /dev/null +++ b/apiTest/src/test/resources/files/subscription-get.json @@ -0,0 +1,7 @@ +{ + "clientSubscriptionId": "{{request.pathSegments.[1]}}", + "notificationEndpoint": { + "callbackUrl": "https://my-callback-url" + }, + "eventTypes": ["PRISON_COURT_REGISTER_GENERATED"] +} \ No newline at end of file diff --git a/apiTest/src/test/resources/files/subscription-request.json b/apiTest/src/test/resources/files/subscription-request.json new file mode 100644 index 00000000..e235360c --- /dev/null +++ b/apiTest/src/test/resources/files/subscription-request.json @@ -0,0 +1,6 @@ +{ + "notificationEndpoint": { + "callbackUrl": "https://my-callback-url" + }, + "eventTypes": ["PRISON_COURT_REGISTER_GENERATED"] +} diff --git a/apiTest/src/test/resources/mappings/client-subscriptions-get-mapping.json b/apiTest/src/test/resources/mappings/client-subscriptions-get-mapping.json new file mode 100644 index 00000000..05d907b2 --- /dev/null +++ b/apiTest/src/test/resources/mappings/client-subscriptions-get-mapping.json @@ -0,0 +1,15 @@ +{ + "request": { + "method": "GET", + "urlPattern": "/client-subscriptions/([a-zA-Z0-9-]*)" + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/json", + "X-Correlation-Id": "{{request.headers.X-Correlation-Id}}" + }, + "bodyFileName": "subscription-get.json", + "transformers": ["response-template"] + } +} \ No newline at end of file diff --git a/apiTest/src/test/resources/mappings/client-subscriptions-mapping.json b/apiTest/src/test/resources/mappings/client-subscriptions-mapping.json new file mode 100644 index 00000000..9a3d4522 --- /dev/null +++ b/apiTest/src/test/resources/mappings/client-subscriptions-mapping.json @@ -0,0 +1,15 @@ +{ + "request": { + "method": "POST", + "url": "/client-subscriptions" + }, + "response": { + "status": 201, + "headers": { + "Content-Type": "application/json", + "X-Correlation-Id": "{{#if request.headers.X-Correlation-Id}}{{request.headers.X-Correlation-Id}}{{else}}{{randomValue type='UUID'}}{{/if}}" + }, + "bodyFileName": "subscription-created.json", + "transformers": ["response-template"] + } +} \ No newline at end of file diff --git a/apiTest/src/test/resources/mappings/material-metadata-mapping.json b/apiTest/src/test/resources/mappings/material-metadata-mapping.json index 1f8af0b7..5f1ba827 100644 --- a/apiTest/src/test/resources/mappings/material-metadata-mapping.json +++ b/apiTest/src/test/resources/mappings/material-metadata-mapping.json @@ -6,8 +6,10 @@ "response": { "status": 200, "headers": { - "Content-Type": "application/json" + "Content-Type": "application/json", + "X-Correlation-Id": "{{request.headers.X-Correlation-Id}}" }, - "bodyFileName": "material-response.json" + "bodyFileName": "material-response.json", + "transformers": ["response-template"] } } diff --git a/src/main/java/uk/gov/hmcts/cp/filters/TracingFilter.java b/src/main/java/uk/gov/hmcts/cp/filters/TracingFilter.java index b198b62b..5442dc59 100644 --- a/src/main/java/uk/gov/hmcts/cp/filters/TracingFilter.java +++ b/src/main/java/uk/gov/hmcts/cp/filters/TracingFilter.java @@ -20,8 +20,7 @@ @Slf4j public class TracingFilter extends OncePerRequestFilter { - public static final String CORRELATION_ID_HEADER = "X-Correlation-Id"; - public static final String MDC_CORRELATION_ID = "correlationId"; + public static final String CORRELATION_ID_KEY = "X-Correlation-Id"; @Override protected boolean shouldNotFilter(@Nonnull final HttpServletRequest request) { @@ -33,15 +32,18 @@ protected void doFilterInternal(@Nonnull final HttpServletRequest request, @Nonnull final HttpServletResponse response, @Nonnull final FilterChain filterChain) throws ServletException, IOException { try { - String correlationId = request.getHeader(CORRELATION_ID_HEADER); - if (correlationId == null) { - correlationId = UUID.randomUUID().toString(); - } - MDC.put(MDC_CORRELATION_ID, correlationId); - response.setHeader(CORRELATION_ID_HEADER, correlationId); + final String correlationId = getCorrelationId(request); + MDC.put(CORRELATION_ID_KEY, getCorrelationId(request)); + response.setHeader(CORRELATION_ID_KEY, correlationId); filterChain.doFilter(request, response); } finally { - MDC.remove(MDC_CORRELATION_ID); + MDC.remove(CORRELATION_ID_KEY); } } + + private String getCorrelationId(final HttpServletRequest request) { + return request.getHeader(CORRELATION_ID_KEY) == null + ? UUID.randomUUID().toString() + : request.getHeader(CORRELATION_ID_KEY); + } } diff --git a/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientService.java b/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientService.java index c8151f79..f914448f 100644 --- a/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientService.java +++ b/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientService.java @@ -15,7 +15,7 @@ import java.time.OffsetDateTime; import java.util.UUID; -import static uk.gov.hmcts.cp.filters.TracingFilter.MDC_CORRELATION_ID; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; @Service @AllArgsConstructor @@ -30,7 +30,7 @@ public class ServiceBusClientService { public void queueMessage(final String topicName, final String targetUrl, final String messageString, final int failureCount) { final ServiceBusSenderClient serviceBusSenderClient = configService.senderClient(topicName); - final UUID correlationId = UUID.fromString(MDC.get(MDC_CORRELATION_ID)); + final UUID correlationId = UUID.fromString(MDC.get(CORRELATION_ID_KEY)); final ServiceBusWrappedMessage wrappedMessage = wrapperMapper.newWrapper(correlationId, failureCount, targetUrl, messageString); final OffsetDateTime nextTryTime = retryService.getNextTryTime(failureCount); final ServiceBusMessage serviceBusMessage = mapper.newMessage(jsonMapper.toJson(wrappedMessage), nextTryTime); diff --git a/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusProcessorService.java b/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusProcessorService.java index d33c764a..d777325b 100644 --- a/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusProcessorService.java +++ b/src/main/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusProcessorService.java @@ -18,7 +18,7 @@ import java.util.Map; import static org.awaitility.Awaitility.await; -import static uk.gov.hmcts.cp.filters.TracingFilter.MDC_CORRELATION_ID; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; import static uk.gov.hmcts.cp.servicebus.config.ServiceBusConfigService.PCR_INBOUND_TOPIC; import static uk.gov.hmcts.cp.servicebus.config.ServiceBusConfigService.PCR_OUTBOUND_TOPIC; @@ -85,7 +85,7 @@ public void handleMessage(final String topicName, final ServiceBusReceivedMessag final ServiceBusWrappedMessage queueMessage = jsonMapper.fromJson(wrappedMessageString, ServiceBusWrappedMessage.class); log.info("Processing {} with targetUrl:{}", topicName, queueMessage.getTargetUrl()); try { - MDC.put(MDC_CORRELATION_ID, queueMessage.getCorrelationId().toString()); + MDC.put(CORRELATION_ID_KEY, queueMessage.getCorrelationId().toString()); serviceBusHandlers.handleMessage(topicName, queueMessage.getTargetUrl(), queueMessage.getMessage()); } catch (Exception exception) { final int failureCount = queueMessage.getFailureCount() + 1; @@ -97,7 +97,7 @@ public void handleMessage(final String topicName, final ServiceBusReceivedMessag clientService.queueMessage(topicName, queueMessage.getTargetUrl(), queueMessage.getMessage(), failureCount); // Because we added a new message and swallowed the error then the current message will be dropped } finally { - MDC.remove(MDC_CORRELATION_ID); + MDC.remove(CORRELATION_ID_KEY); } } diff --git a/src/main/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptor.java b/src/main/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptor.java index 295f0f51..a12f9f05 100644 --- a/src/main/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptor.java +++ b/src/main/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptor.java @@ -9,7 +9,7 @@ import java.io.IOException; -import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_HEADER; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; @Component public class OutboundTracingInterceptor implements ClientHttpRequestInterceptor { @@ -18,9 +18,9 @@ public class OutboundTracingInterceptor implements ClientHttpRequestInterceptor public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException { - final String correlationId = MDC.get("correlationId"); + final String correlationId = MDC.get(CORRELATION_ID_KEY); if (correlationId != null) { - request.getHeaders().set(CORRELATION_ID_HEADER, correlationId); + request.getHeaders().set(CORRELATION_ID_KEY, correlationId); } return execution.execute(request, body); } diff --git a/src/main/java/uk/gov/hmcts/cp/subscription/controllers/NotificationController.java b/src/main/java/uk/gov/hmcts/cp/subscription/controllers/NotificationController.java index a581f2b8..79d0da63 100644 --- a/src/main/java/uk/gov/hmcts/cp/subscription/controllers/NotificationController.java +++ b/src/main/java/uk/gov/hmcts/cp/subscription/controllers/NotificationController.java @@ -32,7 +32,7 @@ import java.util.Optional; import java.util.UUID; -import static uk.gov.hmcts.cp.filters.TracingFilter.MDC_CORRELATION_ID; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; import static uk.gov.hmcts.cp.servicebus.config.ServiceBusConfigService.PCR_INBOUND_TOPIC; /** @@ -77,7 +77,7 @@ public ResponseEntity createNotification( public ResponseEntity getDocument( @NotNull @PathVariable("clientSubscriptionId") final UUID clientSubscriptionId, @NotNull @PathVariable("documentId") final UUID documentId, - @RequestHeader(value = MDC_CORRELATION_ID, required = false) final UUID xCorrelationId) { + @RequestHeader(value = CORRELATION_ID_KEY, required = false) final UUID xCorrelationId) { final UUID clientId = UUID.fromString(MDC.get(ClientIdResolutionFilter.MDC_CLIENT_ID)); final DocumentContent content = notificationManager.getPcrDocumentContent(clientSubscriptionId, clientId, documentId); final Resource resource = new ByteArrayResource(content.getBody()); diff --git a/src/main/java/uk/gov/hmcts/cp/subscription/controllers/SubscriptionController.java b/src/main/java/uk/gov/hmcts/cp/subscription/controllers/SubscriptionController.java index 4e51ee27..4238adff 100644 --- a/src/main/java/uk/gov/hmcts/cp/subscription/controllers/SubscriptionController.java +++ b/src/main/java/uk/gov/hmcts/cp/subscription/controllers/SubscriptionController.java @@ -16,7 +16,7 @@ import java.util.UUID; -import static uk.gov.hmcts.cp.filters.TracingFilter.MDC_CORRELATION_ID; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; @RestController @RequiredArgsConstructor @@ -28,7 +28,7 @@ public class SubscriptionController implements SubscriptionApi { @Override public ResponseEntity createClientSubscription( final ClientSubscriptionRequest clientSubscriptionRequest, - @RequestHeader(value = MDC_CORRELATION_ID, required = false) final UUID xCorrelationId) { + @RequestHeader(value = CORRELATION_ID_KEY, required = false) final UUID xCorrelationId) { final UUID clientId = UUID.fromString(MDC.get(ClientIdResolutionFilter.MDC_CLIENT_ID)); log.info("createClientSubscription callbackUrl:{} clientId:{}", Encode.forJava(clientSubscriptionRequest.getNotificationEndpoint().getCallbackUrl()), clientId); @@ -41,7 +41,7 @@ public ResponseEntity createClientSubscription( public ResponseEntity updateClientSubscription( final UUID clientSubscriptionId, final ClientSubscriptionRequest clientSubscriptionRequest, - @RequestHeader(value = MDC_CORRELATION_ID, required = false) final UUID xCorrelationId) { + @RequestHeader(value = CORRELATION_ID_KEY, required = false) final UUID xCorrelationId) { final UUID clientId = UUID.fromString(MDC.get(ClientIdResolutionFilter.MDC_CLIENT_ID)); log.info("updateClientSubscription clientSubscriptionId:{} clientId:{}", clientSubscriptionId, clientId); final ClientSubscription response = subscriptionService.updateSubscription( @@ -52,7 +52,7 @@ public ResponseEntity updateClientSubscription( @Override public ResponseEntity getClientSubscription( final UUID clientSubscriptionId, - @RequestHeader(value = MDC_CORRELATION_ID, required = false) final UUID xCorrelationId) { + @RequestHeader(value = CORRELATION_ID_KEY, required = false) final UUID xCorrelationId) { final UUID clientId = UUID.fromString(MDC.get(ClientIdResolutionFilter.MDC_CLIENT_ID)); log.info("getClientSubscription clientSubscriptionId:{} clientId:{}", clientSubscriptionId, clientId); final ClientSubscription response = subscriptionService.getSubscription(clientSubscriptionId, clientId); @@ -62,7 +62,7 @@ public ResponseEntity getClientSubscription( @Override public ResponseEntity deleteClientSubscription( final UUID clientSubscriptionId, - @RequestHeader(value = MDC_CORRELATION_ID, required = false) final UUID xCorrelationId) { + @RequestHeader(value = CORRELATION_ID_KEY, required = false) final UUID xCorrelationId) { final UUID clientId = UUID.fromString(MDC.get(ClientIdResolutionFilter.MDC_CLIENT_ID)); log.info("deleteClientSubscription clientSubscriptionId:{} clientId:{}", clientSubscriptionId, clientId); subscriptionService.deleteSubscription(clientSubscriptionId, clientId); diff --git a/src/test/java/uk/gov/hmcts/cp/filters/TracingFilterTest.java b/src/test/java/uk/gov/hmcts/cp/filters/TracingFilterTest.java index b9036c53..b094f07c 100644 --- a/src/test/java/uk/gov/hmcts/cp/filters/TracingFilterTest.java +++ b/src/test/java/uk/gov/hmcts/cp/filters/TracingFilterTest.java @@ -45,22 +45,22 @@ void shouldAlwaysFilter_all_paths() { @Test void doFilterInternal_puts_correlationId_in_MDC_and_response_when_header_present() throws ServletException, IOException { final String correlationId = UUID.randomUUID().toString(); - when(request.getHeader(TracingFilter.CORRELATION_ID_HEADER)).thenReturn(correlationId); + when(request.getHeader(TracingFilter.CORRELATION_ID_KEY)).thenReturn(correlationId); filter.doFilterInternal(request, response, filterChain); - verify(response).setHeader(TracingFilter.CORRELATION_ID_HEADER, correlationId); + verify(response).setHeader(TracingFilter.CORRELATION_ID_KEY, correlationId); verify(filterChain).doFilter(request, response); - assertThat(MDC.get(TracingFilter.MDC_CORRELATION_ID)).isNull(); + assertThat(MDC.get(TracingFilter.CORRELATION_ID_KEY)).isNull(); } @Test void doFilterInternal_generates_correlationId_when_header_absent() throws ServletException, IOException { - when(request.getHeader(TracingFilter.CORRELATION_ID_HEADER)).thenReturn(null); + when(request.getHeader(TracingFilter.CORRELATION_ID_KEY)).thenReturn(null); filter.doFilterInternal(request, response, filterChain); - verify(response).setHeader(eq(TracingFilter.CORRELATION_ID_HEADER), anyString()); + verify(response).setHeader(eq(TracingFilter.CORRELATION_ID_KEY), anyString()); verify(filterChain).doFilter(request, response); } } diff --git a/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrInboundIntegrationTest.java b/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrInboundIntegrationTest.java index 7d6182b6..46b78460 100644 --- a/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrInboundIntegrationTest.java +++ b/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrInboundIntegrationTest.java @@ -21,7 +21,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static uk.gov.hmcts.cp.filters.TracingFilter.MDC_CORRELATION_ID; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; import static uk.gov.hmcts.cp.openapi.model.EventType.PRISON_COURT_REGISTER_GENERATED; import static uk.gov.hmcts.cp.servicebus.config.ServiceBusConfigService.PCR_INBOUND_TOPIC; @@ -61,7 +61,7 @@ void inbound_notification_should_process_material_service() { MaterialMetadata materialMetadata = new MaterialMetadata(); when(materialService.waitForMaterialMetadata(materialId)).thenReturn(materialMetadata); EventPayload eventPayload = EventPayload.builder().eventType(PRISON_COURT_REGISTER_GENERATED).materialId(materialId).build(); - MDC.put(MDC_CORRELATION_ID, UUID.randomUUID().toString()); + MDC.put(CORRELATION_ID_KEY, UUID.randomUUID().toString()); clientService.queueMessage(PCR_INBOUND_TOPIC, null, jsonMapper.toJson(eventPayload), 0); MDC.clear(); @@ -74,7 +74,7 @@ void inbound_notification_should_process_material_service() { void process_message_should_retry_n_times_then_send_to_DLQ() { when(materialService.waitForMaterialMetadata(materialId)).thenReturn(null); EventPayload eventPayload = EventPayload.builder().eventType(PRISON_COURT_REGISTER_GENERATED).materialId(materialId).build(); - MDC.put(MDC_CORRELATION_ID, UUID.randomUUID().toString()); + MDC.put(CORRELATION_ID_KEY, UUID.randomUUID().toString()); clientService.queueMessage(PCR_INBOUND_TOPIC, null, jsonMapper.toJson(eventPayload), 0); MDC.clear(); diff --git a/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrOutboundIntegrationTest.java b/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrOutboundIntegrationTest.java index d2518bfa..03ba6ef2 100644 --- a/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrOutboundIntegrationTest.java +++ b/src/test/java/uk/gov/hmcts/cp/servicebus/integration/ServiceBusPcrOutboundIntegrationTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; import static uk.gov.hmcts.cp.servicebus.config.ServiceBusConfigService.PCR_OUTBOUND_TOPIC; @Slf4j @@ -79,7 +80,7 @@ void process_message_should_retry_n_times_then_stop_because_sent_to_DLQ() { private void queueMessageForCallbackUrl(String callbackUrl) { EventNotificationPayload payload = EventNotificationPayload.builder().build(); - MDC.put("correlationId", UUID.randomUUID().toString()); + MDC.put(CORRELATION_ID_KEY, UUID.randomUUID().toString()); clientService.queueMessage(PCR_OUTBOUND_TOPIC, callbackUrl, jsonMapper.toJson(payload), 0); MDC.clear(); } diff --git a/src/test/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientServiceTest.java b/src/test/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientServiceTest.java index e4dcc39a..4839919b 100644 --- a/src/test/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientServiceTest.java +++ b/src/test/java/uk/gov/hmcts/cp/servicebus/services/ServiceBusClientServiceTest.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; import static uk.gov.hmcts.cp.servicebus.config.ServiceBusConfigService.PCR_INBOUND_TOPIC; @ExtendWith(MockitoExtension.class) @@ -49,7 +50,7 @@ class ServiceBusClientServiceTest { @Test void queue_message_should_pass_to_topic() { UUID correlationId = UUID.randomUUID(); - MDC.put("correlationId", correlationId.toString()); + MDC.put(CORRELATION_ID_KEY, correlationId.toString()); when(configService.senderClient(PCR_INBOUND_TOPIC)).thenReturn(senderClient); when(wrapperMapper.newWrapper(correlationId, 1, callbackUrl, "message")).thenReturn(wrappedMessage); when(jsonMapper.toJson(wrappedMessage)).thenReturn("wrapped-message"); diff --git a/src/test/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptorTest.java b/src/test/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptorTest.java index 789d181e..0955114e 100644 --- a/src/test/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptorTest.java +++ b/src/test/java/uk/gov/hmcts/cp/subscription/config/OutboundTracingInterceptorTest.java @@ -13,6 +13,8 @@ import org.springframework.http.client.ClientHttpResponse; import uk.gov.hmcts.cp.filters.TracingFilter; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; + import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -46,14 +48,14 @@ void tearDown() { @Test void intercept_adds_X_Correlation_Id_from_MDC() throws Exception { final String correlationId = UUID.randomUUID().toString(); - MDC.put("correlationId", correlationId); + MDC.put(CORRELATION_ID_KEY, correlationId); final HttpHeaders headers = new HttpHeaders(); when(request.getHeaders()).thenReturn(headers); when(execution.execute(request, new byte[0])).thenReturn(clientHttpResponse); interceptor.intercept(request, new byte[0], execution); - assertThat(headers.getFirst(TracingFilter.CORRELATION_ID_HEADER)) + assertThat(headers.getFirst(TracingFilter.CORRELATION_ID_KEY)) .isEqualTo(correlationId); } @@ -65,6 +67,6 @@ void intercept_does_not_add_header_when_MDC_correlationId_absent() throws Except interceptor.intercept(request, new byte[0], execution); - assertThat(request.getHeaders().getFirst(TracingFilter.CORRELATION_ID_HEADER)).isNull(); + assertThat(request.getHeaders().getFirst(TracingFilter.CORRELATION_ID_KEY)).isNull(); } } diff --git a/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/SpringLoggingIntegrationTest.java b/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/SpringLoggingIntegrationTest.java index a395b294..96ac4ee0 100644 --- a/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/SpringLoggingIntegrationTest.java +++ b/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/SpringLoggingIntegrationTest.java @@ -13,8 +13,10 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.util.Map; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; @Slf4j class SpringLoggingIntegrationTest extends IntegrationTestBase { @@ -26,9 +28,11 @@ void afterEach() { System.setOut(originalStdOut); } + UUID correlationId = UUID.randomUUID(); + @Test void springboot_test_should_log_correct_fields() throws IOException { - MDC.put("any-mdc-field", "1234-1234"); + MDC.put(CORRELATION_ID_KEY, correlationId.toString()); final ByteArrayOutputStream capturedStdOut = captureStdOut(); log.info("spring boot test message", new RuntimeException("TestException")); @@ -36,18 +40,19 @@ void springboot_test_should_log_correct_fields() throws IOException { assertThat(logMessage).isNotEmpty(); final Map capturedFields = - new ObjectMapper().readValue(logMessage, new TypeReference<>() { }); + new ObjectMapper().readValue(logMessage, new TypeReference<>() { + }); - assertThat(capturedFields.get("any-mdc-field")).isEqualTo("1234-1234"); + assertThat(capturedFields.get(CORRELATION_ID_KEY)).isEqualTo(correlationId.toString()); assertThat(capturedFields.get("timestamp")).isNotNull(); - assertThat(capturedFields.get("logger_name")) - .isEqualTo("uk.gov.hmcts.cp.subscription.integration.controllers.SpringLoggingIntegrationTest"); - assertThat(capturedFields.get("thread_name")).isEqualTo("Test worker"); - assertThat(capturedFields.get("level")).isEqualTo("INFO"); assertThat(capturedFields.get("message").toString()) .contains("spring boot test message") .contains("java.lang.RuntimeException: TestException") .contains("uk.gov.hmcts.cp.subscription.integration.controllers.SpringLoggingIntegrationTest"); + assertThat(capturedFields.get("logger_name")) + .isEqualTo("uk.gov.hmcts.cp.subscription.integration.controllers.SpringLoggingIntegrationTest"); + assertThat(capturedFields.get("thread_name")).isEqualTo("Test worker"); + assertThat(capturedFields.get("level")).isEqualTo("INFO"); } private ByteArrayOutputStream captureStdOut() { diff --git a/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/TracingIntegrationTest.java b/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/TracingIntegrationTest.java index 7a7c421b..13c60c50 100644 --- a/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/TracingIntegrationTest.java +++ b/src/test/java/uk/gov/hmcts/cp/subscription/integration/controllers/TracingIntegrationTest.java @@ -1,7 +1,6 @@ package uk.gov.hmcts.cp.subscription.integration.controllers; import jakarta.annotation.Resource; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; @@ -16,7 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_HEADER; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.MOCK, @@ -48,11 +47,11 @@ void incomingRequestShouldReturnOk() throws Exception { @Test void subscriptionEndpointWithCorrelationIdShouldEchoHeaderInResponse() throws Exception { MvcResult result = mockMvc.perform(get("/client-subscriptions/{id}", UUID.randomUUID()) - .header(CORRELATION_ID_HEADER, TEST_CORRELATION_ID) + .header(CORRELATION_ID_KEY, TEST_CORRELATION_ID) .header("X-Client-Id", "11111111-2222-3333-4444-555555555555")) .andReturn(); - String responseCorrelationId = result.getResponse().getHeader(CORRELATION_ID_HEADER); + String responseCorrelationId = result.getResponse().getHeader(CORRELATION_ID_KEY); assertThat(responseCorrelationId).isEqualTo(TEST_CORRELATION_ID); assertThat(springApplicationName).isEqualTo("cp-crime-hearing-case-event-subscription"); } diff --git a/src/test/java/uk/gov/hmcts/cp/subscription/integration/e2e/PcrSynchronousE2EIntegrationTest.java b/src/test/java/uk/gov/hmcts/cp/subscription/integration/e2e/PcrSynchronousE2EIntegrationTest.java index 6261bd4b..2427aee6 100644 --- a/src/test/java/uk/gov/hmcts/cp/subscription/integration/e2e/PcrSynchronousE2EIntegrationTest.java +++ b/src/test/java/uk/gov/hmcts/cp/subscription/integration/e2e/PcrSynchronousE2EIntegrationTest.java @@ -37,7 +37,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_HEADER; +import static uk.gov.hmcts.cp.filters.TracingFilter.CORRELATION_ID_KEY; import static uk.gov.hmcts.cp.subscription.integration.helpers.JwtHelper.bearerTokenWithAzp; import static uk.gov.hmcts.cp.subscription.integration.stubs.CallbackStub.getDocumentIdFromCallbackServeEvents; import static uk.gov.hmcts.cp.subscription.integration.stubs.CallbackStub.stubCallbackEndpoint; @@ -225,7 +225,7 @@ private ResultActions postPcrEvent(String payloadPath) throws Exception { return mockMvc.perform(post(NOTIFICATIONS_URI) .contentType(MediaType.APPLICATION_JSON) .header("Accept", MediaType.APPLICATION_JSON_VALUE) - .header(CORRELATION_ID_HEADER, correlationId) + .header(CORRELATION_ID_KEY, correlationId) .content(loadPayload(payloadPath))); } @@ -269,21 +269,21 @@ private void then_subscriber_cannot_retrieve_document() throws Exception { private void getDocumentAndExpectPdf(UUID subId, UUID docId) throws Exception { mockMvc.perform(get(DOCUMENT_URI, subId, docId) .header("Authorization", AUTHORIZATION_HEADER_VALUE) - .header(CORRELATION_ID_HEADER, correlationId)) + .header(CORRELATION_ID_KEY, correlationId)) .andExpect(status().isOk()) .andExpect(header().string("Content-Type", org.hamcrest.Matchers.containsString("application/pdf"))) .andExpect(header().string("Content-Disposition", org.hamcrest.Matchers.containsString("PrisonCourtRegister"))) - .andExpect(header().string(CORRELATION_ID_HEADER, correlationId)); + .andExpect(header().string(CORRELATION_ID_KEY, correlationId)); } private void getDocumentAndExpectPdf(UUID subId, UUID docId, String clientId) throws Exception { mockMvc.perform(get(DOCUMENT_URI, subId, docId) .header("Authorization", bearerTokenWithAzp(clientId)) - .header(CORRELATION_ID_HEADER, correlationId)) + .header(CORRELATION_ID_KEY, correlationId)) .andExpect(status().isOk()) .andExpect(header().string("Content-Type", org.hamcrest.Matchers.containsString("application/pdf"))) .andExpect(header().string("Content-Disposition", org.hamcrest.Matchers.containsString("PrisonCourtRegister"))) - .andExpect(header().string(CORRELATION_ID_HEADER, correlationId)); + .andExpect(header().string(CORRELATION_ID_KEY, correlationId)); } private void createSubscription() throws Exception {