resolve conflicts

Change-Id: I87f854430f7083cd2f2e28b4ec4a7112ef6fe4f1
This commit is contained in:
Jean-Baptiste Queru
2010-09-08 10:02:35 -07:00
15 changed files with 3053 additions and 8 deletions

View File

@ -12,7 +12,7 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
LOCAL_STATIC_JAVA_LIBRARIES := core-tests-supportlib android-common
LOCAL_STATIC_JAVA_LIBRARIES := core-tests-supportlib android-common frameworks-core-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreTests

View File

@ -36,12 +36,16 @@
android:description="@string/permdesc_testDenied" />
<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" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

View File

@ -0,0 +1,888 @@
/*
* 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 android.net;
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.DownloadManager;
import android.net.NetworkInfo;
import android.net.DownloadManager.Query;
import android.net.DownloadManager.Request;
import android.net.wifi.WifiManager;
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.Iterator;
import java.util.List;
import java.util.Random;
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 static final int DEFAULT_FILE_SIZE = 130 * 1024; // 130kb
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_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
// 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;
/**
* {@inheritDoc}
*/
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equalsIgnoreCase(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
++mNumDownloadsCompleted;
Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " +
intent.getAction() + " --> total count: " + mNumDownloadsCompleted);
}
}
/**
* 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;
}
}
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);
return info.isConnected();
}
}
/**
* {@inheritDoc}
*/
@Override
public void setUp() throws Exception {
mContext = getInstrumentation().getContext();
mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE);
mServer = new MockWebServer();
// 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)
*/
protected 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)
*/
protected 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)
*/
protected 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.
*
* @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}.
* @return The random data that is generated.
*/
protected byte[] generateData(int size, DataType type) {
return generateData(size, type, null);
}
/**
* 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.
*/
protected 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
*/
protected 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
*/
protected 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.");
}
}
}
/**
* Verifies the contents of a downloaded file versus the contents of a File.
*
* @param pfd The file whose data we want to verify
* @param file The file containing the data we expect to see in the aforementioned file
* @throws IOException If there was a problem reading either of the two files
*/
protected void verifyFileContents(ParcelFileDescriptor pfd, File file) throws IOException {
byte[] actual = new byte[FILE_BLOCK_READ_SIZE];
byte[] expected = new byte[FILE_BLOCK_READ_SIZE];
AutoCloseInputStream input = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
assertEquals(file.length(), pfd.getStatSize());
DataInputStream inFile = new DataInputStream(new FileInputStream(file));
int actualRead = 0;
int expectedRead = 0;
while (((actualRead = input.read(actual)) != -1) &&
((expectedRead = inFile.read(expected)) != -1)) {
assertEquals(actualRead, expectedRead);
compareByteArrays(actual, expected);
}
}
/**
* Sets the MIME type of file that will be served from the mock server
*
* @param type The MIME type to return from the server
*/
protected void setServerMimeType(DownloadFileType type) {
mFileType = getMimeMapping(type);
}
/**
* 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
*/
protected Uri getServerUri(String filename) throws Exception {
URL url = mServer.getUrl("/" + filename);
return Uri.parse(url.toString());
}
/**
* 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
*/
protected void logDBColumnData(Cursor cursor, String column) {
int index = cursor.getColumnIndex(column);
Log.i(LOG_TAG, "columnName: " + column);
Log.i(LOG_TAG, "columnValue: " + cursor.getString(index));
}
/**
* 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;
}
/**
* 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
*/
protected void verifyAndCleanupSingleFileDownload(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());
mServer.checkForExceptions();
verifyFileSize(pfd, fileSize);
verifyFileContents(pfd, fileData);
} finally {
pfd.close();
cursor.close();
mDownloadManager.remove(requestId);
}
}
/**
* 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 {
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_MAX_WAIT_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 create a large file of random data on the SD card.
*
* @param filename (optional) The name of the file to create on the SD card; pass in null to
* use a default temp filename.
* @param type The type of file to create
* @param subdirectory If not null, the subdirectory under the SD card where the file should go
* @return The File that was created
* @throws IOException if there was an error while creating the file.
*/
protected File createFileOnSD(String filename, long fileSize, DataType type,
String subdirectory) throws IOException {
// Build up the file path and name
String sdPath = Environment.getExternalStorageDirectory().getPath();
StringBuilder fullPath = new StringBuilder(sdPath);
if (subdirectory != null) {
fullPath.append(File.separatorChar).append(subdirectory);
}
File file = null;
if (filename == null) {
file = File.createTempFile("DMTEST_", null, new File(fullPath.toString()));
}
else {
fullPath.append(File.separatorChar).append(filename);
file = new File(fullPath.toString());
file.createNewFile();
}
// Fill the file with random data
DataOutputStream output = new DataOutputStream(new FileOutputStream(file));
final int CHUNK_SIZE = 1000000; // copy random data in 1000000-char chunks
long remaining = fileSize;
int nextChunkSize = CHUNK_SIZE;
byte[] randomData = null;
Random rng = new LoggingRng();
try {
while (remaining > 0) {
if (remaining < CHUNK_SIZE) {
nextChunkSize = (int)remaining;
remaining = 0;
}
else {
remaining -= CHUNK_SIZE;
}
randomData = generateData(nextChunkSize, type, rng);
output.write(randomData);
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error writing to file " + file.getAbsolutePath());
file.delete();
throw e;
} finally {
output.close();
}
return file;
}
/**
* Helper to wait for a particular download to finish, or else a timeout to occur
*
* @param id The download id to query on (wait for)
*/
protected void waitForDownloadOrTimeout(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
*
* @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);
}
/**
* Helper to wait for all downloads to finish, or else a specified timeout to occur
*
* @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
*
* @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
*/
protected boolean waitForDownloadOrTimeoutNoThrow(long id, long poll, long timeoutMillis) {
try {
doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis);
} 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
*/
protected 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
*/
protected 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 we've finished the downloads then we're done
if (cursor.getCount() == 0) {
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 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.
*
* @param body The body to return in the response from the server
*/
protected 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
*/
protected 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.
*/
protected long doCommonStandardEnqueue() throws Exception {
Uri uri = getServerUri(DEFAULT_FILENAME);
Request request = new Request(uri);
request.setTitle(DEFAULT_FILENAME);
long dlRequest = mDownloadManager.enqueue(request);
Log.i(LOG_TAG, "request ID: " + dlRequest);
return dlRequest;
}
/**
* 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
*/
protected void verifyInt(Cursor cursor, String columnName, int expected) {
int index = cursor.getColumnIndex(columnName);
int actual = cursor.getInt(index);
assertEquals(expected, actual);
}
/**
* Helper to verify a String 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 String value
*/
protected void verifyString(Cursor cursor, String columnName, String expected) {
int index = cursor.getColumnIndex(columnName);
String actual = cursor.getString(index);
Log.i(LOG_TAG, ": " + actual);
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;
}
}

View File

