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