Skip to content

Commit

Permalink
Po 690 api exception handling (#516)
Browse files Browse the repository at this point in the history
* remove duplicate exception handling

* fix column name in entity

* change nocontent to notfound

* remove unused test class

* add auth error handling

* add auth error handling

* add more global exception handling

* api unauthorised test

* fix existing tests

* add 503 test

* change warn to error

* remove test container

* remove unused test

* remove dissimilar assertion that is already tested in Response Util test
  • Loading branch information
DeclanClarkeCGI committed Sep 4, 2024
1 parent e85bc7c commit 7ca5d81
Show file tree
Hide file tree
Showing 28 changed files with 559 additions and 190 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void testGetBusinessUnitById_WhenBusinessUnitDoesNotExist() throws Exception {
when(businessUnitService.getBusinessUnit((short)2)).thenReturn(null);

mockMvc.perform(get("/api/business-unit/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -98,7 +98,7 @@ void testPostBusinessUnitsSearch_WhenBusinessUnitDoesNotExist() throws Exception
mockMvc.perform(post("/api/business-unit/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void testGetCourtById_WhenCourtDoesNotExist() throws Exception {
when(courtService.getCourt(2L)).thenReturn(null);

mockMvc.perform(get("/api/court/2").header("authorization", "Bearer some_value"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -103,7 +103,7 @@ void testPostCourtsSearch_WhenCourtDoesNotExist() throws Exception {
.header("authorization", "Bearer some_value")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void testGetDefendantAccountById_WhenDefendantAccountDoesNotExist() throws Excep

mockMvc.perform(get("/api/defendant-account/2")
.header("authorization", "Bearer some_value"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -118,7 +118,7 @@ void testPostDefendantAccountsSearch_WhenDefendantAccountDoesNotExist() throws E
.header("authorization", "Bearer some_value")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -217,7 +217,7 @@ public void testGetNotesForDefendantAccount_zeroNotes() throws Exception {

mockMvc.perform(get("/api/defendant-account/notes/{defendantId}", "dummyDefendantId")
.header("authorization", "Bearer some_value"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package uk.gov.hmcts.opal.controllers;

import jakarta.persistence.QueryTimeoutException;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
Expand All @@ -11,6 +15,8 @@
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import uk.gov.hmcts.opal.authentication.service.AccessTokenService;
import uk.gov.hmcts.opal.controllers.advice.GlobalExceptionHandler;
import uk.gov.hmcts.opal.dto.ToJsonString;
import uk.gov.hmcts.opal.dto.search.DraftAccountSearchDto;
import uk.gov.hmcts.opal.entity.BusinessUnitEntity;
Expand All @@ -19,12 +25,14 @@
import uk.gov.hmcts.opal.service.opal.JsonSchemaValidationService;
import uk.gov.hmcts.opal.service.opal.UserStateService;

import java.net.ConnectException;
import java.time.LocalDate;
import java.util.logging.Logger;

import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertTrue;
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.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
Expand All @@ -33,7 +41,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest
@ContextConfiguration(classes = DraftAccountController.class)
@ContextConfiguration(classes = {DraftAccountController.class, GlobalExceptionHandler.class})
@ActiveProfiles({"integration"})
class DraftAccountControllerIntegrationTest {

Expand All @@ -49,6 +57,9 @@ class DraftAccountControllerIntegrationTest {
@MockBean
UserStateService userStateService;

@MockBean
AccessTokenService tokenService;

@SpyBean
private JsonSchemaValidationService jsonSchemaValidationService;

Expand Down Expand Up @@ -82,7 +93,7 @@ void testGetDraftAccountById_WhenDraftAccountDoesNotExist() throws Exception {
when(draftAccountService.getDraftAccount(2L)).thenReturn(null);

mockMvc.perform(get("/api/draft-account/2").header("authorization", "Bearer some_value"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -111,7 +122,34 @@ void testPostDraftAccountsSearch_WhenDraftAccountDoesNotExist() throws Exception
.header("authorization", "Bearer some_value")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

@Test
void shouldReturn408WhenTimeout() throws Exception {
// Simulating a timeout exception when the repository is called
doThrow(new QueryTimeoutException()).when(draftAccountService).getDraftAccount(1L);

mockMvc.perform(get("/api/draft-account/1")
.header("Authorization", "Bearer " + "some_value"))
.andExpect(status().isRequestTimeout())
.andExpect(content().contentType("application/json"))
.andExpect(content().json("""
{
"error": "Request Timeout",
"message": "The request did not receive a response from the database within the timeout period"
}"""));
}

@Test
void shouldReturn406WhenResponseContentTypeNotSupported() throws Exception {

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

mockMvc.perform(get("/api/draft-account/1")
.header("Authorization", "Bearer " + "some_value")
.accept("application/xml"))
.andExpect(status().isNotAcceptable());
}

private DraftAccountEntity createDraftAccountEntity() {
Expand All @@ -127,4 +165,25 @@ private DraftAccountEntity createDraftAccountEntity() {
.timelineData("{}")
.build();
}

@Test
void shouldReturn503WhenDownstreamServiceIsUnavailable() throws Exception {

Mockito.doAnswer(
invocation -> {
throw new PSQLException("Connection refused", PSQLState.CONNECTION_FAILURE, new ConnectException());
})
.when(draftAccountService).getDraftAccount(1L);


mockMvc.perform(get("/api/draft-account/1")
.header("Authorization", "Bearer " + "some_value"))
.andExpect(status().isServiceUnavailable())
.andExpect(content().contentType("application/json"))
.andExpect(content().json("""
{
"error": "Service Unavailable",
"message": "Opal Fines Database is currently unavailable"
}"""));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void testGetEnforcerById_WhenEnforcerDoesNotExist() throws Exception {
when(enforcerService.getEnforcer(2L)).thenReturn(null);

mockMvc.perform(get("/api/enforcer/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -102,7 +102,7 @@ void testPostEnforcersSearch_WhenEnforcerDoesNotExist() throws Exception {
mockMvc.perform(post("/api/enforcer/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ void testGetLocalJusticeAreaById_WhenLocalJusticeAreaDoesNotExist() throws Excep
when(localJusticeAreaService.getLocalJusticeArea((short)2)).thenReturn(null);

mockMvc.perform(get("/api/local-justice-area/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -85,7 +85,7 @@ void testPostLocalJusticeAreasSearch_WhenLocalJusticeAreaDoesNotExist() throws E
mockMvc.perform(post("/api/local-justice-area/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

private LocalJusticeAreaEntity createLocalJusticeAreaEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void testGetMajorCreditorById_WhenMajorCreditorDoesNotExist() throws Exception {
when(majorCreditorService.getMajorCreditor(2L)).thenReturn(null);

mockMvc.perform(get("/api/major-creditor/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -89,7 +89,7 @@ void testPostMajorCreditorsSearch_WhenMajorCreditorDoesNotExist() throws Excepti
mockMvc.perform(post("/api/major-creditor/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void testGetOffenceById_WhenOffenceDoesNotExist() throws Exception {
when(offenceService.getOffence((short)2)).thenReturn(null);

mockMvc.perform(get("/api/offence/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand All @@ -81,7 +81,7 @@ void testPostOffencesSearch_WhenOffenceDoesNotExist() throws Exception {
mockMvc.perform(post("/api/offence/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

private OffenceEntity createOffenceEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ void testGetResultById_WhenResultDoesNotExist() throws Exception {
when(resultService.getResult(2L)).thenReturn(null);

mockMvc.perform(get("/api/result/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -119,7 +119,7 @@ void testPostResultsSearch_WhenResultDoesNotExist() throws Exception {
mockMvc.perform(post("/api/result/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,31 @@ void testParseToken() throws Exception {
.andExpect(status().isOk())
.andExpect(jsonPath("$").value("testUser"));
}

@Test
void testGetTokenForUserFailure() throws Exception {
AccessTokenResponse accessTokenResponse = new AccessTokenResponse();
accessTokenResponse.setAccessToken("testAccessToken");

when(accessTokenService.getTestUserToken(anyString())).thenReturn(accessTokenResponse);

SecurityToken securityToken = SecurityToken.builder()
.accessToken(TEST_TOKEN)
.userState(USER_STATE)
.build();
when(authorisationService.getSecurityToken("testAccessToken")).thenReturn(securityToken);

mockMvc.perform(get("/api/testing-support/token/user")
.header("X-User-Email", "test@example.com"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.accessToken").value("testToken"))
.andExpect(jsonPath("$.userState.userName").value("name"))
.andExpect(jsonPath("$.userState.userId").value("123"))
.andExpect(jsonPath("$.userState.roles[0].businessUnitId").value("123"))
.andExpect(jsonPath("$.userState.roles[0].businessUserId").value("BU123"))
.andExpect(jsonPath("$.userState.roles[0].permissions[0].permissionId").value("1"))
.andExpect(jsonPath("$.userState.roles[0].permissions[0].permissionName")
.value("Notes"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void testGetConfigurationItemById_WhenConfigurationItemDoesNotExist() throws Exc
when(configurationItemService.getConfigurationItem(2L)).thenReturn(null);

mockMvc.perform(get("/dev/configuration-item/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand All @@ -84,7 +84,7 @@ void testPostConfigurationItemsSearch_WhenConfigurationItemDoesNotExist() throws
mockMvc.perform(post("/dev/configuration-item/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

private ConfigurationItemEntity createConfigurationItemEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void testGetImpositionById_WhenImpositionDoesNotExist() throws Exception {
when(impositionService.getImposition(2L)).thenReturn(null);

mockMvc.perform(get("/dev/imposition/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -94,7 +94,7 @@ void testPostImpositionsSearch_WhenImpositionDoesNotExist() throws Exception {
mockMvc.perform(post("/dev/imposition/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

private ImpositionEntity createImpositionEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void testGetLogActionById_WhenLogActionDoesNotExist() throws Exception {
when(logActionService.getLogAction((short)2)).thenReturn(null);

mockMvc.perform(get("/dev/log-action/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand All @@ -77,7 +77,7 @@ void testPostLogActionsSearch_WhenLogActionDoesNotExist() throws Exception {
mockMvc.perform(post("/dev/log-action/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

private LogActionEntity createLogActionEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void testGetLogAuditDetailById_WhenLogAuditDetailDoesNotExist() throws Exception
when(logAuditDetailService.getLogAuditDetail(2L)).thenReturn(null);

mockMvc.perform(get("/dev/log-audit-detail/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand Down Expand Up @@ -89,7 +89,7 @@ void testPostLogAuditDetailsSearch_WhenLogAuditDetailDoesNotExist() throws Excep
mockMvc.perform(post("/dev/log-audit-detail/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

private LogAuditDetailEntity createLogAuditDetailEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void testGetTillById_WhenTillDoesNotExist() throws Exception {
when(tillService.getTill(2L)).thenReturn(null);

mockMvc.perform(get("/dev/till/2"))
.andExpect(status().isNoContent());
.andExpect(status().isNotFound());
}

@Test
Expand All @@ -81,7 +81,7 @@ void testPostTillsSearch_WhenTillDoesNotExist() throws Exception {
mockMvc.perform(post("/dev/till/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"criteria\":\"2\"}"))
.andExpect(status().isNoContent());
.andExpect(status().isOk());
}

private TillEntity createTillEntity() {
Expand Down
Loading

0 comments on commit 7ca5d81

Please sign in to comment.