@ -0,0 +1,381 @@
/*
* 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 android.net;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.DownloadManager.Query;
import android.net.DownloadManager.Request;
import android.net.DownloadManagerBaseTest.DataType;
import android.net.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
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.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.Random;
import junit.framework.AssertionFailedError;
import coretestutils.http.MockResponse;
import coretestutils.http.MockWebServer;
/**
* Integration tests of the DownloadManager API.
*/
public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest {
private static String LOG_TAG = "android.net.DownloadManagerIntegrationTest";
private static String PROHIBITED_DIRECTORY = "/system";
protected MultipleDownloadsCompletedReceiver mReceiver = null;
/**
* {@inheritDoc}
*/
@Override
public void setUp() throws Exception {
super.setUp();
setWiFiStateOn(true);
mServer.play();
removeAllCurrentDownloads();
mReceiver = registerNewMultipleDownloadsReceiver();
}
/**
* {@inheritDoc}
*/
@Override
public void tearDown() throws Exception {
super.tearDown();
setWiFiStateOn(true);
if (mReceiver != null) {
mContext.unregisterReceiver(mReceiver);
mReceiver = null;
removeAllCurrentDownloads();
}
}
/**
* Helper that does the actual basic download verification.
*/
protected void doBasicDownload(byte[] blobData) throws Exception {
long dlRequest = doStandardEnqueue(blobData);
// wait for the download to complete
waitForDownloadOrTimeout(dlRequest);
verifyAndCleanupSingleFileDownload(dlRequest, blobData);
assertEquals(1, mReceiver.numDownloadsCompleted());
}
/**
* Test a basic download of a binary file 500k in size.
*/
@LargeTest
public void testBasicBinaryDownload() throws Exception {
int fileSize = 500 * 1024; // 500k
byte[] blobData = generateData(fileSize, DataType.BINARY);
doBasicDownload(blobData);
}
/**
* Tests the basic downloading of a text file 300000 bytes in size.
*/
@LargeTest
public void testBasicTextDownload() throws Exception {
int fileSize = 300000;
byte[] blobData = generateData(fileSize, DataType.TEXT);
doBasicDownload(blobData);
}
/**
* 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_ERROR_CODE,
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());
}
/**
* Attempts to download several files simultaneously
*/
@LargeTest
public void testMultipleDownloads() throws Exception {
// need to be sure all current downloads have stopped first
removeAllCurrentDownloads();
int NUM_FILES = 50;
int MAX_FILE_SIZE = 500 * 1024; // 500 kb
Random r = new LoggingRng();
for (int i=0; i<NUM_FILES; ++i) {
int size = r.nextInt(MAX_FILE_SIZE);
byte[] blobData = generateData(size, DataType.TEXT);
Uri uri = getServerUri(DEFAULT_FILENAME);
Request request = new Request(uri);
request.setTitle(String.format("%s--%d", DEFAULT_FILENAME, i));
// Prepare the mock server with a standard response
enqueueResponse(HTTP_OK, blobData);
Log.i(LOG_TAG, "request: " + i);
mDownloadManager.enqueue(request);
}
waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
Cursor cursor = mDownloadManager.query(new Query());
try {
assertEquals(NUM_FILES, cursor.getCount());
if (cursor.moveToFirst()) {
do {
int status = cursor.getInt(cursor.getColumnIndex(
DownloadManager.COLUMN_STATUS));
String filename = cursor.getString(cursor.getColumnIndex(
DownloadManager.COLUMN_URI));
String errorString = String.format(
"File %s failed to download successfully. Status code: %d",
filename, status);
assertEquals(errorString, DownloadManager.STATUS_SUCCESSFUL, status);
} while (cursor.moveToNext());
}
assertEquals(NUM_FILES, mReceiver.numDownloadsCompleted());
} finally {
cursor.close();
}
}
/**
* Tests trying to download to SD card when the file with same name already exists.
*/
@LargeTest
public void testDownloadToExternal_fileExists() throws Exception {
File existentFile = createFileOnSD(null, 1, DataType.TEXT, null);
byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
// Prepare the mock server with a standard response
enqueueResponse(HTTP_OK, blobData);
try {
Uri uri = getServerUri(DEFAULT_FILENAME);
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);
// wait for the download to complete
waitForDownloadOrTimeout(dlRequest);
Cursor cursor = getCursor(dlRequest);
try {
verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED);
verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE,
DownloadManager.ERROR_FILE_ERROR);
} finally {
cursor.close();
}
} finally {
existentFile.delete();
}
}
/**
* Tests trying to download a file to SD card.
*/
@LargeTest
public void testDownloadToExternal() throws Exception {
String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
File downloadedFile = new File(localDownloadDirectory, DEFAULT_FILENAME);
// make sure the file doesn't already exist in the directory
downloadedFile.delete();
try {
byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
// Prepare the mock server with a standard response
enqueueResponse(HTTP_OK, blobData);
Uri uri = getServerUri(DEFAULT_FILENAME);
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);
// wait for the download to complete
waitForDownloadOrTimeout(dlRequest);
verifyAndCleanupSingleFileDownload(dlRequest, blobData);
assertEquals(1, mReceiver.numDownloadsCompleted());
} finally {
downloadedFile.delete();
}
}
/**
* Tests trying to download a file to the system partition.
*/
@LargeTest
public void testDownloadToProhibitedDirectory() throws Exception {
File downloadedFile = new File(PROHIBITED_DIRECTORY, DEFAULT_FILENAME);
try {
byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
// Prepare the mock server with a standard response
enqueueResponse(HTTP_OK, blobData);
Uri uri = getServerUri(DEFAULT_FILENAME);
Request request = new Request(uri);
Uri localUri = Uri.fromFile(downloadedFile);
Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath());
request.setDestinationUri(localUri);
try {
mDownloadManager.enqueue(request);
fail("Failed to throw SecurityException when trying to write to /system.");
} catch (SecurityException s) {
assertFalse(downloadedFile.exists());
}
} finally {
// Just in case file somehow got created, make sure to delete it
downloadedFile.delete();
}
}
/**
* 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
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 trying to download two large files (50M bytes, followed by 60M bytes)
*/
@LargeTest
public void testInsufficientSpaceSingleFiles() throws Exception {
long fileSize1 = 50000000L;
long fileSize2 = 60000000L;
File largeFile1 = createFileOnSD(null, fileSize1, DataType.TEXT, null);
File largeFile2 = createFileOnSD(null, fileSize2, DataType.TEXT, null);
try {
long dlRequest = doStandardEnqueue(largeFile1);
waitForDownloadOrTimeout(dlRequest);
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileContents(pfd, largeFile1);
verifyFileSize(pfd, largeFile1.length());
dlRequest = doStandardEnqueue(largeFile2);
waitForDownloadOrTimeout(dlRequest);
Cursor cursor = getCursor(dlRequest);
try {
verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE,
DownloadManager.ERROR_INSUFFICIENT_SPACE);
} finally {
cursor.close();
}
} finally {
largeFile1.delete();
largeFile2.delete();
}
}
}

View File

