Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package uk.gov.hmcts.cp.subscription.controllers;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import uk.gov.hmcts.cp.openapi.model.PcrEventPayload;
import uk.gov.hmcts.cp.subscription.services.NotificationService;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
@Slf4j
public class NotificationController {

private final NotificationService notificationService;

@PostMapping("/notifications/pcr/{materialId}")
public ResponseEntity<PcrEventPayload> notificationPCR(@PathVariable UUID materialId, @RequestBody @Valid PcrEventPayload pcrEventPayload) {

Check warning on line 25 in src/main/java/uk/gov/hmcts/cp/subscription/controllers/NotificationController.java

View workflow job for this annotation

GitHub Actions / pmd-analysis

Parameter 'pcrEventPayload' is not assigned and could be declared final

Reports method and constructor parameters that can be made final because they are never reassigned within the body of the method. This rule ignores unused parameters so as not to overlap with the rule {% rule java/bestpractices/UnusedFormalParameter %}. It will also ignore the parameters of abstract methods. MethodArgumentCouldBeFinal (Priority: 3, Ruleset: Code Style) https://docs.pmd-code.org/snapshot/pmd_rules_java_codestyle.html#methodargumentcouldbefinal

Check warning on line 25 in src/main/java/uk/gov/hmcts/cp/subscription/controllers/NotificationController.java

View workflow job for this annotation

GitHub Actions / pmd-analysis

Parameter 'materialId' is not assigned and could be declared final

Reports method and constructor parameters that can be made final because they are never reassigned within the body of the method. This rule ignores unused parameters so as not to overlap with the rule {% rule java/bestpractices/UnusedFormalParameter %}. It will also ignore the parameters of abstract methods. MethodArgumentCouldBeFinal (Priority: 3, Ruleset: Code Style) https://docs.pmd-code.org/snapshot/pmd_rules_java_codestyle.html#methodargumentcouldbefinal

notificationService.processPcrEvent(materialId);
return new ResponseEntity<>(pcrEventPayload, HttpStatus.CREATED);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package uk.gov.hmcts.cp.subscription.services;

import feign.FeignException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import uk.gov.hmcts.cp.subscription.clients.MaterialClient;

import java.util.UUID;

@Service
@RequiredArgsConstructor
@Slf4j
public class NotificationService {

private final MaterialClient client;

public void processPcrEvent(final UUID materialId) {
try {
client.getContentById(materialId);
log.info("Successfully received document.");
} catch (FeignException ex) {
log.error("Failed to get document.", ex);
throw ex;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package uk.gov.hmcts.cp.subscription.controllers;


import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import uk.gov.hmcts.cp.openapi.model.PcrEventPayload;
import uk.gov.hmcts.cp.subscription.services.NotificationService;
import wiremock.com.fasterxml.jackson.databind.ObjectMapper;
import wiremock.com.fasterxml.jackson.databind.SerializationFeature;
import wiremock.com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.util.UUID;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(NotificationController.class)
class NotificationControllerTest {

@Autowired
private MockMvc mockMvc;

private ObjectMapper objectMapper;

@MockitoBean
private NotificationService notificationService;

@BeforeEach
void setUp() {
objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}

@Test
void shouldProcessPcrNotificationAndReturnCreated() throws Exception {
UUID materialId = UUID.randomUUID();

ClassPathResource resource = new ClassPathResource("requests/pcr-request.json");
PcrEventPayload payload = objectMapper.readValue(resource.getFile(), PcrEventPayload.class);

payload.setEventType("PRISON_COURT_REGISTER_GENERATED");

mockMvc.perform(post("/notifications/pcr/{materialId}", materialId)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(payload)))
.andExpect(status().isCreated())
.andExpect(content().json(objectMapper.writeValueAsString(payload)));

Mockito.verify(notificationService)
.processPcrEvent(materialId);
}

@Test
void shouldReturnBadRequestWhenPayloadInvalid() throws Exception {
UUID materialId = UUID.randomUUID();

PcrEventPayload invalidPayload = new PcrEventPayload(); // missing required fields

mockMvc.perform(post("/notifications/pcr/{materialId}", materialId)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(invalidPayload)))
.andExpect(status().isBadRequest());

Mockito.verifyNoInteractions(notificationService);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package uk.gov.hmcts.cp.subscription.integration;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.wiremock.spring.ConfigureWireMock;
import org.wiremock.spring.EnableWireMock;
import uk.gov.hmcts.cp.subscription.config.TestContainersInitialise;

import java.nio.file.Files;
import java.util.UUID;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = TestContainersInitialise.class)
@AutoConfigureMockMvc
@EnableWireMock({@ConfigureWireMock(name = "material-client", baseUrlProperties = "material-client.url")})
class NotificationIntegrationTest {

@Autowired
private MockMvc mockMvc;

@Test
void shouldReturnCreated_whenPostingFullJson() throws Exception {
UUID materialId = UUID.randomUUID();

// Load request JSON from resources/request/pcr-event.json
ClassPathResource resource = new ClassPathResource("requests/pcr-request.json");
String requestJson = Files.readString(resource.getFile().toPath());

// Perform POST request
mockMvc.perform(post("/notifications/pcr/7c198796-08bb-4803-b456-fa0c29ca6021", materialId)
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isCreated());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package uk.gov.hmcts.cp.subscription.services;

import feign.FeignException;
import feign.Request;
import feign.Response;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import uk.gov.hmcts.cp.subscription.clients.MaterialClient;

import java.nio.charset.Charset;
import java.util.Collections;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

class NotificationServiceTest {

private MaterialClient materialClient;
private NotificationService notificationService;

@BeforeEach
void setUp() {
materialClient = mock(MaterialClient.class);
notificationService = new NotificationService(materialClient);
}

@Test
void shouldCallClientAndLogSuccess() {
UUID materialId = UUID.randomUUID();
notificationService.processPcrEvent(materialId);
verify(materialClient, times(1)).getContentById(materialId);
}

@Test
void shouldThrowFeignExceptionWhenClientFails() {
UUID materialId = UUID.randomUUID();

Response response = Response.builder()
.request(Request.create(Request.HttpMethod.GET, "/dummy", Collections.emptyMap(), null, Charset.defaultCharset(), null))
.status(500)
.reason("Internal Server Error")
.build();

FeignException feignException = FeignException.errorStatus("getContentById", response);
doThrow(feignException).when(materialClient).getContentById(materialId);
assertThrows(FeignException.class, () -> notificationService.processPcrEvent(materialId));
verify(materialClient, times(1)).getContentById(materialId);
}
}
26 changes: 26 additions & 0 deletions src/test/resources/requests/pcr-request.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"eventId": "7c198796-08bb-4803-b456-fa0c29ca6021",
"eventType": "PRISON_COURT_REGISTER_GENERATED",
"timestamp": "2024-01-15T10:30:00Z",
"defendants": [
{
"masterDefendantId": "7c198796-08bb-4803-b456-fa0c29ca6022",
"name": "string",
"dateOfBirth": "1990-05-15",
"custodyEstablishmentDetails": {
"emailAddress": "string@email.com"
},
"cases": [
{
"urn": "string",
"documents": [
{
"url": "http://documents/pcr/7c198796-08bb-4803-b456-fa0c29ca6021",
"timestamp": "2024-01-15T10:29:55.123Z"
}
]
}
]
}
]
}
Loading