OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.net; | |
6 | |
7 import android.test.suitebuilder.annotation.SmallTest; | |
8 | |
9 import org.chromium.base.test.util.Feature; | |
10 import org.chromium.net.impl.ChromiumUrlRequest; | |
11 | |
12 import java.io.ByteArrayInputStream; | |
13 import java.io.IOException; | |
14 import java.io.InputStream; | |
15 import java.nio.ByteBuffer; | |
16 import java.nio.channels.Channels; | |
17 import java.nio.channels.ReadableByteChannel; | |
18 import java.util.HashMap; | |
19 import java.util.concurrent.Executors; | |
20 | |
21 /** | |
22 * Test fixture to test upload APIs. Uses an in-process test server. | |
23 */ | |
24 @SuppressWarnings("deprecation") | |
25 public class UploadTest extends CronetTestBase { | |
26 private static final String UPLOAD_DATA = "Nifty upload data!"; | |
27 private static final String UPLOAD_CHANNEL_DATA = "Upload channel data"; | |
28 | |
29 private CronetTestFramework mTestFramework; | |
30 | |
31 @Override | |
32 protected void setUp() throws Exception { | |
33 super.setUp(); | |
34 mTestFramework = startCronetTestFrameworkForLegacyApi(null); | |
35 assertNotNull(mTestFramework); | |
36 assertTrue(NativeTestServer.startNativeTestServer(getContext())); | |
37 } | |
38 | |
39 private HttpUrlRequest createRequest( | |
40 String url, HttpUrlRequestListener listener) { | |
41 HashMap<String, String> headers = new HashMap<String, String>(); | |
42 return mTestFramework.mRequestFactory.createRequest( | |
43 url, HttpUrlRequest.REQUEST_PRIORITY_MEDIUM, headers, listener); | |
44 } | |
45 | |
46 /** | |
47 * Sets request to have an upload channel containing the given data. | |
48 * uploadDataLength should generally be uploadData.length(), unless a test | |
49 * needs to get a read error. | |
50 */ | |
51 private void setUploadChannel(HttpUrlRequest request, | |
52 String contentType, | |
53 String uploadData, | |
54 int uploadDataLength) { | |
55 InputStream uploadDataStream = new ByteArrayInputStream( | |
56 uploadData.getBytes()); | |
57 ReadableByteChannel uploadDataChannel = | |
58 Channels.newChannel(uploadDataStream); | |
59 request.setUploadChannel( | |
60 contentType, uploadDataChannel, uploadDataLength); | |
61 } | |
62 | |
63 /** | |
64 * Tests uploading an in-memory string. | |
65 */ | |
66 @SmallTest | |
67 @Feature({"Cronet"}) | |
68 public void testUploadData() throws Exception { | |
69 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
70 HttpUrlRequest request = createRequest( | |
71 NativeTestServer.getEchoBodyURL(), listener); | |
72 request.setUploadData("text/plain", UPLOAD_DATA.getBytes("UTF8")); | |
73 request.start(); | |
74 listener.blockForComplete(); | |
75 | |
76 assertEquals(200, listener.mHttpStatusCode); | |
77 assertEquals(UPLOAD_DATA, listener.mResponseAsString); | |
78 } | |
79 | |
80 /** | |
81 * Tests uploading an in-memory string with a redirect that preserves the | |
82 * POST body. This makes sure the body is correctly sent again. | |
83 */ | |
84 @SmallTest | |
85 @Feature({"Cronet"}) | |
86 public void testUploadDataWithRedirect() throws Exception { | |
87 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
88 HttpUrlRequest request = createRequest( | |
89 NativeTestServer.getRedirectToEchoBody(), listener); | |
90 request.setUploadData("text/plain", UPLOAD_DATA.getBytes("UTF8")); | |
91 request.start(); | |
92 listener.blockForComplete(); | |
93 | |
94 assertEquals(200, listener.mHttpStatusCode); | |
95 assertEquals(UPLOAD_DATA, listener.mResponseAsString); | |
96 } | |
97 | |
98 /** | |
99 * Tests Content-Type can be set when uploading an in-memory string. | |
100 */ | |
101 @SmallTest | |
102 @Feature({"Cronet"}) | |
103 public void testUploadDataContentType() throws Exception { | |
104 String contentTypes[] = {"text/plain", "chicken/spicy"}; | |
105 for (String contentType : contentTypes) { | |
106 TestHttpUrlRequestListener listener = | |
107 new TestHttpUrlRequestListener(); | |
108 HttpUrlRequest request = createRequest( | |
109 NativeTestServer.getEchoHeaderURL("Content-Type"), | |
110 listener); | |
111 request.setUploadData(contentType, UPLOAD_DATA.getBytes("UTF8")); | |
112 request.start(); | |
113 listener.blockForComplete(); | |
114 | |
115 assertEquals(200, listener.mHttpStatusCode); | |
116 assertEquals(contentType, listener.mResponseAsString); | |
117 } | |
118 } | |
119 | |
120 /** | |
121 * Tests the default method when uploading. | |
122 */ | |
123 @SmallTest | |
124 @Feature({"Cronet"}) | |
125 public void testDefaultUploadMethod() throws Exception { | |
126 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
127 HttpUrlRequest request = createRequest( | |
128 NativeTestServer.getEchoMethodURL(), listener); | |
129 request.setUploadData("text/plain", UPLOAD_DATA.getBytes("UTF8")); | |
130 request.start(); | |
131 listener.blockForComplete(); | |
132 | |
133 assertEquals(200, listener.mHttpStatusCode); | |
134 assertEquals("POST", listener.mResponseAsString); | |
135 } | |
136 | |
137 /** | |
138 * Tests methods can be set when uploading. | |
139 */ | |
140 @SmallTest | |
141 @Feature({"Cronet"}) | |
142 public void testUploadMethods() throws Exception { | |
143 String uploadMethods[] = {"POST", "PUT"}; | |
144 for (String uploadMethod : uploadMethods) { | |
145 TestHttpUrlRequestListener listener = | |
146 new TestHttpUrlRequestListener(); | |
147 HttpUrlRequest request = createRequest( | |
148 NativeTestServer.getEchoMethodURL(), listener); | |
149 request.setHttpMethod(uploadMethod); | |
150 request.setUploadData("text/plain", UPLOAD_DATA.getBytes("UTF8")); | |
151 request.start(); | |
152 listener.blockForComplete(); | |
153 | |
154 assertEquals(200, listener.mHttpStatusCode); | |
155 assertEquals(uploadMethod, listener.mResponseAsString); | |
156 } | |
157 } | |
158 | |
159 /** | |
160 * Tests uploading from a channel. | |
161 */ | |
162 @SmallTest | |
163 @Feature({"Cronet"}) | |
164 public void testUploadChannel() throws Exception { | |
165 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
166 HttpUrlRequest request = createRequest( | |
167 NativeTestServer.getEchoBodyURL(), listener); | |
168 setUploadChannel(request, "text/plain", UPLOAD_CHANNEL_DATA, | |
169 UPLOAD_CHANNEL_DATA.length()); | |
170 request.start(); | |
171 listener.blockForComplete(); | |
172 | |
173 assertEquals(200, listener.mHttpStatusCode); | |
174 assertEquals(UPLOAD_CHANNEL_DATA, listener.mResponseAsString); | |
175 } | |
176 | |
177 /** | |
178 * Tests uploading from a channel in the case a redirect preserves the post | |
179 * body. Since channels can't be rewound, the request fails when we try to | |
180 * rewind it to send the second request. | |
181 */ | |
182 @SmallTest | |
183 @Feature({"Cronet"}) | |
184 public void testUploadChannelWithRedirect() throws Exception { | |
185 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
186 HttpUrlRequest request = createRequest( | |
187 NativeTestServer.getRedirectToEchoBody(), listener); | |
188 setUploadChannel(request, "text/plain", UPLOAD_CHANNEL_DATA, | |
189 UPLOAD_CHANNEL_DATA.length()); | |
190 request.start(); | |
191 listener.blockForComplete(); | |
192 | |
193 assertEquals(0, listener.mHttpStatusCode); | |
194 assertEquals( | |
195 "System error: net::ERR_UPLOAD_STREAM_REWIND_NOT_SUPPORTED(-25)"
, | |
196 listener.mException.getMessage()); | |
197 } | |
198 | |
199 /** | |
200 * Tests uploading from a channel when there's a read error. The body | |
201 * should be 0-padded. | |
202 */ | |
203 @SmallTest | |
204 @Feature({"Cronet"}) | |
205 public void testUploadChannelWithReadError() throws Exception { | |
206 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
207 HttpUrlRequest request = createRequest( | |
208 NativeTestServer.getEchoBodyURL(), listener); | |
209 setUploadChannel(request, "text/plain", UPLOAD_CHANNEL_DATA, | |
210 UPLOAD_CHANNEL_DATA.length() + 2); | |
211 request.start(); | |
212 listener.blockForComplete(); | |
213 | |
214 assertEquals(0, listener.mHttpStatusCode); | |
215 assertNull(listener.mResponseAsString); | |
216 } | |
217 | |
218 /** | |
219 * Tests Content-Type can be set when uploading from a channel. | |
220 */ | |
221 @SmallTest | |
222 @Feature({"Cronet"}) | |
223 public void testUploadChannelContentType() throws Exception { | |
224 String contentTypes[] = {"text/plain", "chicken/spicy"}; | |
225 for (String contentType : contentTypes) { | |
226 TestHttpUrlRequestListener listener = | |
227 new TestHttpUrlRequestListener(); | |
228 HttpUrlRequest request = createRequest( | |
229 NativeTestServer.getEchoHeaderURL("Content-Type"), | |
230 listener); | |
231 setUploadChannel(request, contentType, UPLOAD_CHANNEL_DATA, | |
232 UPLOAD_CHANNEL_DATA.length()); | |
233 request.start(); | |
234 listener.blockForComplete(); | |
235 | |
236 assertEquals(200, listener.mHttpStatusCode); | |
237 assertEquals(contentType, listener.mResponseAsString); | |
238 } | |
239 } | |
240 | |
241 @SmallTest | |
242 @Feature({"Cronet"}) | |
243 public void testAppendChunkRaceWithCancel() throws Exception { | |
244 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); | |
245 byteBuffer.put(UPLOAD_DATA.getBytes()); | |
246 byteBuffer.position(0); | |
247 | |
248 // Try to recreate race described in crbug.com/434855 when request | |
249 // is canceled from another thread while adding chunks to upload. | |
250 for (int test = 0; test < 100; ++test) { | |
251 TestHttpUrlRequestListener listener = | |
252 new TestHttpUrlRequestListener(); | |
253 final ChromiumUrlRequest request = | |
254 (ChromiumUrlRequest) createRequest("http://127.0.0.1:8000", | |
255 listener); | |
256 request.setChunkedUpload("dangerous/crocodile"); | |
257 request.start(); | |
258 Runnable cancelTask = new Runnable() { | |
259 public void run() { | |
260 request.cancel(); | |
261 } | |
262 }; | |
263 Executors.newCachedThreadPool().execute(cancelTask); | |
264 try { | |
265 request.appendChunk(byteBuffer, false); | |
266 request.appendChunk(byteBuffer, false); | |
267 request.appendChunk(byteBuffer, false); | |
268 request.appendChunk(byteBuffer, true); | |
269 // IOException may be thrown if appendChunk detects that request | |
270 // is already destroyed. | |
271 } catch (IOException e) { | |
272 assertEquals("Native peer destroyed.", e.getMessage()); | |
273 } | |
274 listener.blockForComplete(); | |
275 } | |
276 } | |
277 | |
278 @SmallTest | |
279 @Feature({"Cronet"}) | |
280 public void testAppendChunkPreAndPost() throws Exception { | |
281 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); | |
282 byteBuffer.put(UPLOAD_DATA.getBytes()); | |
283 byteBuffer.position(0); | |
284 | |
285 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
286 ChromiumUrlRequest request = (ChromiumUrlRequest) createRequest( | |
287 NativeTestServer.getEchoBodyURL(), listener); | |
288 request.setChunkedUpload("dangerous/crocodile"); | |
289 try { | |
290 request.appendChunk(byteBuffer, false); | |
291 fail("Exception not thrown."); | |
292 } catch (IllegalStateException e) { | |
293 assertEquals("Request not yet started.", e.getMessage()); | |
294 } | |
295 request.start(); | |
296 request.appendChunk(byteBuffer, true); | |
297 listener.blockForComplete(); | |
298 try { | |
299 request.appendChunk(byteBuffer, true); | |
300 fail("Exception not thrown."); | |
301 } catch (IOException e) { | |
302 assertEquals("Native peer destroyed.", e.getMessage()); | |
303 } | |
304 } | |
305 | |
306 @SmallTest | |
307 @Feature({"Cronet"}) | |
308 public void testAppendChunkEmptyChunk() throws Exception { | |
309 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); | |
310 byteBuffer.put(UPLOAD_DATA.getBytes()); | |
311 byteBuffer.flip(); | |
312 | |
313 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
314 ChromiumUrlRequest request = (ChromiumUrlRequest) createRequest( | |
315 NativeTestServer.getEchoBodyURL(), listener); | |
316 request.setChunkedUpload("dangerous/crocodile"); | |
317 request.start(); | |
318 | |
319 // Upload one non-empty followed by one empty chunk. | |
320 request.appendChunk(byteBuffer, false); | |
321 byteBuffer.position(0); | |
322 byteBuffer.limit(0); | |
323 request.appendChunk(byteBuffer, true); | |
324 | |
325 listener.blockForComplete(); | |
326 | |
327 assertEquals(200, listener.mHttpStatusCode); | |
328 assertEquals(UPLOAD_DATA, listener.mResponseAsString); | |
329 } | |
330 | |
331 @SmallTest | |
332 @Feature({"Cronet"}) | |
333 public void testAppendChunkEmptyBody() throws Exception { | |
334 TestHttpUrlRequestListener listener = new TestHttpUrlRequestListener(); | |
335 ChromiumUrlRequest request = (ChromiumUrlRequest) createRequest( | |
336 NativeTestServer.getEchoBodyURL(), listener); | |
337 request.setChunkedUpload("dangerous/crocodile"); | |
338 request.start(); | |
339 | |
340 // Upload a single empty chunk. | |
341 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(0); | |
342 request.appendChunk(byteBuffer, true); | |
343 | |
344 listener.blockForComplete(); | |
345 | |
346 assertEquals(200, listener.mHttpStatusCode); | |
347 assertEquals("", listener.mResponseAsString); | |
348 } | |
349 } | |
OLD | NEW |