DownloadManagerFunctionalTest.java revision 82e891b3259350a92b55969a6380ca1240ee0829
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 17package android.app; 18 19import coretestutils.http.MockResponse; 20 21import android.app.DownloadManager.Query; 22import android.app.DownloadManager.Request; 23import android.app.DownloadManagerBaseTest.DataType; 24import android.database.Cursor; 25import android.net.Uri; 26import android.os.Environment; 27import android.os.ParcelFileDescriptor; 28import android.os.StatFs; 29import android.test.suitebuilder.annotation.LargeTest; 30import android.util.Log; 31 32import java.io.File; 33import java.io.FileOutputStream; 34import java.io.IOException; 35import java.util.Iterator; 36import java.util.Random; 37import java.util.Set; 38 39/** 40 * Integration tests of the DownloadManager API. 41 */ 42public class DownloadManagerFunctionalTest extends DownloadManagerBaseTest { 43 private static final String TAG = "DownloadManagerFunctionalTest"; 44 private final static String CACHE_DIR = 45 Environment.getDownloadCacheDirectory().getAbsolutePath(); 46 private final static String PROHIBITED_DIRECTORY = 47 Environment.getRootDirectory().getAbsolutePath(); 48 49 /** 50 * {@inheritDoc} 51 */ 52 @Override 53 public void setUp() throws Exception { 54 super.setUp(); 55 setWiFiStateOn(true); 56 mServer.play(); 57 removeAllCurrentDownloads(); 58 } 59 60 /** 61 * {@inheritDoc} 62 */ 63 @Override 64 public void tearDown() throws Exception { 65 super.tearDown(); 66 setWiFiStateOn(true); 67 removeAllCurrentDownloads(); 68 69 if (mReceiver != null) { 70 mContext.unregisterReceiver(mReceiver); 71 mReceiver = null; 72 } 73 } 74 75 /** 76 * Verifies a particular error code was received from a download 77 * 78 * @param uri The uri to enqueue to the DownloadManager 79 * @param error The error code expected 80 * @throws Exception if the test fails 81 */ 82 public void doErrorTest(Uri uri, int error) throws Exception { 83 Request request = new Request(uri); 84 request.setTitle(DEFAULT_FILENAME); 85 86 long dlRequest = mDownloadManager.enqueue(request); 87 waitForDownloadOrTimeout(dlRequest); 88 89 Cursor cursor = getCursor(dlRequest); 90 try { 91 verifyInt(cursor, DownloadManager.COLUMN_REASON, error); 92 } finally { 93 cursor.close(); 94 } 95 } 96 97 /** 98 * Test a basic download of a binary file 500k in size. 99 */ 100 @LargeTest 101 public void testBinaryDownloadToSystemCache() throws Exception { 102 int fileSize = 1024; 103 byte[] blobData = generateData(fileSize, DataType.BINARY); 104 105 long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); 106 verifyDownload(dlRequest, blobData); 107 mDownloadManager.remove(dlRequest); 108 } 109 110 /** 111 * Tests the basic downloading of a text file 300000 bytes in size. 112 */ 113 @LargeTest 114 public void testTextDownloadToSystemCache() throws Exception { 115 int fileSize = 1024; 116 byte[] blobData = generateData(fileSize, DataType.TEXT); 117 118 long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); 119 verifyDownload(dlRequest, blobData); 120 mDownloadManager.remove(dlRequest); 121 } 122 123 /** 124 * Helper to verify a standard single-file download from the mock server, and clean up after 125 * verification 126 * 127 * Note that this also calls the Download manager's remove, which cleans up the file from cache. 128 * 129 * @param requestId The id of the download to remove 130 * @param fileData The data to verify the file contains 131 */ 132 private void verifyDownload(long requestId, byte[] fileData) 133 throws Exception { 134 int fileSize = fileData.length; 135 ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(requestId); 136 Cursor cursor = mDownloadManager.query(new Query().setFilterById(requestId)); 137 try { 138 assertEquals(1, cursor.getCount()); 139 assertTrue(cursor.moveToFirst()); 140 141 mServer.checkForExceptions(); 142 143 verifyFileSize(pfd, fileSize); 144 verifyFileContents(pfd, fileData); 145 int colIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); 146 String fileName = cursor.getString(colIndex); 147 assertTrue(fileName.startsWith(CACHE_DIR)); 148 } finally { 149 pfd.close(); 150 cursor.close(); 151 } 152 } 153 154 /** 155 * Attempts to download several files simultaneously 156 */ 157 @LargeTest 158 public void testMultipleDownloads() throws Exception { 159 // need to be sure all current downloads have stopped first 160 removeAllCurrentDownloads(); 161 int NUM_FILES = 10; 162 int MAX_FILE_SIZE = 10 * 1024; // 10 kb 163 164 Random r = new LoggingRng(); 165 for (int i=0; i<NUM_FILES; ++i) { 166 int size = r.nextInt(MAX_FILE_SIZE); 167 byte[] blobData = generateData(size, DataType.TEXT); 168 169 Uri uri = getServerUri(DEFAULT_FILENAME + i); 170 Request request = new Request(uri); 171 request.setTitle(String.format("%s--%d", DEFAULT_FILENAME + i, i)); 172 173 // Prepare the mock server with a standard response 174 enqueueResponse(HTTP_OK, blobData); 175 176 long requestID = mDownloadManager.enqueue(request); 177 } 178 179 waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME); 180 Cursor cursor = mDownloadManager.query(new Query()); 181 try { 182 assertEquals(NUM_FILES, cursor.getCount()); 183 184 if (cursor.moveToFirst()) { 185 do { 186 int status = cursor.getInt(cursor.getColumnIndex( 187 DownloadManager.COLUMN_STATUS)); 188 String filename = cursor.getString(cursor.getColumnIndex( 189 DownloadManager.COLUMN_URI)); 190 String errorString = String.format( 191 "File %s failed to download successfully. Status code: %d", 192 filename, status); 193 assertEquals(errorString, DownloadManager.STATUS_SUCCESSFUL, status); 194 } while (cursor.moveToNext()); 195 } 196 197 assertEquals(NUM_FILES, mReceiver.numDownloadsCompleted()); 198 } finally { 199 cursor.close(); 200 } 201 } 202 203 /** 204 * Tests trying to download to SD card when the file with same name already exists. 205 */ 206 @LargeTest 207 public void testDownloadToExternal_fileExists() throws Exception { 208 File existentFile = createFileOnSD(null, 1, DataType.TEXT, null); 209 byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); 210 211 // Prepare the mock server with a standard response 212 enqueueResponse(HTTP_OK, blobData); 213 214 try { 215 Uri uri = getServerUri(DEFAULT_FILENAME); 216 Request request = new Request(uri); 217 218 Uri localUri = Uri.fromFile(existentFile); 219 request.setDestinationUri(localUri); 220 221 long dlRequest = mDownloadManager.enqueue(request); 222 223 // wait for the download to complete 224 waitForDownloadOrTimeout(dlRequest); 225 Cursor cursor = getCursor(dlRequest); 226 227 try { 228 verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_SUCCESSFUL); 229 } finally { 230 cursor.close(); 231 } 232 } finally { 233 existentFile.delete(); 234 } 235 } 236 237 /** 238 * Tests trying to download a file to SD card. 239 */ 240 @LargeTest 241 public void testDownloadToExternal() throws Exception { 242 String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath(); 243 File downloadedFile = new File(localDownloadDirectory, DEFAULT_FILENAME); 244 // make sure the file doesn't already exist in the directory 245 downloadedFile.delete(); 246 247 try { 248 byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); 249 250 // Prepare the mock server with a standard response 251 enqueueResponse(HTTP_OK, blobData); 252 253 Uri uri = getServerUri(DEFAULT_FILENAME); 254 Request request = new Request(uri); 255 256 Uri localUri = Uri.fromFile(downloadedFile); 257 request.setDestinationUri(localUri); 258 259 long dlRequest = mDownloadManager.enqueue(request); 260 261 // wait for the download to complete 262 waitForDownloadOrTimeout(dlRequest); 263 264 verifyAndCleanupSingleFileDownload(dlRequest, blobData); 265 266 assertEquals(1, mReceiver.numDownloadsCompleted()); 267 } finally { 268 downloadedFile.delete(); 269 } 270 } 271 272 /** 273 * Tests trying to download a file to the system partition. 274 */ 275 @LargeTest 276 public void testDownloadToProhibitedDirectory() throws Exception { 277 File downloadedFile = new File(PROHIBITED_DIRECTORY, DEFAULT_FILENAME); 278 try { 279 byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); 280 281 // Prepare the mock server with a standard response 282 enqueueResponse(HTTP_OK, blobData); 283 284 Uri uri = getServerUri(DEFAULT_FILENAME); 285 Request request = new Request(uri); 286 287 Uri localUri = Uri.fromFile(downloadedFile); 288 request.setDestinationUri(localUri); 289 290 try { 291 mDownloadManager.enqueue(request); 292 fail("Failed to throw SecurityException when trying to write to /system."); 293 } catch (SecurityException s) { 294 assertFalse(downloadedFile.exists()); 295 } 296 } finally { 297 // Just in case file somehow got created, make sure to delete it 298 downloadedFile.delete(); 299 } 300 } 301 302 /** 303 * Tests that we get the correct download ID from the download notification. 304 */ 305 @LargeTest 306 public void testGetDownloadIdOnNotification() throws Exception { 307 byte[] blobData = generateData(3000, DataType.TEXT); // file size = 3000 bytes 308 309 MockResponse response = enqueueResponse(HTTP_OK, blobData); 310 long dlRequest = doCommonStandardEnqueue(); 311 waitForDownloadOrTimeout(dlRequest); 312 313 Set<Long> ids = mReceiver.getDownloadIds(); 314 assertEquals(1, ids.size()); 315 Iterator<Long> it = ids.iterator(); 316 assertEquals("Download ID received from notification does not match initial id!", 317 dlRequest, it.next().longValue()); 318 } 319 320 /** 321 * Tests the download failure error after too many redirects (>5). 322 */ 323 @LargeTest 324 public void testErrorTooManyRedirects() throws Exception { 325 Uri uri = getServerUri(DEFAULT_FILENAME); 326 327 // force 6 redirects 328 for (int i = 0; i < 6; ++i) { 329 MockResponse response = enqueueResponse(HTTP_REDIRECT); 330 response.addHeader("Location", uri.toString()); 331 } 332 doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS); 333 } 334 335 /** 336 * Tests the download failure error from an unhandled HTTP status code 337 */ 338 @LargeTest 339 public void testErrorUnhandledHttpCode() throws Exception { 340 Uri uri = getServerUri(DEFAULT_FILENAME); 341 MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT); 342 343 doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE); 344 } 345 346 /** 347 * Tests the download failure error from an unhandled HTTP status code 348 */ 349 @LargeTest 350 public void testErrorHttpDataError_invalidRedirect() throws Exception { 351 Uri uri = getServerUri(DEFAULT_FILENAME); 352 MockResponse response = enqueueResponse(HTTP_REDIRECT); 353 response.addHeader("Location", "://blah.blah.blah.com"); 354 355 doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR); 356 } 357 358 /** 359 * Tests that we can remove a download from the download manager. 360 */ 361 @LargeTest 362 public void testRemoveDownload() throws Exception { 363 int fileSize = 1024; 364 byte[] blobData = generateData(fileSize, DataType.BINARY); 365 366 long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); 367 Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest)); 368 try { 369 assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount()); 370 mDownloadManager.remove(dlRequest); 371 cursor.requery(); 372 assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount()); 373 } finally { 374 cursor.close(); 375 } 376 } 377 378 /** 379 * Tests that we can set the title of a download. 380 */ 381 @LargeTest 382 public void testSetTitle() throws Exception { 383 int fileSize = 1024; 384 byte[] blobData = generateData(fileSize, DataType.BINARY); 385 MockResponse response = enqueueResponse(HTTP_OK, blobData); 386 387 // An arbitrary unicode string title 388 final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" + 389 "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'"; 390 391 Uri uri = getServerUri(DEFAULT_FILENAME); 392 Request request = new Request(uri); 393 request.setTitle(title); 394 395 long dlRequest = mDownloadManager.enqueue(request); 396 waitForDownloadOrTimeout(dlRequest); 397 398 Cursor cursor = getCursor(dlRequest); 399 try { 400 verifyString(cursor, DownloadManager.COLUMN_TITLE, title); 401 } finally { 402 cursor.close(); 403 } 404 } 405 406 /** 407 * Tests that a download set for Wifi does not progress while Wifi is disabled, but resumes 408 * once Wifi is re-enabled. 409 */ 410 @LargeTest 411 public void testDownloadNoWifi() throws Exception { 412 long timeout = 60 * 1000; // wait only 60 seconds before giving up 413 int fileSize = 1024; // 140k 414 byte[] blobData = generateData(fileSize, DataType.TEXT); 415 416 setWiFiStateOn(false); 417 enqueueResponse(HTTP_OK, blobData); 418 419 try { 420 Uri uri = getServerUri(DEFAULT_FILENAME); 421 Request request = new Request(uri); 422 request.setAllowedNetworkTypes(Request.NETWORK_WIFI); 423 424 long dlRequest = mDownloadManager.enqueue(request); 425 426 // wait for the download to complete 427 boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest, 428 WAIT_FOR_DOWNLOAD_POLL_TIME, timeout); 429 assertFalse("Download proceeded without Wifi connection!", success); 430 431 setWiFiStateOn(true); 432 waitForDownloadOrTimeout(dlRequest); 433 434 assertEquals(1, mReceiver.numDownloadsCompleted()); 435 } finally { 436 setWiFiStateOn(true); 437 } 438 } 439 440 /** 441 * Tests when the server drops the connection after all headers (but before any data send). 442 */ 443 @LargeTest 444 public void testDropConnection_headers() throws Exception { 445 byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); 446 447 MockResponse response = enqueueResponse(HTTP_OK, blobData); 448 response.setCloseConnectionAfterHeader("content-length"); 449 long dlRequest = doCommonStandardEnqueue(); 450 451 // Download will never complete when header is dropped 452 boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest, DEFAULT_WAIT_POLL_TIME, 453 DEFAULT_MAX_WAIT_TIME); 454 455 assertFalse(success); 456 } 457 458 /** 459 * Tests that we get an error code when the server drops the connection during a download. 460 */ 461 @LargeTest 462 public void testServerDropConnection_body() throws Exception { 463 byte[] blobData = generateData(25000, DataType.TEXT); // file size = 25000 bytes 464 465 MockResponse response = enqueueResponse(HTTP_OK, blobData); 466 response.setCloseConnectionAfterXBytes(15382); 467 long dlRequest = doCommonStandardEnqueue(); 468 waitForDownloadOrTimeout(dlRequest); 469 470 Cursor cursor = getCursor(dlRequest); 471 try { 472 verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); 473 verifyInt(cursor, DownloadManager.COLUMN_REASON, 474 DownloadManager.ERROR_CANNOT_RESUME); 475 } finally { 476 cursor.close(); 477 } 478 // Even tho the server drops the connection, we should still get a completed notification 479 assertEquals(1, mReceiver.numDownloadsCompleted()); 480 } 481 482 /** 483 * Tests downloading a file to system cache when there isn't enough space in the system cache 484 * to hold the entire file. DownloadManager deletes enough files to make space for the 485 * new download. 486 */ 487 @LargeTest 488 public void testDownloadToCacheWithAlmostFullCache() throws Exception { 489 int DOWNLOAD_FILE_SIZE = 1024 * 1024; // 1MB 490 491 StatFs fs = new StatFs(CACHE_DIR); 492 int blockSize = fs.getBlockSize(); 493 int availableBlocks = fs.getAvailableBlocks(); 494 int availableBytes = blockSize * availableBlocks; 495 Log.i(TAG, "INITIAL stage, available space in /cache: " + availableBytes); 496 File outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR)); 497 byte[] buffer = new byte[blockSize]; 498 499 try { 500 // fill cache to ensure we don't have enough space - take half the size of the 501 // download size, and leave that much freespace left on the cache partition 502 if (DOWNLOAD_FILE_SIZE <= availableBytes) { 503 int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2); 504 505 int writeSizeBlocks = writeSizeBytes / blockSize; 506 int remainderSizeBlocks = availableBlocks - writeSizeBlocks; 507 508 FileOutputStream fo = null; 509 try { 510 fo = new FileOutputStream(outFile); 511 while (fs.getAvailableBlocks() >= remainderSizeBlocks) { 512 fo.write(buffer); 513 fs.restat(CACHE_DIR); 514 } 515 } catch (IOException e) { 516 Log.e(LOG_TAG, "error filling file: ", e); 517 throw e; 518 } finally { 519 if (fo != null) { 520 fo.close(); 521 } 522 } 523 } 524 525 // /cache should now be almost full. 526 long spaceAvailable = fs.getAvailableBlocks() * blockSize; 527 Log.i(TAG, "BEFORE download, available space in /cache: " + spaceAvailable); 528 assertTrue(DOWNLOAD_FILE_SIZE > spaceAvailable); 529 530 // try to download 1MB file into /cache - and it should succeed 531 byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT); 532 long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); 533 verifyAndCleanupSingleFileDownload(dlRequest, blobData); 534 } finally { 535 if (outFile != null) { 536 outFile.delete(); 537 } 538 } 539 } 540 541 /** 542 * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've 543 * run out of space. 544 */ 545 @LargeTest 546 public void testDownloadToCacheNonPurgeableWithFullCache() throws Exception { 547 int fileSize = 1024 * 1024; // 1MB 548 byte[] blobData = generateData(fileSize, DataType.BINARY); 549 long dlRequest = -1; 550 551 // Fill up the cache partition with DOWNLOAD_CACHE_NON_PURGEABLE downloads 552 // until 500KB is left. 553 boolean spaceAvailable = true; 554 while (spaceAvailable) { 555 // since this tests package has android.permission.DOWNLOAD_CACHE_NON_PURGEABLE 556 // permission, downloads are automatically set to be DOWNLOAD_CACHE_NON_PURGEABLE 557 dlRequest = enqueueDownloadRequest(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); 558 waitForDownloadOrTimeout(dlRequest); 559 560 // Check if we've filled up the cache yet 561 StatFs fs = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); 562 int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks(); 563 Log.i(TAG, "available space in /cache: " + availableBytes); 564 spaceAvailable = (availableBytes > fileSize) ? true : false; 565 } 566 567 // Now add one more 1MB download (should not fit in the space left over) 568 dlRequest = enqueueDownloadRequest(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); 569 waitForDownloadOrTimeout(dlRequest); 570 571 // For the last download we should have failed b/c there is not enough space left in cache 572 Cursor cursor = getCursor(dlRequest); 573 try { 574 verifyInt(cursor, DownloadManager.COLUMN_REASON, 575 DownloadManager.ERROR_INSUFFICIENT_SPACE); 576 } finally { 577 cursor.close(); 578 } 579 } 580} 581