mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 22:28:03 +01:00
retry hCaptcha errors
Co-authored-by: Jon Chambers <63609320+jon-signal@users.noreply.github.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
@@ -22,6 +23,7 @@ import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicCaptchaConfiguration;
|
||||
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
|
||||
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
|
||||
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
|
||||
|
||||
public class HCaptchaClientTest {
|
||||
@@ -44,7 +46,7 @@ public class HCaptchaClientTest {
|
||||
public void captchaProcessed(final boolean success, final float score, final boolean expectedResult)
|
||||
throws IOException, InterruptedException {
|
||||
|
||||
final HttpClient client = mockResponder(200, String.format("""
|
||||
final FaultTolerantHttpClient client = mockResponder(200, String.format("""
|
||||
{
|
||||
"success": %b,
|
||||
"score": %f,
|
||||
@@ -64,14 +66,14 @@ public class HCaptchaClientTest {
|
||||
|
||||
@Test
|
||||
public void errorResponse() throws IOException, InterruptedException {
|
||||
final HttpClient httpClient = mockResponder(503, "");
|
||||
final FaultTolerantHttpClient httpClient = mockResponder(503, "");
|
||||
final HCaptchaClient client = new HCaptchaClient("fake", httpClient, mockConfig(true, 0.5));
|
||||
assertThrows(IOException.class, () -> client.verify(SITE_KEY, Action.CHALLENGE, TOKEN, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidScore() throws IOException, InterruptedException {
|
||||
final HttpClient httpClient = mockResponder(200, """
|
||||
final FaultTolerantHttpClient httpClient = mockResponder(200, """
|
||||
{"success" : true, "score": 1.1}
|
||||
""");
|
||||
final HCaptchaClient client = new HCaptchaClient("fake", httpClient, mockConfig(true, 0.5));
|
||||
@@ -80,7 +82,7 @@ public class HCaptchaClientTest {
|
||||
|
||||
@Test
|
||||
public void badBody() throws IOException, InterruptedException {
|
||||
final HttpClient httpClient = mockResponder(200, """
|
||||
final FaultTolerantHttpClient httpClient = mockResponder(200, """
|
||||
{"success" : true,
|
||||
""");
|
||||
final HCaptchaClient client = new HCaptchaClient("fake", httpClient, mockConfig(true, 0.5));
|
||||
@@ -102,15 +104,14 @@ public class HCaptchaClientTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static HttpClient mockResponder(final int statusCode, final String jsonBody)
|
||||
throws IOException, InterruptedException {
|
||||
HttpClient httpClient = mock(HttpClient.class);
|
||||
private static FaultTolerantHttpClient mockResponder(final int statusCode, final String jsonBody) {
|
||||
FaultTolerantHttpClient httpClient = mock(FaultTolerantHttpClient.class);
|
||||
@SuppressWarnings("unchecked") final HttpResponse<Object> httpResponse = mock(HttpResponse.class);
|
||||
|
||||
when(httpResponse.body()).thenReturn(jsonBody);
|
||||
when(httpResponse.statusCode()).thenReturn(statusCode);
|
||||
|
||||
when(httpClient.send(any(), any())).thenReturn(httpResponse);
|
||||
when(httpClient.sendAsync(any(), any())).thenReturn(CompletableFuture.completedFuture(httpResponse));
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,11 @@ import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
|
||||
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
|
||||
@@ -19,6 +24,8 @@ import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -114,6 +121,35 @@ class FaultTolerantHttpClientTest {
|
||||
wireMock.verify(3, getRequestedFor(urlEqualTo("/failure")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRetryGetOnException() {
|
||||
final HttpClient mockHttpClient = mock(HttpClient.class);
|
||||
final FaultTolerantHttpClient client = new FaultTolerantHttpClient(
|
||||
"test",
|
||||
mockHttpClient,
|
||||
retryExecutor,
|
||||
Duration.ofSeconds(1),
|
||||
new RetryConfiguration(),
|
||||
throwable -> throwable instanceof IOException,
|
||||
new CircuitBreakerConfiguration());
|
||||
|
||||
when(mockHttpClient.sendAsync(any(), any()))
|
||||
.thenReturn(CompletableFuture.failedFuture(new IOException("test exception")));
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create("http://localhost:1234/failure"))
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
try {
|
||||
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).join();
|
||||
throw new AssertionError("Should have failed!");
|
||||
} catch (CompletionException e) {
|
||||
assertThat(e.getCause()).isInstanceOf(IOException.class);
|
||||
}
|
||||
verify(mockHttpClient, times(3)).sendAsync(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNetworkFailureCircuitBreaker() throws InterruptedException {
|
||||
CircuitBreakerConfiguration circuitBreakerConfiguration = new CircuitBreakerConfiguration();
|
||||
|
||||
Reference in New Issue
Block a user