1 package org.robolectric.shadows.httpclient;
2 
3 import static com.google.common.truth.Truth.assertThat;
4 import static java.nio.charset.StandardCharsets.UTF_8;
5 import static org.junit.Assert.assertFalse;
6 import static org.junit.Assert.assertNotNull;
7 import static org.junit.Assert.assertNull;
8 import static org.junit.Assert.assertSame;
9 import static org.junit.Assert.fail;
10 import static org.robolectric.shadows.httpclient.Shadows.shadowOf;
11 
12 import com.google.common.io.CharStreams;
13 import java.io.BufferedReader;
14 import java.io.ByteArrayInputStream;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.io.InputStreamReader;
18 import java.net.URI;
19 import org.apache.http.HttpRequest;
20 import org.apache.http.HttpResponse;
21 import org.apache.http.client.methods.HttpGet;
22 import org.apache.http.client.methods.HttpPost;
23 import org.apache.http.client.methods.HttpUriRequest;
24 import org.apache.http.conn.ConnectTimeoutException;
25 import org.apache.http.conn.ConnectionKeepAliveStrategy;
26 import org.apache.http.impl.client.BasicResponseHandler;
27 import org.apache.http.impl.client.DefaultHttpClient;
28 import org.apache.http.impl.client.DefaultRequestDirector;
29 import org.apache.http.message.BasicHeader;
30 import org.apache.http.params.HttpConnectionParams;
31 import org.apache.http.params.HttpParams;
32 import org.apache.http.protocol.HttpContext;
33 import org.junit.After;
34 import org.junit.Assert;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 import org.robolectric.util.TestRunnerWithManifest;
39 
40 @RunWith(TestRunnerWithManifest.class)
41 public class ShadowDefaultRequestDirectorTest {
42 
43   private DefaultRequestDirector requestDirector;
44   private ConnectionKeepAliveStrategy connectionKeepAliveStrategy;
45 
46   @Before
setUp_EnsureStaticStateIsReset()47   public void setUp_EnsureStaticStateIsReset() {
48     FakeHttpLayer fakeHttpLayer = FakeHttp.getFakeHttpLayer();
49     assertFalse(fakeHttpLayer.hasPendingResponses());
50     assertFalse(fakeHttpLayer.hasRequestInfos());
51     assertFalse(fakeHttpLayer.hasResponseRules());
52 
53     connectionKeepAliveStrategy =
54         new ConnectionKeepAliveStrategy() {
55           @Override
56           public long getKeepAliveDuration(HttpResponse httpResponse, HttpContext httpContext) {
57             return 0;
58           }
59         };
60     requestDirector =
61         new DefaultRequestDirector(
62             null,
63             null,
64             null,
65             connectionKeepAliveStrategy,
66             null,
67             null,
68             null,
69             null,
70             null,
71             null,
72             null,
73             null);
74   }
75 
76   @After
tearDown_EnsureStaticStateIsReset()77   public void tearDown_EnsureStaticStateIsReset() throws Exception {
78     FakeHttp.addPendingHttpResponse(200, "a happy response body");
79   }
80 
81   @Test
shouldGetHttpResponseFromExecute()82   public void shouldGetHttpResponseFromExecute() throws Exception {
83     FakeHttp.addPendingHttpResponse(new TestHttpResponse(200, "a happy response body"));
84     HttpResponse response = requestDirector.execute(null, new HttpGet("http://example.com"), null);
85 
86     assertNotNull(response);
87     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
88     assertThat(getStringContent(response)).isEqualTo("a happy response body");
89   }
90 
91   @Test
shouldPreferPendingResponses()92   public void shouldPreferPendingResponses() throws Exception {
93     FakeHttp.addPendingHttpResponse(new TestHttpResponse(200, "a happy response body"));
94 
95     FakeHttp.addHttpResponseRule(HttpGet.METHOD_NAME, "http://some.uri",
96         new TestHttpResponse(200, "a cheery response body"));
97 
98     HttpResponse response = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
99 
100     assertNotNull(response);
101     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
102     assertThat(getStringContent(response)).isEqualTo("a happy response body");
103   }
104 
105   @Test
shouldReturnRequestsByRule()106   public void shouldReturnRequestsByRule() throws Exception {
107     FakeHttp.addHttpResponseRule(HttpGet.METHOD_NAME, "http://some.uri",
108         new TestHttpResponse(200, "a cheery response body"));
109 
110     HttpResponse response = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
111 
112     assertNotNull(response);
113     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
114     assertThat(getStringContent(response)).isEqualTo("a cheery response body");
115   }
116 
117   @Test
shouldReturnRequestsByRule_MatchingMethod()118   public void shouldReturnRequestsByRule_MatchingMethod() throws Exception {
119     FakeHttp.setDefaultHttpResponse(404, "no such page");
120     FakeHttp.addHttpResponseRule(HttpPost.METHOD_NAME, "http://some.uri",
121         new TestHttpResponse(200, "a cheery response body"));
122 
123     HttpResponse response = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
124 
125     assertNotNull(response);
126     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(404);
127   }
128 
129   @Test
shouldReturnRequestsByRule_AnyMethod()130   public void shouldReturnRequestsByRule_AnyMethod() throws Exception {
131     FakeHttp.addHttpResponseRule(
132         "http://some.uri", new TestHttpResponse(200, "a cheery response body"));
133 
134     HttpResponse getResponse = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
135     assertNotNull(getResponse);
136     assertThat(getResponse.getStatusLine().getStatusCode()).isEqualTo(200);
137     assertThat(getStringContent(getResponse)).isEqualTo("a cheery response body");
138 
139     HttpResponse postResponse =
140         requestDirector.execute(null, new HttpPost("http://some.uri"), null);
141     assertNotNull(postResponse);
142     assertThat(postResponse.getStatusLine().getStatusCode()).isEqualTo(200);
143     assertThat(getStringContent(postResponse)).isEqualTo("a cheery response body");
144   }
145 
146   @Test
shouldReturnRequestsByRule_KeepsTrackOfOpenContentStreams()147   public void shouldReturnRequestsByRule_KeepsTrackOfOpenContentStreams() throws Exception {
148     TestHttpResponse testHttpResponse = new TestHttpResponse(200, "a cheery response body");
149     FakeHttp.addHttpResponseRule("http://some.uri", testHttpResponse);
150 
151     assertThat(testHttpResponse.entityContentStreamsHaveBeenClosed()).isTrue();
152 
153     HttpResponse getResponse = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
154     InputStream getResponseStream = getResponse.getEntity().getContent();
155     assertThat(CharStreams.toString(new InputStreamReader(getResponseStream, UTF_8)))
156         .isEqualTo("a cheery response body");
157     assertThat(testHttpResponse.entityContentStreamsHaveBeenClosed()).isFalse();
158 
159     HttpResponse postResponse =
160         requestDirector.execute(null, new HttpPost("http://some.uri"), null);
161     InputStream postResponseStream = postResponse.getEntity().getContent();
162     assertThat(CharStreams.toString(new InputStreamReader(postResponseStream, UTF_8)))
163         .isEqualTo("a cheery response body");
164     assertThat(testHttpResponse.entityContentStreamsHaveBeenClosed()).isFalse();
165 
166     getResponseStream.close();
167     assertThat(testHttpResponse.entityContentStreamsHaveBeenClosed()).isFalse();
168 
169     postResponseStream.close();
170     assertThat(testHttpResponse.entityContentStreamsHaveBeenClosed()).isTrue();
171   }
172 
173   @Test
shouldReturnRequestsByRule_WithTextResponse()174   public void shouldReturnRequestsByRule_WithTextResponse() throws Exception {
175     FakeHttp.addHttpResponseRule("http://some.uri", "a cheery response body");
176 
177     HttpResponse response = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
178 
179     assertNotNull(response);
180     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
181     assertThat(getStringContent(response)).isEqualTo("a cheery response body");
182   }
183 
184   @Test
clearHttpResponseRules_shouldRemoveAllRules()185   public void clearHttpResponseRules_shouldRemoveAllRules() throws Exception {
186     FakeHttp.addHttpResponseRule("http://some.uri", "a cheery response body");
187     FakeHttp.clearHttpResponseRules();
188     FakeHttp.addHttpResponseRule("http://some.uri", "a gloomy response body");
189 
190     HttpResponse response = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
191 
192     assertNotNull(response);
193     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
194     assertThat(getStringContent(response)).isEqualTo("a gloomy response body");
195   }
196 
197   @Test
clearPendingHttpResponses()198   public void clearPendingHttpResponses() throws Exception {
199     FakeHttp.addPendingHttpResponse(200, "earlier");
200     FakeHttp.clearPendingHttpResponses();
201     FakeHttp.addPendingHttpResponse(500, "later");
202 
203     HttpResponse response = requestDirector.execute(null, new HttpGet("http://some.uri"), null);
204 
205     assertNotNull(response);
206     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(500);
207     assertThat(getStringContent(response)).isEqualTo("later");
208   }
209 
210   @Test
shouldReturnRequestsByRule_WithCustomRequestMatcher()211   public void shouldReturnRequestsByRule_WithCustomRequestMatcher() throws Exception {
212     FakeHttp.setDefaultHttpResponse(404, "no such page");
213 
214     FakeHttp.addHttpResponseRule(new RequestMatcher() {
215       @Override
216       public boolean matches(HttpRequest request) {
217         return request.getRequestLine().getUri().equals("http://matching.uri");
218       }
219     }, new TestHttpResponse(200, "a cheery response body"));
220 
221     HttpResponse response = requestDirector.execute(null, new HttpGet("http://matching.uri"), null);
222     assertNotNull(response);
223     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
224     assertThat(getStringContent(response)).isEqualTo("a cheery response body");
225 
226     response = requestDirector.execute(null, new HttpGet("http://non-matching.uri"), null);
227     assertNotNull(response);
228     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(404);
229     assertThat(getStringContent(response)).isEqualTo("no such page");
230   }
231 
232   @Test
shouldGetHttpResponseFromExecuteSimpleApi()233   public void shouldGetHttpResponseFromExecuteSimpleApi() throws Exception {
234     FakeHttp.addPendingHttpResponse(200, "a happy response body");
235     HttpResponse response = requestDirector.execute(null, new HttpGet("http://example.com"), null);
236 
237     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
238     assertThat(getStringContent(response)).isEqualTo("a happy response body");
239   }
240 
241   @Test
shouldHandleMultipleInvocations()242   public void shouldHandleMultipleInvocations() throws Exception {
243     FakeHttp.addPendingHttpResponse(200, "a happy response body");
244     FakeHttp.addPendingHttpResponse(201, "another happy response body");
245 
246     HttpResponse response1 = requestDirector.execute(null, new HttpGet("http://example.com"), null);
247     HttpResponse response2 = requestDirector.execute(null, new HttpGet("www.example.com"), null);
248 
249     assertThat(response1.getStatusLine().getStatusCode()).isEqualTo(200);
250     assertThat(getStringContent(response1)).isEqualTo("a happy response body");
251 
252     assertThat(response2.getStatusLine().getStatusCode()).isEqualTo(201);
253     assertThat(getStringContent(response2)).isEqualTo("another happy response body");
254   }
255 
256   @Test
shouldHandleMultipleInvocationsOfExecute()257   public void shouldHandleMultipleInvocationsOfExecute() throws Exception {
258     FakeHttp.addPendingHttpResponse(200, "a happy response body");
259     FakeHttp.addPendingHttpResponse(201, "another happy response body");
260 
261     requestDirector.execute(null, new HttpGet("http://example.com"), null);
262     requestDirector.execute(null, new HttpGet("www.example.com"), null);
263 
264     HttpUriRequest request1 = (HttpUriRequest) FakeHttp.getSentHttpRequest(0);
265     assertThat(request1.getMethod()).isEqualTo(HttpGet.METHOD_NAME);
266     assertThat(request1.getURI()).isEqualTo(URI.create("http://example.com"));
267 
268     HttpUriRequest request2 = (HttpUriRequest) FakeHttp.getSentHttpRequest(1);
269     assertThat(request2.getMethod()).isEqualTo(HttpGet.METHOD_NAME);
270     assertThat(request2.getURI()).isEqualTo(URI.create("www.example.com"));
271   }
272 
273   @Test
shouldRejectUnexpectedCallsToExecute()274   public void shouldRejectUnexpectedCallsToExecute() throws Exception {
275     try {
276       requestDirector.execute(null, new HttpGet("http://example.com"), null);
277       fail();
278     } catch (RuntimeException expected) {
279       assertThat(expected.getMessage())
280           .isEqualTo(
281               "Unexpected call to execute, no pending responses are available. "
282                   + "See Robolectric.addPendingResponse(). Request was: GET http://example.com");
283     }
284   }
285 
286   @Test
shouldRecordExtendedRequestData()287   public void shouldRecordExtendedRequestData() throws Exception {
288     FakeHttp.addPendingHttpResponse(200, "a happy response body");
289     HttpGet httpGet = new HttpGet("http://example.com");
290     requestDirector.execute(null, httpGet, null);
291 
292     assertSame(FakeHttp.getSentHttpRequestInfo(0).getHttpRequest(), httpGet);
293     ConnectionKeepAliveStrategy strategy =
294         shadowOf((DefaultRequestDirector) FakeHttp.getSentHttpRequestInfo(0).getRequestDirector())
295             .getConnectionKeepAliveStrategy();
296     assertSame(strategy, connectionKeepAliveStrategy);
297   }
298 
299   @Test
getNextSentHttpRequestInfo_shouldRemoveHttpRequestInfos()300   public void getNextSentHttpRequestInfo_shouldRemoveHttpRequestInfos() throws Exception {
301     FakeHttp.addPendingHttpResponse(200, "a happy response body");
302     HttpGet httpGet = new HttpGet("http://example.com");
303     requestDirector.execute(null, httpGet, null);
304 
305     assertSame(FakeHttp.getNextSentHttpRequestInfo().getHttpRequest(), httpGet);
306     assertNull(FakeHttp.getNextSentHttpRequestInfo());
307   }
308 
309   @Test
getNextSentHttpRequest_shouldRemoveHttpRequests()310   public void getNextSentHttpRequest_shouldRemoveHttpRequests() throws Exception {
311     FakeHttp.addPendingHttpResponse(200, "a happy response body");
312     HttpGet httpGet = new HttpGet("http://example.com");
313     requestDirector.execute(null, httpGet, null);
314 
315     assertSame(FakeHttp.getNextSentHttpRequest(), httpGet);
316     assertNull(FakeHttp.getNextSentHttpRequest());
317   }
318 
319   @Test
shouldSupportBasicResponseHandlerHandleResponse()320   public void shouldSupportBasicResponseHandlerHandleResponse() throws Exception {
321     FakeHttp.addPendingHttpResponse(200, "OK", new BasicHeader("Content-Type", "text/plain"));
322 
323     DefaultHttpClient client = new DefaultHttpClient();
324     HttpResponse response = client.execute(new HttpGet("http://www.nowhere.org"));
325 
326     assertThat(((HttpUriRequest) FakeHttp.getSentHttpRequest(0)).getURI())
327         .isEqualTo(URI.create("http://www.nowhere.org"));
328 
329     Assert.assertNotNull(response);
330     String responseStr = new BasicResponseHandler().handleResponse(response);
331     Assert.assertEquals("OK", responseStr);
332   }
333 
334   @Test
shouldFindLastRequestMade()335   public void shouldFindLastRequestMade() throws Exception {
336     FakeHttp.addPendingHttpResponse(200, "a happy response body");
337     FakeHttp.addPendingHttpResponse(200, "a happy response body");
338     FakeHttp.addPendingHttpResponse(200, "a happy response body");
339 
340     DefaultHttpClient client = new DefaultHttpClient();
341     client.execute(new HttpGet("http://www.first.org"));
342     client.execute(new HttpGet("http://www.second.org"));
343     client.execute(new HttpGet("http://www.third.org"));
344 
345     assertThat(((HttpUriRequest) FakeHttp.getLatestSentHttpRequest()).getURI())
346         .isEqualTo(URI.create("http://www.third.org"));
347   }
348 
349 
350   @Test
shouldSupportConnectionTimeoutWithExceptions()351   public void shouldSupportConnectionTimeoutWithExceptions() throws Exception {
352     FakeHttp.setDefaultHttpResponse(new TestHttpResponse() {
353       @Override
354       public HttpParams getParams() {
355         HttpParams httpParams = super.getParams();
356         HttpConnectionParams.setConnectionTimeout(httpParams, -1);
357         return httpParams;
358       }
359     });
360 
361     DefaultHttpClient client = new DefaultHttpClient();
362     try {
363       client.execute(new HttpGet("http://www.nowhere.org"));
364     } catch (ConnectTimeoutException x) {
365       return;
366     }
367 
368     fail("Exception should have been thrown");
369   }
370 
371   @Test
shouldSupportSocketTimeoutWithExceptions()372   public void shouldSupportSocketTimeoutWithExceptions() throws Exception {
373     FakeHttp.setDefaultHttpResponse(new TestHttpResponse() {
374       @Override
375       public HttpParams getParams() {
376         HttpParams httpParams = super.getParams();
377         HttpConnectionParams.setSoTimeout(httpParams, -1);
378         return httpParams;
379       }
380     });
381 
382     DefaultHttpClient client = new DefaultHttpClient();
383     try {
384       client.execute(new HttpGet("http://www.nowhere.org"));
385     } catch (ConnectTimeoutException x) {
386       return;
387     }
388 
389     fail("Exception should have been thrown");
390   }
391 
392   @Test(expected = IOException.class)
shouldSupportRealHttpRequests()393   public void shouldSupportRealHttpRequests() throws Exception {
394     FakeHttp.getFakeHttpLayer().interceptHttpRequests(false);
395     DefaultHttpClient client = new DefaultHttpClient();
396     client.execute(new HttpGet("http://www.this-host-should-not-exist-123456790.org:999"));
397   }
398 
399   @Test
shouldSupportRealHttpRequestsAddingRequestInfo()400   public void shouldSupportRealHttpRequestsAddingRequestInfo() throws Exception {
401     FakeHttp.getFakeHttpLayer().interceptHttpRequests(false);
402     DefaultHttpClient client = new DefaultHttpClient();
403 
404     // it's really bad to depend on an external server in order to get a test pass,
405     // but this test is about making sure that we can intercept calls to external servers
406     // so, I think that in this specific case, it's appropriate...
407     client.execute(new HttpGet("http://google.com"));
408 
409     assertNotNull(FakeHttp.getFakeHttpLayer().getLastSentHttpRequestInfo());
410     assertNotNull(FakeHttp.getFakeHttpLayer().getLastHttpResponse());
411   }
412 
413   @Test
realHttpRequestsShouldMakeContentDataAvailable()414   public void realHttpRequestsShouldMakeContentDataAvailable() throws Exception {
415     FakeHttp.getFakeHttpLayer().interceptHttpRequests(false);
416     FakeHttp.getFakeHttpLayer().interceptResponseContent(true);
417     DefaultHttpClient client = new DefaultHttpClient();
418 
419     client.execute(new HttpGet("http://google.com"));
420 
421     byte[] cachedContent = FakeHttp.getFakeHttpLayer().getHttpResposeContentList().get(0);
422     assertThat(cachedContent.length).isNotEqualTo(0);
423 
424     InputStream content =
425         FakeHttp.getFakeHttpLayer().getLastHttpResponse().getEntity().getContent();
426     BufferedReader contentReader = new BufferedReader(new InputStreamReader(content, UTF_8));
427     String firstLineOfContent = contentReader.readLine();
428     assertThat(firstLineOfContent).contains("Google");
429 
430     BufferedReader cacheReader =
431         new BufferedReader(new InputStreamReader(new ByteArrayInputStream(cachedContent), UTF_8));
432     String firstLineOfCachedContent = cacheReader.readLine();
433     assertThat(firstLineOfCachedContent).isEqualTo(firstLineOfContent);
434   }
435 
436   @Test
shouldReturnResponseFromHttpResponseGenerator()437   public void shouldReturnResponseFromHttpResponseGenerator() throws Exception {
438     FakeHttp.addPendingHttpResponse(new HttpResponseGenerator() {
439       @Override
440       public HttpResponse getResponse(HttpRequest request) {
441         return new TestHttpResponse(200, "a happy response body");
442       }
443     });
444     HttpResponse response = requestDirector.execute(null, new HttpGet("http://example.com"), null);
445 
446     assertNotNull(response);
447     assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
448     assertThat(getStringContent(response)).isEqualTo("a happy response body");
449   }
450 
getStringContent(HttpResponse response)451   private static String getStringContent(HttpResponse response) throws IOException {
452     return CharStreams.toString(new InputStreamReader(response.getEntity().getContent(), UTF_8));
453   }
454 
455 }