diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index b1e38ee4e3bbf..f2857fa54641f 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -36,6 +36,9 @@ android:description="@string/permdesc_testDenied" /> + + + diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java index 8df37ad7eda28..1bb2a576c955c 100644 --- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java @@ -16,8 +16,12 @@ package android.app; +import coretestutils.http.MockResponse; +import coretestutils.http.MockWebServer; + import android.app.DownloadManager.Query; import android.app.DownloadManager.Request; +import android.app.DownloadManagerBaseTest.DataType; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -27,11 +31,10 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.net.wifi.WifiManager; -import android.os.Bundle; import android.os.Environment; import android.os.ParcelFileDescriptor; -import android.os.SystemClock; import android.os.ParcelFileDescriptor.AutoCloseInputStream; +import android.os.SystemClock; import android.provider.Settings; import android.test.InstrumentationTestCase; import android.util.Log; @@ -43,19 +46,12 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; -import java.util.concurrent.TimeoutException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.Iterator; -import java.util.List; import java.util.Random; import java.util.Set; -import java.util.Vector; - -import junit.framework.AssertionFailedError; - -import coretestutils.http.MockResponse; -import coretestutils.http.MockWebServer; +import java.util.concurrent.TimeoutException; /** * Base class for Instrumented tests for the Download Manager. @@ -67,7 +63,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { protected String mFileType = "text/plain"; protected Context mContext = null; protected MultipleDownloadsCompletedReceiver mReceiver = null; - protected static final int DEFAULT_FILE_SIZE = 130 * 1024; // 130kb + protected static final int DEFAULT_FILE_SIZE = 10 * 1024; // 10kb protected static final int FILE_BLOCK_READ_SIZE = 1024 * 1024; protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest"; @@ -85,6 +81,9 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes + protected static final int DOWNLOAD_TO_SYSTEM_CACHE = 1; + protected static final int DOWNLOAD_TO_DOWNLOAD_CACHE_DIR = 2; + // Just a few popular file types used to return from a download protected enum DownloadFileType { PLAINTEXT, @@ -888,30 +887,46 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { */ protected void removeAllCurrentDownloads() { Log.i(LOG_TAG, "Removing all current registered downloads..."); + ArrayList ids = new ArrayList(); Cursor cursor = mDownloadManager.query(new Query()); try { if (cursor.moveToFirst()) { do { int index = cursor.getColumnIndex(DownloadManager.COLUMN_ID); long downloadId = cursor.getLong(index); - - mDownloadManager.remove(downloadId); + ids.add(downloadId); } while (cursor.moveToNext()); } } finally { cursor.close(); } + // delete all ids + for (long id : ids) { + mDownloadManager.remove(id); + } + // make sure the database is empty + cursor = mDownloadManager.query(new Query()); + try { + assertEquals(0, cursor.getCount()); + } finally { + cursor.close(); + } } /** * Helper to perform a standard enqueue of data to the mock server. + * download is performed to the downloads cache dir (NOT systemcache dir) * * @param body The body to return in the response from the server */ protected long doStandardEnqueue(byte[] body) throws Exception { + return enqueueDownloadRequest(body, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); + } + + protected long enqueueDownloadRequest(byte[] body, int location) throws Exception { // Prepare the mock server with a standard response enqueueResponse(HTTP_OK, body); - return doCommonStandardEnqueue(); + return doEnqueue(location); } /** @@ -920,9 +935,13 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { * @param body The body to return in the response from the server, contained in the file */ protected long doStandardEnqueue(File body) throws Exception { + return enqueueDownloadRequest(body, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); + } + + protected long enqueueDownloadRequest(File body, int location) throws Exception { // Prepare the mock server with a standard response enqueueResponse(HTTP_OK, body); - return doCommonStandardEnqueue(); + return doEnqueue(location); } /** @@ -930,13 +949,17 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { * doing a standard enqueue request to the server. */ protected long doCommonStandardEnqueue() throws Exception { - Uri uri = getServerUri(DEFAULT_FILENAME); - Request request = new Request(uri); - request.setTitle(DEFAULT_FILENAME); + return doEnqueue(DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); + } - long dlRequest = mDownloadManager.enqueue(request); - Log.i(LOG_TAG, "request ID: " + dlRequest); - return dlRequest; + private long doEnqueue(int location) throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + Request request = new Request(uri).setTitle(DEFAULT_FILENAME); + if (location == DOWNLOAD_TO_SYSTEM_CACHE) { + request.setDestinationToSystemCache(); + } + + return mDownloadManager.enqueue(request); } /** @@ -997,4 +1020,16 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { return cursor; } + /** + * Helper that does the actual basic download verification. + */ + protected long doBasicDownload(byte[] blobData, int location) throws Exception { + long dlRequest = enqueueDownloadRequest(blobData, location); + + // wait for the download to complete + waitForDownloadOrTimeout(dlRequest); + + assertEquals(1, mReceiver.numDownloadsCompleted()); + return dlRequest; + } } \ No newline at end of file diff --git a/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java similarity index 80% rename from core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java rename to core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java index 4f7910847e28b..06f3ba448c167 100644 --- a/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java @@ -16,51 +16,35 @@ package android.app; +import coretestutils.http.MockResponse; + import android.app.DownloadManager.Query; import android.app.DownloadManager.Request; import android.app.DownloadManagerBaseTest.DataType; -import android.app.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.database.Cursor; import android.net.Uri; -import android.net.wifi.WifiManager; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.StatFs; -import android.os.SystemClock; -import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import java.io.File; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; -import java.net.URL; import java.util.Iterator; import java.util.Random; import java.util.Set; -import junit.framework.AssertionFailedError; - -import coretestutils.http.MockResponse; -import coretestutils.http.MockWebServer; - /** * Integration tests of the DownloadManager API. */ -public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { - - private final static String LOG_TAG = "android.net.DownloadManagerIntegrationTest"; - private final static String PROHIBITED_DIRECTORY = - Environment.getRootDirectory().getAbsolutePath(); +public class DownloadManagerFunctionalTest extends DownloadManagerBaseTest { + private static final String TAG = "DownloadManagerFunctionalTest"; private final static String CACHE_DIR = Environment.getDownloadCacheDirectory().getAbsolutePath(); + private final static String PROHIBITED_DIRECTORY = + Environment.getRootDirectory().getAbsolutePath(); /** * {@inheritDoc} @@ -88,27 +72,13 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { } } - /** - * Helper that does the actual basic download verification. - */ - protected long doBasicDownload(byte[] blobData) throws Exception { - long dlRequest = doStandardEnqueue(blobData); - - // wait for the download to complete - waitForDownloadOrTimeout(dlRequest); - - assertEquals(1, mReceiver.numDownloadsCompleted()); - return dlRequest; - } - /** * Verifies a particular error code was received from a download * * @param uri The uri to enqueue to the DownloadManager * @param error The error code expected - * @throws an Exception if the test fails + * @throws Exception if the test fails */ - @LargeTest public void doErrorTest(Uri uri, int error) throws Exception { Request request = new Request(uri); request.setTitle(DEFAULT_FILENAME); @@ -128,66 +98,57 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { * Test a basic download of a binary file 500k in size. */ @LargeTest - public void testBasicBinaryDownload() throws Exception { - int fileSize = 500 * 1024; // 500k + public void testBinaryDownloadToSystemCache() throws Exception { + int fileSize = 1024; byte[] blobData = generateData(fileSize, DataType.BINARY); - long dlRequest = doBasicDownload(blobData); - verifyAndCleanupSingleFileDownload(dlRequest, blobData); + long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); + verifyDownload(dlRequest, blobData); + mDownloadManager.remove(dlRequest); } /** * Tests the basic downloading of a text file 300000 bytes in size. */ @LargeTest - public void testBasicTextDownload() throws Exception { - int fileSize = 300000; + public void testTextDownloadToSystemCache() throws Exception { + int fileSize = 1024; byte[] blobData = generateData(fileSize, DataType.TEXT); - long dlRequest = doBasicDownload(blobData); - verifyAndCleanupSingleFileDownload(dlRequest, blobData); + long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); + verifyDownload(dlRequest, blobData); + mDownloadManager.remove(dlRequest); } - + /** - * Tests when the server drops the connection after all headers (but before any data send). + * Helper to verify a standard single-file download from the mock server, and clean up after + * verification + * + * Note that this also calls the Download manager's remove, which cleans up the file from cache. + * + * @param requestId The id of the download to remove + * @param fileData The data to verify the file contains */ - @LargeTest - public void testDropConnection_headers() throws Exception { - byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); - - MockResponse response = enqueueResponse(HTTP_OK, blobData); - response.setCloseConnectionAfterHeader("content-length"); - long dlRequest = doCommonStandardEnqueue(); - - // Download will never complete when header is dropped - boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest, DEFAULT_WAIT_POLL_TIME, - DEFAULT_MAX_WAIT_TIME); - - assertFalse(success); - } - - /** - * Tests that we get an error code when the server drops the connection during a download. - */ - @LargeTest - public void testServerDropConnection_body() throws Exception { - byte[] blobData = generateData(25000, DataType.TEXT); // file size = 25000 bytes - - MockResponse response = enqueueResponse(HTTP_OK, blobData); - response.setCloseConnectionAfterXBytes(15382); - long dlRequest = doCommonStandardEnqueue(); - waitForDownloadOrTimeout(dlRequest); - - Cursor cursor = getCursor(dlRequest); + private void verifyDownload(long requestId, byte[] fileData) + throws Exception { + int fileSize = fileData.length; + ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(requestId); + Cursor cursor = mDownloadManager.query(new Query().setFilterById(requestId)); try { - verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); - verifyInt(cursor, DownloadManager.COLUMN_REASON, - DownloadManager.ERROR_CANNOT_RESUME); + assertEquals(1, cursor.getCount()); + assertTrue(cursor.moveToFirst()); + + mServer.checkForExceptions(); + + verifyFileSize(pfd, fileSize); + verifyFileContents(pfd, fileData); + int colIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); + String fileName = cursor.getString(colIndex); + assertTrue(fileName.startsWith(CACHE_DIR)); } finally { + pfd.close(); cursor.close(); } - // Even tho the server drops the connection, we should still get a completed notification - assertEquals(1, mReceiver.numDownloadsCompleted()); } /** @@ -198,7 +159,7 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { // need to be sure all current downloads have stopped first removeAllCurrentDownloads(); int NUM_FILES = 10; - int MAX_FILE_SIZE = 500 * 1024; // 500 kb + int MAX_FILE_SIZE = 10 * 1024; // 10 kb Random r = new LoggingRng(); for (int i=0; i= remainderSizeBlocks) { - fo.write(buffer); - fs.restat(CACHE_DIR); - } - } catch (IOException e) { - Log.e(LOG_TAG, "error filling file: ", e); - throw e; - } finally { - if (fo != null) { - fo.close(); - } - } - } - - Log.i(LOG_TAG, "Done creating filler file."); - assertTrue(DOWNLOAD_FILE_SIZE > (fs.getAvailableBlocks() * blockSize)); - byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT); - long dlRequest = doBasicDownload(blobData); - verifyAndCleanupSingleFileDownload(dlRequest, blobData); - - } finally { - if (outFile != null) { - outFile.delete(); - } - } - } - - /** - * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've - * run out of space. - */ - @LargeTest - public void testDownloadCacheNonPurgeable() throws Exception { - int fileSize = 10000000; - byte[] blobData = generateData(fileSize, DataType.BINARY); - long dlRequest = -1; - - // Fill up the cache partition until there's not enough room for another download. - // Note that we need to initiate a download first, then check for the available space. This - // is b/c there could be some files that are still left in the cache that can (and will be) - // cleared out, but not until DM gets a request for a download and reclaims that - // space first. - boolean spaceAvailable = true; - while (spaceAvailable) { - dlRequest = doStandardEnqueue(blobData); - waitForDownloadOrTimeout(dlRequest); - - // Check if we've filled up the cache yet - StatFs fs = new StatFs(CACHE_DIR); - Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks()); - Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize()); - int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks(); - spaceAvailable = (availableBytes > fileSize) ? true : false; - } - - // Now add one more download (should not fit in the space left over) - dlRequest = doStandardEnqueue(blobData); - waitForDownloadOrTimeout(dlRequest); - - // For the last download we should have failed b/c there is not enough space left in cache - Cursor cursor = getCursor(dlRequest); - try { - verifyInt(cursor, DownloadManager.COLUMN_REASON, - DownloadManager.ERROR_INSUFFICIENT_SPACE); - } finally { - cursor.close(); - } - } - /** * Tests that we get the correct download ID from the download notification. */ @@ -545,10 +360,10 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { */ @LargeTest public void testRemoveDownload() throws Exception { - int fileSize = 100 * 1024; // 100k + int fileSize = 1024; byte[] blobData = generateData(fileSize, DataType.BINARY); - long dlRequest = doBasicDownload(blobData); + long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest)); try { assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount()); @@ -565,7 +380,7 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { */ @LargeTest public void testSetTitle() throws Exception { - int fileSize = 50 * 1024; // 50k + int fileSize = 1024; byte[] blobData = generateData(fileSize, DataType.BINARY); MockResponse response = enqueueResponse(HTTP_OK, blobData); @@ -587,4 +402,179 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { cursor.close(); } } + + /** + * Tests that a download set for Wifi does not progress while Wifi is disabled, but resumes + * once Wifi is re-enabled. + */ + @LargeTest + public void testDownloadNoWifi() throws Exception { + long timeout = 60 * 1000; // wait only 60 seconds before giving up + int fileSize = 1024; // 140k + byte[] blobData = generateData(fileSize, DataType.TEXT); + + setWiFiStateOn(false); + enqueueResponse(HTTP_OK, blobData); + + try { + Uri uri = getServerUri(DEFAULT_FILENAME); + Request request = new Request(uri); + request.setAllowedNetworkTypes(Request.NETWORK_WIFI); + + long dlRequest = mDownloadManager.enqueue(request); + + // wait for the download to complete + boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest, + WAIT_FOR_DOWNLOAD_POLL_TIME, timeout); + assertFalse("Download proceeded without Wifi connection!", success); + + setWiFiStateOn(true); + waitForDownloadOrTimeout(dlRequest); + + assertEquals(1, mReceiver.numDownloadsCompleted()); + } finally { + setWiFiStateOn(true); + } + } + + /** + * Tests when the server drops the connection after all headers (but before any data send). + */ + @LargeTest + public void testDropConnection_headers() throws Exception { + byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); + + MockResponse response = enqueueResponse(HTTP_OK, blobData); + response.setCloseConnectionAfterHeader("content-length"); + long dlRequest = doCommonStandardEnqueue(); + + // Download will never complete when header is dropped + boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest, DEFAULT_WAIT_POLL_TIME, + DEFAULT_MAX_WAIT_TIME); + + assertFalse(success); + } + + /** + * Tests that we get an error code when the server drops the connection during a download. + */ + @LargeTest + public void testServerDropConnection_body() throws Exception { + byte[] blobData = generateData(25000, DataType.TEXT); // file size = 25000 bytes + + MockResponse response = enqueueResponse(HTTP_OK, blobData); + response.setCloseConnectionAfterXBytes(15382); + long dlRequest = doCommonStandardEnqueue(); + waitForDownloadOrTimeout(dlRequest); + + Cursor cursor = getCursor(dlRequest); + try { + verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); + verifyInt(cursor, DownloadManager.COLUMN_REASON, + DownloadManager.ERROR_CANNOT_RESUME); + } finally { + cursor.close(); + } + // Even tho the server drops the connection, we should still get a completed notification + assertEquals(1, mReceiver.numDownloadsCompleted()); + } + + /** + * Tests downloading a file to system cache when there isn't enough space in the system cache + * to hold the entire file. DownloadManager deletes enough files to make space for the + * new download. + */ + @LargeTest + public void testDownloadToCacheWithAlmostFullCache() throws Exception { + int DOWNLOAD_FILE_SIZE = 1024 * 1024; // 1MB + + StatFs fs = new StatFs(CACHE_DIR); + int blockSize = fs.getBlockSize(); + int availableBlocks = fs.getAvailableBlocks(); + int availableBytes = blockSize * availableBlocks; + Log.i(TAG, "INITIAL stage, available space in /cache: " + availableBytes); + File outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR)); + byte[] buffer = new byte[blockSize]; + + try { + // fill cache to ensure we don't have enough space - take half the size of the + // download size, and leave that much freespace left on the cache partition + if (DOWNLOAD_FILE_SIZE <= availableBytes) { + int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2); + + int writeSizeBlocks = writeSizeBytes / blockSize; + int remainderSizeBlocks = availableBlocks - writeSizeBlocks; + + FileOutputStream fo = null; + try { + fo = new FileOutputStream(outFile); + while (fs.getAvailableBlocks() >= remainderSizeBlocks) { + fo.write(buffer); + fs.restat(CACHE_DIR); + } + } catch (IOException e) { + Log.e(LOG_TAG, "error filling file: ", e); + throw e; + } finally { + if (fo != null) { + fo.close(); + } + } + } + + // /cache should now be almost full. + long spaceAvailable = fs.getAvailableBlocks() * blockSize; + Log.i(TAG, "BEFORE download, available space in /cache: " + spaceAvailable); + assertTrue(DOWNLOAD_FILE_SIZE > spaceAvailable); + + // try to download 1MB file into /cache - and it should succeed + byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT); + long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); + verifyAndCleanupSingleFileDownload(dlRequest, blobData); + } finally { + if (outFile != null) { + outFile.delete(); + } + } + } + + /** + * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've + * run out of space. + */ + @LargeTest + public void testDownloadToCacheNonPurgeableWithFullCache() throws Exception { + int fileSize = 1024 * 1024; // 1MB + byte[] blobData = generateData(fileSize, DataType.BINARY); + long dlRequest = -1; + + // Fill up the cache partition with DOWNLOAD_CACHE_NON_PURGEABLE downloads + // until 500KB is left. + boolean spaceAvailable = true; + while (spaceAvailable) { + // since this tests package has android.permission.DOWNLOAD_CACHE_NON_PURGEABLE + // permission, downloads are automatically set to be DOWNLOAD_CACHE_NON_PURGEABLE + dlRequest = enqueueDownloadRequest(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); + waitForDownloadOrTimeout(dlRequest); + + // Check if we've filled up the cache yet + StatFs fs = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); + int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks(); + Log.i(TAG, "available space in /cache: " + availableBytes); + spaceAvailable = (availableBytes > fileSize) ? true : false; + } + + // Now add one more 1MB download (should not fit in the space left over) + dlRequest = enqueueDownloadRequest(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); + waitForDownloadOrTimeout(dlRequest); + + // For the last download we should have failed b/c there is not enough space left in cache + Cursor cursor = getCursor(dlRequest); + try { + verifyInt(cursor, DownloadManager.COLUMN_REASON, + DownloadManager.ERROR_INSUFFICIENT_SPACE); + } finally { + cursor.close(); + } + } } diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java index e0b28d0e8fbd4..18b279f39652f 100644 --- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java +++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java @@ -16,19 +16,21 @@ package android.app; -import java.io.File; -import java.util.Random; import android.app.DownloadManager.Query; import android.app.DownloadManager.Request; import android.database.Cursor; import android.net.Uri; import android.os.ParcelFileDescriptor; +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.Suppress; import android.util.Log; +import java.io.File; +import java.util.Random; + public class DownloadManagerStressTest extends DownloadManagerBaseTest { - private static String LOG_TAG = "android.net.DownloadManagerStressTest"; /** * {@inheritDoc} @@ -42,8 +44,25 @@ public class DownloadManagerStressTest extends DownloadManagerBaseTest { } /** - * Attempts to downloading thousands of files simultaneously + * {@inheritDoc} */ + @Override + public void tearDown() throws Exception { + super.tearDown(); + setWiFiStateOn(true); + removeAllCurrentDownloads(); + + if (mReceiver != null) { + mContext.unregisterReceiver(mReceiver); + mReceiver = null; + } + } + + /** + * Attempts to downloading thousands of files simultaneously + * don't run this test - downloadmanager needs to allow only a few simultaneous downloads. + */ + @Suppress public void testDownloadThousands() throws Exception { int NUM_FILES = 1500; int MAX_FILE_SIZE = 3000; @@ -106,6 +125,7 @@ public class DownloadManagerStressTest extends DownloadManagerBaseTest { /** * Tests trying to download a large file (50M bytes). */ + @LargeTest public void testDownloadLargeFile() throws Exception { long fileSize = 50000000L; // note: kept relatively small to not exceed /cache dir size File largeFile = createFileOnSD(null, fileSize, DataType.TEXT, null); @@ -129,31 +149,4 @@ public class DownloadManagerStressTest extends DownloadManagerBaseTest { largeFile.delete(); } } - - /** - * Tests trying to download a large file (~600M bytes) when there's not enough space in cache - */ - public void testInsufficientSpace() throws Exception { - // @TODO: Rework this to fill up cache partition with a dynamically calculated size - long fileSize = 600000000L; - File largeFile = createFileOnSD(null, fileSize, DataType.TEXT, null); - - Cursor cursor = null; - try { - long dlRequest = doStandardEnqueue(largeFile); - - // wait for the download to complete - waitForDownloadOrTimeout(dlRequest); - - cursor = getCursor(dlRequest); - verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); - verifyInt(cursor, DownloadManager.COLUMN_REASON, - DownloadManager.ERROR_INSUFFICIENT_SPACE); - } finally { - if (cursor != null) { - cursor.close(); - } - largeFile.delete(); - } - } } diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk index 7206f4ade0b33..a419068c633c4 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk @@ -18,8 +18,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SRC_FILES := $(call all-java-files-under, src) \ - ../../../coretests/src/android/app/DownloadManagerBaseTest.java +LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib LOCAL_SDK_VERSION := current diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerBaseTest.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerBaseTest.java new file mode 100644 index 0000000000000..acd2a188dada6 --- /dev/null +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerBaseTest.java @@ -0,0 +1,816 @@ +/* + * 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.frameworks.downloadmanagertests; + +import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.os.SystemClock; +import android.os.ParcelFileDescriptor.AutoCloseInputStream; +import android.provider.Settings; +import android.test.InstrumentationTestCase; +import android.util.Log; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.concurrent.TimeoutException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.Vector; + +import junit.framework.AssertionFailedError; + +import coretestutils.http.MockResponse; +import coretestutils.http.MockWebServer; + +/** + * Base class for Instrumented tests for the Download Manager. + */ +public class DownloadManagerBaseTest extends InstrumentationTestCase { + + protected DownloadManager mDownloadManager = null; + protected MockWebServer mServer = null; + protected String mFileType = "text/plain"; + protected Context mContext = null; + protected MultipleDownloadsCompletedReceiver mReceiver = null; + protected static final int DEFAULT_FILE_SIZE = 10 * 1024; // 10kb + protected static final int FILE_BLOCK_READ_SIZE = 1024 * 1024; + + protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest"; + protected static final int HTTP_OK = 200; + protected static final int HTTP_REDIRECT = 307; + 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 String DEFAULT_FILENAME = "somefile.txt"; + + protected static final int DEFAULT_MAX_WAIT_TIME = 2 * 60 * 1000; // 2 minutes + protected static final int DEFAULT_WAIT_POLL_TIME = 5 * 1000; // 5 seconds + + protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000; // 1 second + protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes + protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes + + protected static final int DOWNLOAD_TO_SYSTEM_CACHE = 1; + protected static final int DOWNLOAD_TO_DOWNLOAD_CACHE_DIR = 2; + + // Just a few popular file types used to return from a download + protected enum DownloadFileType { + PLAINTEXT, + APK, + GIF, + GARBAGE, + UNRECOGNIZED, + ZIP + } + + protected enum DataType { + TEXT, + BINARY + } + + public static class LoggingRng extends Random { + + /** + * Constructor + * + * Creates RNG with self-generated seed value. + */ + public LoggingRng() { + this(SystemClock.uptimeMillis()); + } + + /** + * Constructor + * + * Creats RNG with given initial seed value + + * @param seed The initial seed value + */ + public LoggingRng(long seed) { + super(seed); + Log.i(LOG_TAG, "Seeding RNG with value: " + seed); + } + } + + public static class MultipleDownloadsCompletedReceiver extends BroadcastReceiver { + private volatile int mNumDownloadsCompleted = 0; + private Set downloadIds = Collections.synchronizedSet(new HashSet()); + + /** + * {@inheritDoc} + */ + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equalsIgnoreCase(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { + synchronized(this) { + long id = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID); + Log.i(LOG_TAG, "Received Notification for download: " + id); + if (!downloadIds.contains(id)) { + ++mNumDownloadsCompleted; + Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " + + intent.getAction() + " --> total count: " + mNumDownloadsCompleted); + downloadIds.add(id); + + DownloadManager dm = (DownloadManager)context.getSystemService( + Context.DOWNLOAD_SERVICE); + + Cursor cursor = dm.query(new Query().setFilterById(id)); + try { + if (cursor.moveToFirst()) { + int status = cursor.getInt(cursor.getColumnIndex( + DownloadManager.COLUMN_STATUS)); + Log.i(LOG_TAG, "Download status is: " + status); + } else { + fail("No status found for completed download!"); + } + } finally { + cursor.close(); + } + } else { + Log.i(LOG_TAG, "Notification for id: " + id + " has already been made."); + } + } + } + } + + /** + * Gets the number of times the {@link #onReceive} callback has been called for the + * {@link DownloadManager.ACTION_DOWNLOAD_COMPLETED} action, indicating the number of + * downloads completed thus far. + * + * @return the number of downloads completed so far. + */ + public int numDownloadsCompleted() { + return mNumDownloadsCompleted; + } + + /** + * Gets the list of download IDs. + * @return A Set with the ids of the completed downloads. + */ + public Set getDownloadIds() { + synchronized(this) { + Set returnIds = new HashSet(downloadIds); + return returnIds; + } + } + + } + + public static class WiFiChangedReceiver extends BroadcastReceiver { + private Context mContext = null; + + /** + * Constructor + * + * Sets the current state of WiFi. + * + * @param context The current app {@link Context}. + */ + public WiFiChangedReceiver(Context context) { + mContext = context; + } + + /** + * {@inheritDoc} + */ + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) { + Log.i(LOG_TAG, "ConnectivityManager state change: " + intent.getAction()); + synchronized (this) { + this.notify(); + } + } + } + + /** + * Gets the current state of WiFi. + * + * @return Returns true if WiFi is on, false otherwise. + */ + public boolean getWiFiIsOn() { + ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + NetworkInfo info = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + Log.i(LOG_TAG, "WiFi Connection state is currently: " + info.isConnected()); + return info.isConnected(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setUp() throws Exception { + mContext = getInstrumentation().getContext(); + mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE); + mServer = new MockWebServer(); + mReceiver = registerNewMultipleDownloadsReceiver(); + // Note: callers overriding this should call mServer.play() with the desired port # + } + + /** + * Helper to enqueue a response from the MockWebServer. + * + * @param status The HTTP status code to return for this response + * @param body The body to return in this response + * @return Returns the mock web server response that was queued (which can be modified) + */ + private MockResponse enqueueResponse(int status, byte[] body) { + return doEnqueueResponse(status).setBody(body); + + } + + /** + * Helper to enqueue a response from the MockWebServer. + * + * @param status The HTTP status code to return for this response + * @param bodyFile The body to return in this response + * @return Returns the mock web server response that was queued (which can be modified) + */ + private MockResponse enqueueResponse(int status, File bodyFile) { + return doEnqueueResponse(status).setBody(bodyFile); + } + + /** + * Helper for enqueue'ing a response from the MockWebServer. + * + * @param status The HTTP status code to return for this response + * @return Returns the mock web server response that was queued (which can be modified) + */ + private MockResponse doEnqueueResponse(int status) { + MockResponse response = new MockResponse().setResponseCode(status); + response.addHeader("Content-type", mFileType); + mServer.enqueue(response); + return response; + } + + /** + * Helper to generate a random blob of bytes using a given RNG. + * + * @param size The size of the data to generate + * @param type The type of data to generate: currently, one of {@link DataType.TEXT} or + * {@link DataType.BINARY}. + * @param rng (optional) The RNG to use; pass null to use + * @return The random data that is generated. + */ + private byte[] generateData(int size, DataType type, Random rng) { + int min = Byte.MIN_VALUE; + int max = Byte.MAX_VALUE; + + // Only use chars in the HTTP ASCII printable character range for Text + if (type == DataType.TEXT) { + min = 32; + max = 126; + } + byte[] result = new byte[size]; + Log.i(LOG_TAG, "Generating data of size: " + size); + + if (rng == null) { + rng = new LoggingRng(); + } + + for (int i = 0; i < size; ++i) { + result[i] = (byte) (min + rng.nextInt(max - min + 1)); + } + return result; + } + + /** + * Helper to verify the size of a file. + * + * @param pfd The input file to compare the size of + * @param size The expected size of the file + */ + protected void verifyFileSize(ParcelFileDescriptor pfd, long size) { + assertEquals(pfd.getStatSize(), size); + } + + /** + * Helper to verify the contents of a downloaded file versus a byte[]. + * + * @param actual The file of whose contents to verify + * @param expected The data we expect to find in the aforementioned file + * @throws IOException if there was a problem reading from the file + */ + private void verifyFileContents(ParcelFileDescriptor actual, byte[] expected) + throws IOException { + AutoCloseInputStream input = new ParcelFileDescriptor.AutoCloseInputStream(actual); + long fileSize = actual.getStatSize(); + + assertTrue(fileSize <= Integer.MAX_VALUE); + assertEquals(expected.length, fileSize); + + byte[] actualData = new byte[expected.length]; + assertEquals(input.read(actualData), fileSize); + compareByteArrays(actualData, expected); + } + + /** + * Helper to compare 2 byte arrays. + * + * @param actual The array whose data we want to verify + * @param expected The array of data we expect to see + */ + private void compareByteArrays(byte[] actual, byte[] expected) { + assertEquals(actual.length, expected.length); + int length = actual.length; + for (int i = 0; i < length; ++i) { + // assert has a bit of overhead, so only do the assert when the values are not the same + if (actual[i] != expected[i]) { + fail("Byte arrays are not equal."); + } + } + } + + /** + * Gets the MIME content string for a given type + * + * @param type The MIME type to return + * @return the String representation of that MIME content type + */ + protected String getMimeMapping(DownloadFileType type) { + switch (type) { + case APK: + return "application/vnd.android.package-archive"; + case GIF: + return "image/gif"; + case ZIP: + return "application/x-zip-compressed"; + case GARBAGE: + return "zip\\pidy/doo/da"; + case UNRECOGNIZED: + return "application/new.undefined.type.of.app"; + } + return "text/plain"; + } + + /** + * Gets the Uri that should be used to access the mock server + * + * @param filename The name of the file to try to retrieve from the mock server + * @return the Uri to use for access the file on the mock server + */ + private Uri getServerUri(String filename) throws Exception { + URL url = mServer.getUrl("/" + filename); + return Uri.parse(url.toString()); + } + + /** + * Helper to create and register a new MultipleDownloadCompletedReciever + * + * This is used to track many simultaneous downloads by keeping count of all the downloads + * that have completed. + * + * @return A new receiver that records and can be queried on how many downloads have completed. + */ + protected MultipleDownloadsCompletedReceiver registerNewMultipleDownloadsReceiver() { + MultipleDownloadsCompletedReceiver receiver = new MultipleDownloadsCompletedReceiver(); + mContext.registerReceiver(receiver, new IntentFilter( + DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + return receiver; + } + + /** + * Enables or disables WiFi. + * + * Note: Needs the following permissions: + * android.permission.ACCESS_WIFI_STATE + * android.permission.CHANGE_WIFI_STATE + * @param enable true if it should be enabled, false if it should be disabled + */ + protected void setWiFiStateOn(boolean enable) throws Exception { + Log.i(LOG_TAG, "Setting WiFi State to: " + enable); + WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE); + + manager.setWifiEnabled(enable); + + String timeoutMessage = "Timed out waiting for Wifi to be " + + (enable ? "enabled!" : "disabled!"); + + WiFiChangedReceiver receiver = new WiFiChangedReceiver(mContext); + mContext.registerReceiver(receiver, new IntentFilter( + ConnectivityManager.CONNECTIVITY_ACTION)); + + synchronized (receiver) { + long timeoutTime = SystemClock.elapsedRealtime() + DEFAULT_MAX_WAIT_TIME; + boolean timedOut = false; + + while (receiver.getWiFiIsOn() != enable && !timedOut) { + try { + receiver.wait(DEFAULT_WAIT_POLL_TIME); + + if (SystemClock.elapsedRealtime() > timeoutTime) { + timedOut = true; + } + } + catch (InterruptedException e) { + // ignore InterruptedExceptions + } + } + if (timedOut) { + fail(timeoutMessage); + } + } + assertEquals(enable, receiver.getWiFiIsOn()); + } + + /** + * Helper to enables or disables airplane mode. If successful, it also broadcasts an intent + * indicating that the mode has changed. + * + * Note: Needs the following permission: + * android.permission.WRITE_SETTINGS + * @param enable true if airplane mode should be ON, false if it should be OFF + */ + protected void setAirplaneModeOn(boolean enable) throws Exception { + int state = enable ? 1 : 0; + + // Change the system setting + Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, + state); + + String timeoutMessage = "Timed out waiting for airplane mode to be " + + (enable ? "enabled!" : "disabled!"); + + // wait for airplane mode to change state + int currentWaitTime = 0; + while (Settings.System.getInt(mContext.getContentResolver(), + Settings.System.AIRPLANE_MODE_ON, -1) != state) { + timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, DEFAULT_MAX_WAIT_TIME, + timeoutMessage); + } + + // Post the intent + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", true); + mContext.sendBroadcast(intent); + } + + /** + * Helper to wait for a particular download to finish, or else a timeout to occur + * + * Does not wait for a receiver notification of the download. + * + * @param id The download id to query on (wait for) + */ + private void waitForDownloadOrTimeout_skipNotification(long id) throws TimeoutException, + InterruptedException { + waitForDownloadOrTimeout(id, WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME); + } + + /** + * Helper to wait for a particular download to finish, or else a timeout to occur + * + * Also guarantees a notification has been posted for the download. + * + * @param id The download id to query on (wait for) + */ + protected void waitForDownloadOrTimeout(long id) throws TimeoutException, + InterruptedException { + waitForDownloadOrTimeout_skipNotification(id); + waitForReceiverNotifications(1); + } + + /** + * Helper to wait for a particular download to finish, or else a timeout to occur + * + * Also guarantees a notification has been posted for the download. + * + * @param id The download id to query on (wait for) + * @param poll The amount of time to wait + * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete + */ + protected void waitForDownloadOrTimeout(long id, long poll, long timeoutMillis) + throws TimeoutException, InterruptedException { + doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis); + waitForReceiverNotifications(1); + } + + /** + * Helper to wait for all downloads to finish, or else a specified timeout to occur + * + * Makes no guaranee that notifications have been posted for all downloads. + * + * @param poll The amount of time to wait + * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete + */ + protected void waitForDownloadsOrTimeout(long poll, long timeoutMillis) throws TimeoutException, + InterruptedException { + doWaitForDownloadsOrTimeout(new Query(), poll, timeoutMillis); + } + + /** + * Helper to wait for all downloads to finish, or else a timeout to occur, but does not throw + * + * Also guarantees a notification has been posted for the download. + * + * @param id The id of the download to query against + * @param poll The amount of time to wait + * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete + * @return true if download completed successfully (didn't timeout), false otherwise + */ + private boolean waitForDownloadOrTimeoutNoThrow(long id, long poll, long timeoutMillis) { + try { + doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis); + waitForReceiverNotifications(1); + } catch (TimeoutException e) { + return false; + } + return true; + } + + /** + * Helper function to synchronously wait, or timeout if the maximum threshold has been exceeded. + * + * @param currentTotalWaitTime The total time waited so far + * @param poll The amount of time to wait + * @param maxTimeoutMillis The total wait time threshold; if we've waited more than this long, + * we timeout and fail + * @param timedOutMessage The message to display in the failure message if we timeout + * @return The new total amount of time we've waited so far + * @throws TimeoutException if timed out waiting for SD card to mount + */ + private int timeoutWait(int currentTotalWaitTime, long poll, long maxTimeoutMillis, + String timedOutMessage) throws TimeoutException { + long now = SystemClock.elapsedRealtime(); + long end = now + poll; + + // if we get InterruptedException's, ignore them and just keep sleeping + while (now < end) { + try { + Thread.sleep(end - now); + } catch (InterruptedException e) { + // ignore interrupted exceptions + } + now = SystemClock.elapsedRealtime(); + } + + currentTotalWaitTime += poll; + if (currentTotalWaitTime > maxTimeoutMillis) { + throw new TimeoutException(timedOutMessage); + } + return currentTotalWaitTime; + } + + /** + * Helper to wait for all downloads to finish, or else a timeout to occur + * + * @param query The query to pass to the download manager + * @param poll The poll time to wait between checks + * @param timeoutMillis The max amount of time (in ms) to wait for the download(s) to complete + */ + private void doWaitForDownloadsOrTimeout(Query query, long poll, long timeoutMillis) + throws TimeoutException { + int currentWaitTime = 0; + while (true) { + query.setFilterByStatus(DownloadManager.STATUS_PENDING | DownloadManager.STATUS_PAUSED + | DownloadManager.STATUS_RUNNING); + Cursor cursor = mDownloadManager.query(query); + + try { + if (cursor.getCount() == 0) { + Log.i(LOG_TAG, "All downloads should be done..."); + break; + } + currentWaitTime = timeoutWait(currentWaitTime, poll, timeoutMillis, + "Timed out waiting for all downloads to finish"); + } finally { + cursor.close(); + } + } + } + + /** + * Synchronously waits for external store to be mounted (eg: SD Card). + * + * @throws InterruptedException if interrupted + * @throws Exception if timed out waiting for SD card to mount + */ + protected void waitForExternalStoreMount() throws Exception { + String extStorageState = Environment.getExternalStorageState(); + int currentWaitTime = 0; + while (!extStorageState.equals(Environment.MEDIA_MOUNTED)) { + Log.i(LOG_TAG, "Waiting for SD card..."); + currentWaitTime = timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, + DEFAULT_MAX_WAIT_TIME, "Timed out waiting for SD Card to be ready!"); + extStorageState = Environment.getExternalStorageState(); + } + } + + /** + * Synchronously waits for a download to start. + * + * @param dlRequest the download request id used by Download Manager to track the download. + * @throws Exception if timed out while waiting for SD card to mount + */ + protected void waitForDownloadToStart(long dlRequest) throws Exception { + Cursor cursor = getCursor(dlRequest); + try { + int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); + int value = cursor.getInt(columnIndex); + int currentWaitTime = 0; + + while (value != DownloadManager.STATUS_RUNNING && + (value != DownloadManager.STATUS_FAILED) && + (value != DownloadManager.STATUS_SUCCESSFUL)) { + Log.i(LOG_TAG, "Waiting for download to start..."); + currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, + MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for download to start!"); + cursor.requery(); + assertTrue(cursor.moveToFirst()); + columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); + value = cursor.getInt(columnIndex); + } + assertFalse("Download failed immediately after start", + value == DownloadManager.STATUS_FAILED); + } finally { + cursor.close(); + } + } + + /** + * Synchronously waits for our receiver to receive notification for a given number of + * downloads. + * + * @param targetNumber The number of notifications for unique downloads to wait for; pass in + * -1 to not wait for notification. + * @throws Exception if timed out while waiting + */ + private void waitForReceiverNotifications(int targetNumber) throws TimeoutException { + int count = mReceiver.numDownloadsCompleted(); + int currentWaitTime = 0; + + while (count < targetNumber) { + Log.i(LOG_TAG, "Waiting for notification of downloads..."); + currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, + MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for download notifications!" + + " Received " + count + "notifications."); + count = mReceiver.numDownloadsCompleted(); + } + } + + /** + * Synchronously waits for a file to increase in size (such as to monitor that a download is + * progressing). + * + * @param file The file whose size to track. + * @throws Exception if timed out while waiting for the file to grow in size. + */ + protected void waitForFileToGrow(File file) throws Exception { + int currentWaitTime = 0; + + // File may not even exist yet, so wait until it does (or we timeout) + while (!file.exists()) { + Log.i(LOG_TAG, "Waiting for file to exist..."); + currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, + MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be created."); + } + + // Get original file size... + long originalSize = file.length(); + + while (file.length() <= originalSize) { + Log.i(LOG_TAG, "Waiting for file to be written to..."); + currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, + MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be written to."); + } + } + + /** + * Helper to remove all downloads that are registered with the DL Manager. + * + * Note: This gives us a clean slate b/c it includes downloads that are pending, running, + * paused, or have completed. + */ + protected void removeAllCurrentDownloads() { + Log.i(LOG_TAG, "Removing all current registered downloads..."); + Cursor cursor = mDownloadManager.query(new Query()); + try { + if (cursor.moveToFirst()) { + do { + int index = cursor.getColumnIndex(DownloadManager.COLUMN_ID); + long downloadId = cursor.getLong(index); + + mDownloadManager.remove(downloadId); + } while (cursor.moveToNext()); + } + } finally { + cursor.close(); + } + } + + /** + * Helper to perform a standard enqueue of data to the mock server. + * download is performed to the downloads cache dir (NOT systemcache dir) + * + * @param body The body to return in the response from the server + */ + private long doStandardEnqueue(byte[] body) throws Exception { + // Prepare the mock server with a standard response + enqueueResponse(HTTP_OK, body); + return doCommonStandardEnqueue(); + } + + /** + * Helper to perform a standard enqueue of data to the mock server. + * + * @param body The body to return in the response from the server, contained in the file + */ + private long doStandardEnqueue(File body) throws Exception { + // Prepare the mock server with a standard response + enqueueResponse(HTTP_OK, body); + return doCommonStandardEnqueue(); + } + + /** + * Helper to do the additional steps (setting title and Uri of default filename) when + * doing a standard enqueue request to the server. + */ + private long doCommonStandardEnqueue() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + Request request = new Request(uri).setTitle(DEFAULT_FILENAME); + return mDownloadManager.enqueue(request); + } + + /** + * Helper to verify an int value in a Cursor + * + * @param cursor The cursor containing the query results + * @param columnName The name of the column to query + * @param expected The expected int value + */ + private void verifyInt(Cursor cursor, String columnName, int expected) { + int index = cursor.getColumnIndex(columnName); + int actual = cursor.getInt(index); + assertEquals(expected, actual); + } + + /** + * Performs a query based on ID and returns a Cursor for the query. + * + * @param id The id of the download in DL Manager; pass -1 to query all downloads + * @return A cursor for the query results + */ + protected Cursor getCursor(long id) throws Exception { + Query query = new Query(); + if (id != -1) { + query.setFilterById(id); + } + + Cursor cursor = mDownloadManager.query(query); + int currentWaitTime = 0; + + try { + while (!cursor.moveToFirst()) { + Thread.sleep(DEFAULT_WAIT_POLL_TIME); + currentWaitTime += DEFAULT_WAIT_POLL_TIME; + if (currentWaitTime > DEFAULT_MAX_WAIT_TIME) { + fail("timed out waiting for a non-null query result"); + } + cursor.requery(); + } + } catch (Exception e) { + cursor.close(); + throw e; + } + return cursor; + } +} \ No newline at end of file diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java index e1d7b4c0f8851..ba5ee2cc6ef7b 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java @@ -18,7 +18,6 @@ package com.android.frameworks.downloadmanagertests; import android.app.DownloadManager; import android.app.DownloadManager.Query; import android.app.DownloadManager.Request; -import android.app.DownloadManagerBaseTest; import android.content.Context; import android.content.Intent; import android.database.Cursor;