@ -0,0 +1,156 @@
/*
* 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 android.net;
import java.io.File;
import java.util.Random;
import android.database.Cursor;
import android.net.DownloadManager.Query;
import android.net.DownloadManager.Request;
import android.os.ParcelFileDescriptor;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
public class DownloadManagerStressTest extends DownloadManagerBaseTest {
private static String LOG_TAG = "android.net.DownloadManagerStressTest";
/**
* {@inheritDoc}
*/
@Override
public void setUp() throws Exception {
super.setUp();
mServer.play(0);
removeAllCurrentDownloads();
}
/**
* Attempts to downloading thousands of files simultaneously
*/
public void testDownloadThousands() throws Exception {
int NUM_FILES = 1500;
int MAX_FILE_SIZE = 3000;
long[] reqs = new long[NUM_FILES];
// need to be sure all current downloads have stopped first
MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver();
Cursor cursor = null;
try {
Random r = new LoggingRng();
for (int i = 0; i < NUM_FILES; ++i) {
int size = r.nextInt(MAX_FILE_SIZE);
byte[] blobData = generateData(size, DataType.TEXT);
Uri uri = getServerUri(DEFAULT_FILENAME);
Request request = new Request(uri);
request.setTitle(String.format("%s--%d", DEFAULT_FILENAME, i));
// Prepare the mock server with a standard response
enqueueResponse(HTTP_OK, blobData);
Log.i(LOG_TAG, "issuing request: " + i);
long reqId = mDownloadManager.enqueue(request);
reqs[i] = reqId;
}
// wait for the download to complete or timeout
waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
cursor = mDownloadManager.query(new Query());
assertEquals(NUM_FILES, cursor.getCount());
Log.i(LOG_TAG, "Verified number of downloads in download manager is what we expect.");
while (cursor.moveToNext()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
String filename = cursor.getString(cursor.getColumnIndex(
DownloadManager.COLUMN_URI));
String errorString = String.format("File %s failed to download successfully. " +
"Status code: %d", filename, status);
assertEquals(errorString, DownloadManager.STATUS_SUCCESSFUL, status);
}
Log.i(LOG_TAG, "Verified each download was successful.");
assertEquals(NUM_FILES, receiver.numDownloadsCompleted());
Log.i(LOG_TAG, "Verified number of completed downloads in our receiver.");
// Verify that for each request, we can open the downloaded file
for (int i = 0; i < NUM_FILES; ++i) {
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(reqs[i]);
pfd.close();
}
Log.i(LOG_TAG, "Verified we can open each file.");
} finally {
if (cursor != null) {
cursor.close();
}
mContext.unregisterReceiver(receiver);
removeAllCurrentDownloads();
}
}
/**
* Tests trying to download a large file (50M bytes).
*/
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);
MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver();
try {
long dlRequest = doStandardEnqueue(largeFile);
// wait for the download to complete
waitForDownloadOrTimeout(dlRequest);
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileContents(pfd, largeFile);
verifyFileSize(pfd, largeFile.length());
assertEquals(1, receiver.numDownloadsCompleted());
mContext.unregisterReceiver(receiver);
} catch (Exception e) {
throw e;
} finally {
largeFile.delete();
}
}
/**
* Tests trying to download a large file (~300M bytes) when there's not enough space in cache
*/
public void testInsufficientSpace() throws Exception {
long fileSize = 300000000L;
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_ERROR_CODE,
DownloadManager.ERROR_INSUFFICIENT_SPACE);
} finally {
if (cursor != null) {
cursor.close();
}
largeFile.delete();
}
}
}

View File

@ -37,7 +37,9 @@ import java.io.InputStreamReader;
import java.io.StringReader;
import java.lang.Runtime;
import java.lang.Process;
import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -117,7 +119,14 @@ public class PackageManagerHostTestUtils extends Assert {
/**
* Helper method to run tests and return the listener that collected the results.
*
* For the optional params, pass null to use the default values.
* @param pkgName Android application package for tests
* @param className (optional) The class containing the method to test
* @param methodName (optional) The method in the class of which to test
* @param runnerName (optional) The name of the TestRunner of the test on the device to be run
* @param params (optional) Any additional parameters to pass into the Test Runner
* @return the {@link CollectingTestRunListener}
* @throws TimeoutException in case of a timeout on the connection.
* @throws AdbCommandRejectedException if adb rejects the command
@ -125,15 +134,46 @@ public class PackageManagerHostTestUtils extends Assert {
* a period longer than the max time to output.
* @throws IOException if connection to device was lost.
*/
private CollectingTestRunListener doRunTests(String pkgName) throws IOException,
TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
pkgName, mDevice);
private CollectingTestRunListener doRunTests(String pkgName, String className, String
methodName, String runnerName, Map<String, String> params) throws IOException,
TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName, runnerName,
mDevice);
if (className != null && methodName != null) {
testRunner.setMethodName(className, methodName);
}
// Add in any additional args to pass into the test
if (params != null) {
for (Entry<String, String> argPair : params.entrySet()) {
testRunner.addInstrumentationArg(argPair.getKey(), argPair.getValue());
}
}
CollectingTestRunListener listener = new CollectingTestRunListener();
testRunner.run(listener);
return listener;
}
/**
* Runs the specified packages tests, and returns whether all tests passed or not.
*
* @param pkgName Android application package for tests
* @param className The class containing the method to test
* @param methodName The method in the class of which to test
* @param runnerName The name of the TestRunner of the test on the device to be run
* @param params Any additional parameters to pass into the Test Runner
* @return true if test passed, false otherwise.
*/
public boolean runDeviceTestsDidAllTestsPass(String pkgName, String className,
String methodName, String runnerName, Map<String, String> params) throws IOException {
CollectingTestRunListener listener = doRunTests(pkgName, className, methodName,
runnerName, params);
return listener.didAllTestsPass();
}
/**
* Runs the specified packages tests, and returns whether all tests passed or not.
*
@ -145,9 +185,9 @@ public class PackageManagerHostTestUtils extends Assert {
* a period longer than the max time to output.
* @throws IOException if connection to device was lost.
*/
public boolean runDeviceTestsDidAllTestsPass(String pkgName) throws IOException,
public boolean runDeviceTestsDidAllTestsPass(String pkgName) throws IOException,
TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException {
CollectingTestRunListener listener = doRunTests(pkgName);
CollectingTestRunListener listener = doRunTests(pkgName, null, null, null, null);
return listener.didAllTestsPass();
}
@ -531,7 +571,7 @@ public class PackageManagerHostTestUtils extends Assert {
}
// For collecting results from running device tests
private static class CollectingTestRunListener implements ITestRunListener {
public static class CollectingTestRunListener implements ITestRunListener {
private boolean mAllTestsPassed = true;
private String mTestRunErrorMessage = null;

View File

@ -0,0 +1,201 @@
/*
* 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 android.net;
import android.content.pm.PackageManagerHostTestUtils;
import android.content.pm.PackageManagerHostTestUtils.CollectingTestRunListener;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.Log;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.SyncService;
import com.android.ddmlib.SyncService.ISyncProgressMonitor;
import com.android.ddmlib.SyncService.SyncResult;
import com.android.hosttest.DeviceTestCase;
import com.android.hosttest.DeviceTestSuite;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
import junit.framework.Test;
/**
* Host-based tests of the DownloadManager API. (Uses a device-based app to actually invoke the
* various tests.)
*/
public class DownloadManagerHostTests extends DeviceTestCase {
protected PackageManagerHostTestUtils mPMUtils = null;
private static final String LOG_TAG = "android.net.DownloadManagerHostTests";
private static final String FILE_DOWNLOAD_APK = "DownloadManagerTestApp.apk";
private static final String FILE_DOWNLOAD_PKG = "com.android.frameworks.downloadmanagertests";
private static final String FILE_DOWNLOAD_CLASS =
"com.android.frameworks.downloadmanagertests.DownloadManagerTestApp";
private static final String DOWNLOAD_TEST_RUNNER_NAME =
"com.android.frameworks.downloadmanagertests.DownloadManagerTestRunner";
// Extra parameters to pass to the TestRunner
private static final String EXTERNAL_DOWNLOAD_URI_KEY = "external_download_uri";
// Note: External environment variable ANDROID_TEST_EXTERNAL_URI must be set to point to the
// external URI under which the files downloaded by the tests can be found. Note that the Uri
// must be accessible by the device during a test run.
private static String EXTERNAL_DOWNLOAD_URI_VALUE = null;
Hashtable<String, String> mExtraParams = null;
public static Test suite() {
return new DeviceTestSuite(DownloadManagerHostTests.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
// ensure apk path has been set before test is run
assertNotNull(getTestAppPath());
mPMUtils = new PackageManagerHostTestUtils(getDevice());
EXTERNAL_DOWNLOAD_URI_VALUE = System.getenv("ANDROID_TEST_EXTERNAL_URI");
assertNotNull(EXTERNAL_DOWNLOAD_URI_VALUE);
mExtraParams = getExtraParams();
}
/**
* Helper function to get extra params that can be used to pass into the helper app.
*/
protected Hashtable<String, String> getExtraParams() {
Hashtable<String, String> extraParams = new Hashtable<String, String>();
extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, EXTERNAL_DOWNLOAD_URI_VALUE);
return extraParams;
}
/**
* Tests that a large download over WiFi
* @throws Exception if the test failed at any point
*/
public void testLargeDownloadOverWiFi() throws Exception {
mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "runLargeDownloadOverWiFi", DOWNLOAD_TEST_RUNNER_NAME,
mExtraParams);
assertTrue("Failed to install large file over WiFi in < 10 minutes!", testPassed);
}
/**
* Spawns a device-based function to initiate a download on the device, reboots the device,
* then waits and verifies the download succeeded.
*
* @throws Exception if the test failed at any point
*/
public void testDownloadManagerSingleReboot() throws Exception {
mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "initiateDownload", DOWNLOAD_TEST_RUNNER_NAME,
mExtraParams);
assertTrue("Failed to initiate download properly!", testPassed);
mPMUtils.rebootDevice();
testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "verifyFileDownloadSucceeded", DOWNLOAD_TEST_RUNNER_NAME,
mExtraParams);
assertTrue("Failed to verify initiated download completed properyly!", testPassed);
}
/**
* Spawns a device-based function to initiate a download on the device, reboots the device three
* times (using different intervals), then waits and verifies the download succeeded.
*
* @throws Exception if the test failed at any point
*/
public void testDownloadManagerMultipleReboots() throws Exception {
mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "initiateDownload", DOWNLOAD_TEST_RUNNER_NAME,
mExtraParams);
assertTrue("Failed to initiate download properly!", testPassed);
Thread.sleep(5000);
// Do 3 random reboots - after 13, 9, and 19 seconds
Log.i(LOG_TAG, "First reboot...");
mPMUtils.rebootDevice();
Thread.sleep(13000);
Log.i(LOG_TAG, "Second reboot...");
mPMUtils.rebootDevice();
Thread.sleep(9000);
Log.i(LOG_TAG, "Third reboot...");
mPMUtils.rebootDevice();
Thread.sleep(19000);
testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "verifyFileDownloadSucceeded", DOWNLOAD_TEST_RUNNER_NAME,
mExtraParams);
assertTrue("Failed to verify initiated download completed properyly!", testPassed);
}
/**
* Spawns a device-based function to test download while WiFi is enabled/disabled multiple times
* during the download.
*
* @throws Exception if the test failed at any point
*/
public void testDownloadMultipleWiFiEnableDisable() throws Exception {
mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "runDownloadMultipleWiFiEnableDisable",
DOWNLOAD_TEST_RUNNER_NAME, mExtraParams);
assertTrue(testPassed);
}
/**
* Spawns a device-based function to test switching on/off both airplane mode and WiFi
*
* @throws Exception if the test failed at any point
*/
public void testDownloadMultipleSwitching() throws Exception {
mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "runDownloadMultipleSwitching",
DOWNLOAD_TEST_RUNNER_NAME, mExtraParams);
assertTrue(testPassed);
}
/**
* Spawns a device-based function to test switching on/off airplane mode multiple times
*
* @throws Exception if the test failed at any point
*/
public void testDownloadMultipleAirplaneModeEnableDisable() throws Exception {
mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(),
File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true);
boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG,
FILE_DOWNLOAD_CLASS, "runDownloadMultipleAirplaneModeEnableDisable",
DOWNLOAD_TEST_RUNNER_NAME, mExtraParams);
assertTrue(testPassed);
}
}

