Skip to content

Commit 11aab96

Browse files
committed
Proxy tests
1 parent 165ff59 commit 11aab96

File tree

3 files changed

+126
-18
lines changed

3 files changed

+126
-18
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,5 +493,10 @@
493493
<version>2.2</version>
494494
<scope>test</scope>
495495
</dependency>
496+
<dependency>
497+
<groupId>org.mock-server</groupId>
498+
<artifactId>mockserver-junit-rule-no-dependencies</artifactId>
499+
<version>5.14.0</version>
500+
</dependency>
496501
</dependencies>
497502
</project>

src/main/java/com/google/firebase/internal/ApacheHttp2Transport.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@
2929
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
3030
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
3131
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
32+
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
3233
import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
34+
import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
3335
import org.apache.hc.core5.http.config.Http1Config;
3436
import org.apache.hc.core5.http2.HttpVersionPolicy;
3537
import org.apache.hc.core5.http2.config.H2Config;
3638
import org.apache.hc.core5.io.CloseMode;
39+
import org.apache.hc.core5.ssl.SSLContexts;
3740

3841
/**
3942
* HTTP/2 enabled async transport based on the Apache HTTP Client library
@@ -64,16 +67,20 @@ public static CloseableHttpAsyncClient newDefaultHttpAsyncClient() {
6467

6568
public static HttpAsyncClientBuilder defaultHttpAsyncClientBuilder() {
6669
PoolingAsyncClientConnectionManager connectionManager =
67-
new PoolingAsyncClientConnectionManager();
68-
69-
// Set Max total connections and max per route to match google api client limits
70-
// https://github.com/googleapis/google-http-java-client/blob/f9d4e15bd3c784b1fd3b0f3468000a91c6f79715/google-http-client-apache-v5/src/main/java/com/google/api/client/http/apache/v5/Apache5HttpTransport.java#L151
71-
connectionManager.setMaxTotal(200);
72-
connectionManager.setDefaultMaxPerRoute(20);
73-
connectionManager.setDefaultConnectionConfig(
74-
ConnectionConfig.custom().setTimeToLive(-1, TimeUnit.MILLISECONDS).build());
75-
connectionManager.setDefaultTlsConfig(
76-
TlsConfig.custom().setVersionPolicy(HttpVersionPolicy.NEGOTIATE).build());
70+
PoolingAsyncClientConnectionManagerBuilder.create()
71+
// Set Max total connections to match google api client limits
72+
// https://github.com/googleapis/google-http-java-client/blob/f9d4e15bd3c784b1fd3b0f3468000a91c6f79715/google-http-client-apache-v5/src/main/java/com/google/api/client/http/apache/v5/Apache5HttpTransport.java#L151
73+
.setMaxConnTotal(200)
74+
// Set max connections per route to match the concurrent stream limit of the FCM backend.
75+
.setMaxConnPerRoute(100)
76+
.setDefaultConnectionConfig(
77+
ConnectionConfig.custom().setTimeToLive(-1, TimeUnit.MILLISECONDS).build())
78+
.setDefaultTlsConfig(
79+
TlsConfig.custom().setVersionPolicy(HttpVersionPolicy.NEGOTIATE).build())
80+
.setTlsStrategy(ClientTlsStrategyBuilder.create()
81+
.setSslContext(SSLContexts.createSystemDefault())
82+
.build())
83+
.build();
7784

7885
return HttpAsyncClientBuilder.create()
7986
// Set maxConcurrentStreams to 100 to match the concurrent stream limit of the FCM backend.

src/test/java/com/google/firebase/internal/ApacheHttp2TransportIT.java

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@
2121
import static org.junit.Assert.assertNull;
2222
import static org.junit.Assert.assertTrue;
2323
import static org.junit.Assert.fail;
24+
import static org.mockserver.model.Header.header;
25+
import static org.mockserver.model.HttpForward.forward;
26+
import static org.mockserver.model.HttpRequest.request;
27+
import static org.mockserver.model.HttpResponse.response;
2428

29+
import com.google.api.client.http.GenericUrl;
2530
import com.google.api.client.http.HttpRequestFactory;
2631
import com.google.api.client.http.HttpResponseException;
32+
import com.google.api.client.http.HttpTransport;
2733
import com.google.api.client.http.LowLevelHttpResponse;
2834
import com.google.api.client.json.JsonFactory;
2935
import com.google.api.client.util.GenericData;
@@ -53,13 +59,17 @@
5359
import org.junit.BeforeClass;
5460
import org.junit.Test;
5561

62+
import org.mockserver.integration.ClientAndServer;
63+
import org.mockserver.model.HttpForward.Scheme;
64+
import org.mockserver.socket.PortFactory;
65+
5666
public class ApacheHttp2TransportIT {
5767
private static FirebaseApp app;
5868
private static final GoogleCredentials MOCK_CREDENTIALS = new MockGoogleCredentials("test_token");
5969
private static final ImmutableMap<String, Object> payload =
6070
ImmutableMap.<String, Object>of("foo", "bar");
6171

62-
// Sets a 5 second delay before server response to simulate a slow network that
72+
// Sets a 5 second delay before server response to simulate a slow network that
6373
// results in a read timeout.
6474
private static final String DELAY_URL = "https://nghttp2.org/httpbin/delay/5";
6575
private static final String GET_URL = "https://nghttp2.org/httpbin/get";
@@ -69,9 +79,13 @@ public class ApacheHttp2TransportIT {
6979
private static Socket fillerSocket;
7080
private static int port;
7181

82+
private static ClientAndServer mockProxy;
83+
private static ClientAndServer mockServer;
84+
7285
@BeforeClass
7386
public static void setUpClass() throws IOException {
74-
// Start server socket with a backlog queue of 1 and a automatically assigned port
87+
// Start server socket with a backlog queue of 1 and a automatically assigned
88+
// port
7589
serverSocket = new ServerSocket(0, 1);
7690
port = serverSocket.getLocalPort();
7791
// Fill the backlog queue to force socket to ignore future connections
@@ -89,14 +103,26 @@ public static void cleanUpClass() throws IOException {
89103
}
90104
}
91105

92-
93106
@After
94107
public void cleanup() {
95108
if (app != null) {
96109
app.delete();
97110
}
111+
112+
if (mockProxy != null && mockProxy.isRunning()) {
113+
mockProxy.close();
114+
}
115+
116+
if (mockServer != null && mockServer.isRunning()) {
117+
mockServer.close();
118+
}
119+
120+
System.clearProperty("http.proxyHost");
121+
System.clearProperty("http.proxyPort");
122+
System.clearProperty("https.proxyHost");
123+
System.clearProperty("https.proxyPort");
98124
}
99-
125+
100126
@Test(timeout = 10_000L)
101127
public void testUnauthorizedGetRequest() throws FirebaseException {
102128
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
@@ -115,7 +141,7 @@ public void testUnauthorizedPostRequest() throws FirebaseException {
115141

116142
@Test(timeout = 10_000L)
117143
public void testConnectTimeoutAuthorizedGet() throws FirebaseException {
118-
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
144+
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
119145
.setCredentials(MOCK_CREDENTIALS)
120146
.setConnectTimeout(100)
121147
.build(), "test-app");
@@ -270,6 +296,77 @@ public void process(
270296
assertTrue("Expected to have called our test interceptor", interceptorCalled.get());
271297
}
272298

299+
@Test(timeout = 10_000L)
300+
public void testVerifyProxyIsRespected() {
301+
try {
302+
System.setProperty("https.proxyHost", "localhost");
303+
System.setProperty("https.proxyPort", "8080");
304+
305+
HttpTransport transport = new ApacheHttp2Transport();
306+
transport.createRequestFactory().buildGetRequest(new GenericUrl(GET_URL)).execute();
307+
fail("No exception thrown for HTTP error response");
308+
} catch (IOException e) {
309+
assertEquals("Connection exception in request", e.getMessage());
310+
assertTrue(e.getCause().getMessage().contains("localhost:8080"));
311+
}
312+
}
313+
314+
@Test(timeout = 10_000L)
315+
public void testProxyMockHttp() throws Exception {
316+
// Start MockServer
317+
mockProxy = ClientAndServer.startClientAndServer(PortFactory.findFreePort());
318+
mockServer = ClientAndServer.startClientAndServer(PortFactory.findFreePort());
319+
320+
System.setProperty("http.proxyHost", "localhost");
321+
System.setProperty("http.proxyPort", mockProxy.getPort().toString());
322+
323+
// Configure proxy to receieve requests and forward them to a mock destination
324+
// server
325+
mockProxy
326+
.when(
327+
request())
328+
.forward(
329+
forward()
330+
.withHost("localhost")
331+
.withPort(mockServer.getPort())
332+
.withScheme(Scheme.HTTP));
333+
334+
// Configure server to listen and respond
335+
mockServer
336+
.when(
337+
request())
338+
.respond(
339+
response()
340+
.withStatusCode(200)
341+
.withBody("Expected server response"));
342+
343+
// Send a request through the proxy
344+
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
345+
.setCredentials(MOCK_CREDENTIALS)
346+
.setWriteTimeout(100)
347+
.build(), "test-app");
348+
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
349+
HttpRequestInfo request = HttpRequestInfo.buildGetRequest("http://www.google.com");
350+
IncomingHttpResponse response = httpClient.send(request);
351+
352+
// Verify that the proxy received request with destination host
353+
mockProxy.verify(
354+
request()
355+
.withMethod("GET")
356+
.withPath("/")
357+
.withHeader(header("Host", "www.google.com")));
358+
359+
// Verify the forwarded request is received by the server
360+
mockServer.verify(
361+
request()
362+
.withMethod("GET")
363+
.withPath("/"));
364+
365+
// Verify response
366+
assertEquals(200, response.getStatusCode());
367+
assertEquals(response.getContent(), "Expected server response");
368+
}
369+
273370
private static ErrorHandlingHttpClient<FirebaseException> getHttpClient(boolean authorized,
274371
FirebaseApp app) {
275372
HttpRequestFactory requestFactory;
@@ -285,12 +382,11 @@ private static ErrorHandlingHttpClient<FirebaseException> getHttpClient(boolean
285382

286383
private static ErrorHandlingHttpClient<FirebaseException> getHttpClient(boolean authorized) {
287384
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
288-
.setCredentials(MOCK_CREDENTIALS)
289-
.build(), "test-app");
385+
.setCredentials(MOCK_CREDENTIALS)
386+
.build(), "test-app");
290387
return getHttpClient(authorized, app);
291388
}
292389

293-
294390
private static class TestHttpErrorHandler implements HttpErrorHandler<FirebaseException> {
295391
@Override
296392
public FirebaseException handleIOException(IOException e) {

0 commit comments

Comments
 (0)