75 lines
4.6 KiB
Java
75 lines
4.6 KiB
Java
package com.baiyue.common.web;
|
|
|
|
import feign.*;
|
|
import org.junit.jupiter.api.Test;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
import static org.assertj.core.api.Assertions.*;
|
|
|
|
class EventDeliveryFeignConfigurationTest {
|
|
interface Endpoint { @RequestLine("POST /events") String send(); }
|
|
interface TypedEndpoint { @RequestLine("POST /events") com.baiyue.common.core.api.ApiResponse<Map<String, Object>> send(); }
|
|
|
|
@Test void wireCodeMustBeAStringAndAmbiguousJsonCannotBeAcknowledged() {
|
|
for (String body : List.of("{\"code\":200}", "{\"code\":true}", "{\"code\":\"200\",\"code\":\"500\"}", "{\"code\":\"200\"} {}", "{}")) {
|
|
var decoded = new AtomicInteger();
|
|
TypedEndpoint endpoint = Feign.builder()
|
|
.decoder((response, type) -> { decoded.incrementAndGet(); return com.baiyue.common.core.api.ApiResponse.success(Map.of()); })
|
|
.addCapability(new EventDeliveryFeignConfiguration().eventDeliveryCapability(3000, 15000, 60))
|
|
.client((request, options) -> Response.builder().request(request).status(200).reason("OK").headers(Map.of()).body(body, StandardCharsets.UTF_8).build())
|
|
.target(TypedEndpoint.class, "http://event-consumer.invalid");
|
|
assertThatThrownBy(endpoint::send).isInstanceOf(feign.codec.DecodeException.class);
|
|
assertThat(decoded.get()).isZero();
|
|
}
|
|
}
|
|
|
|
@Test void validStringCodePreservesBodyForTheConfiguredDecoder() {
|
|
String body = "{\"code\":\"200\",\"data\":{\"outcome\":\"APPLIED\"}}";
|
|
TypedEndpoint endpoint = Feign.builder().decoder((response, type) -> {
|
|
assertThat(new String(response.body().asInputStream().readAllBytes(), StandardCharsets.UTF_8)).isEqualTo(body);
|
|
return com.baiyue.common.core.api.ApiResponse.success(Map.of("outcome", "APPLIED"));
|
|
}).addCapability(new EventDeliveryFeignConfiguration().eventDeliveryCapability(3000, 15000, 60))
|
|
.client((request, options) -> Response.builder().request(request).status(200).reason("OK").headers(Map.of()).body(body, StandardCharsets.UTF_8).build())
|
|
.target(TypedEndpoint.class, "http://event-consumer.invalid");
|
|
assertThat(endpoint.send().data()).containsEntry("outcome", "APPLIED");
|
|
}
|
|
|
|
@Test void builtClientOverridesLegacyTimeoutAndRedirectSettings() {
|
|
var capability = new EventDeliveryFeignConfiguration().eventDeliveryCapability(3000, 15000, 60);
|
|
var observed = new AtomicReference<Request.Options>();
|
|
Endpoint endpoint = Feign.builder().options(new Request.Options(1, 5000))
|
|
.addCapability(capability).client((request, options) -> {
|
|
observed.set(options);
|
|
return Response.builder().request(request).status(200).reason("OK")
|
|
.headers(Map.of()).body("ok", StandardCharsets.UTF_8).build();
|
|
}).target(Endpoint.class, "http://event-consumer.invalid");
|
|
assertThat(endpoint.send()).isEqualTo("ok");
|
|
assertThat(observed.get().connectTimeoutMillis()).isEqualTo(3000);
|
|
assertThat(observed.get().readTimeoutMillis()).isEqualTo(15000);
|
|
assertThat(observed.get().isFollowRedirects()).isFalse();
|
|
}
|
|
|
|
@Test void retryAfterResponseCannotTriggerHiddenHttpRetries() {
|
|
var calls = new AtomicInteger();
|
|
Endpoint endpoint = Feign.builder().retryer(new Retryer.Default(1, 1, 3))
|
|
.addCapability(new EventDeliveryFeignConfiguration().eventDeliveryCapability(3000, 15000, 60))
|
|
.client((request, options) -> {
|
|
calls.incrementAndGet();
|
|
return Response.builder().request(request).status(503).reason("Unavailable")
|
|
.headers(Map.of("Retry-After", List.of("0"))).build();
|
|
}).target(Endpoint.class, "http://event-consumer.invalid");
|
|
assertThatThrownBy(endpoint::send).isInstanceOf(RetryableException.class);
|
|
assertThat(calls.get()).isEqualTo(1);
|
|
}
|
|
|
|
@Test void invalidTimeoutsAndTooShortLeaseAreRejected() {
|
|
var configuration = new EventDeliveryFeignConfiguration();
|
|
assertThatThrownBy(() -> configuration.eventDeliveryCapability(0, 15000, 60)).isInstanceOf(IllegalArgumentException.class);
|
|
assertThatThrownBy(() -> configuration.eventDeliveryCapability(3000, 15000, 18)).isInstanceOf(IllegalArgumentException.class);
|
|
assertThatThrownBy(() -> configuration.eventDeliveryCapability(3000, -1, 60)).isInstanceOf(IllegalArgumentException.class);
|
|
}
|
|
}
|