View File

@ -0,0 +1,29 @@
# 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.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
../../../coretests/src/android/net/DownloadManagerBaseTest.java
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := DownloadManagerTestApp
include $(BUILD_PACKAGE)

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.downloadmanagertests">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application android:label="DownloadManagerTestApp">
<uses-library android:name="android.test.runner" />
</application>
<instrumentation
android:name=".DownloadManagerTestRunner"
android:targetPackage="com.android.frameworks.downloadmanagertests"
android:label="Frameworks Download Manager Test App" />
</manifest>

View File

@ -0,0 +1,463 @@
/*
* 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.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.DownloadManager;
import android.net.DownloadManager.Query;
import android.net.DownloadManager.Request;
import android.net.DownloadManagerBaseTest;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.Settings;
import android.test.suitebuilder.annotation.LargeTest;
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.FileWriter;
import coretestutils.http.MockResponse;
import coretestutils.http.MockWebServer;
import coretestutils.http.RecordedRequest;
/**
* Class to test downloading files from a real (not mock) external server.
*/
public class DownloadManagerTestApp extends DownloadManagerBaseTest {
protected static String DOWNLOAD_STARTED_FLAG = "DMTEST_DOWNLOAD_STARTED";
protected static String LOG_TAG =
"com.android.frameworks.downloadmanagertests.DownloadManagerTestApp";
protected static String DOWNLOAD_500K_FILENAME = "External541kb.apk";
protected static long DOWNLOAD_500K_FILESIZE = 570927;
protected static String DOWNLOAD_1MB_FILENAME = "External1mb.apk";
protected static long DOWNLOAD_1MB_FILESIZE = 1041262;
protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk";
protected static long DOWNLOAD_10MB_FILESIZE = 10258741;
// Values to be obtained from TestRunner
private String externalDownloadUriValue = null;
/**
* {@inheritDoc }
*/
@Override
public void setUp() throws Exception {
super.setUp();
DownloadManagerTestRunner mRunner = (DownloadManagerTestRunner)getInstrumentation();
externalDownloadUriValue = mRunner.externalDownloadUriValue;
assertNotNull(externalDownloadUriValue);
if (!externalDownloadUriValue.endsWith("/")) {
externalDownloadUriValue += "/";
}
}
/**
* Gets the external URL of the file to download
*
* @return the Uri of the external file to download
*/
private Uri getExternalFileUri(String file) {
return Uri.parse(externalDownloadUriValue + file);
}
/**
* Gets the path to the file that flags that a download has started. The file contains the
* DownloadManager id of the download being trackted between reboot sessions.
*
* @return The path of the file tracking that a download has started
* @throws InterruptedException if interrupted
* @throws Exception if timed out while waiting for SD card to mount
*/
protected String getDownloadStartedFilePath() {
String path = Environment.getExternalStorageDirectory().getPath();
return path + File.separatorChar + DOWNLOAD_STARTED_FLAG;
}
/**
* Common setup steps for downloads.
*
* Note that these are not included in setUp, so that individual tests can control their own
* state between reboots, etc.
*/
protected void doCommonDownloadSetup() throws Exception {
setWiFiStateOn(true);
setAirplaneModeOn(false);
waitForExternalStoreMount();
removeAllCurrentDownloads();
}
/**
* Initiates a download.
*
* Queues up a download to the download manager, and saves the DownloadManager's assigned
* download ID for this download to a file.
*
* @throws Exception if unsuccessful
*/
public void initiateDownload() throws Exception {
String filename = DOWNLOAD_1MB_FILENAME;
mContext.deleteFile(DOWNLOAD_STARTED_FLAG);
FileOutputStream fileOutput = mContext.openFileOutput(DOWNLOAD_STARTED_FLAG, 0);
DataOutputStream outputFile = null;
doCommonDownloadSetup();
try {
long dlRequest = -1;
// Make sure there are no pending downloads currently going on
removeAllCurrentDownloads();
Uri remoteUri = getExternalFileUri(filename);
Request request = new Request(remoteUri);
dlRequest = mDownloadManager.enqueue(request);
waitForDownloadToStart(dlRequest);
assertTrue(dlRequest != -1);
// Store ID of download for later retrieval
outputFile = new DataOutputStream(fileOutput);
outputFile.writeLong(dlRequest);
} finally {
if (outputFile != null) {
outputFile.flush();
outputFile.close();
}
}
}
/**
* Waits for a previously-initiated download and verifies it has completed successfully.
*
* @throws Exception if unsuccessful
*/
public void verifyFileDownloadSucceeded() throws Exception {
String filename = DOWNLOAD_1MB_FILENAME;
long filesize = DOWNLOAD_1MB_FILESIZE;
long dlRequest = -1;
boolean rebootMarkerValid = false;
DataInputStream dataInputFile = null;
setWiFiStateOn(true);
setAirplaneModeOn(false);
try {
FileInputStream inFile = mContext.openFileInput(DOWNLOAD_STARTED_FLAG);
dataInputFile = new DataInputStream(inFile);
dlRequest = dataInputFile.readLong();
} catch (Exception e) {
// The file was't valid so we just leave the flag false
Log.i(LOG_TAG, "Unable to determine initial download id.");
throw e;
} finally {
if (dataInputFile != null) {
dataInputFile.close();
}
mContext.deleteFile(DOWNLOAD_STARTED_FLAG);
}
assertTrue(dlRequest != -1);
Cursor cursor = getCursor(dlRequest);
ParcelFileDescriptor pfd = null;
try {
assertTrue("Unable to query last initiated download!", cursor.moveToFirst());
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int currentWaitTime = 0;
// Wait until the download finishes
waitForDownloadOrTimeout(dlRequest);
Log.i(LOG_TAG, "Verifying download information...");
// Verify specific info about the file (size, name, etc)...
pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} catch (Exception e) {
Log.i(LOG_TAG, "error: " + e.toString());
throw e;
} finally {
// Clean up...
cursor.close();
mDownloadManager.remove(dlRequest);
if (pfd != null) {
pfd.close();
}
}
}
/**
* Tests downloading a large file over WiFi (~10 Mb).
*
* @throws Exception if unsuccessful
*/
public void runLargeDownloadOverWiFi() throws Exception {
String filename = DOWNLOAD_10MB_FILENAME;
long filesize = DOWNLOAD_10MB_FILESIZE;
long dlRequest = -1;
doCommonDownloadSetup();
// Make sure there are no pending downloads currently going on
removeAllCurrentDownloads();
Uri remoteUri = getExternalFileUri(filename);
Request request = new Request(remoteUri);
request.setMediaType(getMimeMapping(DownloadFileType.APK));
dlRequest = mDownloadManager.enqueue(request);
// Rather large file, so wait up to 15 mins...
waitForDownloadOrTimeout(dlRequest, WAIT_FOR_DOWNLOAD_POLL_TIME, 15 * 60 * 1000);
Cursor cursor = getCursor(dlRequest);
ParcelFileDescriptor pfd = null;
try {
Log.i(LOG_TAG, "Verifying download information...");
// Verify specific info about the file (size, name, etc)...
pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} finally {
if (pfd != null) {
pfd.close();
}
mDownloadManager.remove(dlRequest);
cursor.close();
}
}
/**
* Tests that downloads resume when switching back and forth from having connectivity to
* having no connectivity using both WiFi and airplane mode.
*
* Note: Device has no mobile access when running this test.
*
* @throws Exception if unsuccessful
*/
public void runDownloadMultipleSwitching() throws Exception {
String filename = DOWNLOAD_500K_FILENAME;
long filesize = DOWNLOAD_500K_FILESIZE;
doCommonDownloadSetup();
String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
File downloadedFile = new File(localDownloadDirectory, filename);
long dlRequest = -1;
try {
downloadedFile.delete();
// Make sure there are no pending downloads currently going on
removeAllCurrentDownloads();
Uri remoteUri = getExternalFileUri(filename);
Request request = new Request(remoteUri);
// Local destination of downloaded file
Uri localUri = Uri.fromFile(downloadedFile);
Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath());
request.setDestinationUri(localUri);
request.setAllowedNetworkTypes(Request.NETWORK_MOBILE | Request.NETWORK_WIFI);
dlRequest = mDownloadManager.enqueue(request);
waitForDownloadToStart(dlRequest);
// make sure we're starting to download some data...
waitForFileToGrow(downloadedFile);
// download disable
setWiFiStateOn(false);
// download disable
Log.i(LOG_TAG, "Turning on airplane mode...");
setAirplaneModeOn(true);
Thread.sleep(30 * 1000); // wait 30 secs
// download disable
setWiFiStateOn(true);
Thread.sleep(30 * 1000); // wait 30 secs
// download enable
Log.i(LOG_TAG, "Turning off airplane mode...");
setAirplaneModeOn(false);
Thread.sleep(5 * 1000); // wait 5 seconds
// download disable
Log.i(LOG_TAG, "Turning off WiFi...");
setWiFiStateOn(false);
Thread.sleep(30 * 1000); // wait 30 secs
// finally, turn WiFi back on and finish up the download
Log.i(LOG_TAG, "Turning on WiFi...");
setWiFiStateOn(true);
Log.i(LOG_TAG, "Waiting up to 3 minutes for download to complete...");
waitForDownloadsOrTimeout(dlRequest, 3 * 60 * 1000);
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} finally {
Log.i(LOG_TAG, "Cleaning up files...");
if (dlRequest != -1) {
mDownloadManager.remove(dlRequest);
}
downloadedFile.delete();
}
}
/**
* Tests that downloads resume when switching on/off WiFi at various intervals.
*
* Note: Device has no mobile access when running this test.
*
* @throws Exception if unsuccessful
*/
public void runDownloadMultipleWiFiEnableDisable() throws Exception {
String filename = DOWNLOAD_500K_FILENAME;
long filesize = DOWNLOAD_500K_FILESIZE;
doCommonDownloadSetup();
String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
File downloadedFile = new File(localDownloadDirectory, filename);
long dlRequest = -1;
try {
downloadedFile.delete();
// Make sure there are no pending downloads currently going on
removeAllCurrentDownloads();
Uri remoteUri = getExternalFileUri(filename);
Request request = new Request(remoteUri);
// Local destination of downloaded file
Uri localUri = Uri.fromFile(downloadedFile);
Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath());
request.setDestinationUri(localUri);
request.setAllowedNetworkTypes(Request.NETWORK_WIFI);
dlRequest = mDownloadManager.enqueue(request);
waitForDownloadToStart(dlRequest);
// are we making any progress?
waitForFileToGrow(downloadedFile);
// download disable
Log.i(LOG_TAG, "Turning off WiFi...");
setWiFiStateOn(false);
Thread.sleep(40 * 1000); // wait 40 seconds
// enable download...
Log.i(LOG_TAG, "Turning on WiFi again...");
setWiFiStateOn(true);
waitForFileToGrow(downloadedFile);
// download disable
Log.i(LOG_TAG, "Turning off WiFi...");
setWiFiStateOn(false);
Thread.sleep(20 * 1000); // wait 20 seconds
// enable download...
Log.i(LOG_TAG, "Turning on WiFi again...");
setWiFiStateOn(true);
Log.i(LOG_TAG, "Waiting up to 3 minutes for download to complete...");
waitForDownloadsOrTimeout(dlRequest, 3 * 60 * 1000);
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} finally {
Log.i(LOG_TAG, "Cleaning up files...");
if (dlRequest != -1) {
mDownloadManager.remove(dlRequest);
}
downloadedFile.delete();
}
}
/**
* Tests that downloads resume when switching on/off Airplane mode numerous times at
* various intervals.
*
* Note: Device has no mobile access when running this test.
*
* @throws Exception if unsuccessful
*/
public void runDownloadMultipleAirplaneModeEnableDisable() throws Exception {
String filename = DOWNLOAD_500K_FILENAME;
long filesize = DOWNLOAD_500K_FILESIZE;
// make sure WiFi is enabled, and airplane mode is not on
doCommonDownloadSetup();
String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
File downloadedFile = new File(localDownloadDirectory, filename);
long dlRequest = -1;
try {
downloadedFile.delete();
// Make sure there are no pending downloads currently going on
removeAllCurrentDownloads();
Uri remoteUri = getExternalFileUri(filename);
Request request = new Request(remoteUri);
// Local destination of downloaded file
Uri localUri = Uri.fromFile(downloadedFile);
Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath());
request.setDestinationUri(localUri);
request.setAllowedNetworkTypes(Request.NETWORK_WIFI);
dlRequest = mDownloadManager.enqueue(request);
waitForDownloadToStart(dlRequest);
// are we making any progress?
waitForFileToGrow(downloadedFile);
// download disable
Log.i(LOG_TAG, "Turning on Airplane mode...");
setAirplaneModeOn(true);
Thread.sleep(60 * 1000); // wait 1 minute
// download enable
Log.i(LOG_TAG, "Turning off Airplane mode...");
setAirplaneModeOn(false);
// make sure we're starting to download some data...
waitForFileToGrow(downloadedFile);
// reenable the connection to start up the download again
Log.i(LOG_TAG, "Turning on Airplane mode again...");
setAirplaneModeOn(true);
Thread.sleep(20 * 1000); // wait 20 seconds
// Finish up the download...
Log.i(LOG_TAG, "Turning off Airplane mode again...");
setAirplaneModeOn(false);
Log.i(LOG_TAG, "Waiting up to 3 minutes for donwload to complete...");
waitForDownloadsOrTimeout(dlRequest, 180 * 1000); // wait up to 3 mins before timeout
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} finally {
Log.i(LOG_TAG, "Cleaning up files...");
if (dlRequest != -1) {
mDownloadManager.remove(dlRequest);
}
downloadedFile.delete();
}
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.os.Bundle;
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
import android.util.Log;
import com.android.frameworks.downloadmanagertests.DownloadManagerTestApp;
import junit.framework.TestSuite;
/**
* Instrumentation Test Runner for all download manager tests.
*
* To run the download manager tests:
*
* adb shell am instrument -e external_download_1mb_uri <uri> external_download_500k_uri <uri> \
* -w com.android.frameworks.downloadmanagertests/.DownloadManagerTestRunner
*/
public class DownloadManagerTestRunner extends InstrumentationTestRunner {
private static final String EXTERNAL_DOWNLOAD_URI_KEY = "external_download_uri";
public String externalDownloadUriValue = null;
@Override
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(DownloadManagerTestApp.class);
return suite;
}
@Override
public ClassLoader getLoader() {
return DownloadManagerTestRunner.class.getClassLoader();
}
@Override
public void onCreate(Bundle icicle) {
// Extract the extra params passed in from the bundle...
String externalDownloadUri = (String) icicle.get(EXTERNAL_DOWNLOAD_URI_KEY);
if (externalDownloadUri != null) {
externalDownloadUriValue = externalDownloadUri;
}
super.onCreate(icicle);
}
}

