@Test public void get_set_ChannelHandlerContext_works_as_expected() { // given requestBuilderWrapper = new RequestBuilderWrapper( url, httpMethod, requestBuilder, customCircuitBreaker, disableCircuitBreaker); ChannelHandlerContext ctx = mock(ChannelHandlerContext.class); // when requestBuilderWrapper.setCtx(ctx); // then assertThat(ctx).isEqualTo(requestBuilderWrapper.getCtx()); }
@Test public void get_set_HttpMethod_works_as_expected() { // given requestBuilderWrapper = new RequestBuilderWrapper( url, httpMethod, requestBuilder, customCircuitBreaker, disableCircuitBreaker); String alteredMethod = "POST"; // when requestBuilderWrapper.setHttpMethod(alteredMethod); // then assertThat(alteredMethod).isEqualTo(requestBuilderWrapper.getHttpMethod()); verify(requestBuilder).setMethod(alteredMethod); }
@Test public void get_set_Url_works_as_expected() { // given requestBuilderWrapper = new RequestBuilderWrapper( url, httpMethod, requestBuilder, customCircuitBreaker, disableCircuitBreaker); String alternateUrl = "http://alteredUrl.testing"; // when requestBuilderWrapper.setUrl(alternateUrl); // then assertThat(alternateUrl).isEqualTo(requestBuilderWrapper.getUrl()); verify(requestBuilder).setUrl(alternateUrl); }
@Test public void get_set_DisableCircuitBreaker_works_as_expected() { // given requestBuilderWrapper = new RequestBuilderWrapper( url, httpMethod, requestBuilder, customCircuitBreaker, disableCircuitBreaker); boolean alteredDisableCircuitBreaker = false; // when requestBuilderWrapper.setDisableCircuitBreaker(alteredDisableCircuitBreaker); // then assertThat(requestBuilderWrapper.isDisableCircuitBreaker()).isFalse(); }
this.performSubSpanAroundDownstreamCalls = performSubSpanAroundDownstreamCalls; this.circuitBreakerManualTask = circuitBreakerManualTask; this.rbwCopyWithHttpMethodAndUrlOnly = new RequestBuilderWrapper( requestBuilderWrapper.getUrl(), requestBuilderWrapper.getHttpMethod(), null, null,
@Test public void get_set_CustomCircuitBreaker_works_as_expected() { // given requestBuilderWrapper = new RequestBuilderWrapper( url, httpMethod, requestBuilder, customCircuitBreaker, disableCircuitBreaker); Optional<CircuitBreaker<Response>> alteredCircuitBreaker = Optional.of(new CircuitBreakerImpl<>()); // when requestBuilderWrapper.setCustomCircuitBreaker(alteredCircuitBreaker); // then assertThat(requestBuilderWrapper.getCustomCircuitBreaker()).isEqualTo(alteredCircuitBreaker); } }
switch (httpMethod) { case "CONNECT": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.prepareConnect(url), customCircuitBreaker, disableCircuitBreaker); case "DELETE": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.prepareDelete(url), customCircuitBreaker, disableCircuitBreaker); case "GET": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.prepareGet(url), customCircuitBreaker, disableCircuitBreaker); case "HEAD": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.prepareHead(url), customCircuitBreaker, disableCircuitBreaker); case "POST": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.preparePost(url), customCircuitBreaker, disableCircuitBreaker); case "OPTIONS": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.prepareOptions(url), customCircuitBreaker, disableCircuitBreaker); case "PUT": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.preparePut(url), customCircuitBreaker, disableCircuitBreaker); case "PATCH": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.preparePatch(url), customCircuitBreaker, disableCircuitBreaker); case "TRACE": return new RequestBuilderWrapper(url, httpMethod, asyncHttpClient.prepareTrace(url), customCircuitBreaker, disableCircuitBreaker); default:
AsyncHttpClient.BoundRequestBuilder reqMock = mock(AsyncHttpClient.BoundRequestBuilder.class); Optional<CircuitBreaker<Response>> customCb = Optional.empty(); RequestBuilderWrapper rbw = new RequestBuilderWrapper(url, method, reqMock, customCb, false); if (useNettyEventLoop) rbw.setCtx(ctxMock);
@Nullable @Override public String getRequestUrl(@Nullable RequestBuilderWrapper request) { if (request == null) { return null; } return request.getUrl(); }
@Nullable @Override public String getRequestHttpMethod(@Nullable RequestBuilderWrapper request) { if (request == null) { return null; } return request.getHttpMethod(); }
/** * Executes the given request asynchronously, handling the response with the given responseHandlerFunction, and * returns a {@link CompletableFuture} that represents the result of executing the * responseHandlerFunction on the downstream response. Any error anywhere along the way will cause the returned * future to be completed with {@link CompletableFuture#completeExceptionally(Throwable)}. * <p/> * NOTE: This is a helper method for calling {@link #executeAsyncHttpRequest(RequestBuilderWrapper, * AsyncResponseHandler, java.util.Deque, java.util.Map)} that uses {@link * ChannelAttributes#getHttpProcessingStateForChannel(ChannelHandlerContext)} to extract the {@link * HttpProcessingState} from the given ctx argument, and then grabs {@link * HttpProcessingState#getDistributedTraceStack()} and {@link HttpProcessingState#getLoggerMdcContextMap()} to use * as the distributed trace stack and MDC info for the downstream call. */ public <O> CompletableFuture<O> executeAsyncHttpRequest(RequestBuilderWrapper requestBuilderWrapper, AsyncResponseHandler<O> responseHandlerFunction, ChannelHandlerContext ctx) { HttpProcessingState state = ChannelAttributes.getHttpProcessingStateForChannel(ctx).get(); if (state == null) throw new IllegalStateException("state cannot be null"); Map<String, String> mdcContextMap = state.getLoggerMdcContextMap(); Deque<Span> distributedTraceStack = state.getDistributedTraceStack(); requestBuilderWrapper.setCtx(ctx); return executeAsyncHttpRequest(requestBuilderWrapper, responseHandlerFunction, distributedTraceStack, mdcContextMap); }
protected Optional<CircuitBreaker<Response>> getCircuitBreaker(RequestBuilderWrapper requestBuilderWrapper) { if (requestBuilderWrapper.disableCircuitBreaker) return Optional.empty(); // Circuit breaking is enabled for this call. So we return the custom one specified or use the default one if a // custom one is not specified. if (requestBuilderWrapper.customCircuitBreaker.isPresent()) return requestBuilderWrapper.customCircuitBreaker; // No custom circuit breaker. Use the default for the given request's host. Uri uri = Uri.create(requestBuilderWrapper.url); String host = uri.getHost(); EventLoop nettyEventLoop = requestBuilderWrapper.getCtx() == null ? null : requestBuilderWrapper.getCtx().channel().eventLoop(); CircuitBreaker<Integer> defaultStatusCodeCircuitBreaker = getDefaultHttpStatusCodeCircuitBreakerForKey( host, Optional.ofNullable(nettyEventLoop), Optional.ofNullable(nettyEventLoop) ); return Optional.of( new CircuitBreakerDelegate<>( defaultStatusCodeCircuitBreaker, response -> (response == null ? null : response.getStatusCode()) ) ); }
@DataProvider(value = { "spanNameFromStrategy | PATCH | spanNameFromStrategy", "null | PATCH | async_downstream_call-PATCH", " | PATCH | async_downstream_call-PATCH", "[whitespace] | PATCH | async_downstream_call-PATCH", "null | null | async_downstream_call-UNKNOWN_HTTP_METHOD", }, splitBy = "\\|") @Test public void getSubspanSpanName_works_as_expected( String strategyResult, String httpMethod, String expectedResult ) { // given if ("[whitespace]".equals(strategyResult)) { strategyResult = " \n\r\t "; } initialSpanNameFromStrategy.set(strategyResult); requestBuilderWrapper.setHttpMethod(httpMethod); // when String result = handlerSpy.getSubspanSpanName( requestBuilderWrapper, tagAndNamingStrategy ); // then assertThat(result).isEqualTo(expectedResult); }
@Test public void constructor_sets_values_as_expected() { // given requestBuilderWrapper = new RequestBuilderWrapper( url, httpMethod, requestBuilder, customCircuitBreaker, disableCircuitBreaker); // then assertThat(requestBuilderWrapper.url).isEqualTo(url); assertThat(requestBuilderWrapper.httpMethod).isEqualTo(httpMethod); assertThat(requestBuilderWrapper.customCircuitBreaker).isEqualTo(customCircuitBreaker); assertThat(requestBuilderWrapper.disableCircuitBreaker).isEqualTo(disableCircuitBreaker); }
String result = request.getUrl(); if (StringUtils.isBlank(result)) { return null;
@Test public void getRequestHttpMethod_works_as_expected() { // given String expectedResult = UUID.randomUUID().toString(); doReturn(expectedResult).when(requestMock).getHttpMethod(); // when String result = adapterSpy.getRequestHttpMethod(requestMock); // then assertThat(result).isEqualTo(expectedResult); }
@Test public void executeAsyncHttpRequest_with_ctx_extracts_mdc_and_tracing_info_from_ctx_and_delegates_to_kitchen_sink_execute_method() { // given RequestBuilderWrapper rbwMock = mock(RequestBuilderWrapper.class); AsyncResponseHandler responseHandlerMock = mock(AsyncResponseHandler.class); CompletableFuture cfMock = mock(CompletableFuture.class); doReturn(cfMock).when(helperSpy).executeAsyncHttpRequest( any(RequestBuilderWrapper.class), any(AsyncResponseHandler.class), any(Deque.class), any(Map.class) ); Map<String, String> mdcMock = mock(Map.class); Deque<Span> spanStackMock = mock(Deque.class); state.setLoggerMdcContextMap(mdcMock); state.setDistributedTraceStack(spanStackMock); // when CompletableFuture result = helperSpy.executeAsyncHttpRequest(rbwMock, responseHandlerMock, ctxMock); // then verify(helperSpy).executeAsyncHttpRequest(rbwMock, responseHandlerMock, spanStackMock, mdcMock); assertThat(result).isSameAs(cfMock); verify(rbwMock).setCtx(ctxMock); }
@Test public void getCircuitBreaker_returns_empty_if_disableCircuitBreaker_is_true() { // given RequestBuilderWrapper rbw = new RequestBuilderWrapper( "foo", "bar", mock(AsyncHttpClient.BoundRequestBuilder.class), Optional.of(mock(CircuitBreaker.class)), true); // when Optional<CircuitBreaker<Response>> result = helperSpy.getCircuitBreaker(rbw); // then assertThat(result).isEmpty(); }
@Test public void getRequestUrl_works_as_expected() { // given String expectedResult = UUID.randomUUID().toString(); doReturn(expectedResult).when(requestMock).getUrl(); // when String result = adapterSpy.getRequestUrl(requestMock); // then assertThat(result).isEqualTo(expectedResult); }
@Test public void getCircuitBreaker_returns_custom_circuit_breaker_if_disableCircuitBreaker_is_false_and_customCircuitBreaker_exists() { // given Optional<CircuitBreaker<Response>> customCb = Optional.of(mock(CircuitBreaker.class)); RequestBuilderWrapper rbw = new RequestBuilderWrapper( "foo", "bar", mock(AsyncHttpClient.BoundRequestBuilder.class), customCb, false); // when Optional<CircuitBreaker<Response>> result = helperSpy.getCircuitBreaker(rbw); // then assertThat(result).isSameAs(customCb); }