summaryrefslogtreecommitdiffstats
path: root/tests/src
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src')
-rw-r--r--tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java150
-rw-r--r--tests/src/com/android/providers/downloads/FakeSystemFacade.java13
-rw-r--r--tests/src/tests/http/MockWebServer.java33
3 files changed, 142 insertions, 54 deletions
diff --git a/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java b/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java
index 76b3d589..8d4655bb 100644
--- a/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java
+++ b/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java
@@ -26,7 +26,9 @@ import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
+import android.os.Environment;
import android.provider.Downloads;
+import android.test.MoreAsserts;
import android.test.RenamingDelegatingContext;
import android.test.ServiceTestCase;
import android.test.mock.MockContentResolver;
@@ -55,18 +57,23 @@ import java.util.Set;
*/
@LargeTest
public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadService> {
- private static final int HTTP_PARTIAL_CONTENT = 206;
+ private static final String LOG_TAG = "DownloadManagerFunctionalTest";
+
private static final String PROVIDER_AUTHORITY = "downloads";
+ private static final int RETRY_DELAY_MILLIS = 61 * 1000;
+ private static final long REQUEST_TIMEOUT_MILLIS = 10 * 1000;
+ private static final String FILE_CONTENT = "hello world";
+
private static final int HTTP_OK = 200;
- private static final String LOG_TAG = "DownloadManagerFunctionalTest";
+ private static final int HTTP_PARTIAL_CONTENT = 206;
private static final int HTTP_NOT_FOUND = 404;
- private static final String FILE_CONTENT = "hello world";
- private static final long REQUEST_TIMEOUT_MILLIS = 5000;
+ private static final int HTTP_SERVICE_UNAVAILABLE = 503;
private MockWebServer mServer;
// resolves requests to the DownloadProvider we set up
private MockContentResolver mResolver;
private TestContext mTestContext;
+ private FakeSystemFacade mSystemFacade;
/**
* Context passed to the provider and the service. Allows most methods to pass through to the
@@ -148,6 +155,9 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
mTestContext.setResolver(mResolver);
setContext(mTestContext);
+ setupService();
+ mSystemFacade = new FakeSystemFacade();
+ getService().mSystemFacade = mSystemFacade;
mServer = new MockWebServer();
mServer.play();
@@ -205,26 +215,55 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
assertEquals(Downloads.STATUS_PENDING, getDownloadStatus(downloadUri));
assertTrue(mTestContext.mHasServiceBeenStarted);
- startService(null);
-
- RecordedRequest request = takeRequest();
+ RecordedRequest request = runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
assertEquals("GET", request.getMethod());
assertEquals(path, request.getPath());
+ assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
+ assertStartsWith(Environment.getExternalStorageDirectory().getPath(),
+ getDownloadFilename(downloadUri));
+ }
- waitForDownloadToStop(downloadUri, Downloads.STATUS_SUCCESS);
+ public void testDownloadToCache() throws Exception {
+ enqueueResponse(HTTP_OK, FILE_CONTENT);
+ Uri downloadUri = requestDownload("/path");
+ updateDownload(downloadUri, Downloads.COLUMN_DESTINATION,
+ Integer.toString(Downloads.DESTINATION_CACHE_PARTITION));
+ runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
- checkForUnexpectedRequests();
+ assertStartsWith(Environment.getDownloadCacheDirectory().getPath(),
+ getDownloadFilename(downloadUri));
}
public void testFileNotFound() throws Exception {
enqueueEmptyResponse(HTTP_NOT_FOUND);
Uri downloadUri = requestDownload("/nonexistent_path");
assertEquals(Downloads.STATUS_PENDING, getDownloadStatus(downloadUri));
+ runUntilStatus(downloadUri, HTTP_NOT_FOUND);
+ }
- startService(null);
- takeRequest();
- waitForDownloadToStop(downloadUri, HTTP_NOT_FOUND);
- checkForUnexpectedRequests();
+ public void testRetryAfter() throws Exception {
+ final int delay = 120;
+ enqueueEmptyResponse(HTTP_SERVICE_UNAVAILABLE).addHeader("Retry-after", delay);
+ Uri downloadUri = requestDownload("/path");
+ runUntilStatus(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
+
+ // download manager adds random 0-30s offset
+ mSystemFacade.incrementTimeMillis((delay + 31) * 1000);
+
+ enqueueResponse(HTTP_OK, FILE_CONTENT);
+ runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
+ }
+
+ public void testRedirect() throws Exception {
+ enqueueEmptyResponse(301).addHeader("Location", mServer.getUrl("/other_path").toString());
+ enqueueResponse(HTTP_OK, FILE_CONTENT);
+ Uri downloadUri = requestDownload("/path");
+ RecordedRequest request = runUntilStatus(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
+ assertEquals("/path", request.getPath());
+
+ mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
+ request = runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
+ assertEquals("/other_path", request.getPath());
}
public void testBasicConnectivityChanges() throws Exception {
@@ -235,18 +274,13 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
mTestContext.mFakeIConnectivityManager.setNetworkState(NetworkInfo.State.DISCONNECTED);
startService(null);
waitForDownloadToStop(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
- checkForUnexpectedRequests();
// connecting should start the download
mTestContext.mFakeIConnectivityManager.setNetworkState(NetworkInfo.State.CONNECTED);
- startService(null); // normally done by DownloadReceiver
- takeRequest();
- waitForDownloadToStop(downloadUri, Downloads.STATUS_SUCCESS);
- checkForUnexpectedRequests();
+ runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
}
- // disabled due to excessive sleep
- public void disabledTestInterruptedDownload() throws Exception {
+ public void testInterruptedDownload() throws Exception {
int initialLength = 5;
String etag = "my_etag";
int totalLength = FILE_CONTENT.length();
@@ -257,12 +291,9 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
.setCloseConnectionAfter(true);
Uri downloadUri = requestDownload("/path");
- startService(null);
- takeRequest();
- waitForDownloadToStop(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
+ runUntilStatus(downloadUri, Downloads.STATUS_RUNNING_PAUSED);
- Thread.sleep(61 * 1000); // TODO: avoid this by stubbing the system clock
- mServer.drainRequests();
+ mSystemFacade.incrementTimeMillis(RETRY_DELAY_MILLIS);
// the second response returns partial content for the rest of the data
enqueueResponse(HTTP_PARTIAL_CONTENT, FILE_CONTENT.substring(initialLength))
.addHeader("Content-range",
@@ -270,17 +301,18 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
.addHeader("Etag", etag);
// TODO: ideally we wouldn't need to call startService again, but there's a bug where the
// service won't retry a download until an intent comes in
- startService(null);
- waitForDownloadToStop(downloadUri, Downloads.STATUS_SUCCESS);
+ RecordedRequest request = runUntilStatus(downloadUri, Downloads.STATUS_SUCCESS);
- RecordedRequest request = takeRequest();
List<String> headers = request.getHeaders();
assertTrue("No Range header: " + headers,
headers.contains("Range: bytes=" + initialLength + "-"));
assertTrue("No ETag header: " + headers, headers.contains("If-Match: " + etag));
-
assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
- checkForUnexpectedRequests();
+ }
+
+ private void assertStartsWith(String expectedPrefix, String actual) {
+ String regex = "^" + expectedPrefix + ".*";
+ MoreAsserts.assertMatchesRegex(regex, actual);
}
/**
@@ -295,8 +327,19 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
return response;
}
- private void enqueueEmptyResponse(int status) {
- enqueueResponse(status, "");
+ private MockResponse enqueueEmptyResponse(int status) {
+ return enqueueResponse(status, "");
+ }
+
+ /**
+ * Run the service and wait for a request and for the download to reach the given status.
+ * @return the request received
+ */
+ private RecordedRequest runUntilStatus(Uri downloadUri, int status) throws Exception {
+ startService(null);
+ RecordedRequest request = takeRequest();
+ waitForDownloadToStop(downloadUri, status);
+ return request;
}
/**
@@ -324,7 +367,7 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
* Wait for a download to given a given status, with a timeout. Fails if the download reaches
* any other final status.
*/
- private void waitForDownloadToStop(Uri downloadUri, int expectedStatus) {
+ private void waitForDownloadToStop(Uri downloadUri, int expectedStatus) throws Exception {
// TODO(showard): find a better way to accomplish this
long startTimeMillis = System.currentTimeMillis();
int status = getDownloadStatus(downloadUri);
@@ -335,11 +378,8 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
if (System.currentTimeMillis() > startTimeMillis + REQUEST_TIMEOUT_MILLIS) {
fail("Download timed out with status " + status);
}
- try {
- Thread.sleep(100);
- } catch (InterruptedException exc) {
- // no problem
- }
+ Thread.sleep(100);
+ mServer.checkForExceptions();
status = getDownloadStatus(downloadUri);
}
@@ -348,12 +388,20 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
}
private int getDownloadStatus(Uri downloadUri) {
- final String[] columns = new String[] {Downloads.COLUMN_STATUS};
+ return Integer.valueOf(getDownloadField(downloadUri, Downloads.COLUMN_STATUS));
+ }
+
+ private String getDownloadFilename(Uri downloadUri) {
+ return getDownloadField(downloadUri, Downloads._DATA);
+ }
+
+ private String getDownloadField(Uri downloadUri, String column) {
+ final String[] columns = new String[] {column};
Cursor cursor = mResolver.query(downloadUri, columns, null, null, null);
try {
assertEquals(1, cursor.getCount());
cursor.moveToFirst();
- return cursor.getInt(0);
+ return cursor.getString(0);
} finally {
cursor.close();
}
@@ -369,6 +417,16 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
return mResolver.insert(Downloads.CONTENT_URI, values);
}
+ /**
+ * Update one field of a download in the provider.
+ */
+ private void updateDownload(Uri downloadUri, String column, String value) {
+ ContentValues values = new ContentValues();
+ values.put(column, value);
+ int numChanged = mResolver.update(downloadUri, values, null, null);
+ assertEquals(1, numChanged);
+ }
+
private String readStream(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
@@ -380,16 +438,4 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi
reader.close();
}
}
-
- /**
- * Check for any extra requests made to the MockWebServer that weren't consumed with
- * {@link #takeRequest()}.
- */
- private void checkForUnexpectedRequests() {
- if (mServer == null) {
- return;
- }
- List<RecordedRequest> extraRequests = mServer.drainRequests();
- assertEquals("Invalid requests: " + extraRequests.toString(), 0, extraRequests.size());
- }
}
diff --git a/tests/src/com/android/providers/downloads/FakeSystemFacade.java b/tests/src/com/android/providers/downloads/FakeSystemFacade.java
new file mode 100644
index 00000000..b75e663a
--- /dev/null
+++ b/tests/src/com/android/providers/downloads/FakeSystemFacade.java
@@ -0,0 +1,13 @@
+package com.android.providers.downloads;
+
+public class FakeSystemFacade implements SystemFacade {
+ private long mTimeMillis = 0;
+
+ void incrementTimeMillis(long delta) {
+ mTimeMillis += delta;
+ }
+
+ public long currentTimeMillis() {
+ return mTimeMillis;
+ }
+}
diff --git a/tests/src/tests/http/MockWebServer.java b/tests/src/tests/http/MockWebServer.java
index b2cb8d7b..11c8063e 100644
--- a/tests/src/tests/http/MockWebServer.java
+++ b/tests/src/tests/http/MockWebServer.java
@@ -27,13 +27,18 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* A scriptable web server. Callers supply canned responses and the server
@@ -50,6 +55,8 @@ public final class MockWebServer {
= new LinkedBlockingQueue<MockResponse>();
private int bodyLimit = Integer.MAX_VALUE;
private final ExecutorService executor = Executors.newCachedThreadPool();
+ // keep Futures around so we can rethrow any exceptions thrown by Callables
+ private final Queue<Future<?>> futures = new LinkedList<Future<?>>();
private int port = -1;
@@ -107,7 +114,7 @@ public final class MockWebServer {
final ServerSocket ss = new ServerSocket(0);
ss.setReuseAddress(true);
port = ss.getLocalPort();
- executor.submit(new Callable<Void>() {
+ submitCallable(new Callable<Void>() {
public Void call() throws Exception {
int count = 0;
while (true) {
@@ -125,7 +132,7 @@ public final class MockWebServer {
}
private void serveConnection(final Socket s) {
- executor.submit(new Callable<Void>() {
+ submitCallable(new Callable<Void>() {
public Void call() throws Exception {
InputStream in = new BufferedInputStream(s.getInputStream());
OutputStream out = new BufferedOutputStream(s.getOutputStream());
@@ -156,6 +163,28 @@ public final class MockWebServer {
});
}
+ private void submitCallable(Callable<?> callable) {
+ Future<?> future = executor.submit(callable);
+ futures.add(future);
+ }
+
+ /**
+ * Check for and raise any exceptions that have been thrown by child threads. Will not block on
+ * children still running.
+ * @throws ExecutionException for the first child thread that threw an exception
+ */
+ public void checkForExceptions() throws ExecutionException, InterruptedException {
+ final int originalSize = futures.size();
+ for (int i = 0; i < originalSize; i++) {
+ Future<?> future = futures.remove();
+ try {
+ future.get(0, TimeUnit.SECONDS);
+ } catch (TimeoutException e) {
+ futures.add(future); // still running
+ }
+ }
+ }
+
/**
* @param sequenceNumber the index of this request on this connection.
*/