diff options
3 files changed, 535 insertions, 246 deletions
diff --git a/tests/src/com/android/providers/downloads/AbstractDownloadManagerFunctionalTest.java b/tests/src/com/android/providers/downloads/AbstractDownloadManagerFunctionalTest.java new file mode 100644 index 00000000..1394a17d --- /dev/null +++ b/tests/src/com/android/providers/downloads/AbstractDownloadManagerFunctionalTest.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.providers.downloads; + +import android.content.ComponentName; +import android.content.ContentProvider; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.provider.Downloads; +import android.test.MoreAsserts; +import android.test.RenamingDelegatingContext; +import android.test.ServiceTestCase; +import android.test.mock.MockContentResolver; +import android.util.Log; +import tests.http.MockResponse; +import tests.http.MockWebServer; +import tests.http.RecordedRequest; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public abstract class AbstractDownloadManagerFunctionalTest extends + ServiceTestCase<DownloadService> { + + protected static final String LOG_TAG = "DownloadManagerFunctionalTest"; + private static final String PROVIDER_AUTHORITY = "downloads"; + protected static final long REQUEST_TIMEOUT_MILLIS = 10 * 1000; + protected static final long RETRY_DELAY_MILLIS = 61 * 1000; + protected static final String FILE_CONTENT = "hello world"; + protected static final int HTTP_OK = 200; + protected static final int HTTP_PARTIAL_CONTENT = 206; + protected static final int HTTP_NOT_FOUND = 404; + protected static final int HTTP_SERVICE_UNAVAILABLE = 503; + protected MockWebServer mServer; + protected MockContentResolver mResolver; + protected TestContext mTestContext; + protected FakeSystemFacade mSystemFacade; + + static interface StatusReader { + public int getStatus(); + public boolean isComplete(int status); + } + + /** + * Context passed to the provider and the service. Allows most methods to pass through to the + * real Context (this is a LargeTest), with a few exceptions, including renaming file operations + * to avoid file and DB conflicts (via RenamingDelegatingContext). + */ + static class TestContext extends RenamingDelegatingContext { + private static final String FILENAME_PREFIX = "test."; + + private Context mRealContext; + private Set<String> mAllowedSystemServices; + private ContentResolver mResolver; + + boolean mHasServiceBeenStarted = false; + FakeIConnectivityManager mFakeIConnectivityManager; + + public TestContext(Context realContext) { + super(realContext, FILENAME_PREFIX); + mRealContext = realContext; + mAllowedSystemServices = new HashSet<String>(Arrays.asList(new String[] { + Context.NOTIFICATION_SERVICE, + Context.POWER_SERVICE, + })); + mFakeIConnectivityManager = new FakeIConnectivityManager(); + } + + public void setResolver(ContentResolver resolver) { + mResolver = resolver; + } + + /** + * Direct DownloadService to our test instance of DownloadProvider. + */ + @Override + public ContentResolver getContentResolver() { + assert mResolver != null; + return mResolver; + } + + /** + * Stub some system services, allow access to others, and block the rest. + */ + @Override + public Object getSystemService(String name) { + if (name.equals(Context.CONNECTIVITY_SERVICE)) { + return new ConnectivityManager(mFakeIConnectivityManager); + } + if (mAllowedSystemServices.contains(name)) { + return mRealContext.getSystemService(name); + } + return super.getSystemService(name); + } + + /** + * Record when DownloadProvider starts DownloadService. + */ + @Override + public ComponentName startService(Intent service) { + if (service.getComponent().getClassName().equals(DownloadService.class.getName())) { + mHasServiceBeenStarted = true; + return service.getComponent(); + } + throw new UnsupportedOperationException("Unexpected service: " + service); + } + } + + public AbstractDownloadManagerFunctionalTest() { + super(DownloadService.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + Context realContext = getContext(); + mTestContext = new TestContext(realContext); + setupProviderAndResolver(); + assert isDatabaseEmpty(); // ensure we're not messing with real data + + mTestContext.setResolver(mResolver); + setContext(mTestContext); + setupService(); + mSystemFacade = new FakeSystemFacade(); + getService().mSystemFacade = mSystemFacade; + + mServer = new MockWebServer(); + mServer.play(); + } + + @Override + protected void tearDown() throws Exception { + cleanUpDownloads(); + super.tearDown(); + } + + private boolean isDatabaseEmpty() { + Cursor cursor = mResolver.query(Downloads.CONTENT_URI, null, null, null, null); + try { + return cursor.getCount() == 0; + } finally { + cursor.close(); + } + } + + void setupProviderAndResolver() { + ContentProvider provider = new DownloadProvider(); + provider.attachInfo(mTestContext, null); + mResolver = new MockContentResolver(); + mResolver.addProvider(PROVIDER_AUTHORITY, provider); + } + + /** + * Remove any downloaded files and delete any lingering downloads. + */ + void cleanUpDownloads() { + if (mResolver == null) { + return; + } + String[] columns = new String[] {Downloads._DATA}; + Cursor cursor = mResolver.query(Downloads.CONTENT_URI, columns, null, null, null); + try { + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + String filePath = cursor.getString(0); + if (filePath == null) continue; + Log.d(LOG_TAG, "Deleting " + filePath); + new File(filePath).delete(); + } + } finally { + cursor.close(); + } + mResolver.delete(Downloads.CONTENT_URI, null, null); + } + + /** + * Enqueue a response from the MockWebServer. + */ + MockResponse enqueueResponse(int status, String body) { + MockResponse response = new MockResponse() + .setResponseCode(status) + .setBody(body) + .addHeader("Content-type", "text/plain"); + mServer.enqueue(response); + return response; + } + + MockResponse enqueueEmptyResponse(int status) { + return enqueueResponse(status, ""); + } + + /** + * Wait for a request to come to the MockWebServer and return it. + */ + RecordedRequest takeRequest() throws InterruptedException { + RecordedRequest request = mServer.takeRequestWithTimeout(REQUEST_TIMEOUT_MILLIS); + assertNotNull("Timed out waiting for request", request); + return request; + } + + String getServerUri(String path) throws MalformedURLException { + return mServer.getUrl(path).toString(); + } + + /** + * Run the service and wait for a request and for the download to reach the given status. + * @return the request received + */ + protected RecordedRequest runUntilStatus(StatusReader reader, int status) throws Exception { + startService(null); + RecordedRequest request = takeRequest(); + waitForDownloadToStop(reader, status); + return request; + } + + /** + * Wait for a download to given a given status, with a timeout. Fails if the download reaches + * any other final status. + */ + protected void waitForDownloadToStop(StatusReader reader, int expectedStatus) + throws Exception { + // TODO(showard): find a better way to accomplish this + long startTimeMillis = System.currentTimeMillis(); + int status = reader.getStatus(); + while (status != expectedStatus) { + if (reader.isComplete(status)) { + fail("Download completed with unexpected status: " + status); + } + if (System.currentTimeMillis() > startTimeMillis + REQUEST_TIMEOUT_MILLIS) { + fail("Download timed out with status " + status); + } + Thread.sleep(100); + mServer.checkForExceptions(); + status = reader.getStatus(); + } + + long delta = System.currentTimeMillis() - startTimeMillis; + Log.d(LOG_TAG, "Status " + status + " reached after " + delta + "ms"); + } + + protected String readStream(InputStream inputStream) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + try { + char[] buffer = new char[1024]; + int length = reader.read(buffer); + assertTrue("Failed to read anything from input stream", length > -1); + return String.valueOf(buffer, 0, length); + } finally { + reader.close(); + } + } + + protected void assertStartsWith(String expectedPrefix, String actual) { + String regex = "^" + expectedPrefix + ".*"; + MoreAsserts.assertMatchesRegex(regex, actual); + } +} diff --git a/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java b/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java index 8d4655bb..7de90de5 100644 --- a/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java +++ b/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java @@ -16,38 +16,19 @@ package com.android.providers.downloads; -import android.content.ComponentName; -import android.content.ContentProvider; -import android.content.ContentResolver; import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; 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; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; -import tests.http.MockResponse; import tests.http.MockWebServer; import tests.http.RecordedRequest; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.net.MalformedURLException; -import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; /** * This test exercises the entire download manager working together -- it requests downloads through @@ -56,157 +37,7 @@ import java.util.Set; * device to serve downloads. */ @LargeTest -public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadService> { - 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 int HTTP_PARTIAL_CONTENT = 206; - private static final int HTTP_NOT_FOUND = 404; - 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 - * real Context (this is a LargeTest), with a few exceptions, including renaming file operations - * to avoid file and DB conflicts (via RenamingDelegatingContext). - */ - private static class TestContext extends RenamingDelegatingContext { - private static final String FILENAME_PREFIX = "test."; - - private Context mRealContext; - private Set<String> mAllowedSystemServices; - private ContentResolver mResolver; - - boolean mHasServiceBeenStarted = false; - FakeIConnectivityManager mFakeIConnectivityManager; - - public TestContext(Context realContext) { - super(realContext, FILENAME_PREFIX); - mRealContext = realContext; - mAllowedSystemServices = new HashSet<String>(Arrays.asList(new String[] { - Context.NOTIFICATION_SERVICE, - Context.POWER_SERVICE, - })); - mFakeIConnectivityManager = new FakeIConnectivityManager(); - } - - public void setResolver(ContentResolver resolver) { - mResolver = resolver; - } - - /** - * Direct DownloadService to our test instance of DownloadProvider. - */ - @Override - public ContentResolver getContentResolver() { - assert mResolver != null; - return mResolver; - } - - /** - * Stub some system services, allow access to others, and block the rest. - */ - @Override - public Object getSystemService(String name) { - if (name.equals(Context.CONNECTIVITY_SERVICE)) { - return new ConnectivityManager(mFakeIConnectivityManager); - } - if (mAllowedSystemServices.contains(name)) { - return mRealContext.getSystemService(name); - } - return super.getSystemService(name); - } - - /** - * Record when DownloadProvider starts DownloadService. - */ - @Override - public ComponentName startService(Intent service) { - if (service.getComponent().getClassName().equals(DownloadService.class.getName())) { - mHasServiceBeenStarted = true; - return service.getComponent(); - } - throw new UnsupportedOperationException("Unexpected service: " + service); - } - } - - public DownloadManagerFunctionalTest() { - super(DownloadService.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - Context realContext = getContext(); - mTestContext = new TestContext(realContext); - setupProviderAndResolver(); - assert isDatabaseEmpty(); // ensure we're not messing with real data - - mTestContext.setResolver(mResolver); - setContext(mTestContext); - setupService(); - mSystemFacade = new FakeSystemFacade(); - getService().mSystemFacade = mSystemFacade; - - mServer = new MockWebServer(); - mServer.play(); - } - - private void setupProviderAndResolver() { - ContentProvider provider = new DownloadProvider(); - provider.attachInfo(mTestContext, null); - mResolver = new MockContentResolver(); - mResolver.addProvider(PROVIDER_AUTHORITY, provider); - } - - private boolean isDatabaseEmpty() { - Cursor cursor = mResolver.query(Downloads.CONTENT_URI, null, null, null, null); - try { - return cursor.getCount() == 0; - } finally { - cursor.close(); - } - } - - @Override - protected void tearDown() throws Exception { - cleanUpDownloads(); - super.tearDown(); - } - - /** - * Remove any downloaded files and delete any lingering downloads. - */ - private void cleanUpDownloads() { - if (mResolver == null) { - return; - } - String[] columns = new String[] {Downloads._DATA}; - Cursor cursor = mResolver.query(Downloads.CONTENT_URI, columns, null, null, null); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - String filePath = cursor.getString(0); - if (filePath == null) continue; - Log.d(LOG_TAG, "Deleting " + filePath); - new File(filePath).delete(); - } - } finally { - cursor.close(); - } - mResolver.delete(Downloads.CONTENT_URI, null, null); - } - +public class DownloadManagerFunctionalTest extends AbstractDownloadManagerFunctionalTest { public void testBasicRequest() throws Exception { enqueueResponse(HTTP_OK, FILE_CONTENT); @@ -273,7 +104,7 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi // without connectivity, download immediately pauses mTestContext.mFakeIConnectivityManager.setNetworkState(NetworkInfo.State.DISCONNECTED); startService(null); - waitForDownloadToStop(downloadUri, Downloads.STATUS_RUNNING_PAUSED); + super.waitForDownloadToStop(getStatusReader(downloadUri), Downloads.STATUS_RUNNING_PAUSED); // connecting should start the download mTestContext.mFakeIConnectivityManager.setNetworkState(NetworkInfo.State.CONNECTED); @@ -310,47 +141,6 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi assertEquals(FILE_CONTENT, getDownloadContents(downloadUri)); } - private void assertStartsWith(String expectedPrefix, String actual) { - String regex = "^" + expectedPrefix + ".*"; - MoreAsserts.assertMatchesRegex(regex, actual); - } - - /** - * Enqueue a response from the MockWebServer. - */ - private MockResponse enqueueResponse(int status, String body) { - MockResponse response = new MockResponse() - .setResponseCode(status) - .setBody(body) - .addHeader("Content-type", "text/plain"); - mServer.enqueue(response); - return response; - } - - 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; - } - - /** - * Wait for a request to come to the MockWebServer and return it. - */ - private RecordedRequest takeRequest() throws InterruptedException { - RecordedRequest request = mServer.takeRequestWithTimeout(REQUEST_TIMEOUT_MILLIS); - assertNotNull("Timed out waiting for request", request); - return request; - } - /** * Read a downloaded file from disk. */ @@ -363,31 +153,23 @@ 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) throws Exception { - // TODO(showard): find a better way to accomplish this - long startTimeMillis = System.currentTimeMillis(); - int status = getDownloadStatus(downloadUri); - while (status != expectedStatus) { - if (!Downloads.isStatusInformational(status)) { - fail("Download completed with unexpected status: " + status); - } - if (System.currentTimeMillis() > startTimeMillis + REQUEST_TIMEOUT_MILLIS) { - fail("Download timed out with status " + status); + private RecordedRequest runUntilStatus(Uri downloadUri, int status) throws Exception { + return super.runUntilStatus(getStatusReader(downloadUri), status); + } + + private StatusReader getStatusReader(final Uri downloadUri) { + return new StatusReader() { + public int getStatus() { + return getDownloadStatus(downloadUri); } - Thread.sleep(100); - mServer.checkForExceptions(); - status = getDownloadStatus(downloadUri); - } - long delta = System.currentTimeMillis() - startTimeMillis; - Log.d(LOG_TAG, "Status " + status + " reached after " + delta + "ms"); + public boolean isComplete(int status) { + return !Downloads.isStatusInformational(status); + } + }; } - private int getDownloadStatus(Uri downloadUri) { + protected int getDownloadStatus(Uri downloadUri) { return Integer.valueOf(getDownloadField(downloadUri, Downloads.COLUMN_STATUS)); } @@ -412,7 +194,7 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi */ private Uri requestDownload(String path) throws MalformedURLException { ContentValues values = new ContentValues(); - values.put(Downloads.COLUMN_URI, mServer.getUrl(path).toString()); + values.put(Downloads.COLUMN_URI, getServerUri(path)); values.put(Downloads.COLUMN_DESTINATION, Downloads.DESTINATION_EXTERNAL); return mResolver.insert(Downloads.CONTENT_URI, values); } @@ -426,16 +208,4 @@ public class DownloadManagerFunctionalTest extends ServiceTestCase<DownloadServi 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 { - char[] buffer = new char[1024]; - int length = reader.read(buffer); - assertTrue("Failed to read anything from input stream", length > -1); - return String.valueOf(buffer, 0, length); - } finally { - reader.close(); - } - } } diff --git a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java new file mode 100644 index 00000000..1927545f --- /dev/null +++ b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.providers.downloads; + +import android.database.Cursor; +import android.net.DownloadManager; +import android.net.Uri; +import android.os.Environment; +import tests.http.RecordedRequest; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.MalformedURLException; + +public class PublicApiFunctionalTest extends AbstractDownloadManagerFunctionalTest { + /** + * + */ + private static final String REQUEST_PATH = "/path"; + + class Download implements StatusReader { + final long mId; + + private Download(long downloadId) { + this.mId = downloadId; + } + + public int getStatus() { + return (int) getLongField(DownloadManager.COLUMN_STATUS); + } + + public boolean isComplete(int status) { + return status != DownloadManager.STATUS_PENDING + && status != DownloadManager.STATUS_RUNNING + && status != DownloadManager.STATUS_PAUSED; + } + + String getStringField(String field) { + Cursor cursor = mManager.query(new DownloadManager.Query().setFilterById(mId)); + try { + assertEquals(1, cursor.getCount()); + cursor.moveToFirst(); + return cursor.getString(cursor.getColumnIndexOrThrow(field)); + } finally { + cursor.close(); + } + } + + long getLongField(String field) { + Cursor cursor = mManager.query(new DownloadManager.Query().setFilterById(mId)); + try { + assertEquals(1, cursor.getCount()); + cursor.moveToFirst(); + return cursor.getLong(cursor.getColumnIndexOrThrow(field)); + } finally { + cursor.close(); + } + } + + String getContents() throws Exception { + InputStream stream = new FileInputStream( + mManager.openDownloadedFile(mId).getFileDescriptor()); + try { + return readStream(stream); + } finally { + stream.close(); + } + } + + RecordedRequest runUntilStatus(int status) throws Exception { + return PublicApiFunctionalTest.this.runUntilStatus(this, status); + } + } + + private DownloadManager mManager; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mManager = new DownloadManager(mResolver); + } + + public void testBasicRequest() throws Exception { + enqueueResponse(HTTP_OK, FILE_CONTENT); + + Download download = enqueueRequest(getRequest()); + assertEquals(DownloadManager.STATUS_PENDING, + download.getLongField(DownloadManager.COLUMN_STATUS)); + assertEquals(getServerUri(REQUEST_PATH), + download.getStringField(DownloadManager.COLUMN_URI)); + assertEquals(download.mId, download.getLongField(DownloadManager.COLUMN_ID)); + + RecordedRequest request = download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); + assertEquals("GET", request.getMethod()); + assertEquals(REQUEST_PATH, request.getPath()); + + Uri localUri = Uri.parse(download.getStringField(DownloadManager.COLUMN_LOCAL_URI)); + assertEquals("file", localUri.getScheme()); + assertStartsWith(Environment.getDownloadCacheDirectory().getPath(), + localUri.getSchemeSpecificPart()); + assertEquals("text/plain", download.getStringField(DownloadManager.COLUMN_MEDIA_TYPE)); + + int size = FILE_CONTENT.length(); + assertEquals(size, download.getLongField(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); + assertEquals(size, download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); + + assertEquals(FILE_CONTENT, download.getContents()); + } + + public void testTitleAndDescription() throws Exception { + Download download = enqueueRequest(getRequest() + .setTitle("my title") + .setDescription("my description")); + assertEquals("my title", download.getStringField(DownloadManager.COLUMN_TITLE)); + assertEquals("my description", + download.getStringField(DownloadManager.COLUMN_DESCRIPTION)); + } + + public void testDownloadError() throws Exception { + enqueueEmptyResponse(HTTP_NOT_FOUND); + Download download = enqueueRequest(getRequest()); + download.runUntilStatus(DownloadManager.STATUS_FAILED); + assertEquals(HTTP_NOT_FOUND, download.getLongField(DownloadManager.COLUMN_ERROR_CODE)); + } + + public void testUnhandledHttpStatus() throws Exception { + enqueueEmptyResponse(1234); // some invalid HTTP status + Download download = enqueueRequest(getRequest()); + download.runUntilStatus(DownloadManager.STATUS_FAILED); + assertEquals(DownloadManager.ERROR_UNHANDLED_HTTP_CODE, + download.getLongField(DownloadManager.COLUMN_ERROR_CODE)); + } + + public void testInterruptedDownload() throws Exception { + int initialLength = 5; + String etag = "my_etag"; + int totalLength = FILE_CONTENT.length(); + // the first response has normal headers but unexpectedly closes after initialLength bytes + enqueueResponse(HTTP_OK, FILE_CONTENT.substring(0, initialLength)) + .addHeader("Content-length", totalLength) + .addHeader("Etag", etag) + .setCloseConnectionAfter(true); + Download download = enqueueRequest(getRequest()); + + download.runUntilStatus(DownloadManager.STATUS_PAUSED); + assertEquals(initialLength, + download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); + + 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", + "bytes " + initialLength + "-" + totalLength + "/" + totalLength) + .addHeader("Etag", etag); + download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); + assertEquals(totalLength, + download.getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); + } + + public void testFiltering() throws Exception { + enqueueEmptyResponse(HTTP_OK); + Download download1 = enqueueRequest(getRequest()); + download1.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); + enqueueEmptyResponse(HTTP_NOT_FOUND); + Download download2 = enqueueRequest(getRequest()); + download2.runUntilStatus(DownloadManager.STATUS_FAILED); + Download download3 = enqueueRequest(getRequest()); + + Cursor cursor = mManager.query(new DownloadManager.Query()); + checkAndCloseCursor(cursor, download1, download2, download3); + + cursor = mManager.query(new DownloadManager.Query().setFilterById(download2.mId)); + checkAndCloseCursor(cursor, download2); + + cursor = mManager.query(new DownloadManager.Query() + .setFilterByStatus(DownloadManager.STATUS_PENDING)); + checkAndCloseCursor(cursor, download3); + + cursor = mManager.query(new DownloadManager.Query() + .setFilterByStatus(DownloadManager.STATUS_FAILED + | DownloadManager.STATUS_SUCCESSFUL)); + checkAndCloseCursor(cursor, download1, download2); + + cursor = mManager.query(new DownloadManager.Query() + .setFilterByStatus(DownloadManager.STATUS_RUNNING)); + checkAndCloseCursor(cursor); + } + + private void checkAndCloseCursor(Cursor cursor, Download... downloads) { + try { + int idIndex = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID); + assertEquals(downloads.length, cursor.getCount()); + cursor.moveToFirst(); + for (Download download : downloads) { + assertEquals(download.mId, cursor.getLong(idIndex)); + cursor.moveToNext(); + } + } finally { + cursor.close(); + } + } + + public void testInvalidUri() throws Exception { + try { + enqueueRequest(getRequest("/no_host")); + } catch (IllegalArgumentException exc) { // expected + return; + } + + fail("No exception thrown for invalid URI"); + } + + private DownloadManager.Request getRequest() throws MalformedURLException { + return getRequest(getServerUri(REQUEST_PATH)); + } + + private DownloadManager.Request getRequest(String path) { + return new DownloadManager.Request(Uri.parse(path)); + } + + private Download enqueueRequest(DownloadManager.Request request) { + return new Download(mManager.enqueue(request)); + } +} |