@Test public void getDefaultTagStrategy_delegates_to_getZipkinHttpTagStrategy() { // given RequestTracingFilter filterSpy = spy(new RequestTracingFilter()); HttpTagAndSpanNamingStrategy<HttpServletRequest, HttpServletResponse> zipkinStrategyMock = mock(HttpTagAndSpanNamingStrategy.class); doReturn(zipkinStrategyMock).when(filterSpy).getZipkinHttpTagStrategy(); // when HttpTagAndSpanNamingStrategy<HttpServletRequest, HttpServletResponse> result = filterSpy.getDefaultTagStrategy(); // then assertThat(result).isSameAs(zipkinStrategyMock); verify(filterSpy).getDefaultTagStrategy(); }
@Override public void doFilter( ServletRequest request, ServletResponse response ) throws IOException, ServletException { // Verify that when the filter chain is called we're in doFilterInternal, and that the request has ALREADY_FILTERED_ATTRIBUTE_KEY set verify(spyFilter).doFilterInternal(requestMock, responseMock, this); verify(requestMock).setAttribute( RequestTracingFilter.FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE, Boolean.TRUE ); verify(requestMock, times(0)).removeAttribute( RequestTracingFilter.FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE ); ifObjectAddedThenSmartFilterChainCalled.add(true); } };
/** * @param filterConfig The {@link FilterConfig} for initializing this Servlet filter. * @return The {@link HttpTagAndSpanNamingAdapter} that should be used by this instance. Delegates to * {@link #getTagAdapterFromName(String)}, and uses {@link #getDefaultTagAdapter()} as a last resort if * {@link #getTagAdapterFromName(String)} throws an exception. */ protected HttpTagAndSpanNamingAdapter<HttpServletRequest, HttpServletResponse> initializeTagAndNamingAdapter( FilterConfig filterConfig ) { String tagAdapterString = filterConfig.getInitParameter(TAG_AND_SPAN_NAMING_ADAPTER_INIT_PARAM_NAME); try { return getTagAdapterFromName(tagAdapterString); } catch(Throwable t) { logger.warn( "Unable to match tagging adapter " + tagAdapterString + ". Using default ServletRequestTagAdapter", t ); return getDefaultTagAdapter(); } }
/** * @param filterConfig The {@link FilterConfig} for initializing this Servlet filter. * @return The {@link HttpTagAndSpanNamingStrategy} that should be used by this instance. Delegates to * {@link #getTagStrategyFromName(String)}, and uses {@link #getDefaultTagStrategy()} as a last resort if * {@link #getTagStrategyFromName(String)} throws an exception. */ protected HttpTagAndSpanNamingStrategy<HttpServletRequest, HttpServletResponse> initializeTagAndNamingStrategy( FilterConfig filterConfig ) { String tagStrategyString = filterConfig.getInitParameter(TAG_AND_SPAN_NAMING_STRATEGY_INIT_PARAM_NAME); try { return getTagStrategyFromName(tagStrategyString); } catch(Throwable t) { logger.warn("Unable to match tagging strategy " + tagStrategyString + ". Using default Zipkin strategy", t); return getDefaultTagStrategy(); } }
/** * Wrapper around {@link #doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain)} to make sure this * filter's logic is only executed once per request. */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) { throw new ServletException(this.getClass().getName() + " only supports HTTP requests"); } HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; boolean filterHasAlreadyExecuted = request.getAttribute(FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE) != null; if (filterHasAlreadyExecuted || skipDispatch(httpRequest)) { // Already executed or we're supposed to skip, so continue the filter chain without doing the // distributed tracing work. filterChain.doFilter(request, response); } else { // Time to execute the distributed tracing logic. request.setAttribute(FILTER_HAS_ALREADY_EXECUTED_ATTRIBUTE, Boolean.TRUE); doFilterInternal(httpRequest, httpResponse, filterChain); } }
) throws IllegalAccessException, InstantiationException, ClassNotFoundException { RequestTracingFilter filterSpy = spy(new RequestTracingFilter()); HttpTagAndSpanNamingStrategy<HttpServletRequest, HttpServletResponse> zipkinStrategyMock = mock(HttpTagAndSpanNamingStrategy.class); mock(HttpTagAndSpanNamingStrategy.class); doReturn(zipkinStrategyMock).when(filterSpy).getZipkinHttpTagStrategy(); doReturn(openTracingStrategyMock).when(filterSpy).getOpenTracingHttpTagStrategy(); doReturn(noOpStrategyMock).when(filterSpy).getNoOpTagStrategy(); result = filterSpy.getTagStrategyFromName(knownStrategyShortName);
@Test public void init_method_delegates_to_helpers_to_initialize_fields() throws ServletException { // given RequestTracingFilter filterSpy = spy(new RequestTracingFilter()); List<String> expectedUserIdHeaderKeys = Arrays.asList(UUID.randomUUID().toString(), UUID.randomUUID().toString()); doReturn(expectedUserIdHeaderKeys).when(filterSpy).initializeUserIdHeaderKeys(any(FilterConfig.class)); doReturn(tagAndNamingStrategy).when(filterSpy).initializeTagAndNamingStrategy(any(FilterConfig.class)); doReturn(tagAndNamingAdapterMock).when(filterSpy).initializeTagAndNamingAdapter(any(FilterConfig.class)); // when filterSpy.init(filterConfigMock); // then assertThat(filterSpy.userIdHeaderKeysFromInitParam).isSameAs(expectedUserIdHeaderKeys); assertThat(filterSpy.tagAndNamingStrategy).isSameAs(tagAndNamingStrategy); assertThat(filterSpy.tagAndNamingAdapter).isSameAs(tagAndNamingAdapterMock); verify(filterSpy).init(filterConfigMock); verify(filterSpy).initializeUserIdHeaderKeys(filterConfigMock); verify(filterSpy).initializeTagAndNamingStrategy(filterConfigMock); verify(filterSpy).initializeTagAndNamingAdapter(filterConfigMock); verifyNoMoreInteractions(filterSpy); }
@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) ); }
) throws IllegalAccessException, InstantiationException, ClassNotFoundException { RequestTracingFilter filterSpy = spy(new RequestTracingFilter()); doThrow(new RuntimeException("intentional exception")).when(filterSpy).getTagAdapterFromName(anyString()); doReturn(adapterFromDesiredMethodMock).when(filterSpy).getTagAdapterFromName(anyString()); doReturn(fallbackDefaultAdapterMock).when(filterSpy).getDefaultTagAdapter(); filterSpy.initializeTagAndNamingAdapter(filterConfigMock); verify(filterSpy).getTagAdapterFromName(tagAdapterFromFilterConfig); verify(filterSpy).getDefaultTagAdapter(); verify(filterSpy, never()).getDefaultTagAdapter();
) throws IllegalAccessException, InstantiationException, ClassNotFoundException { RequestTracingFilter filterSpy = spy(new RequestTracingFilter()); doThrow(new RuntimeException("intentional exception")).when(filterSpy).getTagStrategyFromName(anyString()); doReturn(strategyFromDesiredMethodMock).when(filterSpy).getTagStrategyFromName(anyString()); doReturn(fallbackDefaultStrategyMock).when(filterSpy).getDefaultTagStrategy(); filterSpy.initializeTagAndNamingStrategy(filterConfigMock); verify(filterSpy).getTagStrategyFromName(tagStrategyFromFilterConfig); verify(filterSpy).getDefaultTagStrategy(); verify(filterSpy, never()).getDefaultTagStrategy();
@DataProvider(value = { "null", "", " ", " \t\r\n " }) @Test public void getTagAdapterFromName_returns_default_adapter_if_passed_null_or_blank_string( String adapterName ) throws IllegalAccessException, InstantiationException, ClassNotFoundException { // given RequestTracingFilter filterSpy = spy(new RequestTracingFilter()); HttpTagAndSpanNamingAdapter<HttpServletRequest, HttpServletResponse> defaultAdapterMock = mock(HttpTagAndSpanNamingAdapter.class); doReturn(defaultAdapterMock).when(filterSpy).getDefaultTagAdapter(); // when HttpTagAndSpanNamingAdapter<HttpServletRequest, HttpServletResponse> result = filterSpy.getTagAdapterFromName(adapterName); // then assertThat(result).isSameAs(defaultAdapterMock); verify(filterSpy).getDefaultTagAdapter(); }
return getZipkinHttpTagStrategy(); return getOpenTracingHttpTagStrategy(); return getNoOpTagStrategy();
@Test public void getUserIdHeaderKeys_returns_userIdHeaderKeysFromInitParam_field() { // given RequestTracingFilter filter = new RequestTracingFilter(); List<String> expectedUserIdHeaderKeys = Arrays.asList(UUID.randomUUID().toString(), UUID.randomUUID().toString()); filter.userIdHeaderKeysFromInitParam = expectedUserIdHeaderKeys; // when List<String> result = filter.getUserIdHeaderKeys(); // then assertThat(result).isSameAs(expectedUserIdHeaderKeys); }
@Bean public RequestTracingFilter requestTracingFilter() { return new RequestTracingFilter(); }
@Test public void getOpenTracingHttpTagStrategy_works_as_expected() { // given RequestTracingFilter filter = new RequestTracingFilter(); // expect assertThat(filter.getOpenTracingHttpTagStrategy()) .isNotNull() .isSameAs(OpenTracingHttpTagStrategy.getDefaultInstance()); }
@Test public void getNoOpTagStrategy_works_as_expected() { // given RequestTracingFilter filter = new RequestTracingFilter(); // expect assertThat(filter.getNoOpTagStrategy()) .isNotNull() .isSameAs(NoOpHttpTagStrategy.getDefaultInstance()); }
@Test public void getDefaultTagAdapter_works_as_expected() { // given RequestTracingFilter filter = new RequestTracingFilter(); // expect assertThat(filter.getDefaultTagAdapter()) .isNotNull() .isSameAs(ServletRequestTagAdapter.getDefaultInstance()); }
@Test public void getZipkinHttpTagStrategy_works_as_expected() { // given RequestTracingFilter filter = new RequestTracingFilter(); // expect assertThat(filter.getZipkinHttpTagStrategy()) .isNotNull() .isSameAs(ZipkinHttpTagStrategy.getDefaultInstance()); }
@Test @UseDataProvider("userIdHeaderKeysInitParamDataProvider") public void initializeUserIdHeaderKeys_gets_user_id_header_key_list_from_init_params( String userIdHeaderKeysInitParamValue, List<String> expectedUserIdHeaderKeysList ) { // given RequestTracingFilter filter = new RequestTracingFilter(); doReturn(userIdHeaderKeysInitParamValue) .when(filterConfigMock) .getInitParameter(RequestTracingFilter.USER_ID_HEADER_KEYS_LIST_INIT_PARAM_NAME); // when List<String> actualUserIdHeaderKeysList = filter.initializeUserIdHeaderKeys(filterConfigMock); // then assertThat(actualUserIdHeaderKeysList).isEqualTo(expectedUserIdHeaderKeysList); if (actualUserIdHeaderKeysList != null) { Exception caughtEx = null; try { actualUserIdHeaderKeysList.add("foo"); } catch (Exception ex) { caughtEx = ex; } assertThat(caughtEx).isNotNull(); assertThat(caughtEx).isInstanceOf(UnsupportedOperationException.class); } }
@DataProvider(value = { "true", "false" }) @Test public void getTagAdapterFromName_returns_expected_strategy_for_fully_qualified_classname( boolean useClassThatExists ) { // given RequestTracingFilter filter = new RequestTracingFilter(); String classname = (useClassThatExists) ? TagAdapterExtension.class.getName() : "foo.doesnotexist.BlahAdapter" + UUID.randomUUID().toString(); AtomicReference<HttpTagAndSpanNamingAdapter<HttpServletRequest, HttpServletResponse>> resultHolder = new AtomicReference<>(); // when Throwable ex = catchThrowable(() -> resultHolder.set(filter.getTagAdapterFromName(classname))); // then if (useClassThatExists) { assertThat(ex).isNull(); assertThat(resultHolder.get()) .isNotNull() .isInstanceOf(TagAdapterExtension.class); } else { assertThat(ex).isInstanceOf(ClassNotFoundException.class); assertThat(resultHolder.get()).isNull(); } }