ConcurrencyLimitingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { ConcurrencyLimiterListener limiterListenerTag = chain.request().tag(ConcurrencyLimiterListener.class); if (limiterListenerTag == null) { return chain.proceed(chain.request()); } ListenableFuture<Limiter.Listener> limiterFuture = limiterListenerTag.limiterListener(); Preconditions.checkState(limiterFuture.isDone(), "Limit listener future should have been fulfilled."); Limiter.Listener listener = Futures.getUnchecked(limiterFuture); try { Response response = chain.proceed(chain.request()); if (DROPPED_CODES.contains(response.code())) { listener.onDropped(); return response; } else if (!response.isSuccessful() || response.isRedirect()) { listener.onIgnore(); return response; } else { return wrapResponse(listener, response); } } catch (IOException e) { listener.onIgnore(); throw e; } } ConcurrencyLimitingInterceptor(); @Override Response intercept(Chain chain);  }
@Test public void dropsIfRateLimited() throws IOException { Response rateLimited = response.newBuilder().code(429).build(); when(chain.proceed(request)).thenReturn(rateLimited); assertThat(interceptor.intercept(chain)).isEqualTo(rateLimited); verify(listener).onDropped(); }
@Test public void dropsIfUnavailable() throws IOException { Response unavailable = response.newBuilder().code(503).build(); when(chain.proceed(request)).thenReturn(unavailable); assertThat(interceptor.intercept(chain)).isEqualTo(unavailable); verify(listener).onDropped(); }
@Test public void ignoresIfRedirect() throws IOException { Response redirect = response.newBuilder().code(308).build(); when(chain.proceed(request)).thenReturn(redirect); assertThat(interceptor.intercept(chain)).isEqualTo(redirect); verify(listener).onIgnore(); }
@Test public void ignoresIfUnsuccessful() throws IOException { Response unsuccessful = response.newBuilder().code(500).build(); when(chain.proceed(request)).thenReturn(unsuccessful); assertThat(interceptor.intercept(chain)).isEqualTo(unsuccessful); verify(listener).onIgnore(); }
@Test public void ignoresIfIoException() throws IOException { IOException exception = new IOException(); when(chain.proceed(request)).thenThrow(exception); assertThatThrownBy(() -> interceptor.intercept(chain)).isEqualTo(exception); verify(listener).onIgnore(); }
@Test public void wrapsResponseBody() throws IOException { String data = "data"; ResponseBody body = ResponseBody.create(MediaType.parse("application/json"), data); when(chain.proceed(request)).thenReturn(response.newBuilder().body(body).build()); Response wrappedResponse = interceptor.intercept(chain); verifyNoMoreInteractions(listener); assertThat(wrappedResponse.body().string()).isEqualTo(data); verify(listener).onSuccess(); }
@Test public void proxyHandlesExceptions() throws IOException { ResponseBody body = ResponseBody.create(MediaType.parse("application/json"), -1, mockSource); when(chain.proceed(request)).thenReturn(response.newBuilder().body(body).build()); IOException exception = new IOException(); when(mockSource.readByteArray()).thenThrow(exception); Response erroneousResponse = interceptor.intercept(chain); assertThatThrownBy(() -> erroneousResponse.body().source().readByteArray()) .isEqualTo(exception); }
@Test public void ignoresIfNoContent() throws IOException { Response noContent = response.newBuilder().code(204).build(); when(chain.proceed(request)).thenReturn(noContent); assertThat(interceptor.intercept(chain)).isEqualTo(noContent); verify(listener).onIgnore(); }
@Test public void marksSuccessIfContentEmpty() throws IOException { Response empty = response.newBuilder() .code(204) .body(ResponseBody.create(MediaType.parse("application/json"), new byte[0])) .build(); when(chain.proceed(request)).thenReturn(empty); assertThat(interceptor.intercept(chain)).isEqualTo(empty); verify(listener).onSuccess(); }