3cd9cf5813b5129a4cdaddc9832d6e235209e246
[android/platform/packages/providers/DownloadProvider.git] / tests / src / com / android / providers / downloads / DownloadManagerFunctionalTest.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.content.ContentValues;
20 import android.database.Cursor;
21 import android.net.ConnectivityManager;
22 import android.net.Uri;
23 import android.os.Environment;
24 import android.provider.Downloads;
25 import android.test.suitebuilder.annotation.LargeTest;
26 import tests.http.MockWebServer;
27 import tests.http.RecordedRequest;
28
29 import java.io.InputStream;
30 import java.net.MalformedURLException;
31 import java.util.List;
32
33 /**
34  * This test exercises the entire download manager working together -- it requests downloads through
35  * the {@link DownloadProvider}, just like a normal client would, and runs the
36  * {@link DownloadService} with start intents.  It sets up a {@link MockWebServer} running on the
37  * device to serve downloads.
38  */
39 @LargeTest
40 public class DownloadManagerFunctionalTest extends AbstractDownloadManagerFunctionalTest {
41     public void testBasicRequest() throws Exception {
42         enqueueResponse(HTTP_OK, FILE_CONTENT);
43
44         String path = "/download_manager_test_path";
45         Uri downloadUri = requestDownload(path);
46         assertEquals(Downloads.STATUS_PENDING, getDownloadStatus(downloadUri));
47         assertTrue(mTestContext.mHasServiceBeenStarted);
48
49         RecordedRequest request = runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
50         assertEquals("GET", request.getMethod());
51         assertEquals(path, request.getPath());
52         assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
53         assertStartsWith(Environment.getExternalStorageDirectory().getPath(),
54                          getDownloadFilename(downloadUri));
55     }
56
57     public void testDownloadToCache() throws Exception {
58         enqueueResponse(HTTP_OK, FILE_CONTENT);
59         Uri downloadUri = requestDownload("/path");
60         updateDownload(downloadUri, Downloads.COLUMN_DESTINATION,
61                        Integer.toString(Downloads.DESTINATION_CACHE_PARTITION));
62         runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
63         assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
64         assertStartsWith(Environment.getDownloadCacheDirectory().getPath(),
65                          getDownloadFilename(downloadUri));
66     }
67
68     public void testFileNotFound() throws Exception {
69         enqueueEmptyResponse(HTTP_NOT_FOUND);
70         Uri downloadUri = requestDownload("/nonexistent_path");
71         assertEquals(Downloads.STATUS_PENDING, getDownloadStatus(downloadUri));
72         runUntilStatus(downloadUri, HTTP_NOT_FOUND);
73     }
74
75     public void testRetryAfter() throws Exception {
76         final int delay = 120;
77         enqueueEmptyResponse(HTTP_SERVICE_UNAVAILABLE).addHeader("Retry-after", delay);
78         Uri downloadUri = requestDownload("/path");
79         runUntilStatus(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
80
81         // download manager adds random 0-30s offset
82         mSystemFacade.incrementTimeMillis((delay + 31) * 1000);
83
84         enqueueResponse(HTTP_OK, FILE_CONTENT);
85         runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
86     }
87
88     public void testRedirect() throws Exception {
89         enqueueEmptyResponse(301).addHeader("Location", mServer.getUrl("/other_path").toString());
90         enqueueResponse(HTTP_OK, FILE_CONTENT);
91         Uri downloadUri = requestDownload("/path");
92         RecordedRequest request = runUntilStatus(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
93         assertEquals("/path", request.getPath());
94
95         mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
96         request = runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
97         assertEquals("/other_path", request.getPath());
98     }
99
100     public void testBasicConnectivityChanges() throws Exception {
101         enqueueResponse(HTTP_OK, FILE_CONTENT);
102         Uri downloadUri = requestDownload("/path");
103
104         // without connectivity, download immediately pauses
105         mSystemFacade.mActiveNetworkType = null;
106         startService(null);
107         waitForDownloadToStop(getStatusReader(downloadUri), Downloads.STATUS_RUNNING_PAUSED);
108
109         // connecting should start the download
110         mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_WIFI;
111         runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
112     }
113
114     public void testRoaming() throws Exception {
115         mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_MOBILE;
116         mSystemFacade.mIsRoaming = true;
117
118         // for a normal download, roaming is fine
119         enqueueResponse(HTTP_OK, FILE_CONTENT);
120         Uri downloadUri = requestDownload("/path");
121         startService(null);
122         runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
123
124         // when roaming is disallowed, the download should pause...
125         downloadUri = requestDownload("/path");
126         updateDownload(downloadUri, Downloads.COLUMN_DESTINATION,
127                        Integer.toString(Downloads.DESTINATION_CACHE_PARTITION_NOROAMING));
128         startService(null);
129         waitForDownloadToStop(getStatusReader(downloadUri), Downloads.STATUS_RUNNING_PAUSED);
130
131         // ...and pick up when we're off roaming
132         enqueueResponse(HTTP_OK, FILE_CONTENT);
133         mSystemFacade.mIsRoaming = false;
134         runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
135     }
136
137     public void testInterruptedDownload() throws Exception {
138         int initialLength = 5;
139         String etag = "my_etag";
140         int totalLength = FILE_CONTENT.length();
141         // the first response has normal headers but unexpectedly closes after initialLength bytes
142         enqueueResponse(HTTP_OK, FILE_CONTENT.substring(0, initialLength))
143                 .addHeader("Content-length", totalLength)
144                 .addHeader("Etag", etag)
145                 .setCloseConnectionAfter(true);
146         Uri downloadUri = requestDownload("/path");
147
148         runUntilStatus(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
149
150         mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
151         // the second response returns partial content for the rest of the data
152         enqueueResponse(HTTP_PARTIAL_CONTENT, FILE_CONTENT.substring(initialLength))
153                 .addHeader("Content-range",
154                            "bytes " + initialLength + "-" + totalLength + "/" + totalLength)
155                 .addHeader("Etag", etag);
156         // TODO: ideally we wouldn't need to call startService again, but there's a bug where the
157         // service won't retry a download until an intent comes in
158         RecordedRequest request = runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
159
160         List<String> headers = request.getHeaders();
161         assertTrue("No Range header: " + headers,
162                    headers.contains("Range: bytes=" + initialLength + "-"));
163         assertTrue("No ETag header: " + headers, headers.contains("If-Match: " + etag));
164         assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
165     }
166
167     /**
168      * Read a downloaded file from disk.
169      */
170     private String getDownloadContents(Uri downloadUri) throws Exception {
171         InputStream inputStream = mResolver.openInputStream(downloadUri);
172         try {
173             return readStream(inputStream);
174         } finally {
175             inputStream.close();
176         }
177     }
178
179     private RecordedRequest runUntilStatus(Uri downloadUri, int status) throws Exception {
180         return super.runUntilStatus(getStatusReader(downloadUri), status);
181     }
182
183     private StatusReader getStatusReader(final Uri downloadUri) {
184         return new StatusReader() {
185             public int getStatus() {
186                 return getDownloadStatus(downloadUri);
187             }
188
189             public boolean isComplete(int status) {
190                 return !Downloads.isStatusInformational(status);
191             }
192         };
193     }
194
195     protected int getDownloadStatus(Uri downloadUri) {
196         return Integer.valueOf(getDownloadField(downloadUri, Downloads.COLUMN_STATUS));
197     }
198
199     private String getDownloadFilename(Uri downloadUri) {
200         return getDownloadField(downloadUri, Downloads._DATA);
201     }
202
203     private String getDownloadField(Uri downloadUri, String column) {
204         final String[] columns = new String[] {column};
205         Cursor cursor = mResolver.query(downloadUri, columns, null, null, null);
206         try {
207             assertEquals(1, cursor.getCount());
208             cursor.moveToFirst();
209             return cursor.getString(0);
210         } finally {
211             cursor.close();
212         }
213     }
214
215     /**
216      * Request a download from the Download Manager.
217      */
218     private Uri requestDownload(String path) throws MalformedURLException {
219         ContentValues values = new ContentValues();
220         values.put(Downloads.COLUMN_URI, getServerUri(path));
221         values.put(Downloads.COLUMN_DESTINATION, Downloads.DESTINATION_EXTERNAL);
222         return mResolver.insert(Downloads.CONTENT_URI, values);
223     }
224
225     /**
226      * Update one field of a download in the provider.
227      */
228     private void updateDownload(Uri downloadUri, String column, String value) {
229         ContentValues values = new ContentValues();
230         values.put(column, value);
231         int numChanged = mResolver.update(downloadUri, values, null, null);
232         assertEquals(1, numChanged);
233     }
234 }