Search in sources :

Example 1 with ErrorResponseInfo

use of com.nike.riposte.server.error.handler.ErrorResponseInfo in project riposte by Nike-Inc.

the class ExceptionHandlingHandler method processUnhandledError.

/**
 * Produces a generic error response. Call this if you know the error is a non-normal unhandled error of the "how
 * did we get here, this should never happen" variety, or if other attempts to deal with the error failed and you
 * need a guaranteed fallback that will produce a generic error response that follows our error contract. If you
 * have an error that happened during normal processing you should try {@link #processError(HttpProcessingState,
 * Object, Throwable)} instead in order to get an error response that is better tailored to the given error rather
 * than this one which guarantees a somewhat unhelpful generic error response.
 */
@NotNull
ResponseInfo<ErrorResponseBody> processUnhandledError(@NotNull HttpProcessingState state, Object msg, @NotNull Throwable cause) {
    RequestInfo<?> requestInfo = getRequestInfo(state, msg);
    // Run the error through the riposteUnhandledErrorHandler
    ErrorResponseInfo contentFromErrorHandler = riposteUnhandledErrorHandler.handleError(cause, requestInfo);
    ResponseInfo<ErrorResponseBody> responseInfo = new FullResponseInfo<>();
    setupResponseInfoBasedOnErrorResponseInfo(responseInfo, contentFromErrorHandler);
    return responseInfo;
}
Also used : ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody) FullResponseInfo(com.nike.riposte.server.http.impl.FullResponseInfo) NotNull(org.jetbrains.annotations.NotNull)

Example 2 with ErrorResponseInfo

use of com.nike.riposte.server.error.handler.ErrorResponseInfo in project riposte by Nike-Inc.

the class ExceptionHandlingHandlerTest method processUnhandledError_uses_getRequestInfo_and_calls_riposteUnhandledErrorHandler_and_returns_value_of_setupResponseInfoBasedOnErrorResponseInfo.

@Test
public void processUnhandledError_uses_getRequestInfo_and_calls_riposteUnhandledErrorHandler_and_returns_value_of_setupResponseInfoBasedOnErrorResponseInfo() throws JsonProcessingException, UnexpectedMajorErrorHandlingError {
    // given
    HttpProcessingState stateMock = mock(HttpProcessingState.class);
    Object msg = new Object();
    Throwable cause = new Exception();
    ExceptionHandlingHandler handlerSpy = spy(handler);
    RequestInfo<?> requestInfoMock = mock(RequestInfo.class);
    ErrorResponseInfo errorResponseInfoMock = mock(ErrorResponseInfo.class);
    doReturn(requestInfoMock).when(handlerSpy).getRequestInfo(stateMock, msg);
    doReturn(errorResponseInfoMock).when(riposteUnhandledErrorHandlerMock).handleError(cause, requestInfoMock);
    // when
    ResponseInfo<ErrorResponseBody> response = handlerSpy.processUnhandledError(stateMock, msg, cause);
    // then
    verify(handlerSpy).getRequestInfo(stateMock, msg);
    verify(riposteUnhandledErrorHandlerMock).handleError(cause, requestInfoMock);
    ArgumentCaptor<ResponseInfo> responseInfoArgumentCaptor = ArgumentCaptor.forClass(ResponseInfo.class);
    verify(handlerSpy).setupResponseInfoBasedOnErrorResponseInfo(responseInfoArgumentCaptor.capture(), eq(errorResponseInfoMock));
    ResponseInfo<ErrorResponseBody> responseInfoPassedIntoSetupMethod = responseInfoArgumentCaptor.getValue();
    assertThat(response, is(responseInfoPassedIntoSetupMethod));
}
Also used : ResponseInfo(com.nike.riposte.server.http.ResponseInfo) ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) FullResponseInfo(com.nike.riposte.server.http.impl.FullResponseInfo) ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) Assertions.catchThrowable(org.assertj.core.api.Assertions.catchThrowable) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody) IncompleteHttpCallTimeoutException(com.nike.riposte.server.error.exception.IncompleteHttpCallTimeoutException) TooManyOpenChannelsException(com.nike.riposte.server.error.exception.TooManyOpenChannelsException) InvalidRipostePipelineException(com.nike.riposte.server.error.exception.InvalidRipostePipelineException) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) Test(org.junit.Test)

Example 3 with ErrorResponseInfo

