@Test public void constructor_uses_provided_list_if_not_empty() { // given List<RequestAndResponseFilter> filters = Collections.singletonList(mock(RequestAndResponseFilter.class)); // when RequestFilterHandler handler = new RequestFilterHandler(filters); // then assertThat(handler.filters).isEqualTo(filters); }
(filter, request) -> filter.filterRequestFirstChunkWithOptionalShortCircuitResponse(request, ctx); return handleFilterLogic(ctx, msg, state, normalFilterCall, shortCircuitFilterCall); (filter, request) -> filter.filterRequestLastChunkWithOptionalShortCircuitResponse(request, ctx); return handleFilterLogic(ctx, msg, state, normalFilterCall, shortCircuitFilterCall);
currentReqInfo = requestInfoUpdateNoNulls(currentReqInfo, result.getLeft()); requestInfoUpdateNoNulls(currentReqInfo, normalFilterCall.apply(filter, currentReqInfo));
@Test public void doChannelRead_does_nothing_and_returns_CONTINUE_when_msg_is_not_first_or_last_chunk() throws Exception { // given HttpContent contentChunkMsg = mock(HttpContent.class); // when PipelineContinuationBehavior result = handlerSpy.doChannelRead(ctxMock, contentChunkMsg); // then assertThat(result).isEqualTo(CONTINUE); verify(handlerSpy, never()).handleFilterLogic(any(), any(), any(), any(), any()); }
@Test public void argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo_only_returns_true_for_HttpRequest_or_LastHttpContent() { // given Object httpRequestMsg = mock(HttpRequest.class); Object lastHttpContentMsg = mock(LastHttpContent.class); Object httpMessageMsg = mock(HttpMessage.class); // expect assertThat(handlerSpy.argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo( DO_CHANNEL_READ, ctxMock, httpRequestMsg, null) ).isTrue(); assertThat(handlerSpy.argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo( DO_CHANNEL_READ, ctxMock, lastHttpContentMsg, null) ).isTrue(); assertThat(handlerSpy.argsAreEligibleForLinkingAndUnlinkingDistributedTracingInfo( DO_CHANNEL_READ, ctxMock, httpMessageMsg, null) ).isFalse(); }
@Test public void doChannelRead_HttpRequest_throws_exception_when_failed_decoder_result() { // given Throwable decoderFailureCauseMock = mock(Throwable.class); DecoderResult decoderResult = DecoderResult.failure(decoderFailureCauseMock); doReturn(decoderResult).when(firstChunkMsgMock).decoderResult(); state.setRequestInfo(null); // when Throwable thrownException = Assertions.catchThrowable(() -> handlerSpy.doChannelRead(ctxMock, firstChunkMsgMock)); // then assertThat(thrownException).isExactlyInstanceOf(InvalidHttpRequestException.class); assertThat(thrownException.getCause()).isSameAs(decoderFailureCauseMock); }
@DataProvider(value = { "CONTINUE", "DO_NOT_FIRE_CONTINUE_EVENT" }, splitBy = "\\|") @Test public void doChannelRead_delegates_to_handleFilterLogic_with_first_chunk_method_references_when_msg_is_HttpRequest( PipelineContinuationBehavior expectedPipelineContinuationBehavior ) throws Exception { // given doReturn(expectedPipelineContinuationBehavior).when(handlerSpy).handleFilterLogic(any(), any(), any(), any(), any()); // when PipelineContinuationBehavior result = handlerSpy.doChannelRead(ctxMock, firstChunkMsgMock); // then assertThat(result).isEqualTo(expectedPipelineContinuationBehavior); ArgumentCaptor<BiFunction> normalFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class); ArgumentCaptor<BiFunction> shortCircuitFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class); verify(handlerSpy).handleFilterLogic(eq(ctxMock), eq(firstChunkMsgMock), eq(state), normalFilterCallCaptor.capture(), shortCircuitFilterCallCaptor.capture()); BiFunction<RequestAndResponseFilter, RequestInfo, RequestInfo> normalFilterCall = normalFilterCallCaptor.getValue(); BiFunction<RequestAndResponseFilter, RequestInfo, Pair<RequestInfo, Optional<ResponseInfo<?>>>> shortCircuitFilterCall = shortCircuitFilterCallCaptor.getValue(); RequestAndResponseFilter filterForNormalCallMock = mock(RequestAndResponseFilter.class); normalFilterCall.apply(filterForNormalCallMock, requestInfoMock); verify(filterForNormalCallMock).filterRequestFirstChunkNoPayload(requestInfoMock, ctxMock); RequestAndResponseFilter filterForShortCircuitCallMock = mock(RequestAndResponseFilter.class); shortCircuitFilterCall.apply(filterForShortCircuitCallMock, requestInfoMock); verify(filterForShortCircuitCallMock).filterRequestFirstChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock); }
(filter, request) -> filter.filterRequestFirstChunkWithOptionalShortCircuitResponse(request, ctx); return handleFilterLogic(ctx, msg, state, normalFilterCall, shortCircuitFilterCall); (filter, request) -> filter.filterRequestLastChunkWithOptionalShortCircuitResponse(request, ctx); return handleFilterLogic(ctx, msg, state, normalFilterCall, shortCircuitFilterCall);
@DataProvider(value = { "CONTINUE", "DO_NOT_FIRE_CONTINUE_EVENT" }, splitBy = "\\|") @Test public void doChannelRead_delegates_to_handleFilterLogic_with_last_chunk_method_references_when_msg_is_LastHttpContent( PipelineContinuationBehavior expectedPipelineContinuationBehavior ) throws Exception { // given doReturn(expectedPipelineContinuationBehavior).when(handlerSpy).handleFilterLogic(any(), any(), any(), any(), any()); // when PipelineContinuationBehavior result = handlerSpy.doChannelRead(ctxMock, lastChunkMsgMock); // then assertThat(result).isEqualTo(expectedPipelineContinuationBehavior); ArgumentCaptor<BiFunction> normalFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class); ArgumentCaptor<BiFunction> shortCircuitFilterCallCaptor = ArgumentCaptor.forClass(BiFunction.class); verify(handlerSpy).handleFilterLogic(eq(ctxMock), eq(lastChunkMsgMock), eq(state), normalFilterCallCaptor.capture(), shortCircuitFilterCallCaptor.capture()); BiFunction<RequestAndResponseFilter, RequestInfo, RequestInfo> normalFilterCall = normalFilterCallCaptor.getValue(); BiFunction<RequestAndResponseFilter, RequestInfo, Pair<RequestInfo, Optional<ResponseInfo<?>>>> shortCircuitFilterCall = shortCircuitFilterCallCaptor.getValue(); RequestAndResponseFilter filterForNormalCallMock = mock(RequestAndResponseFilter.class); normalFilterCall.apply(filterForNormalCallMock, requestInfoMock); verify(filterForNormalCallMock).filterRequestLastChunkWithFullPayload(requestInfoMock, ctxMock); RequestAndResponseFilter filterForShortCircuitCallMock = mock(RequestAndResponseFilter.class); shortCircuitFilterCall.apply(filterForShortCircuitCallMock, requestInfoMock); verify(filterForShortCircuitCallMock).filterRequestLastChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock); }
@Before public void beforeMethod() { channelMock = mock(Channel.class); ctxMock = mock(ChannelHandlerContext.class); stateAttributeMock = mock(Attribute.class); state = new HttpProcessingState(); doReturn(channelMock).when(ctxMock).channel(); doReturn(stateAttributeMock).when(channelMock).attr(ChannelAttributes.HTTP_PROCESSING_STATE_ATTRIBUTE_KEY); doReturn(state).when(stateAttributeMock).get(); firstChunkMsgMock = mock(HttpRequest.class); lastChunkMsgMock = mock(LastHttpContent.class); filter1Mock = mock(RequestAndResponseFilter.class); filter2Mock = mock(RequestAndResponseFilter.class); filtersList = Arrays.asList(filter1Mock, filter2Mock); handlerSpy = spy(new RequestFilterHandler(filtersList)); requestInfoMock = mock(RequestInfo.class); state.setRequestInfo(requestInfoMock); }
currentReqInfo = requestInfoUpdateNoNulls(currentReqInfo, result.getLeft()); requestInfoUpdateNoNulls(currentReqInfo, normalFilterCall.apply(filter, currentReqInfo));
@DataProvider(value = { "true | 0", "true | 1", "false | 0", "false | 1" }, splitBy = "\\|") @Test public void handleFilterLogic_gracefully_handles_a_filter_throwing_an_exception_and_continues_processing_other_filters(boolean isFirstChunk, int explodingFilterIndex) { // given HandleFilterLogicMethodCallArgs args = new HandleFilterLogicMethodCallArgs(isFirstChunk); doThrow(new RuntimeException("kaboom")).when(filtersList.get(explodingFilterIndex)).filterRequestFirstChunkNoPayload(any(), any()); doThrow(new RuntimeException("kaboom")).when(filtersList.get(explodingFilterIndex)).filterRequestLastChunkWithFullPayload(any(), any()); // when handlerSpy.handleFilterLogic(ctxMock, args.msg, args.httpState, args.normalFilterCall, args.shortCircuitFilterCall); // then filtersList.forEach(filter -> { if (isFirstChunk) verify(filter).filterRequestFirstChunkNoPayload(requestInfoMock, ctxMock); else verify(filter).filterRequestLastChunkWithFullPayload(requestInfoMock, ctxMock); }); }
) throws Exception { doReturn(CONTINUE).when(handlerSpy).handleFilterLogic(any(), any(), any(), any(), any()); handlerSpy.doChannelRead(ctxMock, firstChunkMsgMock);
beforeSecurityRequestFilterHandler = beforeSecurityFilters.isEmpty()? null : new RequestFilterHandler(beforeSecurityFilters); afterSecurityRequestFilterHandler = afterSecurityFilters.isEmpty()? null : new RequestFilterHandler(afterSecurityFilters); } else { beforeSecurityRequestFilterHandler = null;
@DataProvider(value = { "true", "false" }, splitBy = "\\|") @Test public void handleFilterLogic_executes_all_filters_and_uses_original_request_when_filters_are_not_short_circuiting_and_return_null(boolean isFirstChunk) { // given HandleFilterLogicMethodCallArgs args = new HandleFilterLogicMethodCallArgs(isFirstChunk); filtersList.forEach(filter -> doReturn(false).when(filter).isShortCircuitRequestFilter()); // when PipelineContinuationBehavior result = handlerSpy.handleFilterLogic(ctxMock, args.msg, args.httpState, args.normalFilterCall, args.shortCircuitFilterCall); // then assertThat(result).isEqualTo(CONTINUE); filtersList.forEach(filter -> { if (isFirstChunk) verify(filter).filterRequestFirstChunkNoPayload(requestInfoMock, ctxMock); else verify(filter).filterRequestLastChunkWithFullPayload(requestInfoMock, ctxMock); }); assertThat(state.getRequestInfo()).isSameAs(requestInfoMock); }
beforeSecurityRequestFilterHandler = beforeSecurityFilters.isEmpty()? null : new RequestFilterHandler(beforeSecurityFilters); afterSecurityRequestFilterHandler = afterSecurityFilters.isEmpty()? null : new RequestFilterHandler(afterSecurityFilters); } else { beforeSecurityRequestFilterHandler = null;
@DataProvider(value = { "true", "false" }, splitBy = "\\|") @Test public void handleFilterLogic_executes_all_filters_and_uses_original_request_when_filters_are_short_circuiting_and_return_null(boolean isFirstChunk) { // given HandleFilterLogicMethodCallArgs args = new HandleFilterLogicMethodCallArgs(isFirstChunk); filtersList.forEach(filter -> doReturn(true).when(filter).isShortCircuitRequestFilter()); // when PipelineContinuationBehavior result = handlerSpy.handleFilterLogic(ctxMock, args.msg, args.httpState, args.normalFilterCall, args.shortCircuitFilterCall); // then assertThat(result).isEqualTo(CONTINUE); filtersList.forEach(filter -> { if (isFirstChunk) verify(filter).filterRequestFirstChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock); else verify(filter).filterRequestLastChunkWithOptionalShortCircuitResponse(requestInfoMock, ctxMock); }); assertThat(state.getRequestInfo()).isSameAs(requestInfoMock); }
@DataProvider(value = { "true", "false" }, splitBy = "\\|") @Test public void constructor_uses_empty_list_if_passed_null_or_empty(boolean isNullList) { // given List<RequestAndResponseFilter> badFiltersList = (isNullList) ? null : Collections.emptyList(); // when RequestFilterHandler handler = new RequestFilterHandler(badFiltersList); // then assertThat(handler.filters) .isNotNull() .isEmpty(); }
PipelineContinuationBehavior result = handlerSpy.handleFilterLogic(ctxMock, args.msg, args.httpState, args.normalFilterCall, args.shortCircuitFilterCall);
PipelineContinuationBehavior result = handlerSpy.handleFilterLogic(ctxMock, args.msg, args.httpState, args.normalFilterCall, args.shortCircuitFilterCall);