@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 }
@After public void afterMethod() { resetTracing(); }
@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 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 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) ); }
@Before public void setupMethod() { requestMock = mock(HttpServletRequest.class); responseMock = mock(HttpServletResponse.class); filterChainMock = mock(FilterChain.class); spanCapturingFilterChain = new SpanCapturingFilterChain(); initialSpanNameFromStrategy = new AtomicReference<>("span-name-from-strategy-" + UUID.randomUUID().toString()); strategyInitialSpanNameMethodCalled = new AtomicBoolean(false); strategyRequestTaggingMethodCalled = new AtomicBoolean(false); strategyResponseTaggingAndFinalSpanNameMethodCalled = new AtomicBoolean(false); strategyInitialSpanNameArgs = new AtomicReference<>(null); strategyRequestTaggingArgs = new AtomicReference<>(null); strategyResponseTaggingArgs = new AtomicReference<>(null); tagAndNamingStrategy = new ArgCapturingHttpTagAndSpanNamingStrategy( initialSpanNameFromStrategy, strategyInitialSpanNameMethodCalled, strategyRequestTaggingMethodCalled, strategyResponseTaggingAndFinalSpanNameMethodCalled, strategyInitialSpanNameArgs, strategyRequestTaggingArgs, strategyResponseTaggingArgs ); tagAndNamingAdapterMock = mock(HttpTagAndSpanNamingAdapter.class); filterConfigMock = mock(FilterConfig.class); doReturn(USER_ID_HEADER_KEYS_INIT_PARAM_VALUE_STRING) .when(filterConfigMock) .getInitParameter(RequestTracingFilter.USER_ID_HEADER_KEYS_LIST_INIT_PARAM_NAME); servletRuntimeMock = mock(ServletRuntime.class); resetTracing(); }
@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_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 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()); }
) throws ServletException, IOException { RequestTracingFilter filterSpy = spy(getBasicFilter()); AtomicReference<Span> spanContextHolder = new AtomicReference<>(); FilterChain explodingFilterChain = (request, response) -> { setupAsyncContextWorkflow();
@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"); }
) { final RequestTracingFilter filter = getBasicFilter(); if (isAsync) { setupAsyncContextWorkflow();
@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_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); }