summaryrefslogtreecommitdiffstats
path: root/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java')
-rw-r--r--tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java172
1 files changed, 138 insertions, 34 deletions
diff --git a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
index 2661a1f2..b6fd611e 100644
--- a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
+++ b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
@@ -16,13 +16,23 @@
package com.android.providers.downloads;
-import static com.google.testing.littlemock.LittleMock.anyInt;
-import static com.google.testing.littlemock.LittleMock.anyString;
-import static com.google.testing.littlemock.LittleMock.atLeastOnce;
-import static com.google.testing.littlemock.LittleMock.isA;
-import static com.google.testing.littlemock.LittleMock.never;
-import static com.google.testing.littlemock.LittleMock.times;
-import static com.google.testing.littlemock.LittleMock.verify;
+import static android.app.DownloadManager.STATUS_FAILED;
+import static android.app.DownloadManager.STATUS_PAUSED;
+import static android.net.TrafficStats.GB_IN_BYTES;
+import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static java.net.HttpURLConnection.HTTP_MOVED_TEMP;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.HttpURLConnection.HTTP_PARTIAL;
+import static java.net.HttpURLConnection.HTTP_PRECON_FAILED;
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.app.DownloadManager;
import android.app.Notification;
@@ -33,20 +43,24 @@ import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Environment;
+import android.os.SystemClock;
import android.provider.Downloads;
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.format.DateUtils;
import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockStreamResponse;
import com.google.mockwebserver.RecordedRequest;
+import com.google.mockwebserver.SocketPolicy;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
import java.util.List;
-
+import java.util.concurrent.TimeoutException;
@LargeTest
public class PublicApiFunctionalTest extends AbstractPublicApiTest {
@@ -76,7 +90,6 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
} else {
mTestDirectory.mkdir();
}
- mSystemFacade.setStartThreadsWithoutWaiting(false);
}
@Override
@@ -122,6 +135,24 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
checkCompleteDownload(download);
}
+ @Suppress
+ public void testExtremelyLarge() throws Exception {
+ // NOTE: suppressed since this takes several minutes to run
+ final long length = 3 * GB_IN_BYTES;
+ final InputStream body = new FakeInputStream(length);
+
+ enqueueResponse(new MockStreamResponse().setResponseCode(HTTP_OK).setBody(body, length)
+ .setHeader("Content-type", "text/plain")
+ .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END));
+
+ final Download download = enqueueRequest(getRequest()
+ .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "extreme.bin"));
+ download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL, 10 * DateUtils.MINUTE_IN_MILLIS);
+
+ assertEquals(length, download.getLongField(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
+ assertEquals(length, download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
+ }
+
private void checkUriContent(Uri uri) throws FileNotFoundException, IOException {
InputStream inputStream = mResolver.openInputStream(uri);
try {
@@ -191,7 +222,7 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
private MockResponse buildPartialResponse(int start, int end) {
int totalLength = FILE_CONTENT.length();
boolean isFirstResponse = (start == 0);
- int status = isFirstResponse ? HTTP_OK : HTTP_PARTIAL_CONTENT;
+ int status = isFirstResponse ? HTTP_OK : HTTP_PARTIAL;
MockResponse response = buildResponse(status, FILE_CONTENT.substring(start, end))
.setHeader("Content-length", totalLength)
.setHeader("Etag", ETAG);
@@ -385,11 +416,72 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
assertEquals(REQUEST_PATH, lastRequest.getPath());
}
+ public void testRunawayRedirect() throws Exception {
+ for (int i = 0; i < 16; i++) {
+ enqueueResponse(buildEmptyResponse(HTTP_MOVED_TEMP)
+ .setHeader("Location", mServer.getUrl("/" + i).toString()));
+ }
+
+ final Download download = enqueueRequest(getRequest());
+
+ // Ensure that we arrive at failed download, instead of spinning forever
+ download.runUntilStatus(DownloadManager.STATUS_FAILED);
+ assertEquals(DownloadManager.ERROR_TOO_MANY_REDIRECTS, download.getReason());
+ }
+
+ public void testRunawayUnavailable() throws Exception {
+ final int RETRY_DELAY = 120;
+ for (int i = 0; i < 16; i++) {
+ enqueueResponse(
+ buildEmptyResponse(HTTP_UNAVAILABLE).setHeader("Retry-after", RETRY_DELAY));
+ }
+
+ final Download download = enqueueRequest(getRequest());
+ for (int i = 0; i < Constants.MAX_RETRIES - 1; i++) {
+ download.runUntilStatus(DownloadManager.STATUS_PAUSED);
+ mSystemFacade.incrementTimeMillis((RETRY_DELAY + 60) * SECOND_IN_MILLIS);
+ }
+
+ // Ensure that we arrive at failed download, instead of spinning forever
+ download.runUntilStatus(DownloadManager.STATUS_FAILED);
+ }
+
public void testNoEtag() throws Exception {
enqueueResponse(buildPartialResponse(0, 5).removeHeader("Etag"));
runSimpleFailureTest(DownloadManager.ERROR_CANNOT_RESUME);
}
+ public void testEtagChanged() throws Exception {
+ final String A = "kittenz";
+ final String B = "puppiez";
+
+ // 1. Try downloading A, but partial result
+ enqueueResponse(buildResponse(HTTP_OK, A.substring(0, 2))
+ .setHeader("Content-length", A.length())
+ .setHeader("Etag", A));
+
+ // 2. Try resuming A, but fail ETag check
+ enqueueResponse(buildEmptyResponse(HTTP_PRECON_FAILED));
+
+ final Download download = enqueueRequest(getRequest());
+ RecordedRequest req;
+
+ // 1. Try downloading A, but partial result
+ download.runUntilStatus(STATUS_PAUSED);
+ assertEquals(DownloadManager.PAUSED_WAITING_TO_RETRY, download.getReason());
+ req = takeRequest();
+ assertNull(getHeaderValue(req, "Range"));
+ assertNull(getHeaderValue(req, "If-Match"));
+
+ // 2. Try resuming A, but fail ETag check
+ mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
+ download.runUntilStatus(STATUS_FAILED);
+ assertEquals(HTTP_PRECON_FAILED, download.getReason());
+ req = takeRequest();
+ assertEquals("bytes=2-", getHeaderValue(req, "Range"));
+ assertEquals(A, getHeaderValue(req, "If-Match"));
+ }
+
public void testSanitizeMediaType() throws Exception {
enqueueResponse(buildEmptyResponse(HTTP_OK)
.setHeader("Content-Type", "text/html; charset=ISO-8859-4"));
@@ -400,7 +492,7 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
public void testNoContentLength() throws Exception {
enqueueResponse(buildEmptyResponse(HTTP_OK).removeHeader("Content-length"));
- runSimpleFailureTest(DownloadManager.ERROR_HTTP_DATA_ERROR);
+ runSimpleFailureTest(DownloadManager.ERROR_CANNOT_RESUME);
}
public void testInsufficientSpace() throws Exception {
@@ -412,22 +504,24 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
}
public void testCancel() throws Exception {
- mSystemFacade.setStartThreadsWithoutWaiting(true);
// return 'real time' from FakeSystemFacade so that DownloadThread will report progress
mSystemFacade.setReturnActualTime(true);
enqueueResponse(buildContinuingResponse());
Download download = enqueueRequest(getRequest());
- startService(null);
// give the download time to get started and progress to 1% completion
// before cancelling it.
boolean rslt = download.runUntilProgress(1);
assertTrue(rslt);
mManager.remove(download.mId);
- startService(null);
- int status = download.runUntilDone();
- // make sure the row is gone from the database
- assertEquals(-1, status);
- mSystemFacade.setReturnActualTime(false);
+
+ // Verify that row is removed from database
+ final long timeout = SystemClock.elapsedRealtime() + (15 * SECOND_IN_MILLIS);
+ while (download.getStatusIfExists() != -1) {
+ if (SystemClock.elapsedRealtime() > timeout) {
+ throw new TimeoutException("Row wasn't removed");
+ }
+ SystemClock.sleep(100);
+ }
}
public void testDownloadCompleteBroadcast() throws Exception {
@@ -512,9 +606,9 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
public void testContentObserver() throws Exception {
enqueueResponse(buildEmptyResponse(HTTP_OK));
- enqueueRequest(getRequest());
mResolver.resetNotified();
- runService();
+ final Download download = enqueueRequest(getRequest());
+ download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
assertTrue(mResolver.mNotifyWasCalled);
}
@@ -524,10 +618,9 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
final Download download = enqueueRequest(
getRequest().setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN));
download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
- runService();
+ verify(mNotifManager, times(1)).cancelAll();
verify(mNotifManager, never()).notify(anyString(), anyInt(), isA(Notification.class));
- // TODO: verify that it never cancels
}
public void testNotificationVisible() throws Exception {
@@ -536,11 +629,10 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
// only shows in-progress notifications
final Download download = enqueueRequest(getRequest());
download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
- runService();
// TODO: verify different notif types with tags
+ verify(mNotifManager, times(1)).cancelAll();
verify(mNotifManager, atLeastOnce()).notify(anyString(), anyInt(), isA(Notification.class));
- verify(mNotifManager, times(1)).cancel(anyString(), anyInt());
}
public void testNotificationVisibleComplete() throws Exception {
@@ -549,17 +641,16 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
final Download download = enqueueRequest(getRequest().setNotificationVisibility(
DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED));
download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
- runService();
// TODO: verify different notif types with tags
+ verify(mNotifManager, times(1)).cancelAll();
verify(mNotifManager, atLeastOnce()).notify(anyString(), anyInt(), isA(Notification.class));
- verify(mNotifManager, times(1)).cancel(anyString(), anyInt());
}
public void testRetryAfter() throws Exception {
final int delay = 120;
enqueueResponse(
- buildEmptyResponse(HTTP_SERVICE_UNAVAILABLE).setHeader("Retry-after", delay));
+ buildEmptyResponse(HTTP_UNAVAILABLE).setHeader("Retry-after", delay));
enqueueResponse(buildEmptyResponse(HTTP_OK));
Download download = enqueueRequest(getRequest());
@@ -643,19 +734,32 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest {
* 3) Resume request to complete download
* @return the last request sent to the server, resuming after the interruption
*/
- private RecordedRequest runRedirectionTest(int status)
- throws MalformedURLException, Exception {
+ private RecordedRequest runRedirectionTest(int status) throws Exception {
enqueueResponse(buildEmptyResponse(status)
.setHeader("Location", mServer.getUrl(REDIRECTED_PATH).toString()));
enqueueInterruptedDownloadResponses(5);
- Download download = enqueueRequest(getRequest());
- runService();
+ final Download download = enqueueRequest(getRequest());
+ download.runUntilStatus(DownloadManager.STATUS_PAUSED);
+ mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
+ download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
+
assertEquals(REQUEST_PATH, takeRequest().getPath());
assertEquals(REDIRECTED_PATH, takeRequest().getPath());
- mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
- download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL);
return takeRequest();
}
+
+ /**
+ * Return value of requested HTTP header, if it exists.
+ */
+ private static String getHeaderValue(RecordedRequest req, String header) {
+ header = header.toLowerCase() + ":";
+ for (String h : req.getHeaders()) {
+ if (h.toLowerCase().startsWith(header)) {
+ return h.substring(header.length()).trim();
+ }
+ }
+ return null;
+ }
}