1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app;
18
19import android.app.DownloadManager.Query;
20import android.app.DownloadManager.Request;
21import android.database.Cursor;
22import android.net.Uri;
23import android.os.Environment;
24import android.os.ParcelFileDescriptor;
25import android.os.StatFs;
26import android.test.suitebuilder.annotation.LargeTest;
27import android.util.Log;
28
29import java.io.File;
30import java.io.FileOutputStream;
31import java.io.IOException;
32import java.util.Random;
33
34/**
35 * Integration tests of the DownloadManager API.
36 */
37public class DownloadManagerStressTest extends DownloadManagerBaseTest {
38    private static final String TAG = "DownloadManagerStressTest";
39    private final static String CACHE_DIR =
40            Environment.getDownloadCacheDirectory().getAbsolutePath();
41
42    /**
43     * {@inheritDoc}
44     */
45    @Override
46    public void setUp() throws Exception {
47        super.setUp();
48        setWiFiStateOn(true);
49        removeAllCurrentDownloads();
50    }
51
52    /**
53     * {@inheritDoc}
54     */
55    @Override
56    public void tearDown() throws Exception {
57        super.tearDown();
58        setWiFiStateOn(true);
59        removeAllCurrentDownloads();
60
61        if (mReceiver != null) {
62            mContext.unregisterReceiver(mReceiver);
63            mReceiver = null;
64        }
65    }
66
67    /**
68     * Attempts to download several files simultaneously
69     */
70    @LargeTest
71    public void testMultipleDownloads() throws Exception {
72        // need to be sure all current downloads have stopped first
73        removeAllCurrentDownloads();
74        int NUM_FILES = 10;
75        int MAX_FILE_SIZE = 10 * 1024; // 10 kb
76
77        Random r = new LoggingRng();
78        for (int i=0; i<NUM_FILES; ++i) {
79            int size = r.nextInt(MAX_FILE_SIZE);
80            byte[] blobData = generateData(size, DataType.TEXT);
81
82            Uri uri = getServerUri(DEFAULT_FILENAME + i);
83            Request request = new Request(uri);
84            request.setTitle(String.format("%s--%d", DEFAULT_FILENAME + i, i));
85
86            // Prepare the mock server with a standard response
87            enqueueResponse(buildResponse(HTTP_OK, blobData));
88
89            long requestID = mDownloadManager.enqueue(request);
90        }
91
92        waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
93        Cursor cursor = mDownloadManager.query(new Query());
94        try {
95            assertEquals(NUM_FILES, cursor.getCount());
96
97            if (cursor.moveToFirst()) {
98                do {
99                    int status = cursor.getInt(cursor.getColumnIndex(
100                            DownloadManager.COLUMN_STATUS));
101                    String filename = cursor.getString(cursor.getColumnIndex(
102                            DownloadManager.COLUMN_URI));
103                    String errorString = String.format(
104                            "File %s failed to download successfully. Status code: %d",
105                            filename, status);
106                    assertEquals(errorString, DownloadManager.STATUS_SUCCESSFUL, status);
107                } while (cursor.moveToNext());
108            }
109
110            assertEquals(NUM_FILES, mReceiver.numDownloadsCompleted());
111        } finally {
112            cursor.close();
113        }
114    }
115    /**
116     * Tests trying to download a large file (50M bytes).
117     */
118    @LargeTest
119    public void testDownloadLargeFile() throws Exception {
120        long fileSize = 50000000L;  // note: kept relatively small to not exceed /cache dir size
121        Log.i(TAG, "creating a file of size: " + fileSize);
122        File largeFile = createFileOnSD(null, fileSize, DataType.TEXT, null);
123        Log.i(TAG, "DONE creating a file of size: " + fileSize);
124        MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver();
125
126        try {
127            long dlRequest = doStandardEnqueue(largeFile);
128
129            // wait for the download to complete
130            waitForDownloadOrTimeout(dlRequest);
131
132            ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
133            verifyFileContents(pfd, largeFile);
134            verifyFileSize(pfd, largeFile.length());
135
136            assertEquals(1, receiver.numDownloadsCompleted());
137            mContext.unregisterReceiver(receiver);
138        } catch (Exception e) {
139            throw e;
140        } finally {
141            largeFile.delete();
142        }
143    }
144
145
146    /**
147     * Tests downloading a file to system cache when there isn't enough space in the system cache
148     * to hold the entire file. DownloadManager deletes enough files to make space for the
149     * new download.
150     */
151    @LargeTest
152    public void testDownloadToCacheWithAlmostFullCache() throws Exception {
153        int DOWNLOAD_FILE_SIZE = 1024 * 1024; // 1MB
154
155        StatFs fs = new StatFs(CACHE_DIR);
156        int blockSize = fs.getBlockSize();
157        int availableBlocks = fs.getAvailableBlocks();
158        int availableBytes = blockSize * availableBlocks;
159        Log.i(TAG, "INITIAL stage, available space in /cache: " + availableBytes);
160        File outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR));
161        byte[] buffer = new byte[blockSize];
162
163        try {
164            // fill cache to ensure we don't have enough space - take half the size of the
165            // download size, and leave that much freespace left on the cache partition
166            if (DOWNLOAD_FILE_SIZE <= availableBytes) {
167                int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2);
168
169                int writeSizeBlocks = writeSizeBytes / blockSize;
170                int remainderSizeBlocks = availableBlocks - writeSizeBlocks;
171
172                FileOutputStream fo = null;
173                try {
174                    fo = new FileOutputStream(outFile);
175                    while (fs.getAvailableBlocks() >= remainderSizeBlocks) {
176                        fo.write(buffer);
177                        fs.restat(CACHE_DIR);
178                    }
179                } catch (IOException e) {
180                    Log.e(LOG_TAG, "error filling file: ", e);
181                    throw e;
182                } finally {
183                    if (fo != null) {
184                        fo.close();
185                    }
186                }
187            }
188
189            // /cache should now be almost full.
190            long spaceAvailable = fs.getAvailableBlocks() * blockSize;
191            Log.i(TAG, "BEFORE download, available space in /cache: " + spaceAvailable);
192            assertTrue(DOWNLOAD_FILE_SIZE > spaceAvailable);
193
194            // try to download 1MB file into /cache - and it should succeed
195            byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT);
196            long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
197            verifyAndCleanupSingleFileDownload(dlRequest, blobData);
198        } finally {
199            if (outFile != null) {
200                outFile.delete();
201            }
202        }
203    }
204}
205