Fix flaky SenderTest

This commit is contained in:
Chris Eager 2021-04-13 15:31:21 -05:00 committed by Chris Eager
parent 14f5271c20
commit 92c25a8373
3 changed files with 81 additions and 85 deletions

View File

@ -20,20 +20,6 @@
<version>${resilience4j.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>mockwebserver</artifactId>
<version>2.1.0</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>

View File

@ -4,32 +4,41 @@
*/
package org.whispersystems.gcm.server;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.any;
import static com.github.tomakehurst.wiremock.client.WireMock.anyRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.ok;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.whispersystems.gcm.server.util.FixtureHelpers.fixture;
import static org.whispersystems.gcm.server.util.JsonHelpers.jsonFixture;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
import com.squareup.okhttp.mockwebserver.rule.MockWebServerRule;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import com.github.tomakehurst.wiremock.client.CountMatchingStrategy;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.*;
import static org.whispersystems.gcm.server.util.FixtureHelpers.fixture;
import static org.whispersystems.gcm.server.util.JsonHelpers.jsonFixture;
import org.junit.Rule;
import org.junit.Test;
public class SenderTest {
@Rule
public MockWebServerRule server = new MockWebServerRule();
public WireMockRule wireMock = new WireMockRule(options().dynamicPort().dynamicHttpsPort());
private static final ObjectMapper mapper = new ObjectMapper();
@ -41,11 +50,13 @@ public class SenderTest {
@Test
public void testSuccess() throws InterruptedException, ExecutionException, TimeoutException, IOException {
MockResponse successResponse = new MockResponse().setResponseCode(200)
.setBody(fixture("fixtures/response-success.json"));
server.enqueue(successResponse);
wireMock.stubFor(any(anyUrl())
.willReturn(aResponse()
.withStatus(200)
.withBody(fixture("fixtures/response-success.json"))));
Sender sender = new Sender("foobarbaz", mapper, 10, server.getUrl("/gcm/send").toExternalForm());
Sender sender = new Sender("foobarbaz", mapper, 10, "http://localhost:" + wireMock.port() + "/gcm/send");
CompletableFuture<Result> future = sender.send(Message.newBuilder().withDestination("1").build());
Result result = future.get(10, TimeUnit.SECONDS);
@ -57,20 +68,19 @@ public class SenderTest {
assertNull(result.getError());
assertNull(result.getCanonicalRegistrationId());
RecordedRequest request = server.takeRequest();
assertEquals(request.getPath(), "/gcm/send");
assertEquals(new String(request.getBody()), jsonFixture("fixtures/message-minimal.json"));
assertEquals(request.getHeader("Authorization"), "key=foobarbaz");
assertEquals(request.getHeader("Content-Type"), "application/json");
assertEquals(server.getRequestCount(), 1);
verify(1, postRequestedFor(urlEqualTo("/gcm/send"))
.withHeader("Authorization", equalTo("key=foobarbaz"))
.withHeader("Content-Type", equalTo("application/json"))
.withRequestBody(equalTo(jsonFixture("fixtures/message-minimal.json"))));
}
@Test
public void testBadApiKey() throws InterruptedException, TimeoutException {
MockResponse unauthorizedResponse = new MockResponse().setResponseCode(401);
server.enqueue(unauthorizedResponse);
wireMock.stubFor(any(anyUrl())
.willReturn(aResponse()
.withStatus(401)));
Sender sender = new Sender("foobar", mapper, 10, server.getUrl("/gcm/send").toExternalForm());
Sender sender = new Sender("foobar", mapper, 10, "http://localhost:" + wireMock.port() + "/gcm/send");
CompletableFuture<Result> future = sender.send(Message.newBuilder().withDestination("1").build());
try {
@ -80,15 +90,16 @@ public class SenderTest {
assertTrue(ee.getCause() instanceof AuthenticationFailedException);
}
assertEquals(server.getRequestCount(), 1);
verify(1, anyRequestedFor(anyUrl()));
}
@Test
public void testBadRequest() throws TimeoutException, InterruptedException {
MockResponse malformed = new MockResponse().setResponseCode(400);
server.enqueue(malformed);
wireMock.stubFor(any(anyUrl())
.willReturn(aResponse()
.withStatus(400)));
Sender sender = new Sender("foobarbaz", mapper, 10, server.getUrl("/gcm/send").toExternalForm());
Sender sender = new Sender("foobarbaz", mapper, 10, "http://localhost:" + wireMock.port() + "/gcm/send");
CompletableFuture<Result> future = sender.send(Message.newBuilder().withDestination("1").build());
try {
@ -98,17 +109,16 @@ public class SenderTest {
assertTrue(e.getCause() instanceof InvalidRequestException);
}
assertEquals(server.getRequestCount(), 1);
verify(1, anyRequestedFor(anyUrl()));
}
@Test
public void testServerError() throws TimeoutException, InterruptedException {
MockResponse error = new MockResponse().setResponseCode(503);
server.enqueue(error);
server.enqueue(error);
server.enqueue(error);
wireMock.stubFor(any(anyUrl())
.willReturn(aResponse()
.withStatus(503)));
Sender sender = new Sender("foobarbaz", mapper, 3, server.getUrl("/gcm/send").toExternalForm());
Sender sender = new Sender("foobarbaz", mapper, 3, "http://localhost:" + wireMock.port() + "/gcm/send");
CompletableFuture<Result> future = sender.send(Message.newBuilder().withDestination("1").build());
try {
@ -118,27 +128,29 @@ public class SenderTest {
assertTrue(ee.getCause() instanceof ServerFailedException);
}
assertEquals(server.getRequestCount(), 3);
verify(3, anyRequestedFor(anyUrl()));
}
@Test
public void testServerErrorRecovery() throws InterruptedException, ExecutionException, TimeoutException {
MockResponse success = new MockResponse().setResponseCode(200)
.setBody(fixture("fixtures/response-success.json"));
MockResponse error = new MockResponse().setResponseCode(503);
wireMock.stubFor(any(anyUrl()).willReturn(aResponse().withStatus(503)));
server.enqueue(error);
server.enqueue(error);
server.enqueue(error);
server.enqueue(success);
Sender sender = new Sender("foobarbaz", mapper, 4, server.getUrl("/gcm/send").toExternalForm());
Sender sender = new Sender("foobarbaz", mapper, 4, "http://localhost:" + wireMock.port() + "/gcm/send");
CompletableFuture<Result> future = sender.send(Message.newBuilder().withDestination("1").build());
// up to three failures can happen, with 100ms exponential backoff
// if we end up using the fourth, and finaly try, it would be after ~700 ms
CompletableFuture.delayedExecutor(300, TimeUnit.MILLISECONDS).execute(() ->
wireMock.stubFor(any(anyUrl())
.willReturn(aResponse()
.withStatus(200)
.withBody(fixture("fixtures/response-success.json"))))
);
Result result = future.get(10, TimeUnit.SECONDS);
assertEquals(server.getRequestCount(), 4);
verify(new CountMatchingStrategy(CountMatchingStrategy.GREATER_THAN, 1), anyRequestedFor(anyUrl()));
assertTrue(result.isSuccess());
assertFalse(result.isThrottled());
assertFalse(result.isUnregistered());
@ -148,18 +160,14 @@ public class SenderTest {
}
@Test
@Ignore
public void testNetworkError() throws TimeoutException, InterruptedException, IOException {
MockResponse response = new MockResponse().setResponseCode(200)
.setBody(fixture("fixtures/response-success.json"));
public void testNetworkError() throws TimeoutException, InterruptedException {
server.enqueue(response);
server.enqueue(response);
server.enqueue(response);
wireMock.stubFor(any(anyUrl())
.willReturn(ok()));
Sender sender = new Sender("foobarbaz", mapper ,2, server.getUrl("/gcm/send").toExternalForm());
Sender sender = new Sender("foobarbaz", mapper ,2, "http://localhost:" + wireMock.port() + "/gcm/send");
server.get().shutdown();
wireMock.stop();
CompletableFuture<Result> future = sender.send(Message.newBuilder().withDestination("1").build());
@ -172,12 +180,11 @@ public class SenderTest {
@Test
public void testNotRegistered() throws InterruptedException, ExecutionException, TimeoutException {
MockResponse response = new MockResponse().setResponseCode(200)
.setBody(fixture("fixtures/response-not-registered.json"));
server.enqueue(response);
wireMock.stubFor(any(anyUrl()).willReturn(aResponse().withStatus(200)
.withBody(fixture("fixtures/response-not-registered.json"))));
Sender sender = new Sender("foobarbaz", mapper,2, server.getUrl("/gcm/send").toExternalForm());
Sender sender = new Sender("foobarbaz", mapper,2, "http://localhost:" + wireMock.port() + "/gcm/send");
CompletableFuture<Result> future = sender.send(Message.newBuilder()
.withDestination("2")
.withDataPart("message", "new message!")

View File

@ -4,31 +4,34 @@
*/
package org.whispersystems.gcm.server;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static junit.framework.TestCase.assertTrue;
import static org.whispersystems.gcm.server.util.FixtureHelpers.fixture;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static junit.framework.TestCase.assertTrue;
import static org.whispersystems.gcm.server.util.FixtureHelpers.fixture;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
public class SimultaneousSenderTest {
@Rule
public WireMockRule wireMock = new WireMockRule(8089);
public WireMockRule wireMock = new WireMockRule(WireMockConfiguration.options().dynamicPort().dynamicHttpsPort());
private static final ObjectMapper mapper = new ObjectMapper();
@ -45,7 +48,7 @@ public class SimultaneousSenderTest {
.withStatus(200)
.withBody(fixture("fixtures/response-success.json"))));
Sender sender = new Sender("foobarbaz", mapper, 2, "http://localhost:8089/gcm/send");
Sender sender = new Sender("foobarbaz", mapper, 2, "http://localhost:" + wireMock.port() + "/gcm/send");
List<CompletableFuture<Result>> results = new LinkedList<>();
for (int i=0;i<1000;i++) {
@ -68,7 +71,7 @@ public class SimultaneousSenderTest {
.willReturn(aResponse()
.withStatus(503)));
Sender sender = new Sender("foobarbaz", mapper, 2, "http://localhost:8089/gcm/send");
Sender sender = new Sender("foobarbaz", mapper, 2, "http://localhost:" + wireMock.port() + "/gcm/send");
List<CompletableFuture<Result>> futures = new LinkedList<>();
for (int i=0;i<1000;i++) {