SyncApiTest.java revision c6bd683320121544811f481709b3fdbcbe9b3866
1/*
2 * Copyright (C) 2014 Square, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.squareup.okhttp;
17
18import com.squareup.okhttp.internal.RecordingHostnameVerifier;
19import com.squareup.okhttp.internal.SslContextBuilder;
20import com.squareup.okhttp.mockwebserver.MockResponse;
21import com.squareup.okhttp.mockwebserver.MockWebServer;
22import com.squareup.okhttp.mockwebserver.RecordedRequest;
23import com.squareup.okhttp.mockwebserver.SocketPolicy;
24import java.io.File;
25import java.io.IOException;
26import java.net.HttpURLConnection;
27import java.util.UUID;
28import javax.net.ssl.SSLContext;
29import org.junit.After;
30import org.junit.Before;
31import org.junit.Test;
32
33import static org.junit.Assert.assertEquals;
34import static org.junit.Assert.assertNull;
35import static org.junit.Assert.assertTrue;
36import static org.junit.Assert.fail;
37
38public final class SyncApiTest {
39  private MockWebServer server = new MockWebServer();
40  private OkHttpClient client = new OkHttpClient();
41
42  private static final SSLContext sslContext = SslContextBuilder.localhost();
43  private HttpResponseCache cache;
44
45  @Before public void setUp() throws Exception {
46    String tmp = System.getProperty("java.io.tmpdir");
47    File cacheDir = new File(tmp, "HttpCache-" + UUID.randomUUID());
48    cache = new HttpResponseCache(cacheDir, Integer.MAX_VALUE);
49  }
50
51  @After public void tearDown() throws Exception {
52    server.shutdown();
53    cache.delete();
54  }
55
56  @Test public void get() throws Exception {
57    server.enqueue(new MockResponse()
58        .setBody("abc")
59        .addHeader("Content-Type: text/plain"));
60    server.play();
61
62    Request request = new Request.Builder()
63        .url(server.getUrl("/"))
64        .header("User-Agent", "SyncApiTest")
65        .build();
66
67    onSuccess(request)
68        .assertCode(200)
69        .assertContainsHeaders("Content-Type: text/plain")
70        .assertBody("abc");
71
72    assertTrue(server.takeRequest().getHeaders().contains("User-Agent: SyncApiTest"));
73  }
74
75  @Test public void connectionPooling() throws Exception {
76    server.enqueue(new MockResponse().setBody("abc"));
77    server.enqueue(new MockResponse().setBody("def"));
78    server.enqueue(new MockResponse().setBody("ghi"));
79    server.play();
80
81    onSuccess(new Request.Builder().url(server.getUrl("/a")).build())
82        .assertBody("abc");
83
84    onSuccess(new Request.Builder().url(server.getUrl("/b")).build())
85        .assertBody("def");
86
87    onSuccess(new Request.Builder().url(server.getUrl("/c")).build())
88        .assertBody("ghi");
89
90    assertEquals(0, server.takeRequest().getSequenceNumber());
91    assertEquals(1, server.takeRequest().getSequenceNumber());
92    assertEquals(2, server.takeRequest().getSequenceNumber());
93  }
94
95  @Test public void tls() throws Exception {
96    server.useHttps(sslContext.getSocketFactory(), false);
97    server.enqueue(new MockResponse()
98        .setBody("abc")
99        .addHeader("Content-Type: text/plain"));
100    server.play();
101
102    client.setSslSocketFactory(sslContext.getSocketFactory());
103    client.setHostnameVerifier(new RecordingHostnameVerifier());
104
105    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
106        .assertHandshake();
107  }
108
109  @Test public void recoverFromTlsHandshakeFailure() throws Exception {
110    server.useHttps(sslContext.getSocketFactory(), false);
111    server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
112    server.enqueue(new MockResponse().setBody("abc"));
113    server.play();
114
115    client.setSslSocketFactory(sslContext.getSocketFactory());
116    client.setHostnameVerifier(new RecordingHostnameVerifier());
117
118    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
119        .assertBody("abc");
120  }
121
122  @Test public void post() throws Exception {
123    server.enqueue(new MockResponse().setBody("abc"));
124    server.play();
125
126    Request request = new Request.Builder()
127        .url(server.getUrl("/"))
128        .post(Request.Body.create(MediaType.parse("text/plain"), "def"))
129        .build();
130
131    onSuccess(request)
132        .assertCode(200)
133        .assertBody("abc");
134
135    RecordedRequest recordedRequest = server.takeRequest();
136    assertEquals("def", recordedRequest.getUtf8Body());
137    assertEquals("3", recordedRequest.getHeader("Content-Length"));
138    assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type"));
139  }
140
141  @Test public void conditionalCacheHit() throws Exception {
142    server.enqueue(new MockResponse().setBody("A").addHeader("ETag: v1"));
143    server.enqueue(new MockResponse()
144        .clearHeaders()
145        .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
146    server.play();
147
148    client.setOkResponseCache(cache);
149
150    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
151        .assertCode(200).assertBody("A");
152    assertNull(server.takeRequest().getHeader("If-None-Match"));
153
154    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
155        .assertCode(200).assertBody("A");
156    assertEquals("v1", server.takeRequest().getHeader("If-None-Match"));
157  }
158
159  @Test public void conditionalCacheMiss() throws Exception {
160    server.enqueue(new MockResponse().setBody("A").addHeader("ETag: v1"));
161    server.enqueue(new MockResponse().setBody("B"));
162    server.play();
163
164    client.setOkResponseCache(cache);
165
166    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
167        .assertCode(200).assertBody("A");
168    assertNull(server.takeRequest().getHeader("If-None-Match"));
169
170    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
171        .assertCode(200).assertBody("B");
172    assertEquals("v1", server.takeRequest().getHeader("If-None-Match"));
173  }
174
175  @Test public void redirect() throws Exception {
176    server.enqueue(new MockResponse()
177        .setResponseCode(301)
178        .addHeader("Location: /b")
179        .addHeader("Test", "Redirect from /a to /b")
180        .setBody("/a has moved!"));
181    server.enqueue(new MockResponse()
182        .setResponseCode(302)
183        .addHeader("Location: /c")
184        .addHeader("Test", "Redirect from /b to /c")
185        .setBody("/b has moved!"));
186    server.enqueue(new MockResponse().setBody("C"));
187    server.play();
188
189    onSuccess(new Request.Builder().url(server.getUrl("/a")).build())
190        .assertCode(200)
191        .assertBody("C")
192        .redirectedBy()
193        .assertCode(302)
194        .assertContainsHeaders("Test: Redirect from /b to /c")
195        .redirectedBy()
196        .assertCode(301)
197        .assertContainsHeaders("Test: Redirect from /a to /b");
198
199    assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection.
200    assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused.
201    assertEquals(2, server.takeRequest().getSequenceNumber()); // Connection reused again!
202  }
203
204  @Test public void redirectWithRedirectsDisabled() throws Exception {
205    client.setFollowProtocolRedirects(false);
206    server.enqueue(new MockResponse()
207        .setResponseCode(301)
208        .addHeader("Location: /b")
209        .addHeader("Test", "Redirect from /a to /b")
210        .setBody("/a has moved!"));
211    server.play();
212
213    onSuccess(new Request.Builder().url(server.getUrl("/a")).build())
214        .assertCode(301)
215        .assertBody("/a has moved!")
216        .assertContainsHeaders("Location: /b");
217  }
218
219  @Test public void follow20Redirects() throws Exception {
220    for (int i = 0; i < 20; i++) {
221      server.enqueue(new MockResponse()
222          .setResponseCode(301)
223          .addHeader("Location: /" + (i + 1))
224          .setBody("Redirecting to /" + (i + 1)));
225    }
226    server.enqueue(new MockResponse().setBody("Success!"));
227    server.play();
228
229    onSuccess(new Request.Builder().url(server.getUrl("/0")).build())
230        .assertCode(200)
231        .assertBody("Success!");
232  }
233
234  @Test public void doesNotFollow21Redirects() throws Exception {
235    for (int i = 0; i < 21; i++) {
236      server.enqueue(new MockResponse()
237          .setResponseCode(301)
238          .addHeader("Location: /" + (i + 1))
239          .setBody("Redirecting to /" + (i + 1)));
240    }
241    server.play();
242
243    try {
244      client.execute(new Request.Builder().url(server.getUrl("/0")).build());
245      fail();
246    } catch (IOException e) {
247      assertEquals("Too many redirects: 21", e.getMessage());
248    }
249  }
250
251  @Test public void postBodyRetransmittedOnRedirect() throws Exception {
252    server.enqueue(new MockResponse()
253        .setResponseCode(302)
254        .addHeader("Location: /b")
255        .setBody("Moved to /b !"));
256    server.enqueue(new MockResponse()
257        .setBody("This is b."));
258    server.play();
259
260    Request request = new Request.Builder()
261        .url(server.getUrl("/"))
262        .post(Request.Body.create(MediaType.parse("text/plain"), "body!"))
263        .build();
264
265    onSuccess(request)
266        .assertCode(200)
267        .assertBody("This is b.");
268
269    RecordedRequest request1 = server.takeRequest();
270    assertEquals("body!", request1.getUtf8Body());
271    assertEquals("5", request1.getHeader("Content-Length"));
272    assertEquals("text/plain; charset=utf-8", request1.getHeader("Content-Type"));
273    assertEquals(0, request1.getSequenceNumber());
274
275    RecordedRequest request2 = server.takeRequest();
276    assertEquals("body!", request2.getUtf8Body());
277    assertEquals("5", request2.getHeader("Content-Length"));
278    assertEquals("text/plain; charset=utf-8", request2.getHeader("Content-Type"));
279    assertEquals(1, request2.getSequenceNumber());
280  }
281
282  private RecordedResponse onSuccess(Request request) throws IOException {
283    Response response = client.execute(request);
284    return new RecordedResponse(request, response, response.body().string(), null);
285  }
286}
287