View File

@ -0,0 +1,27 @@
# 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := frameworks-core-util-lib
include $(BUILD_STATIC_JAVA_LIBRARY)
# Build the test APKs using their own makefiles
include $(call all-makefiles-under,$(LOCAL_PATH))

View File

@ -0,0 +1,239 @@
/*
* 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 coretestutils.http;
import static coretestutils.http.MockWebServer.ASCII;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.util.Log;
/**
* A scripted response to be replayed by the mock web server.
*/
public class MockResponse {
private static final byte[] EMPTY_BODY = new byte[0];
static final String LOG_TAG = "coretestutils.http.MockResponse";
private String status = "HTTP/1.1 200 OK";
private Map<String, String> headers = new HashMap<String, String>();
private byte[] body = EMPTY_BODY;
private boolean closeConnectionAfter = false;
private String closeConnectionAfterHeader = null;
private int closeConnectionAfterXBytes = -1;
private int pauseConnectionAfterXBytes = -1;
private File bodyExternalFile = null;
public MockResponse() {
addHeader("Content-Length", 0);
}
/**
* Returns the HTTP response line, such as "HTTP/1.1 200 OK".
*/
public String getStatus() {
return status;
}
public MockResponse setResponseCode(int code) {
this.status = "HTTP/1.1 " + code + " OK";
return this;
}
/**
* Returns the HTTP headers, such as "Content-Length: 0".
*/
public List<String> getHeaders() {
List<String> headerStrings = new ArrayList<String>();
for (String header : headers.keySet()) {
headerStrings.add(header + ": " + headers.get(header));
}
return headerStrings;
}
public MockResponse addHeader(String header, String value) {
headers.put(header.toLowerCase(), value);
return this;
}
public MockResponse addHeader(String header, long value) {
return addHeader(header, Long.toString(value));
}
public MockResponse removeHeader(String header) {
headers.remove(header.toLowerCase());
return this;
}
/**
* Returns true if the body should come from an external file, false otherwise.
*/
private boolean bodyIsExternal() {
return bodyExternalFile != null;
}
/**
* Returns an input stream containing the raw HTTP payload.
*/
public InputStream getBody() {
if (bodyIsExternal()) {
try {
return new FileInputStream(bodyExternalFile);
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, "File not found: " + bodyExternalFile.getAbsolutePath());
}
}
return new ByteArrayInputStream(this.body);
}
public MockResponse setBody(File body) {
addHeader("Content-Length", body.length());
this.bodyExternalFile = body;
return this;
}
public MockResponse setBody(byte[] body) {
addHeader("Content-Length", body.length);
this.body = body;
return this;
}
public MockResponse setBody(String body) {
try {
return setBody(body.getBytes(ASCII));
} catch (UnsupportedEncodingException e) {
throw new AssertionError();
}
}
/**
* Sets the body as chunked.
*
* Currently chunked body is not supported for external files as bodies.
*/
public MockResponse setChunkedBody(byte[] body, int maxChunkSize) throws IOException {
addHeader("Transfer-encoding", "chunked");
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
int pos = 0;
while (pos < body.length) {
int chunkSize = Math.min(body.length - pos, maxChunkSize);
bytesOut.write(Integer.toHexString(chunkSize).getBytes(ASCII));
bytesOut.write("\r\n".getBytes(ASCII));
bytesOut.write(body, pos, chunkSize);
bytesOut.write("\r\n".getBytes(ASCII));
pos += chunkSize;
}
bytesOut.write("0\r\n".getBytes(ASCII));
this.body = bytesOut.toByteArray();
return this;
}
public MockResponse setChunkedBody(String body, int maxChunkSize) throws IOException {
return setChunkedBody(body.getBytes(ASCII), maxChunkSize);
}
@Override public String toString() {
return status;
}
public boolean shouldCloseConnectionAfter() {
return closeConnectionAfter;
}
public MockResponse setCloseConnectionAfter(boolean closeConnectionAfter) {
this.closeConnectionAfter = closeConnectionAfter;
return this;
}
/**
* Sets the header after which sending the server should close the connection.
*/
public MockResponse setCloseConnectionAfterHeader(String header) {
closeConnectionAfterHeader = header;
setCloseConnectionAfter(true);
return this;
}
/**
* Returns the header after which sending the server should close the connection.
*/
public String getCloseConnectionAfterHeader() {
return closeConnectionAfterHeader;
}
/**
* Sets the number of bytes in the body to send before which the server should close the
* connection. Set to -1 to unset and send the entire body (default).
*/
public MockResponse setCloseConnectionAfterXBytes(int position) {
closeConnectionAfterXBytes = position;
setCloseConnectionAfter(true);
return this;
}
/**
* Returns the number of bytes in the body to send before which the server should close the
* connection. Returns -1 if the entire body should be sent (default).
*/
public int getCloseConnectionAfterXBytes() {
return closeConnectionAfterXBytes;
}
/**
* Sets the number of bytes in the body to send before which the server should pause the
* connection (stalls in sending data). Only one pause per response is supported.
* Set to -1 to unset pausing (default).
*/
public MockResponse setPauseConnectionAfterXBytes(int position) {
pauseConnectionAfterXBytes = position;
return this;
}
/**
* Returns the number of bytes in the body to send before which the server should pause the
* connection (stalls in sending data). (Returns -1 if it should not pause).
*/
public int getPauseConnectionAfterXBytes() {
return pauseConnectionAfterXBytes;
}
/**
* Returns true if this response is flagged to pause the connection mid-stream, false otherwise
*/
public boolean getShouldPause() {
return (pauseConnectionAfterXBytes != -1);
}
/**
* Returns true if this response is flagged to close the connection mid-stream, false otherwise
*/
public boolean getShouldClose() {
return (closeConnectionAfterXBytes != -1);
}
}