use of com.nike.riposte.server.error.handler.ErrorResponseInfo in project riposte by Nike-Inc.

the class ExceptionHandlingHandlerTest method processError_gets_requestInfo_then_calls_riposteErrorHandler_then_converts_to_response_using_setupResponseInfoBasedOnErrorResponseInfo.

@Test
public void processError_gets_requestInfo_then_calls_riposteErrorHandler_then_converts_to_response_using_setupResponseInfoBasedOnErrorResponseInfo() throws UnexpectedMajorErrorHandlingError, JsonProcessingException {
    // given
    HttpProcessingState stateMock = mock(HttpProcessingState.class);
    Object msg = new Object();
    Throwable cause = new Exception();
    ExceptionHandlingHandler handlerSpy = spy(handler);
    RequestInfo<?> requestInfoMock = mock(RequestInfo.class);
    ErrorResponseInfo errorResponseInfoMock = mock(ErrorResponseInfo.class);
    RiposteErrorHandler riposteErrorHandlerMock = mock(RiposteErrorHandler.class);
    Whitebox.setInternalState(handlerSpy, "riposteErrorHandler", riposteErrorHandlerMock);
    doReturn(requestInfoMock).when(handlerSpy).getRequestInfo(stateMock, msg);
    doReturn(errorResponseInfoMock).when(riposteErrorHandlerMock).maybeHandleError(cause, requestInfoMock);
    // when
    ResponseInfo<ErrorResponseBody> response = handlerSpy.processError(stateMock, msg, cause);
    // then
    verify(handlerSpy).getRequestInfo(stateMock, msg);
    verify(riposteErrorHandlerMock).maybeHandleError(cause, requestInfoMock);
    ArgumentCaptor<ResponseInfo> responseInfoArgumentCaptor = ArgumentCaptor.forClass(ResponseInfo.class);
    verify(handlerSpy).setupResponseInfoBasedOnErrorResponseInfo(responseInfoArgumentCaptor.capture(), eq(errorResponseInfoMock));
    ResponseInfo<ErrorResponseBody> responseInfoPassedIntoSetupMethod = responseInfoArgumentCaptor.getValue();
    assertThat(response, is(responseInfoPassedIntoSetupMethod));
}
Also used : ResponseInfo(com.nike.riposte.server.http.ResponseInfo) ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) FullResponseInfo(com.nike.riposte.server.http.impl.FullResponseInfo) ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) Assertions.catchThrowable(org.assertj.core.api.Assertions.catchThrowable) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody) IncompleteHttpCallTimeoutException(com.nike.riposte.server.error.exception.IncompleteHttpCallTimeoutException) TooManyOpenChannelsException(com.nike.riposte.server.error.exception.TooManyOpenChannelsException) InvalidRipostePipelineException(com.nike.riposte.server.error.exception.InvalidRipostePipelineException) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) RiposteErrorHandler(com.nike.riposte.server.error.handler.RiposteErrorHandler) Test(org.junit.Test)

Example 4 with ErrorResponseInfo

use of com.nike.riposte.server.error.handler.ErrorResponseInfo in project riposte by Nike-Inc.

the class ExceptionHandlingHandlerTest method setupResponseInfoBasedOnErrorResponseInfo_sets_response_content_and_httpStatusCode_and_adds_extra_headers.

