@Test public void doFilter_should_not_explode_if_request_and_response_are_HttpServletRequests_and_HttpServletResponses( ) throws IOException, ServletException { // expect getBasicFilter().doFilter( mock(HttpServletRequest.class), mock(HttpServletResponse.class), mock(FilterChain.class) ); // No explosion no problem }
@Test public void skipDispatch_should_return_false() { // given: filter RequestTracingFilter filter = getBasicFilter(); // when: skipDispatchIsCalled boolean result = filter.skipDispatch(requestMock); // then: the result should be false assertThat(result).isFalse(); }
@Test public void getServletRuntime_uses_cached_value_if_possible() { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); ServletRuntime servletRuntimeMock = mock(ServletRuntime.class); filterSpy.servletRuntime = servletRuntimeMock; // when ServletRuntime result = filterSpy.getServletRuntime(mock(HttpServletRequest.class)); // then assertThat(result).isSameAs(servletRuntimeMock); }
@Test public void doFilterInternal_should_set_trace_id_in_response_header() throws ServletException, IOException { // given: filter RequestTracingFilter filter = getBasicFilter(); // when: doFilterInternal is called filter.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then: response header should be set with the span's trace ID assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); verify(responseMock).setHeader(TraceHeaders.TRACE_ID, spanCapturingFilterChain.capturedSpan.getTraceId()); }
@Test(expected = ServletException.class) public void doFilter_should_explode_if_request_is_not_HttpServletRequest() throws IOException, ServletException { // expect getBasicFilter().doFilter(mock(ServletRequest.class), mock(HttpServletResponse.class), mock(FilterChain.class)); fail("Expected ServletException but no exception was thrown"); }
@Test(expected = ServletException.class) public void doFilter_should_explode_if_response_is_not_HttpServletResponse() throws IOException, ServletException { // expect getBasicFilter().doFilter(mock(HttpServletRequest.class), mock(ServletResponse.class), mock(FilterChain.class)); fail("Expected ServletException but no exception was thrown"); }
@Test public void doFilterInternal_should_not_call_setupTracingCompletionWhenAsyncRequestCompletes_when_isAsyncRequest_returns_false( ) throws ServletException, IOException { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); doReturn(false).when(filterSpy).isAsyncRequest(any(HttpServletRequest.class)); // when filterSpy.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); assertThat(spanCapturingFilterChain.capturedSpan.isCompleted()).isTrue(); verify(filterSpy, never()).setupTracingCompletionWhenAsyncRequestCompletes( any(HttpServletRequest.class), any(HttpServletResponse.class), any(TracingState.class), any(HttpTagAndSpanNamingStrategy.class), any(HttpTagAndSpanNamingAdapter.class) ); }
@Test public void doFilterInternal_should_set_request_attributes_to_new_span_info() throws ServletException, IOException { // given: filter RequestTracingFilter filter = getBasicFilter(); // when: doFilterInternal is called filter.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then: request attributes should be set with the new span's info assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); Span newSpan = spanCapturingFilterChain.capturedSpan; verify(requestMock).setAttribute(TraceHeaders.TRACE_SAMPLED, newSpan.isSampleable()); verify(requestMock).setAttribute(TraceHeaders.TRACE_ID, newSpan.getTraceId()); verify(requestMock).setAttribute(TraceHeaders.SPAN_ID, newSpan.getSpanId()); verify(requestMock).setAttribute(TraceHeaders.PARENT_SPAN_ID, newSpan.getParentSpanId()); verify(requestMock).setAttribute(TraceHeaders.SPAN_NAME, newSpan.getSpanName()); verify(requestMock).setAttribute(Span.class.getName(), newSpan); }
@Test public void doFilterInternal_should_not_add_async_listener_when_isAsyncRequest_returns_false( ) throws ServletException, IOException { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); doReturn(false).when(filterSpy).isAsyncRequest(any(HttpServletRequest.class)); setupAsyncContextWorkflow(); // when filterSpy.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); assertThat(spanCapturingFilterChain.capturedSpan.isCompleted()).isTrue(); assertThat(capturedAsyncListeners).hasSize(0); verify(filterSpy, never()).setupTracingCompletionWhenAsyncRequestCompletes( any(HttpServletRequest.class), any(HttpServletResponse.class), any(TracingState.class), any(HttpTagAndSpanNamingStrategy.class), any(HttpTagAndSpanNamingAdapter.class) ); }
@Test public void doFilterInternal_should_set_request_attributes_to_new_span_info_with_alt_user_id( ) throws ServletException, IOException { // given: filter RequestTracingFilter spyFilter = spy(getBasicFilter()); given(requestMock.getHeader(ALT_USER_ID_HEADER_KEY)).willReturn("testUserId"); // when: doFilterInternal is called spyFilter.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then: request attributes should be set with the new span's info assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); Span newSpan = spanCapturingFilterChain.capturedSpan; assertThat(newSpan.getUserId()).isEqualTo("testUserId"); }
@Test public void doFilter_should_call_doFilterInternal_and_set_ALREADY_FILTERED_ATTRIBUTE_KEY_if_not_already_filtered_and_skipDispatch_returns_false() throws IOException, ServletException { // given: filter that returns false for skipDispatch and request that returns null for already-filtered attribute RequestTracingFilter spyFilter = spy(getBasicFilter()); given(requestMock.getAttribute( RequestTracingFilter.FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE)).willReturn(null); // when: doFilter() is called spyFilter.doFilter(requestMock, responseMock, filterChainMock); // then: doFilterInternal should be called and ALREADY_FILTERED_ATTRIBUTE_KEY should be set on the request verify(spyFilter).doFilterInternal(requestMock, responseMock, filterChainMock); verify(requestMock).setAttribute(RequestTracingFilter.FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE, Boolean.TRUE); }
@Test public void doFilterInternal_should_set_request_attributes_to_new_span_info_with_user_id( ) throws ServletException, IOException { // given: filter RequestTracingFilter spyFilter = spy(getBasicFilter()); given(requestMock.getHeader(USER_ID_HEADER_KEY)).willReturn("testUserId"); // when: doFilterInternal is called spyFilter.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then: request attributes should be set with the new span's info assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); Span newSpan = spanCapturingFilterChain.capturedSpan; assertThat(newSpan.getUserId()).isEqualTo("testUserId"); }
@Test public void getServletRuntime_returns_value_of_ServletRuntime_determineServletRuntime_method_and_caches_result() { // given Class<? extends ServletRuntime> expectedServletRuntimeClass = ServletRuntime.determineServletRuntime(requestMock.getClass(), ASYNC_LISTENER_CLASSNAME).getClass(); RequestTracingFilter filter = getBasicFilter(); assertThat(filter.servletRuntime).isNull(); // when ServletRuntime result = filter.getServletRuntime(requestMock); // then assertThat(result.getClass()).isEqualTo(expectedServletRuntimeClass); assertThat(filter.servletRuntime).isSameAs(result); }
@Test public void doFilter_should_not_call_doFilterInternal_if_already_filtered() throws IOException, ServletException { // given: filter that returns false for skipDispatch but request that returns non-null for already-filtered attribute RequestTracingFilter spyFilter = spy(getBasicFilter()); given(requestMock.getAttribute( RequestTracingFilter.FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE)).willReturn(Boolean.TRUE); // when: doFilter() is called spyFilter.doFilter(requestMock, responseMock, filterChainMock); // then: doFilterInternal should not be called verify(spyFilter, times(0)).doFilterInternal(requestMock, responseMock, filterChainMock); }
@Test public void doFilter_should_not_call_doFilterInternal_if_not_already_filtered_but_skipDispatch_returns_true( ) throws IOException, ServletException { // given: request that returns null for already-filtered attribute but filter that returns true for skipDispatch RequestTracingFilter spyFilter = spy(getBasicFilter()); doReturn(true).when(spyFilter).skipDispatch(any(HttpServletRequest.class)); given(requestMock.getAttribute(RequestTracingFilter.FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE)).willReturn(null); // when: doFilter() is called spyFilter.doFilter(requestMock, responseMock, filterChainMock); // then: doFilterInternal should not be called verify(spyFilter, times(0)).doFilterInternal(requestMock, responseMock, filterChainMock); verify(spyFilter).skipDispatch(requestMock); }
@Test public void doFilterInternal_should_call_setupTracingCompletionWhenAsyncRequestCompletes_when_isAsyncRequest_returns_true( ) throws ServletException, IOException { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); setupAsyncContextWorkflow(); doReturn(true).when(filterSpy).isAsyncRequest(any(HttpServletRequest.class)); // when filterSpy.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); assertThat(spanCapturingFilterChain.capturedSpan.isCompleted()).isFalse(); verify(filterSpy).setupTracingCompletionWhenAsyncRequestCompletes( eq(requestMock), eq(responseMock), any(TracingState.class), any(HttpTagAndSpanNamingStrategy.class), any(HttpTagAndSpanNamingAdapter.class) ); }
@DataProvider(value = { "true", "false" }, splitBy = "\\|") @Test public void isAsyncRequest_delegates_to_ServletRuntime(boolean servletRuntimeResult) { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); doReturn(servletRuntimeMock).when(filterSpy).getServletRuntime(any(HttpServletRequest.class)); doReturn(servletRuntimeResult).when(servletRuntimeMock).isAsyncRequest(any(HttpServletRequest.class)); // when boolean result = filterSpy.isAsyncRequest(requestMock); // then assertThat(result).isEqualTo(servletRuntimeResult); verify(filterSpy).getServletRuntime(requestMock); verify(servletRuntimeMock).isAsyncRequest(requestMock); }
@DataProvider(value = { "true", "false" }) @Test @SuppressWarnings("deprecation") public void isAsyncDispatch_delegates_to_ServletRuntime(boolean servletRuntimeResult) { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); doReturn(servletRuntimeMock).when(filterSpy).getServletRuntime(any(HttpServletRequest.class)); doReturn(servletRuntimeResult).when(servletRuntimeMock).isAsyncDispatch(any(HttpServletRequest.class)); // when boolean result = filterSpy.isAsyncDispatch(requestMock); // then assertThat(result).isEqualTo(servletRuntimeResult); verify(filterSpy).getServletRuntime(requestMock); verify(servletRuntimeMock).isAsyncDispatch(requestMock); }
@Test public void doFilterInternal_should_add_async_listener_but_not_complete_span_when_async_request_is_detected( ) throws ServletException, IOException { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); setupAsyncContextWorkflow(); // when filterSpy.doFilterInternal(requestMock, responseMock, spanCapturingFilterChain); // then assertThat(spanCapturingFilterChain.capturedSpan).isNotNull(); assertThat(spanCapturingFilterChain.capturedSpan.isCompleted()).isFalse(); assertThat(capturedAsyncListeners).hasSize(1); assertThat(capturedAsyncListeners.get(0)).isInstanceOf(WingtipsRequestSpanCompletionAsyncListener.class); verify(filterSpy).setupTracingCompletionWhenAsyncRequestCompletes( eq(requestMock), eq(responseMock), any(TracingState.class), any(HttpTagAndSpanNamingStrategy.class), any(HttpTagAndSpanNamingAdapter.class) ); }
@Test public void setupTracingCompletionWhenAsyncRequestCompletes_delegates_to_ServletRuntime() { // given RequestTracingFilter filterSpy = spy(getBasicFilter()); doReturn(servletRuntimeMock).when(filterSpy).getServletRuntime(any(HttpServletRequest.class)); TracingState tracingStateMock = mock(TracingState.class); // when filterSpy.setupTracingCompletionWhenAsyncRequestCompletes( requestMock, responseMock, tracingStateMock, tagAndNamingStrategy, tagAndNamingAdapterMock ); // then verify(filterSpy).setupTracingCompletionWhenAsyncRequestCompletes( requestMock, responseMock, tracingStateMock, tagAndNamingStrategy, tagAndNamingAdapterMock ); verify(filterSpy).getServletRuntime(requestMock); verify(servletRuntimeMock).setupTracingCompletionWhenAsyncRequestCompletes( requestMock, responseMock, tracingStateMock, tagAndNamingStrategy, tagAndNamingAdapterMock ); verifyNoMoreInteractions(filterSpy, servletRuntimeMock, requestMock, tracingStateMock); }