View File

@ -0,0 +1,426 @@
/*
* 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 coretestutils.http;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import android.util.Log;
/**
* A scriptable web server. Callers supply canned responses and the server
* replays them upon request in sequence.
*
* TODO: merge with the version from libcore/support/src/tests/java once it's in.
*/
public final class MockWebServer {
static final String ASCII = "US-ASCII";
static final String LOG_TAG = "coretestutils.http.MockWebServer";
private final BlockingQueue<RecordedRequest> requestQueue
= new LinkedBlockingQueue<RecordedRequest>();
private final BlockingQueue<MockResponse> responseQueue
= new LinkedBlockingQueue<MockResponse>();
private int bodyLimit = Integer.MAX_VALUE;
private final ExecutorService executor = Executors.newCachedThreadPool();
// keep Futures around so we can rethrow any exceptions thrown by Callables
private final Queue<Future<?>> futures = new LinkedList<Future<?>>();
private final Object downloadPauseLock = new Object();
// global flag to signal when downloads should resume on the server
private volatile boolean downloadResume = false;
private int port = -1;
public int getPort() {
if (port == -1) {
throw new IllegalStateException("Cannot retrieve port before calling play()");
}
return port;
}
/**
* Returns a URL for connecting to this server.
*
* @param path the request path, such as "/".
*/
public URL getUrl(String path) throws MalformedURLException {
return new URL("http://localhost:" + getPort() + path);
}
/**
* Sets the number of bytes of the POST body to keep in memory to the given
* limit.
*/
public void setBodyLimit(int maxBodyLength) {
this.bodyLimit = maxBodyLength;
}
public void enqueue(MockResponse response) {
responseQueue.add(response);
}
/**
* Awaits the next HTTP request, removes it, and returns it. Callers should
* use this to verify the request sent was as intended.
*/
public RecordedRequest takeRequest() throws InterruptedException {
return requestQueue.take();
}
public RecordedRequest takeRequestWithTimeout(long timeoutMillis) throws InterruptedException {
return requestQueue.poll(timeoutMillis, TimeUnit.MILLISECONDS);
}
public List<RecordedRequest> drainRequests() {
List<RecordedRequest> requests = new ArrayList<RecordedRequest>();
requestQueue.drainTo(requests);
return requests;
}
/**
* Starts the server, serves all enqueued requests, and shuts the server
* down using the default (server-assigned) port.
*/
public void play() throws IOException {
play(0);
}
/**
* Starts the server, serves all enqueued requests, and shuts the server
* down.
*
* @param port The port number to use to listen to connections on; pass in 0 to have the
* server automatically assign a free port
*/
public void play(int portNumber) throws IOException {
final ServerSocket ss = new ServerSocket(portNumber);
ss.setReuseAddress(true);
port = ss.getLocalPort();
submitCallable(new Callable<Void>() {
public Void call() throws Exception {
int count = 0;
while (true) {
if (count > 0 && responseQueue.isEmpty()) {
ss.close();
executor.shutdown();
return null;
}
serveConnection(ss.accept());
count++;
}
}
});
}
private void serveConnection(final Socket s) {
submitCallable(new Callable<Void>() {
public Void call() throws Exception {
InputStream in = new BufferedInputStream(s.getInputStream());
OutputStream out = new BufferedOutputStream(s.getOutputStream());
int sequenceNumber = 0;
while (true) {
RecordedRequest request = readRequest(in, sequenceNumber);
if (request == null) {
if (sequenceNumber == 0) {
throw new IllegalStateException("Connection without any request!");
} else {
break;
}
}
requestQueue.add(request);
MockResponse response = computeResponse(request);
writeResponse(out, response);
if (response.shouldCloseConnectionAfter()) {
break;
}
sequenceNumber++;
}
in.close();
out.close();
return null;
}
});
}
private void submitCallable(Callable<?> callable) {
Future<?> future = executor.submit(callable);
futures.add(future);
}
/**
* Check for and raise any exceptions that have been thrown by child threads. Will not block on
* children still running.
* @throws ExecutionException for the first child thread that threw an exception
*/
public void checkForExceptions() throws ExecutionException, InterruptedException {
final int originalSize = futures.size();
for (int i = 0; i < originalSize; i++) {
Future<?> future = futures.remove();
try {
future.get(0, TimeUnit.SECONDS);
} catch (TimeoutException e) {
futures.add(future); // still running
}
}
}
/**
* @param sequenceNumber the index of this request on this connection.
*/
private RecordedRequest readRequest(InputStream in, int sequenceNumber) throws IOException {
String request = readAsciiUntilCrlf(in);
if (request.equals("")) {
return null; // end of data; no more requests
}
List<String> headers = new ArrayList<String>();
int contentLength = -1;
boolean chunked = false;
String header;
while (!(header = readAsciiUntilCrlf(in)).equals("")) {
headers.add(header);
String lowercaseHeader = header.toLowerCase();
if (contentLength == -1 && lowercaseHeader.startsWith("content-length:")) {
contentLength = Integer.parseInt(header.substring(15).trim());
}
if (lowercaseHeader.startsWith("transfer-encoding:") &&
lowercaseHeader.substring(18).trim().equals("chunked")) {
chunked = true;
}
}
boolean hasBody = false;
TruncatingOutputStream requestBody = new TruncatingOutputStream();
List<Integer> chunkSizes = new ArrayList<Integer>();
if (contentLength != -1) {
hasBody = true;
transfer(contentLength, in, requestBody);
} else if (chunked) {
hasBody = true;
while (true) {
int chunkSize = Integer.parseInt(readAsciiUntilCrlf(in).trim(), 16);
if (chunkSize == 0) {
readEmptyLine(in);
break;
}
chunkSizes.add(chunkSize);
transfer(chunkSize, in, requestBody);
readEmptyLine(in);
}
}
if (request.startsWith("GET ")) {
if (hasBody) {
throw new IllegalArgumentException("GET requests should not have a body!");
}
} else if (request.startsWith("POST ")) {
if (!hasBody) {
throw new IllegalArgumentException("POST requests must have a body!");
}
} else {
throw new UnsupportedOperationException("Unexpected method: " + request);
}
return new RecordedRequest(request, headers, chunkSizes,
requestBody.numBytesReceived, requestBody.toByteArray(), sequenceNumber);
}
/**
* Returns a response to satisfy {@code request}.
*/
private MockResponse computeResponse(RecordedRequest request) throws InterruptedException {
if (responseQueue.isEmpty()) {
throw new IllegalStateException("Unexpected request: " + request);
}
return responseQueue.take();
}
private void writeResponse(OutputStream out, MockResponse response) throws IOException {
out.write((response.getStatus() + "\r\n").getBytes(ASCII));
boolean doCloseConnectionAfterHeader = (response.getCloseConnectionAfterHeader() != null);
// Send headers
String closeConnectionAfterHeader = response.getCloseConnectionAfterHeader();
for (String header : response.getHeaders()) {
out.write((header + "\r\n").getBytes(ASCII));
if (doCloseConnectionAfterHeader && header.startsWith(closeConnectionAfterHeader)) {
Log.i(LOG_TAG, "Closing connection after header" + header);
break;
}
}
// Send actual body data
if (!doCloseConnectionAfterHeader) {
out.write(("\r\n").getBytes(ASCII));
InputStream body = response.getBody();
final int READ_BLOCK_SIZE = 10000; // process blocks this size
byte[] currentBlock = new byte[READ_BLOCK_SIZE];
int currentBlockSize = 0;
int writtenSoFar = 0;
boolean shouldPause = response.getShouldPause();
boolean shouldClose = response.getShouldClose();
int pause = response.getPauseConnectionAfterXBytes();
int close = response.getCloseConnectionAfterXBytes();
// Don't bother pausing if it's set to pause -after- the connection should be dropped
if (shouldPause && shouldClose && (pause > close)) {
shouldPause = false;
}
// Process each block we read in...
while ((currentBlockSize = body.read(currentBlock)) != -1) {
int startIndex = 0;
int writeLength = currentBlockSize;
// handle the case of pausing
if (shouldPause && (writtenSoFar + currentBlockSize >= pause)) {
writeLength = pause - writtenSoFar;
out.write(currentBlock, 0, writeLength);
out.flush();
writtenSoFar += writeLength;
// now pause...
try {
Log.i(LOG_TAG, "Pausing connection after " + pause + " bytes");
// Wait until someone tells us to resume sending...
synchronized(downloadPauseLock) {
while (!downloadResume) {
downloadPauseLock.wait();
}
// reset resume back to false
downloadResume = false;
}
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Server was interrupted during pause in download.");
}
startIndex = writeLength;
writeLength = currentBlockSize - writeLength;
}
// handle the case of closing the connection
if (shouldClose && (writtenSoFar + writeLength > close)) {
writeLength = close - writtenSoFar;
out.write(currentBlock, startIndex, writeLength);
writtenSoFar += writeLength;
Log.i(LOG_TAG, "Closing connection after " + close + " bytes");
break;
}
out.write(currentBlock, startIndex, writeLength);
writtenSoFar += writeLength;
}
}
out.flush();
}
/**
* Transfer bytes from {@code in} to {@code out} until either {@code length}
* bytes have been transferred or {@code in} is exhausted.
*/
private void transfer(int length, InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
while (length > 0) {
int count = in.read(buffer, 0, Math.min(buffer.length, length));
if (count == -1) {
return;
}
out.write(buffer, 0, count);
length -= count;
}
}
/**
* Returns the text from {@code in} until the next "\r\n", or null if
* {@code in} is exhausted.
*/
private String readAsciiUntilCrlf(InputStream in) throws IOException {
StringBuilder builder = new StringBuilder();
while (true) {
int c = in.read();
if (c == '\n' && builder.length() > 0 && builder.charAt(builder.length() - 1) == '\r') {
builder.deleteCharAt(builder.length() - 1);
return builder.toString();
} else if (c == -1) {
return builder.toString();
} else {
builder.append((char) c);
}
}
}
private void readEmptyLine(InputStream in) throws IOException {
String line = readAsciiUntilCrlf(in);
if (!line.equals("")) {
throw new IllegalStateException("Expected empty but was: " + line);
}
}
/**
* An output stream that drops data after bodyLimit bytes.
*/
private class TruncatingOutputStream extends ByteArrayOutputStream {
private int numBytesReceived = 0;
@Override public void write(byte[] buffer, int offset, int len) {
numBytesReceived += len;
super.write(buffer, offset, Math.min(len, bodyLimit - count));
}
@Override public void write(int oneByte) {
numBytesReceived++;
if (count < bodyLimit) {
super.write(oneByte);
}
}
}
/**
* Trigger the server to resume sending the download
*/
public void doResumeDownload() {
synchronized (downloadPauseLock) {
downloadResume = true;
downloadPauseLock.notifyAll();
}
}
}

