• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google 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  */
16 package com.squareup.okhttp.mockwebserver;
17 
18 import com.squareup.okhttp.Headers;
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.io.OutputStream;
24 import java.net.ConnectException;
25 import java.net.HttpURLConnection;
26 import java.net.ProtocolException;
27 import java.net.SocketTimeoutException;
28 import java.net.URL;
29 import java.net.URLConnection;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33 import java.util.concurrent.TimeUnit;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import org.junit.After;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.runner.Description;
39 import org.junit.runners.model.Statement;
40 
41 import static java.util.concurrent.TimeUnit.NANOSECONDS;
42 import static java.util.concurrent.TimeUnit.SECONDS;
43 import static org.junit.Assert.assertEquals;
44 import static org.junit.Assert.assertNotNull;
45 import static org.junit.Assert.assertTrue;
46 import static org.junit.Assert.fail;
47 
48 public final class MockWebServerTest {
49   @Rule public final MockWebServer server = new MockWebServer();
50 
defaultMockResponse()51   @Test public void defaultMockResponse() {
52     MockResponse response = new MockResponse();
53     assertEquals(Arrays.asList("Content-Length: 0"), headersToList(response));
54     assertEquals("HTTP/1.1 200 OK", response.getStatus());
55   }
56 
setBodyAdjustsHeaders()57   @Test public void setBodyAdjustsHeaders() throws IOException {
58     MockResponse response = new MockResponse().setBody("ABC");
59     assertEquals(Arrays.asList("Content-Length: 3"), headersToList(response));
60     assertEquals("ABC", response.getBody().readUtf8());
61     assertEquals("HTTP/1.1 200 OK", response.getStatus());
62   }
63 
mockResponseAddHeader()64   @Test public void mockResponseAddHeader() {
65     MockResponse response = new MockResponse()
66         .clearHeaders()
67         .addHeader("Cookie: s=square")
68         .addHeader("Cookie", "a=android");
69     assertEquals(Arrays.asList("Cookie: s=square", "Cookie: a=android"), headersToList(response));
70   }
71 
mockResponseSetHeader()72   @Test public void mockResponseSetHeader() {
73     MockResponse response = new MockResponse()
74         .clearHeaders()
75         .addHeader("Cookie: s=square")
76         .addHeader("Cookie: a=android")
77         .addHeader("Cookies: delicious");
78     response.setHeader("cookie", "r=robot");
79     assertEquals(Arrays.asList("Cookies: delicious", "cookie: r=robot"), headersToList(response));
80   }
81 
regularResponse()82   @Test public void regularResponse() throws Exception {
83     server.enqueue(new MockResponse().setBody("hello world"));
84 
85     URL url = server.getUrl("/");
86     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
87     connection.setRequestProperty("Accept-Language", "en-US");
88     InputStream in = connection.getInputStream();
89     BufferedReader reader = new BufferedReader(new InputStreamReader(in));
90     assertEquals(HttpURLConnection.HTTP_OK, connection.getResponseCode());
91     assertEquals("hello world", reader.readLine());
92 
93     RecordedRequest request = server.takeRequest();
94     assertEquals("GET / HTTP/1.1", request.getRequestLine());
95     assertEquals("en-US", request.getHeader("Accept-Language"));
96   }
97 
redirect()98   @Test public void redirect() throws Exception {
99     server.enqueue(new MockResponse()
100         .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
101         .addHeader("Location: " + server.getUrl("/new-path"))
102         .setBody("This page has moved!"));
103     server.enqueue(new MockResponse().setBody("This is the new location!"));
104 
105     URLConnection connection = server.getUrl("/").openConnection();
106     InputStream in = connection.getInputStream();
107     BufferedReader reader = new BufferedReader(new InputStreamReader(in));
108     assertEquals("This is the new location!", reader.readLine());
109 
110     RecordedRequest first = server.takeRequest();
111     assertEquals("GET / HTTP/1.1", first.getRequestLine());
112     RecordedRequest redirect = server.takeRequest();
113     assertEquals("GET /new-path HTTP/1.1", redirect.getRequestLine());
114   }
115 
116   /**
117    * Test that MockWebServer blocks for a call to enqueue() if a request
118    * is made before a mock response is ready.
119    */
dispatchBlocksWaitingForEnqueue()120   @Test public void dispatchBlocksWaitingForEnqueue() throws Exception {
121     new Thread() {
122       @Override public void run() {
123         try {
124           Thread.sleep(1000);
125         } catch (InterruptedException ignored) {
126         }
127         server.enqueue(new MockResponse().setBody("enqueued in the background"));
128       }
129     }.start();
130 
131     URLConnection connection = server.getUrl("/").openConnection();
132     InputStream in = connection.getInputStream();
133     BufferedReader reader = new BufferedReader(new InputStreamReader(in));
134     assertEquals("enqueued in the background", reader.readLine());
135   }
136 
nonHexadecimalChunkSize()137   @Test public void nonHexadecimalChunkSize() throws Exception {
138     server.enqueue(new MockResponse()
139         .setBody("G\r\nxxxxxxxxxxxxxxxx\r\n0\r\n\r\n")
140         .clearHeaders()
141         .addHeader("Transfer-encoding: chunked"));
142 
143     URLConnection connection = server.getUrl("/").openConnection();
144     InputStream in = connection.getInputStream();
145     try {
146       in.read();
147       fail();
148     } catch (IOException expected) {
149     }
150   }
151 
responseTimeout()152   @Test public void responseTimeout() throws Exception {
153     server.enqueue(new MockResponse()
154         .setBody("ABC")
155         .clearHeaders()
156         .addHeader("Content-Length: 4"));
157     server.enqueue(new MockResponse().setBody("DEF"));
158 
159     URLConnection urlConnection = server.getUrl("/").openConnection();
160     urlConnection.setReadTimeout(1000);
161     InputStream in = urlConnection.getInputStream();
162     assertEquals('A', in.read());
163     assertEquals('B', in.read());
164     assertEquals('C', in.read());
165     try {
166       in.read(); // if Content-Length was accurate, this would return -1 immediately
167       fail();
168     } catch (SocketTimeoutException expected) {
169     }
170 
171     URLConnection urlConnection2 = server.getUrl("/").openConnection();
172     InputStream in2 = urlConnection2.getInputStream();
173     assertEquals('D', in2.read());
174     assertEquals('E', in2.read());
175     assertEquals('F', in2.read());
176     assertEquals(-1, in2.read());
177 
178     assertEquals(0, server.takeRequest().getSequenceNumber());
179     assertEquals(0, server.takeRequest().getSequenceNumber());
180   }
181 
disconnectAtStart()182   @Test public void disconnectAtStart() throws Exception {
183     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AT_START));
184     server.enqueue(new MockResponse()); // The jdk's HttpUrlConnection is a bastard.
185     server.enqueue(new MockResponse());
186     try {
187       server.getUrl("/a").openConnection().getInputStream();
188     } catch (IOException expected) {
189     }
190     server.getUrl("/b").openConnection().getInputStream(); // Should succeed.
191   }
192 
193   /**
194    * Throttle the request body by sleeping 500ms after every 3 bytes. With a
195    * 6-byte request, this should yield one sleep for a total delay of 500ms.
196    */
throttleRequest()197   @Test public void throttleRequest() throws Exception {
198     server.enqueue(new MockResponse()
199         .throttleBody(3, 500, TimeUnit.MILLISECONDS));
200 
201     long startNanos = System.nanoTime();
202     URLConnection connection = server.getUrl("/").openConnection();
203     connection.setDoOutput(true);
204     connection.getOutputStream().write("ABCDEF".getBytes("UTF-8"));
205     InputStream in = connection.getInputStream();
206     assertEquals(-1, in.read());
207     long elapsedNanos = System.nanoTime() - startNanos;
208     long elapsedMillis = NANOSECONDS.toMillis(elapsedNanos);
209 
210     assertTrue(String.format("Request + Response: %sms", elapsedMillis), elapsedMillis >= 500);
211     assertTrue(String.format("Request + Response: %sms", elapsedMillis), elapsedMillis < 1000);
212   }
213 
214   /**
215    * Throttle the response body by sleeping 500ms after every 3 bytes. With a
216    * 6-byte response, this should yield one sleep for a total delay of 500ms.
217    */
218   @Test public void throttleResponse() throws Exception {
219     server.enqueue(new MockResponse()
220         .setBody("ABCDEF")
221         .throttleBody(3, 500, TimeUnit.MILLISECONDS));
222 
223     long startNanos = System.nanoTime();
224     URLConnection connection = server.getUrl("/").openConnection();
225     InputStream in = connection.getInputStream();
226     assertEquals('A', in.read());
227     assertEquals('B', in.read());
228     assertEquals('C', in.read());
229     assertEquals('D', in.read());
230     assertEquals('E', in.read());
231     assertEquals('F', in.read());
232     assertEquals(-1, in.read());
233     long elapsedNanos = System.nanoTime() - startNanos;
234     long elapsedMillis = NANOSECONDS.toMillis(elapsedNanos);
235 
236     assertTrue(String.format("Request + Response: %sms", elapsedMillis), elapsedMillis >= 500);
237     assertTrue(String.format("Request + Response: %sms", elapsedMillis), elapsedMillis < 1000);
238   }
239 
240   /** Delay the response body by sleeping 1s. */
241   @Test public void delayResponse() throws IOException {
242     server.enqueue(new MockResponse()
243         .setBody("ABCDEF")
244         .setBodyDelay(1, SECONDS));
245 
246     long startNanos = System.nanoTime();
247     URLConnection connection = server.getUrl("/").openConnection();
248     InputStream in = connection.getInputStream();
249     assertEquals('A', in.read());
250     long elapsedNanos = System.nanoTime() - startNanos;
251     long elapsedMillis = NANOSECONDS.toMillis(elapsedNanos);
252     assertTrue(String.format("Request + Response: %sms", elapsedMillis), elapsedMillis >= 1000);
253 
254     in.close();
255   }
256 
disconnectRequestHalfway()257   @Test public void disconnectRequestHalfway() throws IOException {
258     server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_DURING_REQUEST_BODY));
259     // Limit the size of the request body that the server holds in memory to an arbitrary
260     // 3.5 MBytes so this test can pass on devices with little memory.
261     server.setBodyLimit(7 * 512 * 1024);
262 
263     HttpURLConnection connection = (HttpURLConnection) server.getUrl("/").openConnection();
264     connection.setRequestMethod("POST");
265     connection.setDoOutput(true);
266     connection.setFixedLengthStreamingMode(1024 * 1024 * 1024); // 1 GB
267     connection.connect();
268     OutputStream out = connection.getOutputStream();
269 
270     byte[] data = new byte[1024 * 1024];
271     int i;
272     for (i = 0; i < 1024; i++) {
273       try {
274         out.write(data);
275         out.flush();
276       } catch (IOException e) {
277         break;
278       }
279     }
280     assertEquals(512f, i, 10f); // Halfway +/- 1%
281   }
282 
disconnectResponseHalfway()283   @Test public void disconnectResponseHalfway() throws IOException {
284     server.enqueue(new MockResponse()
285         .setBody("ab")
286         .setSocketPolicy(SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY));
287 
288     URLConnection connection = server.getUrl("/").openConnection();
289     assertEquals(2, connection.getContentLength());
290     InputStream in = connection.getInputStream();
291     assertEquals('a', in.read());
292     try {
293       int byteRead = in.read();
294       // OpenJDK behavior: end of stream.
295       assertEquals(-1, byteRead);
296     } catch (ProtocolException e) {
297       // On Android, HttpURLConnection is implemented by OkHttp v2. OkHttp
298       // treats an incomplete response body as a ProtocolException.
299     }
300   }
301 
headersToList(MockResponse response)302   private List<String> headersToList(MockResponse response) {
303     Headers headers = response.getHeaders();
304     int size = headers.size();
305     List<String> headerList = new ArrayList<>(size);
306     for (int i = 0; i < size; i++) {
307       headerList.add(headers.name(i) + ": " + headers.value(i));
308     }
309     return headerList;
310   }
311 
shutdownWithoutStart()312   @Test public void shutdownWithoutStart() throws IOException {
313     MockWebServer server = new MockWebServer();
314     server.shutdown();
315   }
316 
shutdownWithoutEnqueue()317   @Test public void shutdownWithoutEnqueue() throws IOException {
318     MockWebServer server = new MockWebServer();
319     server.start();
320     server.shutdown();
321   }
322 
tearDown()323   @After public void tearDown() throws IOException {
324     server.shutdown();
325   }
326 
portImplicitlyStarts()327   @Test public void portImplicitlyStarts() throws IOException {
328     assertTrue(server.getPort() > 0);
329   }
330 
hostNameImplicitlyStarts()331   @Test public void hostNameImplicitlyStarts() throws IOException {
332     assertNotNull(server.getHostName());
333   }
334 
toProxyAddressImplicitlyStarts()335   @Test public void toProxyAddressImplicitlyStarts() throws IOException {
336     assertNotNull(server.toProxyAddress());
337   }
338 
differentInstancesGetDifferentPorts()339   @Test public void differentInstancesGetDifferentPorts() throws IOException {
340     MockWebServer other = new MockWebServer();
341     assertNotEquals(server.getPort(), other.getPort());
342     other.shutdown();
343   }
344 
statementStartsAndStops()345   @Test public void statementStartsAndStops() throws Throwable {
346     final AtomicBoolean called = new AtomicBoolean();
347     Statement statement = server.apply(new Statement() {
348       @Override public void evaluate() throws Throwable {
349         called.set(true);
350         server.getUrl("/").openConnection().connect();
351       }
352     }, Description.EMPTY);
353 
354     statement.evaluate();
355 
356     assertTrue(called.get());
357     try {
358       server.getUrl("/").openConnection().connect();
359       fail();
360     } catch (ConnectException expected) {
361     }
362   }
363 
364   // ANDROID-BEGIN Android uses JUnit 4.10 which does not have assertNotEquals()
assertNotEquals(Object o1, Object o2)365   private static void assertNotEquals(Object o1, Object o2) {
366     org.junit.Assert.assertFalse(o1 == o2 || (o1 != null && o1.equals(o2)));
367   }
368   // ANDROID-END
369 }
370