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