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