Skip to content

Commit

Permalink
Merge pull request #40 from companieshouse/feature/DSND-660-raise-err…
Browse files Browse the repository at this point in the history
…or-and-retry-exceptions

Add transformer error handling and unit tests
  • Loading branch information
EmrysRoberts authored May 23, 2022
2 parents 83741fb + e2a9256 commit a25f9a3
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ public class RetryableErrorException extends RuntimeException {
public RetryableErrorException(String message) {
super(message);
}

public RetryableErrorException(String message, Exception exception) {
super(message, exception);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void handleResponse(
throw new NonRetryableErrorException(msg);
} else if (!httpStatus.is2xxSuccessful()) {
// any other client or server status can be retried
String msg = "Non-Successful 200 response received from disqualified-officers-data-api";
String msg = "Non-Successful response received from disqualified-officers-data-api";
logger.errorContext(logContext, msg + ", retry", null, logMap);
throw new RetryableErrorException(msg);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import uk.gov.companieshouse.api.model.ApiResponse;
import uk.gov.companieshouse.delta.ChsDelta;
import uk.gov.companieshouse.disqualifiedofficers.delta.exception.NonRetryableErrorException;
import uk.gov.companieshouse.disqualifiedofficers.delta.exception.RetryableErrorException;
import uk.gov.companieshouse.disqualifiedofficers.delta.handler.ApiResponseHandler;
import uk.gov.companieshouse.disqualifiedofficers.delta.service.api.ApiClientService;
import uk.gov.companieshouse.disqualifiedofficers.delta.transformer.DisqualifiedOfficersApiTransformer;
Expand Down Expand Up @@ -71,14 +72,26 @@ public void processDelta(Message<ChsDelta> chsDelta) {
.get(0);
if (disqualificationOfficer.getCorporateInd() != null
&& disqualificationOfficer.getCorporateInd().equals("1")) {
InternalCorporateDisqualificationApi apiObject = transformer
.transformCorporateDisqualification(disqualifiedOfficersDelta);
InternalCorporateDisqualificationApi apiObject;
try {
apiObject = transformer.transformCorporateDisqualification(
disqualifiedOfficersDelta);
} catch (Exception ex) {
throw new RetryableErrorException(
"Error when transforming into Api object", ex);
}
//invoke disqualified officers API with Corporate method
invokeDisqualificationsDataApi(logContext, disqualificationOfficer,
apiObject, logMap);
} else {
InternalNaturalDisqualificationApi apiObject = transformer
.transformNaturalDisqualification(disqualifiedOfficersDelta);
InternalNaturalDisqualificationApi apiObject;
try {
apiObject = transformer.transformNaturalDisqualification(
disqualifiedOfficersDelta);
} catch (Exception ex) {
throw new RetryableErrorException(
"Error when transforming into Api object", ex);
}
//invoke disqualified officers API with Natural method
invokeDisqualificationsDataApi(logContext, disqualificationOfficer,
apiObject, logMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
import uk.gov.companieshouse.disqualifiedofficers.delta.exception.NonRetryableErrorException;
import uk.gov.companieshouse.disqualifiedofficers.delta.exception.RetryableErrorException;
import uk.gov.companieshouse.logging.Logger;
Expand All @@ -22,8 +21,6 @@ class ApiResponseHandlerTest {

@Mock
private Logger logger;
@Mock
ResponseStatusException ex;

@Test
void handle200Response() throws NonRetryableErrorException, RetryableErrorException {
Expand All @@ -45,13 +42,23 @@ void handleBadResponse() throws NonRetryableErrorException, RetryableErrorExcept
"400 BAD_REQUEST response received from disqualified-officers-data-api", null, logMap);
}

@Test
void handle404Response() throws NonRetryableErrorException, RetryableErrorException {
HttpStatus httpStatus = HttpStatus.NOT_FOUND;
Map<String, Object> logMap = new HashMap<>();
assertThrows(RetryableErrorException.class, () -> apiResponseHandler.handleResponse(
httpStatus, "status", logMap, logger));
verify(logger).errorContext("status",
"Non-Successful response received from disqualified-officers-data-api, retry", null, logMap);
}

@Test
void handle500Response() throws NonRetryableErrorException, RetryableErrorException {
HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
Map<String, Object> logMap = new HashMap<>();
assertThrows(RetryableErrorException.class, () -> apiResponseHandler.handleResponse(
httpStatus, "status", logMap, logger));
verify(logger).errorContext("status",
"Non-Successful 200 response received from disqualified-officers-data-api, retry", null, logMap);
"Non-Successful response received from disqualified-officers-data-api, retry", null, logMap);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
import uk.gov.companieshouse.api.disqualification.InternalNaturalDisqualificationApi;
import uk.gov.companieshouse.api.model.ApiResponse;
import uk.gov.companieshouse.delta.ChsDelta;
import uk.gov.companieshouse.disqualifiedofficers.delta.exception.NonRetryableErrorException;
import uk.gov.companieshouse.disqualifiedofficers.delta.exception.RetryableErrorException;
import uk.gov.companieshouse.disqualifiedofficers.delta.service.api.ApiClientService;
import uk.gov.companieshouse.disqualifiedofficers.delta.transformer.DisqualifiedOfficersApiTransformer;
import uk.gov.companieshouse.disqualifiedofficers.delta.utils.TestHelper;
import uk.gov.companieshouse.logging.Logger;

import java.io.IOException;

import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -62,4 +65,27 @@ void When_ValidChsDeltaMessage_Expect_ValidDisqualificationDeltaMapping() throws
verify(transformer).transformNaturalDisqualification(expectedDelta);
verify(apiClientService).putDisqualification("context_id", "3002276133", apiObject);
}

@Test
void When_InvalidChsDeltaMessage_Expect_NonRetryableError() {
Message<ChsDelta> mockChsDeltaMessage = testHelper.createInvalidChsDeltaMessage();
assertThrows(NonRetryableErrorException.class, ()->deltaProcessor.processDelta(mockChsDeltaMessage));
}

@Test
void When_ApiReturns500_Expect_RetryableError() throws IOException {
Message<ChsDelta> mockChsDeltaMessage = testHelper.createChsDeltaMessage();
InternalNaturalDisqualificationApi apiObject = testHelper.createDisqualificationApi();
final ApiResponse<Void> response = new ApiResponse<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), null, null);
when(apiClientService.putDisqualification(any(),any(), eq(apiObject))).thenReturn(response);
when(transformer.transformNaturalDisqualification(any())).thenReturn(apiObject);
assertThrows(RetryableErrorException.class, ()->deltaProcessor.processDelta(mockChsDeltaMessage));
}

@Test
void When_Transformer_Fails_Expect_RetryableError() throws IOException {
Message<ChsDelta> mockChsDeltaMessage = testHelper.createBrokenChsDeltaMessage();
when(transformer.transformNaturalDisqualification(any())).thenCallRealMethod();
assertThrows(RetryableErrorException.class, ()->deltaProcessor.processDelta(mockChsDeltaMessage));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import uk.gov.companieshouse.delta.ChsDelta;
import uk.gov.companieshouse.disqualifiedofficers.delta.exception.NonRetryableErrorException;
import uk.gov.companieshouse.logging.Logger;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThrows;

@ExtendWith(MockitoExtension.class)
public class ChsDeltaSerializerTest {
Expand Down Expand Up @@ -45,4 +47,10 @@ void When_serialize_receivesBytes_returnsBytes() {
assertThat(serialize).isEqualTo(byteExample);
}

@Test
void When_serialize_receives_blank_object_exception_thrown() {
ChsDelta payload = new ChsDelta();
assertThrows(NonRetryableErrorException.class, () -> serializer.serialize("",payload));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,7 @@ public Message<ChsDelta> createChsDeltaMessage() throws IOException {
ClassLoader.getSystemClassLoader().getResourceAsStream("disqualified-officers-delta-example.json"));
String data = FileCopyUtils.copyToString(exampleJsonPayload);

ChsDelta mockChsDelta = ChsDelta.newBuilder()
.setData(data)
.setContextId("context_id")
.setAttempt(1)
.build();

return MessageBuilder
.withPayload(mockChsDelta)
.setHeader(KafkaHeaders.RECEIVED_TOPIC, "test")
.setHeader("DISQUALIFIED_OFFICERS_DELTA_RETRY_COUNT", 1)
.build();
return buildMessage(data);
}

public InternalNaturalDisqualificationApi createDisqualificationApi() {
Expand Down Expand Up @@ -117,4 +107,29 @@ public ProducerRecord<String, Object> createRecord(String topic, String header)

return record;
}

public Message<ChsDelta> createInvalidChsDeltaMessage() {
return buildMessage("This is some invalid data");
}

public Message<ChsDelta> createBrokenChsDeltaMessage() throws IOException {
InputStreamReader exampleJsonPayload = new InputStreamReader(
ClassLoader.getSystemClassLoader().getResourceAsStream("invalid-disqualified-officers-delta-example.json"));
String data = FileCopyUtils.copyToString(exampleJsonPayload);
return buildMessage(data);
}

private Message<ChsDelta> buildMessage(String data) {
ChsDelta mockChsDelta = ChsDelta.newBuilder()
.setData(data)
.setContextId("context_id")
.setAttempt(1)
.build();

return MessageBuilder
.withPayload(mockChsDelta)
.setHeader(KafkaHeaders.RECEIVED_TOPIC, "test")
.setHeader("DISQUALIFIED_OFFICERS_DELTA_RETRY_COUNT", 1)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"disqualified_officer": [{
"officer_disq_id": "3000035941",
"external_number": "168544120001",
"officer_id": "3002276133",
"officer_detail_id": "3002842206",
"date_of_birth": "19770718",
"forename": "Jason",
"middle_name": "John",
"surname": "PISTOLAS",
"nationality": "British"
}]
}

0 comments on commit a25f9a3

Please sign in to comment.