View File

@ -0,0 +1,93 @@
/*
* 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 coretestutils.http;
import java.util.List;
/**
* An HTTP request that came into the mock web server.
*/
public final class RecordedRequest {
private final String requestLine;
private final List<String> headers;
private final List<Integer> chunkSizes;
private final int bodySize;
private final byte[] body;
private final int sequenceNumber;
RecordedRequest(String requestLine, List<String> headers, List<Integer> chunkSizes,
int bodySize, byte[] body, int sequenceNumber) {
this.requestLine = requestLine;
this.headers = headers;
this.chunkSizes = chunkSizes;
this.bodySize = bodySize;
this.body = body;
this.sequenceNumber = sequenceNumber;
}
public String getRequestLine() {
return requestLine;
}
public List<String> getHeaders() {
return headers;
}
/**
* Returns the sizes of the chunks of this request's body, or an empty list
* if the request's body was empty or unchunked.
*/
public List<Integer> getChunkSizes() {
return chunkSizes;
}
/**
* Returns the total size of the body of this POST request (before
* truncation).
*/
public int getBodySize() {
return bodySize;
}
/**
* Returns the body of this POST request. This may be truncated.
*/
public byte[] getBody() {
return body;
}
/**
* Returns the index of this request on its HTTP connection. Since a single
* HTTP connection may serve multiple requests, each request is assigned its
* own sequence number.
*/
public int getSequenceNumber() {
return sequenceNumber;
}
@Override public String toString() {
return requestLine;
}
public String getMethod() {
return getRequestLine().split(" ")[0];
}
public String getPath() {
return getRequestLine().split(" ")[1];
}
}