@Test
public void setupResponseInfoBasedOnErrorResponseInfo_sets_response_content_and_httpStatusCode_and_adds_extra_headers() {
    // given
    ResponseInfo<ErrorResponseBody> responseInfo = new FullResponseInfo<>();
    ErrorResponseBody errorResponseBodyMock = mock(ErrorResponseBody.class);
    int httpStatusCode = 42;
    Map<String, List<String>> extraHeaders = new HashMap<>();
    extraHeaders.put("key1", Arrays.asList("foo", "bar"));
    extraHeaders.put("key2", Arrays.asList("baz"));
    ErrorResponseInfo errorInfoMock = mock(ErrorResponseInfo.class);
    doReturn(errorResponseBodyMock).when(errorInfoMock).getErrorResponseBody();
    doReturn(httpStatusCode).when(errorInfoMock).getErrorHttpStatusCode();
    doReturn(extraHeaders).when(errorInfoMock).getExtraHeadersToAddToResponse();
    // when
    handler.setupResponseInfoBasedOnErrorResponseInfo(responseInfo, errorInfoMock);
    // then
    assertThat(responseInfo.getContentForFullResponse(), is(errorResponseBodyMock));
    assertThat(responseInfo.getHttpStatusCode(), is(httpStatusCode));
    int numIndividualValuesInHeaderMap = extraHeaders.entrySet().stream().map(entry -> entry.getValue()).mapToInt(list -> list.size()).sum();
    assertThat(responseInfo.getHeaders().entries().size(), is(numIndividualValuesInHeaderMap));
    extraHeaders.entrySet().stream().forEach(expectedEntry -> assertThat(responseInfo.getHeaders().getAll(expectedEntry.getKey()), is(expectedEntry.getValue())));
}
Also used : CoreMatchers.is(org.hamcrest.CoreMatchers.is) Span(com.nike.wingtips.Span) Arrays(java.util.Arrays) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) ResponseInfo(com.nike.riposte.server.http.ResponseInfo) DataProviderRunner(com.tngtech.java.junit.dataprovider.DataProviderRunner) DO_NOT_FIRE_CONTINUE_EVENT(com.nike.riposte.server.handler.base.PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT) Collections.singletonList(java.util.Collections.singletonList) CoreMatchers.notNullValue(org.hamcrest.CoreMatchers.notNullValue) Mockito.verifyNoInteractions(org.mockito.Mockito.verifyNoInteractions) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody) Mockito.doThrow(org.mockito.Mockito.doThrow) DefaultHttpRequest(io.netty.handler.codec.http.DefaultHttpRequest) ProxyRouterEndpoint(com.nike.riposte.server.http.ProxyRouterEndpoint) Map(java.util.Map) ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) Assertions(org.assertj.core.api.Assertions) Mockito.doReturn(org.mockito.Mockito.doReturn) RiposteErrorHandler(com.nike.riposte.server.error.handler.RiposteErrorHandler) IncompleteHttpCallTimeoutException(com.nike.riposte.server.error.exception.IncompleteHttpCallTimeoutException) ServerSpanNamingAndTaggingStrategy(com.nike.riposte.server.config.distributedtracing.ServerSpanNamingAndTaggingStrategy) HttpRequest(io.netty.handler.codec.http.HttpRequest) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) TooManyOpenChannelsException(com.nike.riposte.server.error.exception.TooManyOpenChannelsException) List(java.util.List) ChannelAttributes(com.nike.riposte.server.channelpipeline.ChannelAttributes) Mockito.mock(org.mockito.Mockito.mock) HttpProcessingState(com.nike.riposte.server.http.HttpProcessingState) FullResponseInfo(com.nike.riposte.server.http.impl.FullResponseInfo) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) UnexpectedMajorErrorHandlingError(com.nike.riposte.server.error.exception.UnexpectedMajorErrorHandlingError) RequestInfo(com.nike.riposte.server.http.RequestInfo) HttpVersion(io.netty.handler.codec.http.HttpVersion) RunWith(org.junit.runner.RunWith) CoreMatchers.not(org.hamcrest.CoreMatchers.not) HashMap(java.util.HashMap) PipelineContinuationBehavior(com.nike.riposte.server.handler.base.PipelineContinuationBehavior) Mockito.spy(org.mockito.Mockito.spy) DataProvider(com.tngtech.java.junit.dataprovider.DataProvider) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ArgumentCaptor(org.mockito.ArgumentCaptor) Assertions.catchThrowable(org.assertj.core.api.Assertions.catchThrowable) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Whitebox(com.nike.riposte.testutils.Whitebox) CoreMatchers.nullValue(org.hamcrest.CoreMatchers.nullValue) Before(org.junit.Before) Attribute(io.netty.util.Attribute) InvalidRipostePipelineException(com.nike.riposte.server.error.exception.InvalidRipostePipelineException) UseDataProvider(com.tngtech.java.junit.dataprovider.UseDataProvider) HttpMethod(io.netty.handler.codec.http.HttpMethod) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException) Test(org.junit.Test) Mockito.times(org.mockito.Mockito.times) Mockito.verify(org.mockito.Mockito.verify) Channel(io.netty.channel.Channel) RiposteUnhandledErrorHandler(com.nike.riposte.server.error.handler.RiposteUnhandledErrorHandler) Mockito.never(org.mockito.Mockito.never) DistributedTracingConfig(com.nike.riposte.server.config.distributedtracing.DistributedTracingConfig) ProxyRouterProcessingState(com.nike.riposte.server.http.ProxyRouterProcessingState) Collections(java.util.Collections) ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) HashMap(java.util.HashMap) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody) Collections.singletonList(java.util.Collections.singletonList) List(java.util.List) ProxyRouterEndpoint(com.nike.riposte.server.http.ProxyRouterEndpoint) FullResponseInfo(com.nike.riposte.server.http.impl.FullResponseInfo) Test(org.junit.Test)

