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