Skip to content

Commit 4b574e6

Browse files
committed
chore: Use fake local server over external endpoint
1 parent 45756e4 commit 4b574e6

1 file changed

Lines changed: 163 additions & 90 deletions

File tree

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

Lines changed: 163 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,29 @@
4040
import java.io.IOException;
4141
import java.net.ServerSocket;
4242
import java.net.Socket;
43+
import java.nio.charset.StandardCharsets;
4344
import java.util.concurrent.atomic.AtomicBoolean;
4445
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
4546
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
47+
import org.apache.hc.core5.http.ClassicHttpRequest;
48+
import org.apache.hc.core5.http.ClassicHttpResponse;
49+
import org.apache.hc.core5.http.ContentType;
4650
import org.apache.hc.core5.http.EntityDetails;
4751
import org.apache.hc.core5.http.Header;
4852
import org.apache.hc.core5.http.HttpException;
53+
import org.apache.hc.core5.http.HttpHeaders;
4954
import org.apache.hc.core5.http.HttpRequest;
5055
import org.apache.hc.core5.http.HttpRequestInterceptor;
56+
import org.apache.hc.core5.http.HttpRequestMapper;
57+
import org.apache.hc.core5.http.HttpResponse;
58+
import org.apache.hc.core5.http.HttpStatus;
59+
import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
60+
import org.apache.hc.core5.http.impl.io.HttpService;
61+
import org.apache.hc.core5.http.io.HttpRequestHandler;
62+
import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
63+
import org.apache.hc.core5.http.io.support.BasicHttpServerRequestHandler;
5164
import org.apache.hc.core5.http.protocol.HttpContext;
65+
import org.apache.hc.core5.http.protocol.HttpProcessor;
5266