Example 5 with ErrorResponseInfo

use of com.nike.riposte.server.error.handler.ErrorResponseInfo in project riposte by Nike-Inc.

the class ExceptionHandlingHandler method processError.

/**
 * Attempts to process the given error using the "normal" error handler {@link #riposteErrorHandler} to produce the
 * most specific error response possible for the given error. If that fails for any reason then the unhandled error
 * handler will take over to guarantee the user gets a generic error response that still follows our error contract.
 * If you already know your error is a non-normal unhandled error of the "how did we get here, this should never
 * happen" variety you can (and should) directly call {@link #processUnhandledError(HttpProcessingState, Object,
 * Throwable)} instead.
 */
@NotNull
protected ResponseInfo<ErrorResponseBody> processError(@NotNull HttpProcessingState state, Object msg, @NotNull Throwable cause) {
    RequestInfo<?> requestInfo = getRequestInfo(state, msg);
    try {
        ErrorResponseInfo contentFromErrorHandler = riposteErrorHandler.maybeHandleError(cause, requestInfo);
        if (contentFromErrorHandler != null) {
            // The regular error handler did handle the error. Setup our ResponseInfo.
            ResponseInfo<ErrorResponseBody> responseInfo = new FullResponseInfo<>();
            setupResponseInfoBasedOnErrorResponseInfo(responseInfo, contentFromErrorHandler);
            return responseInfo;
        }
    } catch (Throwable errorHandlerFailed) {
        logger.error("An unexpected problem occurred while trying to handle an error.", errorHandlerFailed);
    }
    // so the riposteUnhandledErrorHandler should take care of it.
    return processUnhandledError(state, msg, cause);
}
Also used : ErrorResponseInfo(com.nike.riposte.server.error.handler.ErrorResponseInfo) ErrorResponseBody(com.nike.riposte.server.error.handler.ErrorResponseBody) FullResponseInfo(com.nike.riposte.server.http.impl.FullResponseInfo) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

ErrorResponseBody (com.nike.riposte.server.error.handler.ErrorResponseBody)6 ErrorResponseInfo (com.nike.riposte.server.error.handler.ErrorResponseInfo)6 FullResponseInfo (com.nike.riposte.server.http.impl.FullResponseInfo)6 Test (org.junit.Test)4 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)3 IncompleteHttpCallTimeoutException (com.nike.riposte.server.error.exception.IncompleteHttpCallTimeoutException)3 InvalidRipostePipelineException (com.nike.riposte.server.error.exception.InvalidRipostePipelineException)3 TooManyOpenChannelsException (com.nike.riposte.server.error.exception.TooManyOpenChannelsException)3 HttpProcessingState (com.nike.riposte.server.http.HttpProcessingState)3 ResponseInfo (com.nike.riposte.server.http.ResponseInfo)3 Assertions.catchThrowable (org.assertj.core.api.Assertions.catchThrowable)3 RiposteErrorHandler (com.nike.riposte.server.error.handler.RiposteErrorHandler)2 ProxyRouterEndpoint (com.nike.riposte.server.http.ProxyRouterEndpoint)2 ChannelAttributes (com.nike.riposte.server.channelpipeline.ChannelAttributes)1 DistributedTracingConfig (com.nike.riposte.server.config.distributedtracing.DistributedTracingConfig)1 ServerSpanNamingAndTaggingStrategy (com.nike.riposte.server.config.distributedtracing.ServerSpanNamingAndTaggingStrategy)1 UnexpectedMajorErrorHandlingError (com.nike.riposte.server.error.exception.UnexpectedMajorErrorHandlingError)1 RiposteUnhandledErrorHandler (com.nike.riposte.server.error.handler.RiposteUnhandledErrorHandler)1 PipelineContinuationBehavior (com.nike.riposte.server.handler.base.PipelineContinuationBehavior)1 DO_NOT_FIRE_CONTINUE_EVENT (com.nike.riposte.server.handler.base.PipelineContinuationBehavior.DO_NOT_FIRE_CONTINUE_EVENT)1