SyncApiTest.java revision 3c938a3f6b61ce5e2dba0d039b03fe73b89fd26c
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 cache() throws Exception {
142    server.enqueue(new MockResponse().setBody("A").addHeader("ETag: v1"));
143    server.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED));
144    server.play();
145
146    client.setOkResponseCache(cache);
147
148    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
149        .assertCode(200).assertBody("A");
150    assertNull(server.takeRequest().getHeader("If-None-Match"));
151
152    onSuccess(new Request.Builder().url(server.getUrl("/")).build())
153        .assertCode(200).assertBody("A");
154    assertEquals("v1", server.takeRequest().getHeader("If-None-Match"));
155  }
156
157  @Test public void redirect() throws Exception {
158    server.enqueue(new MockResponse()
159        .setResponseCode(301)
160        .addHeader("Location: /b")
161        .addHeader("Test", "Redirect from /a to /b")
162        .setBody("/a has moved!"));
163    server.enqueue(new MockResponse()
164        .setResponseCode(302)
165        .addHeader("Location: /c")
166        .addHeader("Test", "Redirect from /b to /c")
167        .setBody("/b has moved!"));
168    server.enqueue(new MockResponse().setBody("C"));
169    server.play();
170
171    onSuccess(new Request.Builder().url(server.getUrl("/a")).build())
172        .assertCode(200)
173        .assertBody("C")
174        .redirectedBy()
175        .assertCode(302)
176        .assertContainsHeaders("Test: Redirect from /b to /c")
177        .redirectedBy()
178        .assertCode(301)
179        .assertContainsHeaders("Test: Redirect from /a to /b");
180
181    assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection.
182    assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused.
183    assertEquals(2, server.takeRequest().getSequenceNumber()); // Connection reused again!
184  }
185
186  @Test public void redirectWithRedirectsDisabled() throws Exception {
187    client.setFollowProtocolRedirects(false);
188    server.enqueue(new MockResponse()
189        .setResponseCode(301)
190        .addHeader("Location: /b")
191        .addHeader("Test", "Redirect from /a to /b")
192        .setBody("/a has moved!"));
193    server.play();
194
195    onSuccess(new Request.Builder().url(server.getUrl("/a")).build())
196        .assertCode(301)
197        .assertBody("/a has moved!")
198        .assertContainsHeaders("Location: /b");
199  }
200
201  @Test public void follow20Redirects() throws Exception {
202    for (int i = 0; i < 20; i++) {
203      server.enqueue(new MockResponse()
204          .setResponseCode(301)
205          .addHeader("Location: /" + (i + 1))
206          .setBody("Redirecting to /" + (i + 1)));
207    }
208    server.enqueue(new MockResponse().setBody("Success!"));
209    server.play();
210
211    onSuccess(new Request.Builder().url(server.getUrl("/0")).build())
212        .assertCode(200)
213        .assertBody("Success!");
214  }
215
216  @Test public void doesNotFollow21Redirects() throws Exception {
217    for (int i = 0; i < 21; i++) {
218      server.enqueue(new MockResponse()
219          .setResponseCode(301)
220          .addHeader("Location: /" + (i + 1))
221          .setBody("Redirecting to /" + (i + 1)));
222    }
223    server.play();
224
225    try {
226      client.execute(new Request.Builder().url(server.getUrl("/0")).build());
227      fail();
228    } catch (IOException e) {
229      assertEquals("Too many redirects: 21", e.getMessage());
230    }
231  }
232
233  @Test public void postBodyRetransmittedOnRedirect() throws Exception {
234    server.enqueue(new MockResponse()
235        .setResponseCode(302)
236        .addHeader("Location: /b")
237        .setBody("Moved to /b !"));
238    server.enqueue(new MockResponse()
239        .setBody("This is b."));
240    server.play();
241
242    Request request = new Request.Builder()
243        .url(server.getUrl("/"))
244        .post(Request.Body.create(MediaType.parse("text/plain"), "body!"))
245        .build();
246
247    onSuccess(request)
248        .assertCode(200)
249        .assertBody("This is b.");
250
251    RecordedRequest request1 = server.takeRequest();
252    assertEquals("body!", request1.getUtf8Body());
253    assertEquals("5", request1.getHeader("Content-Length"));
254    assertEquals("text/plain; charset=utf-8", request1.getHeader("Content-Type"));
255    assertEquals(0, request1.getSequenceNumber());
256
257    RecordedRequest request2 = server.takeRequest();
258    assertEquals("body!", request2.getUtf8Body());
259    assertEquals("5", request2.getHeader("Content-Length"));
260    assertEquals("text/plain; charset=utf-8", request2.getHeader("Content-Type"));
261    assertEquals(1, request2.getSequenceNumber());
262  }
263
264  private RecordedResponse onSuccess(Request request) throws IOException {
265    Response response = client.execute(request);
266    return new RecordedResponse(request, response, response.body().string(), null);
267  }
268}
269