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