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 android.app; 18 19 import android.app.DownloadManager.Query; 20 import android.app.DownloadManager.Request; 21 import android.database.Cursor; 22 import android.net.Uri; 23 import android.os.Environment; 24 import android.os.ParcelFileDescriptor; 25 import android.test.suitebuilder.annotation.LargeTest; 26 27 import com.google.mockwebserver.MockResponse; 28 29 import java.io.File; 30 import java.util.Iterator; 31 import java.util.Set; 32 33 /** 34 * Integration tests of the DownloadManager API. 35 */ 36 public class DownloadManagerFunctionalTest extends DownloadManagerBaseTest { 37 private static final String TAG = "DownloadManagerFunctionalTest"; 38 private final static String CACHE_DIR = 39 Environment.getDownloadCacheDirectory().getAbsolutePath(); 40 private final static String PROHIBITED_DIRECTORY = 41 Environment.getRootDirectory().getAbsolutePath(); 42 43 /** 44 * {@inheritDoc} 45 */ 46 @Override 47 public void setUp() throws Exception { 48 super.setUp(); 49 setWiFiStateOn(true); 50 removeAllCurrentDownloads(); 51 } 52 53 /** 54 * {@inheritDoc} 55 */ 56 @Override 57 public void tearDown() throws Exception { 58 super.tearDown(); 59 setWiFiStateOn(true); 60 removeAllCurrentDownloads(); 61 62 if (mReceiver != null) { 63 mContext.unregisterReceiver(mReceiver); 64 mReceiver = null; 65 } 66 } 67 68 /** 69 * Verifies a particular error code was received from a download 70 * 71 * @param uri The uri to enqueue to the DownloadManager 72 * @param error The error code expected 73 * @throws Exception if the test fails 74 */ 75 public void doErrorTest(Uri uri, int error) throws Exception { 76 Request request = new Request(uri); 77 request.setTitle(DEFAULT_FILENAME); 78 79 long dlRequest = mDownloadManager.enqueue(request); 80 waitForDownloadOrTimeout(dlRequest); 81 82 Cursor cursor = getCursor(dlRequest); 83 try { 84 verifyInt(cursor, DownloadManager.COLUMN_REASON, error); 85 } finally { 86 cursor.close(); 87 } 88 } 89 90 /** 91 * Test a basic download of a binary file 500k in size. 92 */ 93 @LargeTest 94 public void testBinaryDownloadToSystemCache() throws Exception { 95 int fileSize = 1024; 96 byte[] blobData = generateData(fileSize, DataType.BINARY); 97 98 long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); 99 verifyDownload(dlRequest, blobData); 100 mDownloadManager.remove(dlRequest); 101 } 102 103 /** 104 * Tests the basic downloading of a text file 300000 bytes in size. 105 */ 106 @LargeTest 107 public void testTextDownloadToSystemCache() throws Exception { 108 int fileSize = 1024; 109 byte[] blobData = generateData(fileSize, DataType.TEXT); 110 111 long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); 112 verifyDownload(dlRequest, blobData); 113 mDownloadManager.remove(dlRequest); 114 } 115 116 /** 117 * Helper to verify a standard single-file download from the mock server, and clean up after 118 * verification 119 * 120 * Note that this also calls the Download manager's remove, which cleans up the file from cache. 121 * 122 * @param requestId The id of the download to remove 123 * @param fileData The data to verify the file contains 124 */ 125 private void verifyDownload(long requestId, byte[] fileData) 126 throws Exception { 127 int fileSize = fileData.length; 128 ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(requestId); 129 Cursor cursor = mDownloadManager.query(new Query().setFilterById(requestId)); 130 try { 131 assertEquals(1, cursor.getCount()); 132 assertTrue(cursor.moveToFirst()); 133 134 verifyFileSize(pfd, fileSize); 135 verifyFileContents(pfd, fileData); 136 int colIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); 137 String fileName = cursor.getString(colIndex); 138 assertTrue(fileName.startsWith(CACHE_DIR)); 139 } finally { 140 pfd.close(); 141 cursor.close(); 142 } 143 } 144 145 /** 146 * Tests trying to download to SD card when the file with same name already exists. 147 */ 148 @LargeTest 149 public void testDownloadToExternal_fileExists() throws Exception { 150 File existentFile = createFileOnSD(null, 1, DataType.TEXT, null); 151 byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); 152 153 // Prepare the mock server with a standard response 154 enqueueResponse(buildResponse(HTTP_OK, blobData)); 155 156 try { 157 Uri uri = getServerUri(DEFAULT_FILENAME); 158 Request request = new Request(uri); 159 160 Uri localUri = Uri.fromFile(existentFile); 161 request.setDestinationUri(localUri); 162 163 long dlRequest = mDownloadManager.enqueue(request); 164 165 // wait for the download to complete 166 waitForDownloadOrTimeout(dlRequest); 167 Cursor cursor = getCursor(dlRequest); 168 169 try { 170 verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_SUCCESSFUL); 171 } finally { 172 cursor.close(); 173 } 174 } finally { 175 existentFile.delete(); 176 } 177 } 178 179 /** 180 * Tests trying to download a file to SD card. 181 */ 182 @LargeTest 183 public void testDownloadToExternal() throws Exception { 184 String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath(); 185 File downloadedFile = new File(localDownloadDirectory, DEFAULT_FILENAME); 186 // make sure the file doesn't already exist in the directory 187 downloadedFile.delete(); 188 189 try { 190 byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); 191 192 // Prepare the mock server with a standard response 193 enqueueResponse(buildResponse(HTTP_OK, blobData)); 194 195 Uri uri = getServerUri(DEFAULT_FILENAME); 196 Request request = new Request(uri); 197 198 Uri localUri = Uri.fromFile(downloadedFile); 199 request.setDestinationUri(localUri); 200 201 long dlRequest = mDownloadManager.enqueue(request); 202 203 // wait for the download to complete 204 waitForDownloadOrTimeout(dlRequest); 205 206 verifyAndCleanupSingleFileDownload(dlRequest, blobData); 207 208 assertEquals(1, mReceiver.numDownloadsCompleted()); 209 } finally { 210 downloadedFile.delete(); 211 } 212 } 213 214 /** 215 * Tests trying to download a file to the system partition. 216 */ 217 @LargeTest 218 public void testDownloadToProhibitedDirectory() throws Exception { 219 File downloadedFile = new File(PROHIBITED_DIRECTORY, DEFAULT_FILENAME); 220 try { 221 byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); 222 223 // Prepare the mock server with a standard response 224 enqueueResponse(buildResponse(HTTP_OK, blobData)); 225 226 Uri uri = getServerUri(DEFAULT_FILENAME); 227 Request request = new Request(uri); 228 229 Uri localUri = Uri.fromFile(downloadedFile); 230 request.setDestinationUri(localUri); 231 232 try { 233 mDownloadManager.enqueue(request); 234 fail("Failed to throw SecurityException when trying to write to /system."); 235 } catch (SecurityException s) { 236 assertFalse(downloadedFile.exists()); 237 } 238 } finally { 239 // Just in case file somehow got created, make sure to delete it 240 downloadedFile.delete(); 241 } 242 } 243 244 /** 245 * Tests that we get the correct download ID from the download notification. 246 */ 247 @LargeTest 248 public void testGetDownloadIdOnNotification() throws Exception { 249 byte[] blobData = generateData(3000, DataType.TEXT); // file size = 3000 bytes 250 251 enqueueResponse(buildResponse(HTTP_OK, blobData)); 252 long dlRequest = doCommonStandardEnqueue(); 253 waitForDownloadOrTimeout(dlRequest); 254 255 Set<Long> ids = mReceiver.getDownloadIds(); 256 assertEquals(1, ids.size()); 257 Iterator<Long> it = ids.iterator(); 258 assertEquals("Download ID received from notification does not match initial id!", 259 dlRequest, it.next().longValue()); 260 } 261 262 /** 263 * Tests the download failure error after too many redirects (>5). 264 */ 265 @LargeTest 266 public void testErrorTooManyRedirects() throws Exception { 267 Uri uri = getServerUri(DEFAULT_FILENAME); 268 269 // force 6 redirects 270 for (int i = 0; i < 6; ++i) { 271 final MockResponse resp = buildResponse(HTTP_REDIRECT); 272 resp.setHeader("Location", uri.toString()); 273 enqueueResponse(resp); 274 } 275 doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS); 276 } 277 278 /** 279 * Tests the download failure error from an unhandled HTTP status code 280 */ 281 @LargeTest 282 public void testErrorUnhandledHttpCode() throws Exception { 283 Uri uri = getServerUri(DEFAULT_FILENAME); 284 enqueueResponse(buildResponse(HTTP_PARTIAL_CONTENT)); 285 286 doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE); 287 } 288 289 /** 290 * Tests the download failure error from an unhandled HTTP status code 291 */ 292 @LargeTest 293 public void testErrorHttpDataError_invalidRedirect() throws Exception { 294 Uri uri = getServerUri(DEFAULT_FILENAME); 295 final MockResponse resp = buildResponse(HTTP_REDIRECT); 296 resp.setHeader("Location", "://blah.blah.blah.com"); 297 enqueueResponse(resp); 298 299 doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR); 300 } 301 302 /** 303 * Tests that we can remove a download from the download manager. 304 */ 305 @LargeTest 306 public void testRemoveDownload() throws Exception { 307 int fileSize = 1024; 308 byte[] blobData = generateData(fileSize, DataType.BINARY); 309 310 long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); 311 Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest)); 312 try { 313 assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount()); 314 mDownloadManager.remove(dlRequest); 315 cursor.requery(); 316 assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount()); 317 } finally { 318 cursor.close(); 319 } 320 } 321 322 /** 323 * Tests that we can set the title of a download. 324 */ 325 @LargeTest 326 public void testSetTitle() throws Exception { 327 int fileSize = 1024; 328 byte[] blobData = generateData(fileSize, DataType.BINARY); 329 enqueueResponse(buildResponse(HTTP_OK, blobData)); 330 331 // An arbitrary unicode string title 332 final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" + 333 "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'"; 334 335 Uri uri = getServerUri(DEFAULT_FILENAME); 336 Request request = new Request(uri); 337 request.setTitle(title); 338 339 long dlRequest = mDownloadManager.enqueue(request); 340 waitForDownloadOrTimeout(dlRequest); 341 342 Cursor cursor = getCursor(dlRequest); 343 try { 344 verifyString(cursor, DownloadManager.COLUMN_TITLE, title); 345 } finally { 346 cursor.close(); 347 } 348 } 349 350 /** 351 * Tests that a download set for Wifi does not progress while Wifi is disabled, but resumes 352 * once Wifi is re-enabled. 353 */ 354 @LargeTest 355 public void testDownloadNoWifi() throws Exception { 356 long timeout = 60 * 1000; // wait only 60 seconds before giving up 357 int fileSize = 1024; // 140k 358 byte[] blobData = generateData(fileSize, DataType.TEXT); 359 360 setWiFiStateOn(false); 361 enqueueResponse(buildResponse(HTTP_OK, blobData)); 362 363 try { 364 Uri uri = getServerUri(DEFAULT_FILENAME); 365 Request request = new Request(uri); 366 request.setAllowedNetworkTypes(Request.NETWORK_WIFI); 367 368 long dlRequest = mDownloadManager.enqueue(request); 369 370 // wait for the download to complete 371 boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest, 372 WAIT_FOR_DOWNLOAD_POLL_TIME, timeout); 373 assertFalse("Download proceeded without Wifi connection!", success); 374 375 setWiFiStateOn(true); 376 waitForDownloadOrTimeout(dlRequest); 377 378 assertEquals(1, mReceiver.numDownloadsCompleted()); 379 } finally { 380 setWiFiStateOn(true); 381 } 382 } 383 384 /** 385 * Tests that we get an error code when the server drops the connection during a download. 386 */ 387 @LargeTest 388 public void testServerDropConnection_body() throws Exception { 389 byte[] blobData = generateData(25000, DataType.TEXT); // file size = 25000 bytes 390 391 final MockResponse resp = buildResponse(HTTP_OK, blobData); 392 resp.setHeader("Content-Length", "50000"); 393 enqueueResponse(resp); 394 395 long dlRequest = doCommonStandardEnqueue(); 396 waitForDownloadOrTimeout(dlRequest); 397 398 Cursor cursor = getCursor(dlRequest); 399 try { 400 verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); 401 verifyInt(cursor, DownloadManager.COLUMN_REASON, 402 DownloadManager.ERROR_CANNOT_RESUME); 403 } finally { 404 cursor.close(); 405 } 406 // Even tho the server drops the connection, we should still get a completed notification 407 assertEquals(1, mReceiver.numDownloadsCompleted()); 408 } 409 } 410