Skip to content

Commit

Permalink
PO-756: Add draft account DELETE endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
RustyHMCTS committed Sep 6, 2024
1 parent c9526d2 commit ea4fc96
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
Expand Down Expand Up @@ -187,4 +188,21 @@ void shouldReturn503WhenDownstreamServiceIsUnavailable() throws Exception {
"message": "Opal Fines Database is currently unavailable"
}"""));
}

@Test
void testDeleteDraftAccountById() throws Exception {
DraftAccountEntity draftAccountEntity = createDraftAccountEntity();

when(draftAccountService.getDraftAccount(1L)).thenReturn(draftAccountEntity);

MvcResult result = mockMvc.perform(delete("/api/draft-accounts/1")
.header("authorization", "Bearer some_value"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.message").value("Draft Account '1' deleted"))
.andReturn();

String body = result.getResponse().getContentAsString();
logger.info(":testGetDraftAccountById: Response body:\n" + ToJsonString.toPrettyJson(body));
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package uk.gov.hmcts.opal.controllers;

import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import uk.gov.hmcts.opal.authorisation.model.UserState;
import uk.gov.hmcts.opal.dto.AddDraftAccountRequestDto;
Expand All @@ -37,6 +41,8 @@
public class DraftAccountController {

public static final String ADD_DRAFT_ACCOUNT_REQUEST_JSON = "addDraftAccountRequest.json";
public static final String ACCOUNT_DELETED_MESSAGE_FORMAT = """
{ "message": "Draft Account '%s' deleted"}""";

private final DraftAccountService draftAccountService;

Expand Down Expand Up @@ -94,6 +100,24 @@ public ResponseEntity<DraftAccountResponseDto> postDraftAccount(@RequestBody Add
return buildCreatedResponse(toGetResponseDto(response));
}

@Hidden
@DeleteMapping(value = "/{draftAccountId}", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Deletes the Draft Account for the given draftAccountId.")
@ConditionalOnProperty(prefix = "opal.testing-support-endpoints", name = "enabled", havingValue = "true")
public ResponseEntity<String> deleteDraftAccountById(
@PathVariable Long draftAccountId,
@RequestHeader(value = "Authorization", required = false) String authHeaderValue,
@RequestParam Optional<Boolean> ignoreMissing) {

log.info(":DELETE:deleteDraftAccountById: draftAccountId: {}", draftAccountId);

userStateService.checkForAuthorisedUser(authHeaderValue);

draftAccountService.deleteDraftAccount(draftAccountId, ignoreMissing);

return buildResponse(String.format(ACCOUNT_DELETED_MESSAGE_FORMAT, draftAccountId));
}

DraftAccountResponseDto toGetResponseDto(DraftAccountEntity entity) {
return DraftAccountResponseDto.builder()
.draftAccountId(entity.getDraftAccountId())
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,42 @@
import uk.gov.hmcts.opal.repository.BusinessUnitRepository;
import uk.gov.hmcts.opal.repository.DraftAccountRepository;
import uk.gov.hmcts.opal.repository.jpa.DraftAccountSpecs;
import uk.gov.hmcts.opal.service.DraftAccountServiceInterface;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Optional;

@Service
@Slf4j(topic = "DraftAccountService")
@RequiredArgsConstructor
@Qualifier("draftAccountService")
public class DraftAccountService implements DraftAccountServiceInterface {
public class DraftAccountService {

private final DraftAccountRepository draftAccountRepository;

private final BusinessUnitRepository businessUnitRepository;

private final DraftAccountSpecs specs = new DraftAccountSpecs();

@Override
public DraftAccountEntity getDraftAccount(long draftAccountId) {
return draftAccountRepository.getReferenceById(draftAccountId);
}

@Override
public void deleteDraftAccount(long draftAccountId, Optional<Boolean> ignoreMissing) {
DraftAccountEntity entity = getDraftAccount(draftAccountId);
// If the DB doesn't hold the target entity to be deleted, then no exception is thrown when a deletion is
// attempted. So we need to retrieve the entity first and try to access any property.
// This will throw an exception if the entity doesn't exist.
boolean checkExists = !(ignoreMissing.orElse(false));
if (checkExists && entity.getDraftAccountId() == null) {
// Will not get here, as JPA should throw an exception. But for testing, throw an Exception.
throw new RuntimeException("Draft Account entity '" + draftAccountId + "' does not exist in the DB.");
} else {
draftAccountRepository.delete(entity);
}
}

public List<DraftAccountEntity> searchDraftAccounts(DraftAccountSearchDto criteria) {
Page<DraftAccountEntity> page = draftAccountRepository
.findBy(specs.findBySearchCriteria(criteria),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@ void testSaveDraftAccounts_Success() {
verify(draftAccountService, times(1)).submitDraftAccount(any(), any());
}

@Test
void testDeleteDraftAccount_Success() {
// Act
ResponseEntity<String> response = draftAccountController
.deleteDraftAccountById(7L, BEARER_TOKEN, Optional.empty());

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("""
{ "message": "Draft Account '7' deleted"}""", response.getBody());
verify(draftAccountService, times(1)).deleteDraftAccount(any(Long.class), any());
}

DraftAccountResponseDto toGetDto(DraftAccountEntity entity) {
return DraftAccountResponseDto.builder()
.draftAccountId(entity.getDraftAccountId())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package uk.gov.hmcts.opal.service.opal;

import jakarta.persistence.EntityNotFoundException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
Expand All @@ -24,7 +25,9 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
Expand All @@ -42,7 +45,6 @@ class DraftAccountServiceTest {
@Test
void testGetDraftAccount() {
// Arrange

DraftAccountEntity draftAccountEntity = DraftAccountEntity.builder().build();
when(draftAccountRepository.getReferenceById(any())).thenReturn(draftAccountEntity);

Expand All @@ -51,7 +53,6 @@ void testGetDraftAccount() {

// Assert
assertNotNull(result);

}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -98,6 +99,47 @@ void testSubmitDraftAccounts() {
assertEquals(draftAccountEntity, result);
}

@Test
void testDeleteDraftAccount_success() {
// Arrange
DraftAccountEntity draftAccountEntity = DraftAccountEntity.builder().draftAccountId(1L).build();
when(draftAccountRepository.getReferenceById(any())).thenReturn(draftAccountEntity);

// Act
draftAccountService.deleteDraftAccount(1, Optional.empty());
}

@Test
void testDeleteDraftAccount_fail1() {
// Arrange
DraftAccountEntity draftAccountEntity = mock(DraftAccountEntity.class);
when(draftAccountEntity.getDraftAccountId()).thenThrow(new EntityNotFoundException("No Entity in DB"));
when(draftAccountRepository.getReferenceById(any())).thenReturn(draftAccountEntity);

// Act
EntityNotFoundException enfe = assertThrows(
EntityNotFoundException.class, () -> draftAccountService.deleteDraftAccount(1, Optional.empty())
);

// Assert
assertEquals("No Entity in DB", enfe.getMessage());
}

@Test
void testDeleteDraftAccount_fail2() {
// Arrange
DraftAccountEntity draftAccountEntity = DraftAccountEntity.builder().build();
when(draftAccountRepository.getReferenceById(any())).thenReturn(draftAccountEntity);

// Act
RuntimeException re = assertThrows(
RuntimeException.class, () -> draftAccountService.deleteDraftAccount(8, Optional.empty())
);

// Assert
assertEquals("Draft Account entity '8' does not exist in the DB.", re.getMessage());
}

private String createAccountString() {
return """
{
Expand Down

0 comments on commit ea4fc96

Please sign in to comment.