diff options
author | Vasu Nori <vnori@google.com> | 2010-12-15 14:42:30 -0800 |
---|---|---|
committer | Vasu Nori <vnori@google.com> | 2010-12-16 00:36:50 -0800 |
commit | 82e891b3259350a92b55969a6380ca1240ee0829 (patch) | |
tree | b05aa22363aa3f050e001645beb1104f07731cea /core/tests | |
parent | 4aedb39a49bda340f871c8fac2239de4fe549b03 (diff) | |
download | frameworks_base-82e891b3259350a92b55969a6380ca1240ee0829.zip frameworks_base-82e891b3259350a92b55969a6380ca1240ee0829.tar.gz frameworks_base-82e891b3259350a92b55969a6380ca1240ee0829.tar.bz2 |
fix downloadmanager tests. add few more. fix some. isolate flaky ones
the following work
frameworks/base/core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java
ideally, most of the tests in this should be moved to cts testsuite.
will require reformatting of comments
and probably removal of one or two tests using hidden public API.
packages/providers/DownloadProvider/tests/src/com/android/providers/downloads/DownloadManagerFunctionalTest.java
packages/providers/DownloadProvider/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java
packages/providers/DownloadProvider/tests/src/com/android/providers/downloads/ThreadingTest.java
packages/providers/DownloadProvider/tests/public_api_access/src/com/android/providers/downloads/public_api_access_tests/PublicApiAccessTest.java
packages/providers/DownloadProvider/tests/permission/src/com/android/providers/downloads/permission/tests/DownloadProviderPermissionsTest.java
the following need work
frameworks/base/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
some of these tests fail in a flaky way. they need work
Change-Id: Ib64645005a8f5faa32e0b9a4c5cacfe6e6ae3063
Diffstat (limited to 'core/tests')
-rw-r--r-- | core/tests/coretests/AndroidManifest.xml | 3 | ||||
-rw-r--r-- | core/tests/coretests/src/android/app/DownloadManagerBaseTest.java | 77 | ||||
-rw-r--r-- | core/tests/coretests/src/android/app/DownloadManagerFunctionalTest.java (renamed from core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java) | 440 | ||||
-rw-r--r-- | core/tests/coretests/src/android/app/DownloadManagerStressTest.java | 53 | ||||
-rw-r--r-- | core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk | 3 | ||||
-rw-r--r-- | core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerBaseTest.java | 816 | ||||
-rw-r--r-- | core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java | 1 |
7 files changed, 1114 insertions, 279 deletions
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index b1e38ee..f2857fa 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -36,6 +36,9 @@ android:description="@string/permdesc_testDenied" /> <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" /> + <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" /> + <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" /> + <uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java index 8df37ad..1bb2a57 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<Long> ids = new ArrayList<Long>(); 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 { + return doEnqueue(DOWNLOAD_TO_DOWNLOAD_CACHE_DIR); + } + + private long doEnqueue(int location) throws Exception { Uri uri = getServerUri(DEFAULT_FILENAME); - Request request = new Request(uri); - request.setTitle(DEFAULT_FILENAME); + Request request = new Request(uri).setTitle(DEFAULT_FILENAME); + if (location == DOWNLOAD_TO_SYSTEM_CACHE) { + request.setDestinationToSystemCache(); + } - long dlRequest = mDownloadManager.enqueue(request); - Log.i(LOG_TAG, "request ID: " + dlRequest); - return dlRequest; + 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 index 4f79108..06f3ba4 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} @@ -89,26 +73,12 @@ 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). - */ - @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. + * 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 testServerDropConnection_body() throws Exception { - byte[] blobData = generateData(25000, DataType.TEXT); // file size = 25000 bytes + 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 { + assertEquals(1, cursor.getCount()); + assertTrue(cursor.moveToFirst()); - MockResponse response = enqueueResponse(HTTP_OK, blobData); - response.setCloseConnectionAfterXBytes(15382); - long dlRequest = doCommonStandardEnqueue(); - waitForDownloadOrTimeout(dlRequest); + mServer.checkForExceptions(); - Cursor cursor = getCursor(dlRequest); - try { - verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); - verifyInt(cursor, DownloadManager.COLUMN_REASON, - DownloadManager.ERROR_CANNOT_RESUME); + 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<NUM_FILES; ++i) { @@ -213,7 +174,6 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { enqueueResponse(HTTP_OK, blobData); long requestID = mDownloadManager.enqueue(request); - Log.i(LOG_TAG, "request: " + i + " -- requestID: " + requestID); } waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME); @@ -236,8 +196,6 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { assertEquals(NUM_FILES, mReceiver.numDownloadsCompleted()); } finally { - Log.i(LOG_TAG, "All download IDs: " + mReceiver.getDownloadIds().toString()); - Log.i(LOG_TAG, "Total downloads completed: " + mReceiver.getDownloadIds().size()); cursor.close(); } } @@ -258,7 +216,6 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { Request request = new Request(uri); Uri localUri = Uri.fromFile(existentFile); - Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath()); request.setDestinationUri(localUri); long dlRequest = mDownloadManager.enqueue(request); @@ -268,9 +225,7 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { Cursor cursor = getCursor(dlRequest); try { - verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED); - verifyInt(cursor, DownloadManager.COLUMN_REASON, - DownloadManager.ERROR_FILE_ALREADY_EXISTS); + verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_SUCCESSFUL); } finally { cursor.close(); } @@ -299,7 +254,6 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { Request request = new Request(uri); Uri localUri = Uri.fromFile(downloadedFile); - Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath()); request.setDestinationUri(localUri); long dlRequest = mDownloadManager.enqueue(request); @@ -331,7 +285,6 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { Request request = new Request(uri); Uri localUri = Uri.fromFile(downloadedFile); - Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath()); request.setDestinationUri(localUri); try { @@ -347,13 +300,117 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { } /** + * Tests that we get the correct download ID from the download notification. + */ + @LargeTest + public void testGetDownloadIdOnNotification() throws Exception { + byte[] blobData = generateData(3000, DataType.TEXT); // file size = 3000 bytes + + MockResponse response = enqueueResponse(HTTP_OK, blobData); + long dlRequest = doCommonStandardEnqueue(); + waitForDownloadOrTimeout(dlRequest); + + Set<Long> ids = mReceiver.getDownloadIds(); + assertEquals(1, ids.size()); + Iterator<Long> it = ids.iterator(); + assertEquals("Download ID received from notification does not match initial id!", + dlRequest, it.next().longValue()); + } + + /** + * Tests the download failure error after too many redirects (>5). + */ + @LargeTest + public void testErrorTooManyRedirects() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + + // force 6 redirects + for (int i = 0; i < 6; ++i) { + MockResponse response = enqueueResponse(HTTP_REDIRECT); + response.addHeader("Location", uri.toString()); + } + doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS); + } + + /** + * Tests the download failure error from an unhandled HTTP status code + */ + @LargeTest + public void testErrorUnhandledHttpCode() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT); + + doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE); + } + + /** + * Tests the download failure error from an unhandled HTTP status code + */ + @LargeTest + public void testErrorHttpDataError_invalidRedirect() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + MockResponse response = enqueueResponse(HTTP_REDIRECT); + response.addHeader("Location", "://blah.blah.blah.com"); + + doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR); + } + + /** + * Tests that we can remove a download from the download manager. + */ + @LargeTest + public void testRemoveDownload() throws Exception { + int fileSize = 1024; + byte[] blobData = generateData(fileSize, DataType.BINARY); + + 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()); + mDownloadManager.remove(dlRequest); + cursor.requery(); + assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount()); + } finally { + cursor.close(); + } + } + + /** + * Tests that we can set the title of a download. + */ + @LargeTest + public void testSetTitle() throws Exception { + int fileSize = 1024; + byte[] blobData = generateData(fileSize, DataType.BINARY); + MockResponse response = enqueueResponse(HTTP_OK, blobData); + + // An arbitrary unicode string title + final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" + + "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'"; + + Uri uri = getServerUri(DEFAULT_FILENAME); + Request request = new Request(uri); + request.setTitle(title); + + long dlRequest = mDownloadManager.enqueue(request); + waitForDownloadOrTimeout(dlRequest); + + Cursor cursor = getCursor(dlRequest); + try { + verifyString(cursor, DownloadManager.COLUMN_TITLE, title); + } finally { + 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 = 140 * 1024; // 140k + int fileSize = 1024; // 140k byte[] blobData = generateData(fileSize, DataType.TEXT); setWiFiStateOn(false); @@ -381,21 +438,63 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { } /** - * Tests downloading a file to cache when there isn't enough space in the cache to hold the - * entire file. + * Tests when the server drops the connection after all headers (but before any data send). */ @LargeTest - public void testDownloadToCache_whenFull() throws Exception { - int DOWNLOAD_FILE_SIZE = 500000; + public void testDropConnection_headers() throws Exception { + byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT); - StatFs fs = new StatFs(CACHE_DIR); - Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks()); - Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize()); + 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; - File outFile = null; + 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 @@ -408,13 +507,7 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { FileOutputStream fo = null; try { - outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR)); - Log.v(LOG_TAG, "writing " + writeSizeBlocks + " blocks to file " - + outFile.getAbsolutePath()); - fo = new FileOutputStream(outFile); - - byte[] buffer = new byte[blockSize]; while (fs.getAvailableBlocks() >= remainderSizeBlocks) { fo.write(buffer); fs.restat(CACHE_DIR); @@ -429,12 +522,15 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { } } - Log.i(LOG_TAG, "Done creating filler file."); - assertTrue(DOWNLOAD_FILE_SIZE > (fs.getAvailableBlocks() * blockSize)); + // /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); + long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE); verifyAndCleanupSingleFileDownload(dlRequest, blobData); - } finally { if (outFile != null) { outFile.delete(); @@ -447,31 +543,29 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { * run out of space. */ @LargeTest - public void testDownloadCacheNonPurgeable() throws Exception { - int fileSize = 10000000; + public void testDownloadToCacheNonPurgeableWithFullCache() throws Exception { + int fileSize = 1024 * 1024; // 1MB 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. + // Fill up the cache partition with DOWNLOAD_CACHE_NON_PURGEABLE downloads + // until 500KB is left. boolean spaceAvailable = true; while (spaceAvailable) { - dlRequest = doStandardEnqueue(blobData); + // 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(CACHE_DIR); - Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks()); - Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize()); + 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 download (should not fit in the space left over) - dlRequest = doStandardEnqueue(blobData); + // 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 @@ -483,108 +577,4 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { cursor.close(); } } - - /** - * Tests that we get the correct download ID from the download notification. - */ - @LargeTest - public void testGetDownloadIdOnNotification() throws Exception { - byte[] blobData = generateData(3000, DataType.TEXT); // file size = 3000 bytes - - MockResponse response = enqueueResponse(HTTP_OK, blobData); - long dlRequest = doCommonStandardEnqueue(); - waitForDownloadOrTimeout(dlRequest); - - Set<Long> ids = mReceiver.getDownloadIds(); - assertEquals(1, ids.size()); - Iterator<Long> it = ids.iterator(); - assertEquals("Download ID received from notification does not match initial id!", - dlRequest, it.next().longValue()); - } - - /** - * Tests the download failure error after too many redirects (>5). - */ - @LargeTest - public void testErrorTooManyRedirects() throws Exception { - Uri uri = getServerUri(DEFAULT_FILENAME); - - // force 6 redirects - for (int i = 0; i < 6; ++i) { - MockResponse response = enqueueResponse(HTTP_REDIRECT); - response.addHeader("Location", uri.toString()); - } - doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS); - } - - /** - * Tests the download failure error from an unhandled HTTP status code - */ - @LargeTest - public void testErrorUnhandledHttpCode() throws Exception { - Uri uri = getServerUri(DEFAULT_FILENAME); - MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT); - - doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE); - } - - /** - * Tests the download failure error from an unhandled HTTP status code - */ - @LargeTest - public void testErrorHttpDataError_invalidRedirect() throws Exception { - Uri uri = getServerUri(DEFAULT_FILENAME); - MockResponse response = enqueueResponse(HTTP_REDIRECT); - response.addHeader("Location", "://blah.blah.blah.com"); - - doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR); - } - - /** - * Tests that we can remove a download from the download manager. - */ - @LargeTest - public void testRemoveDownload() throws Exception { - int fileSize = 100 * 1024; // 100k - byte[] blobData = generateData(fileSize, DataType.BINARY); - - long dlRequest = doBasicDownload(blobData); - Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest)); - try { - assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount()); - mDownloadManager.remove(dlRequest); - cursor.requery(); - assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount()); - } finally { - cursor.close(); - } - } - - /** - * Tests that we can set the title of a download. - */ - @LargeTest - public void testSetTitle() throws Exception { - int fileSize = 50 * 1024; // 50k - byte[] blobData = generateData(fileSize, DataType.BINARY); - MockResponse response = enqueueResponse(HTTP_OK, blobData); - - // An arbitrary unicode string title - final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" + - "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'"; - - Uri uri = getServerUri(DEFAULT_FILENAME); - Request request = new Request(uri); - request.setTitle(title); - - long dlRequest = mDownloadManager.enqueue(request); - waitForDownloadOrTimeout(dlRequest); - - Cursor cursor = getCursor(dlRequest); - try { - verifyString(cursor, DownloadManager.COLUMN_TITLE, title); - } finally { - cursor.close(); - } - } } diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java index e0b28d0..18b279f 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 { } /** + * {@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 7206f4a..a419068 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 0000000..acd2a18 --- /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<Long> downloadIds = Collections.synchronizedSet(new HashSet<Long>()); + + /** + * {@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<Long> with the ids of the completed downloads. + */ + public Set<Long> getDownloadIds() { + synchronized(this) { + Set<Long> returnIds = new HashSet<Long>(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 e1d7b4c..ba5ee2c 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; |