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 
17 package com.google.mockwebserver;
18 
19 import java.io.BufferedReader;
20 import java.io.ByteArrayInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.net.HttpURLConnection;
25 import java.net.SocketTimeoutException;
26 import java.net.URL;
27 import java.net.URLConnection;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.List;
31 import junit.framework.TestCase;
32 
33 public final class MockWebServerTest extends TestCase {
34 
35     private MockWebServer server = new MockWebServer();
36 
tearDown()37     @Override protected void tearDown() throws Exception {
38         server.shutdown();
39         super.tearDown();
40     }
41 
testRecordedRequestAccessors()42     public void testRecordedRequestAccessors() {
43         List<String> headers = Arrays.asList(
44                 "User-Agent: okhttp",
45                 "Cookie: s=square",
46                 "Cookie: a=android",
47                 "X-Whitespace:  left",
48                 "X-Whitespace:right  ",
49                 "X-Whitespace:  both  "
50         );
51         List<Integer> chunkSizes = Collections.emptyList();
52         byte[] body = {'A', 'B', 'C'};
53         String requestLine = "GET / HTTP/1.1";
54         RecordedRequest request = new RecordedRequest(
55                 requestLine, headers, chunkSizes, body.length, body, 0, null);
56         assertEquals("s=square", request.getHeader("cookie"));
57         assertEquals(Arrays.asList("s=square", "a=android"), request.getHeaders("cookie"));
58         assertEquals("left", request.getHeader("x-whitespace"));
59         assertEquals(Arrays.asList("left", "right", "both"), request.getHeaders("x-whitespace"));
60         assertEquals("ABC", request.getUtf8Body());
61     }
62 
testDefaultMockResponse()63     public void testDefaultMockResponse() {
64         MockResponse response = new MockResponse();
65         assertEquals(Arrays.asList("Content-Length: 0"), response.getHeaders());
66         assertEquals("HTTP/1.1 200 OK", response.getStatus());
67     }
68 
testSetBodyAdjustsHeaders()69     public void testSetBodyAdjustsHeaders() throws IOException {
70         MockResponse response = new MockResponse().setBody("ABC");
71         assertEquals(Arrays.asList("Content-Length: 3"), response.getHeaders());
72         InputStream in = response.getBodyStream();
73         assertEquals('A', in.read());
74         assertEquals('B', in.read());
75         assertEquals('C', in.read());
76         assertEquals(-1, in.read());
77         assertEquals("HTTP/1.1 200 OK", response.getStatus());
78     }
79 
testMockResponseAddHeader()80     public void testMockResponseAddHeader() {
81         MockResponse response = new MockResponse()
82                 .clearHeaders()
83                 .addHeader("Cookie: s=square")
84                 .addHeader("Cookie", "a=android");
85         assertEquals(Arrays.asList("Cookie: s=square", "Cookie: a=android"),
86                 response.getHeaders());
87     }
88 
testMockResponseSetHeader()89     public void testMockResponseSetHeader() {
90         MockResponse response = new MockResponse()
91                 .clearHeaders()
92                 .addHeader("Cookie: s=square")
93                 .addHeader("Cookie: a=android")
94                 .addHeader("Cookies: delicious");
95         response.setHeader("cookie", "r=robot");
96         assertEquals(Arrays.asList("Cookies: delicious", "cookie: r=robot"),
97                 response.getHeaders());
98     }
99 
testRegularResponse()100     public void testRegularResponse() throws Exception {
101         server.enqueue(new MockResponse().setBody("hello world"));
102         server.play();
103 
104         URL url = server.getUrl("/");
105         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
106         connection.setRequestProperty("Accept-Language", "en-US");
107         InputStream in = connection.getInputStream();
108         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
109         assertEquals(HttpURLConnection.HTTP_OK, connection.getResponseCode());
110         assertEquals("hello world", reader.readLine());
111 
112         RecordedRequest request = server.takeRequest();
113         assertEquals("GET / HTTP/1.1", request.getRequestLine());
114         assertTrue(request.getHeaders().contains("Accept-Language: en-US"));
115     }
116 
testRedirect()117     public void testRedirect() throws Exception {
118         server.play();
119         server.enqueue(new MockResponse()
120                 .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
121                 .addHeader("Location: " + server.getUrl("/new-path"))
122                 .setBody("This page has moved!"));
123         server.enqueue(new MockResponse().setBody("This is the new location!"));
124 
125         URLConnection connection = server.getUrl("/").openConnection();
126         InputStream in = connection.getInputStream();
127         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
128         assertEquals("This is the new location!", reader.readLine());
129 
130         RecordedRequest first = server.takeRequest();
131         assertEquals("GET / HTTP/1.1", first.getRequestLine());
132         RecordedRequest redirect = server.takeRequest();
133         assertEquals("GET /new-path HTTP/1.1", redirect.getRequestLine());
134     }
135 
136     /**
137      * Test that MockWebServer blocks for a call to enqueue() if a request
138      * is made before a mock response is ready.
139      */
testDispatchBlocksWaitingForEnqueue()140     public void testDispatchBlocksWaitingForEnqueue() throws Exception {
141         server.play();
142 
143         new Thread() {
144             @Override public void run() {
145                 try {
146                     Thread.sleep(1000);
147                 } catch (InterruptedException ignored) {
148                 }
149                 server.enqueue(new MockResponse().setBody("enqueued in the background"));
150             }
151         }.start();
152 
153         URLConnection connection = server.getUrl("/").openConnection();
154         InputStream in = connection.getInputStream();
155         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
156         assertEquals("enqueued in the background", reader.readLine());
157     }
158 
testNonHexadecimalChunkSize()159     public void testNonHexadecimalChunkSize() throws Exception {
160         server.enqueue(new MockResponse()
161                 .setBody("G\r\nxxxxxxxxxxxxxxxx\r\n0\r\n\r\n")
162                 .clearHeaders()
163                 .addHeader("Transfer-encoding: chunked"));
164         server.play();
165 
166         URLConnection connection = server.getUrl("/").openConnection();
167         InputStream in = connection.getInputStream();
168         try {
169             in.read();
170             fail();
171         } catch (IOException expected) {
172         }
173     }
174 
testResponseTimeout()175     public void testResponseTimeout() throws Exception {
176         server.enqueue(new MockResponse()
177                 .setBody("ABC")
178                 .clearHeaders()
179                 .addHeader("Content-Length: 4"));
180         server.enqueue(new MockResponse()
181                 .setBody("DEF"));
182         server.play();
183 
184         URLConnection urlConnection = server.getUrl("/").openConnection();
185         urlConnection.setReadTimeout(1000);
186         InputStream in = urlConnection.getInputStream();
187         assertEquals('A', in.read());
188         assertEquals('B', in.read());
189         assertEquals('C', in.read());
190         try {
191             in.read(); // if Content-Length was accurate, this would return -1 immediately
192             fail();
193         } catch (SocketTimeoutException expected) {
194         }
195 
196         URLConnection urlConnection2 = server.getUrl("/").openConnection();
197         InputStream in2 = urlConnection2.getInputStream();
198         assertEquals('D', in2.read());
199         assertEquals('E', in2.read());
200         assertEquals('F', in2.read());
201         assertEquals(-1, in2.read());
202 
203         assertEquals(0, server.takeRequest().getSequenceNumber());
204         assertEquals(0, server.takeRequest().getSequenceNumber());
205     }
206 
testDisconnectAtStart()207     public void testDisconnectAtStart() throws Exception {
208         server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AT_START));
209         server.enqueue(new MockResponse()); // The jdk's HttpUrlConnection is a bastard.
210         server.enqueue(new MockResponse());
211         server.play();
212         try {
213             server.getUrl("/a").openConnection().getInputStream();
214         } catch (IOException e) {
215             // Expected.
216         }
217         server.getUrl("/b").openConnection().getInputStream(); // Should succeed.
218     }
219 
testStreamingResponseBody()220     public void testStreamingResponseBody() throws Exception {
221         InputStream responseBody = new ByteArrayInputStream("ABC".getBytes("UTF-8"));
222         server.enqueue(new MockResponse().setBody(responseBody, 3));
223         server.play();
224 
225         InputStream in = server.getUrl("/").openConnection().getInputStream();
226         assertEquals('A', in.read());
227         assertEquals('B', in.read());
228         assertEquals('C', in.read());
229 
230         assertEquals(-1, responseBody.read()); // The body is exhausted.
231     }
232 }
233