5367
import org.junit.After;
5468
import org.junit.AfterClass;
@@ -61,11 +75,6 @@ public class ApacheHttp2TransportIT {
6175
private static final ImmutableMap<String, Object> payload =
6276
ImmutableMap.<String, Object>of("foo", "bar");
6377

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

7079
private static ServerSocket serverSocket;
7180
private static Socket fillerSocket;
@@ -105,19 +114,45 @@ public void cleanup() {
105114
}
106115

107116
@Test(timeout = 10_000L)
108-
public void testUnauthorizedGetRequest() throws FirebaseException {
109-
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
110-
HttpRequestInfo request = HttpRequestInfo.buildGetRequest(GET_URL);
111-
IncomingHttpResponse response = httpClient.send(request);
112-
assertEquals(200, response.getStatusCode());
117+
public void testUnauthorizedGetRequest() throws Exception {
118+
final HttpRequestHandler handler = new HttpRequestHandler() {
119+
@Override
120+
public void handle(
121+
ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
122+
throws HttpException, IOException {
123+
response.setCode(HttpStatus.SC_OK);
124+
response.setHeader(HttpHeaders.CONTENT_LENGTH, "0");
125+
}
126+
};
127+
try (FakeServer server = new FakeServer(handler)) {
128+
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
129+
HttpRequestInfo request = HttpRequestInfo.buildGetRequest("http://localhost:" + server.getPort());
130+
IncomingHttpResponse response = httpClient.send(request);
131+
assertEquals(200, response.getStatusCode());
132+
}
113133
}
114134

115135
@Test(timeout = 10_000L)
116-
public void testUnauthorizedPostRequest() throws FirebaseException {
117-
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
118-
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest(POST_URL, payload);
119-
GenericData body = httpClient.sendAndParse(request, GenericData.class);
120-
assertEquals("{\"foo\":\"bar\"}", body.get("data"));
136+
public void testUnauthorizedPostRequest() throws Exception {
137+
final HttpRequestHandler handler = new HttpRequestHandler() {
138+
@Override
139+
public void handle(
140+
ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
141+
throws HttpException, IOException {
142+
String responseJson = "{\"data\":\"{\\\"foo\\\":\\\"bar\\\"}\"}";
143+
byte[] responseData = responseJson.getBytes(StandardCharsets.UTF_8);
144+
response.setCode(HttpStatus.SC_OK);
145+
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(responseData.length));
146+
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
147+
response.setEntity(new ByteArrayEntity(responseData, ContentType.APPLICATION_JSON));
148+
}
149+
};
150+
try (FakeServer server = new FakeServer(handler)) {
151+
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(false);
152+
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest("http://localhost:" + server.getPort(), payload);
153+
GenericData body = httpClient.sendAndParse(request, GenericData.class);
154+
assertEquals("{\"foo\":\"bar\"}", body.get("data"));
155+
}
121156
}
122157

123158
@Test(timeout = 10_000L)
@@ -159,84 +194,72 @@ public void testConnectTimeoutAuthorizedPost() throws FirebaseException {
159194
}
160195

161196
@Test(timeout = 10_000L)
162-
public void testReadTimeoutAuthorizedGet() throws FirebaseException {
163-
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
164-
.setCredentials(MOCK_CREDENTIALS)
165-
.setReadTimeout(100)
166-
.build(), "test-app");
167-
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
168-
HttpRequestInfo request = HttpRequestInfo.buildGetRequest(DELAY_URL);
169-
170-
try {
171-
httpClient.send(request);
172-
fail("No exception thrown for HTTP error response");
173-
} catch (FirebaseException e) {
174-
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
175-
assertEquals("IO error: Stream exception in request", e.getMessage());
176-
assertNull(e.getHttpResponse());
197+
public void testReadTimeoutAuthorizedGet() throws Exception {
198+
final HttpRequestHandler handler = new HttpRequestHandler() {
199+
@Override
200+
public void handle(
201+
ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
202+
throws HttpException, IOException {
203+
try {
204+
Thread.sleep(1000);
205+
} catch (InterruptedException e) {
206+
// Ignore
207+
}
208+
response.setCode(HttpStatus.SC_OK);
209+
}
210+
};
211+
try (FakeServer server = new FakeServer(handler)) {
212+
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
213+
.setCredentials(MOCK_CREDENTIALS)
214+
.setConnectTimeout(5000)
215+
.setReadTimeout(100)
216+
.build(), "test-app");
217+
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
218+
HttpRequestInfo request = HttpRequestInfo.buildGetRequest("http://localhost:" + server.getPort());
219+
220+
try {
221+
httpClient.send(request);
222+
fail("No exception thrown for HTTP error response");
223+
} catch (FirebaseException e) {
224+
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
225+
assertEquals("IO error: Connection Timeout", e.getMessage());
226+
assertNull(e.getHttpResponse());
227+
}
177228
}
178229
}
179230

180231
@Test(timeout = 10_000L)
181-
public void testReadTimeoutAuthorizedPost() throws FirebaseException {
182-
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
183-
.setCredentials(MOCK_CREDENTIALS)
184-
.setReadTimeout(100)
185-
.build(), "test-app");
186-
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
187-
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest(DELAY_URL, payload);
188-
189-
try {
190-
httpClient.send(request);
191-
fail("No exception thrown for HTTP error response");
192-
} catch (FirebaseException e) {
193-
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
194-
assertEquals("IO error: Stream exception in request", e.getMessage());
195-
assertNull(e.getHttpResponse());
196-
}
197-
}
198-
199-
@Test(timeout = 10_000L)
200-
public void testWriteTimeoutAuthorizedGet() throws FirebaseException {
201-
// Use a fresh transport so that writeTimeout triggers while waiting for the transport to
202-
// be ready to receive data.
203-
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
204-
.setCredentials(MOCK_CREDENTIALS)
205-
.setWriteTimeout(100)
206-
.setHttpTransport(new ApacheHttp2Transport())
207-
.build(), "test-app");
208-
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
209-
HttpRequestInfo request = HttpRequestInfo.buildGetRequest(GET_URL);
210-
211-
try {
212-
httpClient.send(request);
213-
fail("No exception thrown for HTTP error response");
214-
} catch (FirebaseException e) {
215-
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
216-
assertEquals("IO error: Write Timeout", e.getMessage());
217-
assertNull(e.getHttpResponse());
218-
}
219-
}
220-
221-
@Test(timeout = 10_000L)
222-
public void testWriteTimeoutAuthorizedPost() throws FirebaseException {
223-
// Use a fresh transport so that writeTimeout triggers while waiting for the transport to
224-
// be ready to receive data.
225-
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
226-
.setCredentials(MOCK_CREDENTIALS)
227-
.setWriteTimeout(100)
228-
.setHttpTransport(new ApacheHttp2Transport())
229-
.build(), "test-app");
230-
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
231-
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest(POST_URL, payload);
232-
233-
try {
234-
httpClient.send(request);
235-
fail("No exception thrown for HTTP error response");
236-
} catch (FirebaseException e) {
237-
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
238-
assertEquals("IO error: Write Timeout", e.getMessage());
239-
assertNull(e.getHttpResponse());
232+
public void testReadTimeoutAuthorizedPost() throws Exception {
233+
final HttpRequestHandler handler = new HttpRequestHandler() {
234+
@Override
235+
public void handle(
236+
ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context)
237+
throws HttpException, IOException {
238+
try {
239+
Thread.sleep(1000);
240+
} catch (InterruptedException e) {
241+
// Ignore
242+
}
243+
response.setCode(HttpStatus.SC_OK);
244+
}
245+
};
246+
try (FakeServer server = new FakeServer(handler)) {
247+
app = FirebaseApp.initializeApp(FirebaseOptions.builder()
248+
.setCredentials(MOCK_CREDENTIALS)
249+
.setConnectTimeout(5000)
250+
.setReadTimeout(100)
251+
.build(), "test-app-2");
252+
ErrorHandlingHttpClient<FirebaseException> httpClient = getHttpClient(true, app);
253+
HttpRequestInfo request = HttpRequestInfo.buildJsonPostRequest("http://localhost:" + server.getPort(), payload);
254+
255+
try {
256+
httpClient.send(request);
257+
fail("No exception thrown for HTTP error response");
258+
} catch (FirebaseException e) {
259+
assertEquals(ErrorCode.UNKNOWN, e.getErrorCode());
260+
assertEquals("IO error: Connection Timeout", e.getMessage());
261+
assertNull(e.getHttpResponse());
262+
}
240263
}
241264
}
242265

@@ -290,7 +313,7 @@ public void testVerifyProxyIsRespected() {
290313
System.setProperty("https.proxyPort", "8080");
291314

292315
HttpTransport transport = new ApacheHttp2Transport();
293-
transport.createRequestFactory().buildGetRequest(new GenericUrl(GET_URL)).execute();
316+
transport.createRequestFactory().buildGetRequest(new GenericUrl("https://dummy.nonexistent/get")).execute();
294317
fail("No exception thrown for HTTP error response");
295318
} catch (IOException e) {
296319
assertEquals("Connection exception in request", e.getMessage());
@@ -352,4 +375,54 @@ public FirebaseException handleParseException(IOException e, IncomingHttpRespons
352375
return new FirebaseException(ErrorCode.UNKNOWN, "Parse error", e, response);
353376
}
354377
}
378+
379+
private static class FakeServer implements AutoCloseable {
380+
private final HttpServer server;
381+
382+
FakeServer(final HttpRequestHandler httpHandler) throws IOException {
383+
HttpRequestMapper<HttpRequestHandler> mapper = new HttpRequestMapper<HttpRequestHandler>() {
384+
@Override
385+
public HttpRequestHandler resolve(HttpRequest request, HttpContext context)
386+
throws HttpException {
387+
return httpHandler;
388+
}
389+
};
390+
server = new HttpServer(
391+
0,
392+
HttpService.builder()
393+
.withHttpProcessor(
394+
new HttpProcessor() {
395+
@Override
396+
public void process(
397+
HttpRequest request, EntityDetails entity, HttpContext context)
398+
throws HttpException, IOException {
399+
}
400+
401+
@Override
402+
public void process(
403+
HttpResponse response, EntityDetails entity, HttpContext context)
404+
throws HttpException, IOException {
405+
}
406+
})
407+
.withHttpServerRequestHandler(new BasicHttpServerRequestHandler(mapper))
408+
.build(),
409+
null,
410+
null,
411+
null,
412+
null,
413+
null,
414+
null);
415+
server.start();
416+
}
417+
418+
public int getPort() {
419+
return server.getLocalPort();
420+
}
421+
422+
@Override
423+
public void close() {
424+
server.initiateShutdown();
425+
}
426+
}
355427
}
428+

0 commit comments

Comments
 (0)