From 92c25a83737721c00d6c3d452129f4fac1ef7137 Mon Sep 17 00:00:00 2001 From: Chris Eager Date: Tue, 13 Apr 2021 15:31:21 -0500 Subject: [PATCH] Fix flaky SenderTest --- gcm-sender-async/pom.xml | 14 -- .../whispersystems/gcm/server/SenderTest.java | 127 +++++++++--------- .../gcm/server/SimultaneousSenderTest.java | 25 ++-- 3 files changed, 81 insertions(+), 85 deletions(-) diff --git a/gcm-sender-async/pom.xml b/gcm-sender-async/pom.xml index 51d17e7f7..2f21d6382 100644 --- a/gcm-sender-async/pom.xml +++ b/gcm-sender-async/pom.xml @@ -20,20 +20,6 @@ ${resilience4j.version} - - - com.squareup.okhttp - mockwebserver - 2.1.0 - test - - - org.bouncycastle - bcprov-jdk15on - - - - org.bouncycastle bcprov-jdk16 diff --git a/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SenderTest.java b/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SenderTest.java index d8d709612..179361ccc 100644 --- a/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SenderTest.java +++ b/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SenderTest.java @@ -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 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 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 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 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 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 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 future = sender.send(Message.newBuilder() .withDestination("2") .withDataPart("message", "new message!") diff --git a/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SimultaneousSenderTest.java b/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SimultaneousSenderTest.java index d6d8fd783..496768156 100644 --- a/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SimultaneousSenderTest.java +++ b/gcm-sender-async/src/test/java/org/whispersystems/gcm/server/SimultaneousSenderTest.java @@ -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> 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> futures = new LinkedList<>(); for (int i=0;i<1000;i++) {