Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 67 additions & 99 deletions src/test/java/com/google/firebase/internal/ApacheHttp2TransportIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,24 @@
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpRequestInterceptor;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap;
import org.apache.hc.core5.http.io.HttpRequestHandler;
import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
import org.apache.hc.core5.http.protocol.HttpContext;

import org.junit.After;
Expand All @@ -61,12 +71,6 @@ public class ApacheHttp2TransportIT {
private static final ImmutableMap<String, Object> payload =
ImmutableMap.<String, Object>of("foo", "bar");

// Sets a 5 second delay before server response to simulate a slow network that
// results in a read timeout.
private static final String DELAY_URL = "https://nghttp2.org/httpbin/delay/5";
private static final String GET_URL = "https://nghttp2.org/httpbin/get";
private static final String POST_URL = "https://nghttp2.org/httpbin/post";

private static ServerSocket serverSocket;
private static Socket fillerSocket;
private static int port;
Expand Down Expand Up @@ -105,19 +109,43 @@ public void cleanup() {
}

@Test(timeout = 10_000L)
public void testUnauthorizedGetRequest() throws FirebaseException {
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
HttpRequestInfo request = HttpRequestInfo.buildGetRequest(GET_URL);
IncomingHttpResponse response = httpClient.send(request);
assertEquals(200, response.getStatusCode());
public void testUnauthorizedGetRequest() throws Exception {
final HttpRequestHandler handler = new HttpRequestHandler() {
@Override
public void handle(
ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
throws HttpException, IOException {
response.setCode(HttpStatus.SC_OK);
}
};
try (FakeServer server = new FakeServer(handler)) {
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
HttpRequestInfo request = HttpRequestInfo.buildGetRequest("http://localhost:" + server.getPort());
IncomingHttpResponse response = httpClient.send(request);
assertEquals(200, response.getStatusCode());
}
}

@Test(timeout = 10_000L)
public void testUnauthorizedPostRequest() throws FirebaseException {
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest(POST_URL, payload);
GenericData body = httpClient.sendAndParse(request, GenericData.class);
assertEquals("{\"foo\":\"bar\"}", body.get("data"));
public void testUnauthorizedPostRequest() throws Exception {
final HttpRequestHandler handler = new HttpRequestHandler() {
@Override
public void handle(
ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
throws HttpException, IOException {
String responseJson = "{\"data\":\"{\\\"foo\\\":\\\"bar\\\"}\"}";
byte[] responseData = responseJson.getBytes(StandardCharsets.UTF_8);
response.setCode(HttpStatus.SC_OK);
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
response.setEntity(new ByteArrayEntity(responseData, ContentType.APPLICATION_JSON));
}
};
try (FakeServer server = new FakeServer(handler)) {
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest("http://localhost:" + server.getPort(), payload);
GenericData body = httpClient.sendAndParse(request, GenericData.class);
assertEquals("{\"foo\":\"bar\"}", body.get("data"));
}
}

@Test(timeout = 10_000L)
Expand Down Expand Up @@ -158,88 +186,6 @@ public void testConnectTimeoutAuthorizedPost() throws FirebaseException {
}
}

@Test(timeout = 10_000L)
public void testReadTimeoutAuthorizedGet() throws FirebaseException {
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
.setCredentials(MOCK_CREDENTIALS)
.setReadTimeout(100)
.build(), "test-app");
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
HttpRequestInfo request = HttpRequestInfo.buildGetRequest(DELAY_URL);

try {
httpClient.send(request);
fail("No exception thrown for HTTP error response");
} catch (FirebaseException e) {
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
assertEquals("IO error: Stream exception in request", e.getMessage());
assertNull(e.getHttpResponse());
}
}

@Test(timeout = 10_000L)
public void testReadTimeoutAuthorizedPost() throws FirebaseException {
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
.setCredentials(MOCK_CREDENTIALS)
.setReadTimeout(100)
.build(), "test-app");
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest(DELAY_URL, payload);

try {
httpClient.send(request);
fail("No exception thrown for HTTP error response");
} catch (FirebaseException e) {
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
assertEquals("IO error: Stream exception in request", e.getMessage());
assertNull(e.getHttpResponse());
}
}

@Test(timeout = 10_000L)
public void testWriteTimeoutAuthorizedGet() throws FirebaseException {
// Use a fresh transport so that writeTimeout triggers while waiting for the transport to
// be ready to receive data.
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
.setCredentials(MOCK_CREDENTIALS)
.setWriteTimeout(100)
.setHttpTransport(new ApacheHttp2Transport())
.build(), "test-app");
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
HttpRequestInfo request = HttpRequestInfo.buildGetRequest(GET_URL);

try {
httpClient.send(request);
fail("No exception thrown for HTTP error response");
} catch (FirebaseException e) {
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
assertEquals("IO error: Write Timeout", e.getMessage());
assertNull(e.getHttpResponse());
}
}

@Test(timeout = 10_000L)
public void testWriteTimeoutAuthorizedPost() throws FirebaseException {
// Use a fresh transport so that writeTimeout triggers while waiting for the transport to
// be ready to receive data.
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
.setCredentials(MOCK_CREDENTIALS)
.setWriteTimeout(100)
.setHttpTransport(new ApacheHttp2Transport())
.build(), "test-app");
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest(POST_URL, payload);

try {
httpClient.send(request);
fail("No exception thrown for HTTP error response");
} catch (FirebaseException e) {
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
assertEquals("IO error: Write Timeout", e.getMessage());
assertNull(e.getHttpResponse());
}
}

@Test(timeout = 10_000L)
public void testRequestShouldNotFollowRedirects() throws IOException {
ApacheHttp2Transport transport = new ApacheHttp2Transport();
Expand Down Expand Up @@ -290,7 +236,7 @@ public void testVerifyProxyIsRespected() {
System.setProperty("https.proxyPort", "8080");

HttpTransport transport = new ApacheHttp2Transport();
transport.createRequestFactory().buildGetRequest(new GenericUrl(GET_URL)).execute();
transport.createRequestFactory().buildGetRequest(new GenericUrl("https://dummy.nonexistent/get")).execute();
fail("No exception thrown for HTTP error response");
} catch (IOException e) {
assertEquals("Connection exception in request", e.getMessage());
Expand Down Expand Up @@ -352,4 +298,26 @@ public FirebaseException handleParseException(IOException e, IncomingHttpRespons
return new FirebaseException(ErrorCode.UNKNOWN, "Parse error", e, response);
}
}

private static class FakeServer implements AutoCloseable {
private final HttpServer server;

FakeServer(final HttpRequestHandler httpHandler) throws IOException {
server = ServerBootstrap.bootstrap()
.setListenerPort(0)
.register("*", httpHandler)
.create();
server.start();
}

public int getPort() {
return server.getLocalPort();
}

@Override
public void close() {
server.close();
}
}
}

Loading