Migrate to shared MockWebServer.
[android/platform/packages/providers/DownloadProvider.git] / tests / src / com / android / providers / downloads / PublicApiFunctionalTest.java
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
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.android.providers.downloads;
18
19 import android.app.DownloadManager;
20 import android.content.Intent;
21 import android.database.Cursor;
22 import android.net.ConnectivityManager;
23 import android.net.Uri;
24 import android.os.Environment;
25 import android.provider.Downloads;
26 import android.test.suitebuilder.annotation.LargeTest;
27 import android.util.Log;
28
29 import com.google.mockwebserver.MockResponse;
30 import com.google.mockwebserver.RecordedRequest;
31
32 import java.io.File;
33 import java.io.FileInputStream;
34 import java.io.FileNotFoundException;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.net.MalformedURLException;
38 import java.util.List;
39
40 @LargeTest
41 public class PublicApiFunctionalTest extends AbstractPublicApiTest {
42     private static final String REDIRECTED_PATH = "/other_path";
43     private static final String ETAG = "my_etag";
44
45     protected File mTestDirectory;
46
47     public PublicApiFunctionalTest() {
48         super(new FakeSystemFacade());
49     }
50
51     @Override
52     protected void setUp() throws Exception {
53         super.setUp();
54
55         mTestDirectory = new File(Environment.getExternalStorageDirectory() + File.separator
56                                   + "download_manager_functional_test");
57         if (mTestDirectory.exists()) {
58             for (File file : mTestDirectory.listFiles()) {
59                 file.delete();
60             }
61         } else {
62             mTestDirectory.mkdir();
63         }
64         mSystemFacade.setStartThreadsWithoutWaiting(false);
65     }
66
67     @Override
68     protected void tearDown() throws Exception {
69         if (mTestDirectory != null && mTestDirectory.exists()) {
70             for (File file : mTestDirectory.listFiles()) {
71                 file.delete();
72             }
73             mTestDirectory.delete();
74         }
75         super.tearDown();
76     }
77
78     public void testBasicRequest() throws Exception {
79         enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
80
81         Download download = enqueueRequest(getRequest());
82         assertEquals(DownloadManager.STATUS_PENDING,
83                      download.getLongField(DownloadManager.COLUMN_STATUS));
84         assertEquals(getServerUri(REQUEST_PATH),
85                      download.getStringField(DownloadManager.COLUMN_URI));
86         assertEquals(download.mId, download.getLongField(DownloadManager.COLUMN_ID));
87         assertEquals(mSystemFacade.currentTimeMillis(),
88                      download.getLongField(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP));
89
90         mSystemFacade.incrementTimeMillis(10);
91         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
92         RecordedRequest request = takeRequest();
93         assertEquals("GET", request.getMethod());
94         assertEquals(REQUEST_PATH, request.getPath());
95
96         Uri localUri = Uri.parse(download.getStringField(DownloadManager.COLUMN_LOCAL_URI));
97         assertEquals("content", localUri.getScheme());
98         checkUriContent(localUri);
99         assertEquals("text/plain", download.getStringField(DownloadManager.COLUMN_MEDIA_TYPE));
100
101         int size = FILE_CONTENT.length();
102         assertEquals(size, download.getLongField(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
103         assertEquals(size, download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
104         assertEquals(mSystemFacade.currentTimeMillis(),
105                      download.getLongField(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP));
106
107         checkCompleteDownload(download);
108     }
109
110     private void checkUriContent(Uri uri) throws FileNotFoundException, IOException {
111         InputStream inputStream = mResolver.openInputStream(uri);
112         try {
113             assertEquals(FILE_CONTENT, readStream(inputStream));
114         } finally {
115             inputStream.close();
116         }
117     }
118
119     public void testTitleAndDescription() throws Exception {
120         Download download = enqueueRequest(getRequest()
121                                            .setTitle("my title")
122                                            .setDescription("my description"));
123         assertEquals("my title", download.getStringField(DownloadManager.COLUMN_TITLE));
124         assertEquals("my description",
125                      download.getStringField(DownloadManager.COLUMN_DESCRIPTION));
126     }
127
128     public void testDownloadError() throws Exception {
129         enqueueResponse(buildEmptyResponse(HTTP_NOT_FOUND));
130         runSimpleFailureTest(HTTP_NOT_FOUND);
131     }
132
133     public void testUnhandledHttpStatus() throws Exception {
134         enqueueResponse(buildEmptyResponse(1234)); // some invalid HTTP status
135         runSimpleFailureTest(DownloadManager.ERROR_UNHANDLED_HTTP_CODE);
136     }
137
138     public void testInterruptedDownload() throws Exception {
139         int initialLength = 5;
140         enqueueInterruptedDownloadResponses(initialLength);
141
142         Download download = enqueueRequest(getRequest());
143         download.runUntilStatus(DownloadManager.STATUS_PAUSED);
144         assertEquals(initialLength,
145                      download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
146         assertEquals(FILE_CONTENT.length(),
147                      download.getLongField(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
148         takeRequest(); // get the first request out of the queue
149
150         mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
151         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
152         checkCompleteDownload(download);
153
154         List<String> headers = takeRequest().getHeaders();
155         assertTrue("No Range header: " + headers,
156                    headers.contains("Range: bytes=" + initialLength + "-"));
157         assertTrue("No ETag header: " + headers, headers.contains("If-Match: " + ETAG));
158     }
159
160     public void testInterruptedExternalDownload() throws Exception {
161         enqueueInterruptedDownloadResponses(5);
162         Download download = enqueueRequest(getRequest().setDestinationUri(getExternalUri()));
163         download.runUntilStatus(DownloadManager.STATUS_PAUSED);
164         mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
165         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
166         checkCompleteDownload(download);
167     }
168
169     private void enqueueInterruptedDownloadResponses(int initialLength) {
170         // the first response has normal headers but unexpectedly closes after initialLength bytes
171         enqueueResponse(buildPartialResponse(0, initialLength));
172         // the second response returns partial content for the rest of the data
173         enqueueResponse(buildPartialResponse(initialLength, FILE_CONTENT.length()));
174     }
175
176     private MockResponse buildPartialResponse(int start, int end) {
177         int totalLength = FILE_CONTENT.length();
178         boolean isFirstResponse = (start == 0);
179         int status = isFirstResponse ? HTTP_OK : HTTP_PARTIAL_CONTENT;
180         MockResponse response = buildResponse(status, FILE_CONTENT.substring(start, end))
181                 .setHeader("Content-length", totalLength)
182                 .setHeader("Etag", ETAG);
183         if (!isFirstResponse) {
184             response.setHeader(
185                     "Content-range", "bytes " + start + "-" + totalLength + "/" + totalLength);
186         }
187         return response;
188     }
189
190     // enqueue a huge response to keep the receiveing thread in DownloadThread.java busy for a while
191     // give enough time to do something (cancel/remove etc) on that downloadrequest
192     // while it is in progress
193     private MockResponse buildContinuingResponse() {
194         int numPackets = 100;
195         int contentLength = STRING_1K.length() * numPackets;
196         return buildResponse(HTTP_OK, STRING_1K)
197                .setHeader("Content-length", contentLength)
198                .setHeader("Etag", ETAG)
199                .setBytesPerSecond(1024);
200     }
201
202     public void testFiltering() throws Exception {
203         enqueueResponse(buildEmptyResponse(HTTP_OK));
204         enqueueResponse(buildEmptyResponse(HTTP_NOT_FOUND));
205
206         Download download1 = enqueueRequest(getRequest());
207         download1.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
208
209         mSystemFacade.incrementTimeMillis(1); // ensure downloads are correctly ordered by time
210         Download download2 = enqueueRequest(getRequest());
211         download2.runUntilStatus(DownloadManager.STATUS_FAILED);
212
213         mSystemFacade.incrementTimeMillis(1);
214         Download download3 = enqueueRequest(getRequest());
215
216         Cursor cursor = mManager.query(new DownloadManager.Query());
217         checkAndCloseCursor(cursor, download3, download2, download1);
218
219         cursor = mManager.query(new DownloadManager.Query().setFilterById(download2.mId));
220         checkAndCloseCursor(cursor, download2);
221
222         cursor = mManager.query(new DownloadManager.Query()
223                                 .setFilterByStatus(DownloadManager.STATUS_PENDING));
224         checkAndCloseCursor(cursor, download3);
225
226         cursor = mManager.query(new DownloadManager.Query()
227                                 .setFilterByStatus(DownloadManager.STATUS_FAILED
228                                               | DownloadManager.STATUS_SUCCESSFUL));
229         checkAndCloseCursor(cursor, download2, download1);
230
231         cursor = mManager.query(new DownloadManager.Query()
232                                 .setFilterByStatus(DownloadManager.STATUS_RUNNING));
233         checkAndCloseCursor(cursor);
234
235         mSystemFacade.incrementTimeMillis(1);
236         Download invisibleDownload = enqueueRequest(getRequest().setVisibleInDownloadsUi(false));
237         cursor = mManager.query(new DownloadManager.Query());
238         checkAndCloseCursor(cursor, invisibleDownload, download3, download2, download1);
239         cursor = mManager.query(new DownloadManager.Query().setOnlyIncludeVisibleInDownloadsUi(true));
240         checkAndCloseCursor(cursor, download3, download2, download1);
241     }
242
243     public void testOrdering() throws Exception {
244         enqueueResponse(buildResponse(HTTP_OK, "small contents"));
245         enqueueResponse(buildResponse(HTTP_OK, "large contents large contents"));
246         enqueueResponse(buildEmptyResponse(HTTP_NOT_FOUND));
247
248         Download download1 = enqueueRequest(getRequest());
249         download1.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
250
251         mSystemFacade.incrementTimeMillis(1);
252         Download download2 = enqueueRequest(getRequest());
253         download2.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
254
255         mSystemFacade.incrementTimeMillis(1);
256         Download download3 = enqueueRequest(getRequest());
257         download3.runUntilStatus(DownloadManager.STATUS_FAILED);
258
259         // default ordering -- by timestamp descending
260         Cursor cursor = mManager.query(new DownloadManager.Query());
261         checkAndCloseCursor(cursor, download3, download2, download1);
262
263         cursor = mManager.query(new DownloadManager.Query()
264                 .orderBy(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP,
265                         DownloadManager.Query.ORDER_ASCENDING));
266         checkAndCloseCursor(cursor, download1, download2, download3);
267
268         cursor = mManager.query(new DownloadManager.Query()
269                 .orderBy(DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
270                         DownloadManager.Query.ORDER_DESCENDING));
271         checkAndCloseCursor(cursor, download2, download1, download3);
272
273         cursor = mManager.query(new DownloadManager.Query()
274                 .orderBy(DownloadManager.COLUMN_TOTAL_SIZE_BYTES,
275                         DownloadManager.Query.ORDER_ASCENDING));
276         checkAndCloseCursor(cursor, download3, download1, download2);
277     }
278
279     private void checkAndCloseCursor(Cursor cursor, Download... downloads) {
280         try {
281             int idIndex = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID);
282             assertEquals(downloads.length, cursor.getCount());
283             cursor.moveToFirst();
284             for (Download download : downloads) {
285                 assertEquals(download.mId, cursor.getLong(idIndex));
286                 cursor.moveToNext();
287             }
288         } finally {
289             cursor.close();
290         }
291     }
292
293     public void testInvalidUri() throws Exception {
294         try {
295             enqueueRequest(getRequest("/no_host"));
296         } catch (IllegalArgumentException exc) { // expected
297             return;
298         }
299
300         fail("No exception thrown for invalid URI");
301     }
302
303     public void testDestination() throws Exception {
304         enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
305         Uri destination = getExternalUri();
306         Download download = enqueueRequest(getRequest().setDestinationUri(destination));
307         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
308
309         Uri localUri = Uri.parse(download.getStringField(DownloadManager.COLUMN_LOCAL_URI));
310         assertEquals(destination, localUri);
311
312         InputStream stream = new FileInputStream(destination.getPath());
313         try {
314             assertEquals(FILE_CONTENT, readStream(stream));
315         } finally {
316             stream.close();
317         }
318     }
319
320     private Uri getExternalUri() {
321         return Uri.fromFile(mTestDirectory).buildUpon().appendPath("testfile.txt").build();
322     }
323
324     public void testRequestHeaders() throws Exception {
325         enqueueResponse(buildEmptyResponse(HTTP_OK));
326         Download download = enqueueRequest(getRequest().addRequestHeader("Header1", "value1")
327                                            .addRequestHeader("Header2", "value2"));
328         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
329
330         List<String> headers = takeRequest().getHeaders();
331         assertTrue(headers.contains("Header1: value1"));
332         assertTrue(headers.contains("Header2: value2"));
333     }
334
335     public void testDelete() throws Exception {
336         Download download = enqueueRequest(getRequest().addRequestHeader("header", "value"));
337         mManager.remove(download.mId);
338         Cursor cursor = mManager.query(new DownloadManager.Query());
339         try {
340             assertEquals(0, cursor.getCount());
341         } finally {
342             cursor.close();
343         }
344     }
345
346     public void testSizeLimitOverMobile() throws Exception {
347         enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
348         enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
349
350         mSystemFacade.mMaxBytesOverMobile = (long) FILE_CONTENT.length() - 1;
351         mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_MOBILE;
352         Download download = enqueueRequest(getRequest());
353         download.runUntilStatus(DownloadManager.STATUS_PAUSED);
354
355         mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_WIFI;
356         // first response was read, but aborted after the DL manager processed the Content-Length
357         // header, so we need to enqueue a second one
358         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
359     }
360
361     public void testRedirect301() throws Exception {
362         RecordedRequest lastRequest = runRedirectionTest(301);
363         // for 301, upon retry/resume, we reuse the redirected URI
364         assertEquals(REDIRECTED_PATH, lastRequest.getPath());
365     }
366
367     public void testRedirect302() throws Exception {
368         RecordedRequest lastRequest = runRedirectionTest(302);
369         // for 302, upon retry/resume, we use the original URI
370         assertEquals(REQUEST_PATH, lastRequest.getPath());
371     }
372
373     public void testNoEtag() throws Exception {
374         enqueueResponse(buildPartialResponse(0, 5).removeHeader("Etag"));
375         runSimpleFailureTest(DownloadManager.ERROR_CANNOT_RESUME);
376     }
377
378     public void testSanitizeMediaType() throws Exception {
379         enqueueResponse(buildEmptyResponse(HTTP_OK)
380                 .setHeader("Content-Type", "text/html; charset=ISO-8859-4"));
381         Download download = enqueueRequest(getRequest());
382         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
383         assertEquals("text/html", download.getStringField(DownloadManager.COLUMN_MEDIA_TYPE));
384     }
385
386     public void testNoContentLength() throws Exception {
387         enqueueResponse(buildEmptyResponse(HTTP_OK).removeHeader("Content-length"));
388         runSimpleFailureTest(DownloadManager.ERROR_HTTP_DATA_ERROR);
389     }
390
391     public void testInsufficientSpace() throws Exception {
392         // this would be better done by stubbing the system API to check available space, but in the
393         // meantime, just use an absurdly large header value
394         enqueueResponse(buildEmptyResponse(HTTP_OK)
395                 .setHeader("Content-Length", 1024L * 1024 * 1024 * 1024 * 1024));
396         runSimpleFailureTest(DownloadManager.ERROR_INSUFFICIENT_SPACE);
397     }
398
399     public void testCancel() throws Exception {
400         mSystemFacade.setStartThreadsWithoutWaiting(true);
401         // return 'real time' from FakeSystemFacade so that DownloadThread will report progress
402         mSystemFacade.setReturnActualTime(true);
403         enqueueResponse(buildContinuingResponse());
404         Download download = enqueueRequest(getRequest());
405         startService(null);
406         // give the download time to get started and progress to 1% completion
407         // before cancelling it.
408         boolean rslt = download.runUntilProgress(1);
409         assertTrue(rslt);
410         mManager.remove(download.mId);
411         startService(null);
412         int status = download.runUntilDone();
413         // make sure the row is gone from the database
414         assertEquals(-1, status);
415         mSystemFacade.setReturnActualTime(false);
416     }
417
418     public void testDownloadCompleteBroadcast() throws Exception {
419         enqueueResponse(buildEmptyResponse(HTTP_OK));
420         Download download = enqueueRequest(getRequest());
421         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
422
423         assertEquals(1, mSystemFacade.mBroadcastsSent.size());
424         Intent broadcast = mSystemFacade.mBroadcastsSent.get(0);
425         assertEquals(DownloadManager.ACTION_DOWNLOAD_COMPLETE, broadcast.getAction());
426         assertEquals(PACKAGE_NAME, broadcast.getPackage());
427         long intentId = broadcast.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID);
428         assertEquals(download.mId, intentId);
429     }
430
431     public void testNotificationClickedBroadcast() throws Exception {
432         Download download = enqueueRequest(getRequest());
433
434         DownloadReceiver receiver = new DownloadReceiver();
435         receiver.mSystemFacade = mSystemFacade;
436         Intent intent = new Intent(Constants.ACTION_LIST);
437         intent.setData(Uri.parse(Downloads.Impl.CONTENT_URI + "/" + download.mId));
438         receiver.onReceive(mContext, intent);
439
440         assertEquals(1, mSystemFacade.mBroadcastsSent.size());
441         Intent broadcast = mSystemFacade.mBroadcastsSent.get(0);
442         assertEquals(DownloadManager.ACTION_NOTIFICATION_CLICKED, broadcast.getAction());
443         assertEquals(PACKAGE_NAME, broadcast.getPackage());
444     }
445
446     public void testBasicConnectivityChanges() throws Exception {
447         enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
448
449         // without connectivity, download immediately pauses
450         mSystemFacade.mActiveNetworkType = null;
451         Download download = enqueueRequest(getRequest());
452         download.runUntilStatus(DownloadManager.STATUS_PAUSED);
453
454         // connecting should start the download
455         mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_WIFI;
456         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
457     }
458
459     public void testAllowedNetworkTypes() throws Exception {
460         enqueueResponse(buildEmptyResponse(HTTP_OK));
461         enqueueResponse(buildEmptyResponse(HTTP_OK));
462
463         mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_MOBILE;
464
465         // by default, use any connection
466         Download download = enqueueRequest(getRequest());
467         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
468
469         // restrict a download to wifi...
470         download = enqueueRequest(getRequest()
471                                   .setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI));
472         download.runUntilStatus(DownloadManager.STATUS_PAUSED);
473         // ...then enable wifi
474         mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_WIFI;
475         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
476     }
477
478     public void testRoaming() throws Exception {
479         enqueueResponse(buildEmptyResponse(HTTP_OK));
480         enqueueResponse(buildEmptyResponse(HTTP_OK));
481
482         mSystemFacade.mIsRoaming = true;
483
484         // by default, allow roaming
485         Download download = enqueueRequest(getRequest());
486         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
487
488         // disallow roaming for a download...
489         download = enqueueRequest(getRequest().setAllowedOverRoaming(false));
490         download.runUntilStatus(DownloadManager.STATUS_PAUSED);
491         // ...then turn off roaming
492         mSystemFacade.mIsRoaming = false;
493         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
494     }
495
496     public void testContentObserver() throws Exception {
497         enqueueResponse(buildEmptyResponse(HTTP_OK));
498         enqueueRequest(getRequest());
499         mResolver.resetNotified();
500         runService();
501         assertTrue(mResolver.mNotifyWasCalled);
502     }
503
504     public void testNotifications() throws Exception {
505         enqueueResponse(buildEmptyResponse(HTTP_OK));
506         enqueueResponse(buildEmptyResponse(HTTP_OK));
507
508         Download download = enqueueRequest(getRequest().setShowRunningNotification(false));
509         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
510         assertEquals(0, mSystemFacade.mActiveNotifications.size());
511         assertEquals(0, mSystemFacade.mCanceledNotifications.size());
512
513         download = enqueueRequest(getRequest()); // notifications by default
514         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
515         assertEquals(1, mSystemFacade.mActiveNotifications.size());
516
517         // The notification doesn't actually get canceled until the UpdateThread runs again, which
518         // gets triggered by the DownloadThread updating the status in the provider.
519         runService();
520         assertEquals(0, mSystemFacade.mActiveNotifications.size());
521         assertEquals(1, mSystemFacade.mCanceledNotifications.size());
522     }
523
524     public void testRetryAfter() throws Exception {
525         final int delay = 120;
526         enqueueResponse(
527                 buildEmptyResponse(HTTP_SERVICE_UNAVAILABLE).setHeader("Retry-after", delay));
528         enqueueResponse(buildEmptyResponse(HTTP_OK));
529
530         Download download = enqueueRequest(getRequest());
531         download.runUntilStatus(DownloadManager.STATUS_PAUSED);
532
533         // download manager adds random 0-30s offset
534         mSystemFacade.incrementTimeMillis((delay + 31) * 1000);
535         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
536     }
537
538     public void testManyInterruptions() throws Exception {
539         final int length = FILE_CONTENT.length();
540         for (int i = 0; i < length; i++) {
541             enqueueResponse(buildPartialResponse(i, i + 1));
542         }
543
544         Download download = enqueueRequest(getRequest());
545         for (int i = 0; i < length - 1; i++) {
546             download.runUntilStatus(DownloadManager.STATUS_PAUSED);
547             mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
548         }
549
550         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
551         checkCompleteDownload(download);
552     }
553
554     public void testExistingFile() throws Exception {
555         enqueueResponse(buildEmptyResponse(HTTP_OK));
556
557         // download a file which already exists.
558         // downloadservice should simply create filename with "-" and a number attached
559         // at the end; i.e., download shouldnot fail.
560         Uri destination = getExternalUri();
561         new File(destination.getPath()).createNewFile();
562
563         Download download = enqueueRequest(getRequest().setDestinationUri(destination));
564         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
565     }
566
567     public void testEmptyFields() throws Exception {
568         Download download = enqueueRequest(getRequest());
569         assertEquals("", download.getStringField(DownloadManager.COLUMN_TITLE));
570         assertEquals("", download.getStringField(DownloadManager.COLUMN_DESCRIPTION));
571         assertNull(download.getStringField(DownloadManager.COLUMN_MEDIA_TYPE));
572         assertEquals(0, download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
573         assertEquals(-1, download.getLongField(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
574         // just ensure no exception is thrown
575         download.getLongField(DownloadManager.COLUMN_REASON);
576     }
577
578     public void testRestart() throws Exception {
579         enqueueResponse(buildEmptyResponse(HTTP_NOT_FOUND));
580         enqueueResponse(buildEmptyResponse(HTTP_OK));
581
582         Download download = enqueueRequest(getRequest());
583         download.runUntilStatus(DownloadManager.STATUS_FAILED);
584
585         mManager.restartDownload(download.mId);
586         assertEquals(DownloadManager.STATUS_PENDING,
587                 download.getLongField(DownloadManager.COLUMN_STATUS));
588         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
589     }
590
591     private void checkCompleteDownload(Download download) throws Exception {
592         assertEquals(FILE_CONTENT.length(),
593                      download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
594         assertEquals(FILE_CONTENT, download.getContents());
595     }
596
597     private void runSimpleFailureTest(int expectedErrorCode) throws Exception {
598         Download download = enqueueRequest(getRequest());
599         download.runUntilStatus(DownloadManager.STATUS_FAILED);
600         assertEquals(expectedErrorCode,
601                      download.getLongField(DownloadManager.COLUMN_REASON));
602     }
603
604     /**
605      * Run a redirection test consisting of
606      * 1) Request to REQUEST_PATH with 3xx response redirecting to another URI
607      * 2) Request to REDIRECTED_PATH with interrupted partial response
608      * 3) Resume request to complete download
609      * @return the last request sent to the server, resuming after the interruption
610      */
611     private RecordedRequest runRedirectionTest(int status)
612             throws MalformedURLException, Exception {
613         enqueueResponse(buildEmptyResponse(status)
614                 .setHeader("Location", mServer.getUrl(REDIRECTED_PATH).toString()));
615         enqueueInterruptedDownloadResponses(5);
616
617         Download download = enqueueRequest(getRequest());
618         runService();
619         assertEquals(REQUEST_PATH, takeRequest().getPath());
620         assertEquals(REDIRECTED_PATH, takeRequest().getPath());
621
622         mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
623         download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
624         return takeRequest();
625     }
626 }