DownloadManagerFunctionalTest.java revision 6f35c0ecba6cb1ce5d7563a9962acf9557dbaced
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 coretestutils.http.MockResponse;
20
21import android.app.DownloadManager.Query;
22import android.app.DownloadManager.Request;
23import android.database.Cursor;
24import android.net.Uri;
25import android.os.Environment;
26import android.os.ParcelFileDescriptor;
27import android.test.suitebuilder.annotation.LargeTest;
28
29import java.io.File;
30import java.util.Iterator;
31import java.util.Set;
32
33/**
34 * Integration tests of the DownloadManager API.
35 */
36public class DownloadManagerFunctionalTest extends DownloadManagerBaseTest {
37    private static final String TAG = "DownloadManagerFunctionalTest";
38    private final static String CACHE_DIR =
39            Environment.getDownloadCacheDirectory().getAbsolutePath();
40    private final static String PROHIBITED_DIRECTORY =
41            Environment.getRootDirectory().getAbsolutePath();
42
43    /**
44     * {@inheritDoc}
45     */
46    @Override
47    public void setUp() throws Exception {
48        super.setUp();
49        setWiFiStateOn(true);
50        mServer.play();
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     * Verifies a particular error code was received from a download
71     *
72     * @param uri The uri to enqueue to the DownloadManager
73     * @param error The error code expected
74     * @throws Exception if the test fails
75     */
76    public void doErrorTest(Uri uri, int error) throws Exception {
77        Request request = new Request(uri);
78        request.setTitle(DEFAULT_FILENAME);
79
80        long dlRequest = mDownloadManager.enqueue(request);
81        waitForDownloadOrTimeout(dlRequest);
82
83        Cursor cursor = getCursor(dlRequest);
84        try {
85            verifyInt(cursor, DownloadManager.COLUMN_REASON, error);
86        } finally {
87            cursor.close();
88        }
89    }
90
91    /**
92     * Test a basic download of a binary file 500k in size.
93     */
94    @LargeTest
95    public void testBinaryDownloadToSystemCache() throws Exception {
96        int fileSize = 1024;
97        byte[] blobData = generateData(fileSize, DataType.BINARY);
98
99        long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
100        verifyDownload(dlRequest, blobData);
101        mDownloadManager.remove(dlRequest);
102    }
103
104    /**
105     * Tests the basic downloading of a text file 300000 bytes in size.
106     */
107    @LargeTest
108    public void testTextDownloadToSystemCache() throws Exception {
109        int fileSize = 1024;
110        byte[] blobData = generateData(fileSize, DataType.TEXT);
111
112        long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_SYSTEM_CACHE);
113        verifyDownload(dlRequest, blobData);
114        mDownloadManager.remove(dlRequest);
115    }
116
117    /**
118     * Helper to verify a standard single-file download from the mock server, and clean up after
119     * verification
120     *
121     * Note that this also calls the Download manager's remove, which cleans up the file from cache.
122     *
123     * @param requestId The id of the download to remove
124     * @param fileData The data to verify the file contains
125     */
126    private void verifyDownload(long requestId, byte[] fileData)
127            throws Exception {
128        int fileSize = fileData.length;
129        ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(requestId);
130        Cursor cursor = mDownloadManager.query(new Query().setFilterById(requestId));
131        try {
132            assertEquals(1, cursor.getCount());
133            assertTrue(cursor.moveToFirst());
134
135            mServer.checkForExceptions();
136
137            verifyFileSize(pfd, fileSize);
138            verifyFileContents(pfd, fileData);
139            int colIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
140            String fileName = cursor.getString(colIndex);
141            assertTrue(fileName.startsWith(CACHE_DIR));
142        } finally {
143            pfd.close();
144            cursor.close();
145        }
146    }
147
148    /**
149     * Tests trying to download to SD card when the file with same name already exists.
150     */
151    @LargeTest
152    public void testDownloadToExternal_fileExists() throws Exception {
153        File existentFile = createFileOnSD(null, 1, DataType.TEXT, null);
154        byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
155
156        // Prepare the mock server with a standard response
157        enqueueResponse(HTTP_OK, blobData);
158
159        try {
160            Uri uri = getServerUri(DEFAULT_FILENAME);
161            Request request = new Request(uri);
162
163            Uri localUri = Uri.fromFile(existentFile);
164            request.setDestinationUri(localUri);
165
166            long dlRequest = mDownloadManager.enqueue(request);
167
168            // wait for the download to complete
169            waitForDownloadOrTimeout(dlRequest);
170            Cursor cursor = getCursor(dlRequest);
171
172            try {
173                verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_SUCCESSFUL);
174            } finally {
175                cursor.close();
176            }
177        } finally {
178            existentFile.delete();
179        }
180    }
181
182    /**
183     * Tests trying to download a file to SD card.
184     */
185    @LargeTest
186    public void testDownloadToExternal() throws Exception {
187        String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath();
188        File downloadedFile = new File(localDownloadDirectory, DEFAULT_FILENAME);
189        // make sure the file doesn't already exist in the directory
190        downloadedFile.delete();
191
192        try {
193            byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
194
195            // Prepare the mock server with a standard response
196            enqueueResponse(HTTP_OK, blobData);
197
198            Uri uri = getServerUri(DEFAULT_FILENAME);
199            Request request = new Request(uri);
200
201            Uri localUri = Uri.fromFile(downloadedFile);
202            request.setDestinationUri(localUri);
203
204            long dlRequest = mDownloadManager.enqueue(request);
205
206            // wait for the download to complete
207            waitForDownloadOrTimeout(dlRequest);
208
209            verifyAndCleanupSingleFileDownload(dlRequest, blobData);
210
211            assertEquals(1, mReceiver.numDownloadsCompleted());
212        } finally {
213            downloadedFile.delete();
214        }
215    }
216
217    /**
218     * Tests trying to download a file to the system partition.
219     */
220    @LargeTest
221    public void testDownloadToProhibitedDirectory() throws Exception {
222        File downloadedFile = new File(PROHIBITED_DIRECTORY, DEFAULT_FILENAME);
223        try {
224            byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
225
226            // Prepare the mock server with a standard response
227            enqueueResponse(HTTP_OK, blobData);
228
229            Uri uri = getServerUri(DEFAULT_FILENAME);
230            Request request = new Request(uri);
231
232            Uri localUri = Uri.fromFile(downloadedFile);
233            request.setDestinationUri(localUri);
234
235            try {
236                mDownloadManager.enqueue(request);
237                fail("Failed to throw SecurityException when trying to write to /system.");
238            } catch (SecurityException s) {
239                assertFalse(downloadedFile.exists());
240            }
241        } finally {
242            // Just in case file somehow got created, make sure to delete it
243            downloadedFile.delete();
244        }
245    }
246
247    /**
248     * Tests that we get the correct download ID from the download notification.
249     */
250    @LargeTest
251    public void testGetDownloadIdOnNotification() throws Exception {
252        byte[] blobData = generateData(3000, DataType.TEXT);  // file size = 3000 bytes
253
254        MockResponse response = enqueueResponse(HTTP_OK, blobData);
255        long dlRequest = doCommonStandardEnqueue();
256        waitForDownloadOrTimeout(dlRequest);
257
258        Set<Long> ids = mReceiver.getDownloadIds();
259        assertEquals(1, ids.size());
260        Iterator<Long> it = ids.iterator();
261        assertEquals("Download ID received from notification does not match initial id!",
262                dlRequest, it.next().longValue());
263    }
264
265    /**
266     * Tests the download failure error after too many redirects (>5).
267     */
268    @LargeTest
269    public void testErrorTooManyRedirects() throws Exception {
270        Uri uri = getServerUri(DEFAULT_FILENAME);
271
272        // force 6 redirects
273        for (int i = 0; i < 6; ++i) {
274            MockResponse response = enqueueResponse(HTTP_REDIRECT);
275            response.addHeader("Location", uri.toString());
276        }
277        doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS);
278    }
279
280    /**
281     * Tests the download failure error from an unhandled HTTP status code
282     */
283    @LargeTest
284    public void testErrorUnhandledHttpCode() throws Exception {
285        Uri uri = getServerUri(DEFAULT_FILENAME);
286        MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT);
287
288        doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE);
289    }
290
291    /**
292     * Tests the download failure error from an unhandled HTTP status code
293     */
294    @LargeTest
295    public void testErrorHttpDataError_invalidRedirect() throws Exception {
296        Uri uri = getServerUri(DEFAULT_FILENAME);
297        MockResponse response = enqueueResponse(HTTP_REDIRECT);
298        response.addHeader("Location", "://blah.blah.blah.com");
299
300        doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR);
301    }
302
303    /**
304     * Tests that we can remove a download from the download manager.
305     */
306    @LargeTest
307    public void testRemoveDownload() throws Exception {
308        int fileSize = 1024;
309        byte[] blobData = generateData(fileSize, DataType.BINARY);
310
311        long dlRequest = doBasicDownload(blobData, DOWNLOAD_TO_DOWNLOAD_CACHE_DIR);
312        Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest));
313        try {
314            assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount());
315            mDownloadManager.remove(dlRequest);
316            cursor.requery();
317            assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount());
318        } finally {
319            cursor.close();
320        }
321    }
322
323    /**
324     * Tests that we can set the title of a download.
325     */
326    @LargeTest
327    public void testSetTitle() throws Exception {
328        int fileSize = 1024;
329        byte[] blobData = generateData(fileSize, DataType.BINARY);
330        MockResponse response = enqueueResponse(HTTP_OK, blobData);
331
332        // An arbitrary unicode string title
333        final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" +
334                "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'";
335
336        Uri uri = getServerUri(DEFAULT_FILENAME);
337        Request request = new Request(uri);
338        request.setTitle(title);
339
340        long dlRequest = mDownloadManager.enqueue(request);
341        waitForDownloadOrTimeout(dlRequest);
342
343        Cursor cursor = getCursor(dlRequest);
344        try {
345            verifyString(cursor, DownloadManager.COLUMN_TITLE, title);
346        } finally {
347            cursor.close();
348        }
349    }
350
351    /**
352     * Tests that a download set for Wifi does not progress while Wifi is disabled, but resumes
353     * once Wifi is re-enabled.
354     */
355    @LargeTest
356    public void testDownloadNoWifi() throws Exception {
357        long timeout = 60 * 1000; // wait only 60 seconds before giving up
358        int fileSize = 1024;  // 140k
359        byte[] blobData = generateData(fileSize, DataType.TEXT);
360
361        setWiFiStateOn(false);
362        enqueueResponse(HTTP_OK, blobData);
363
364        try {
365            Uri uri = getServerUri(DEFAULT_FILENAME);
366            Request request = new Request(uri);
367            request.setAllowedNetworkTypes(Request.NETWORK_WIFI);
368
369            long dlRequest = mDownloadManager.enqueue(request);
370
371            // wait for the download to complete
372            boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest,
373                    WAIT_FOR_DOWNLOAD_POLL_TIME, timeout);
374            assertFalse("Download proceeded without Wifi connection!", success);
375
376            setWiFiStateOn(true);
377            waitForDownloadOrTimeout(dlRequest);
378
379            assertEquals(1, mReceiver.numDownloadsCompleted());
380        } finally {
381            setWiFiStateOn(true);
382        }
383    }
384
385    /**
386     * Tests when the server drops the connection after all headers (but before any data send).
387     */
388    @LargeTest
389    public void testDropConnection_headers() throws Exception {
390        byte[] blobData = generateData(DEFAULT_FILE_SIZE, DataType.TEXT);
391
392        MockResponse response = enqueueResponse(HTTP_OK, blobData);
393        response.setCloseConnectionAfterHeader("content-length");
394        long dlRequest = doCommonStandardEnqueue();
395
396        // Download will never complete when header is dropped
397        boolean success = waitForDownloadOrTimeoutNoThrow(dlRequest, DEFAULT_WAIT_POLL_TIME,
398                DEFAULT_MAX_WAIT_TIME);
399
400        assertFalse(success);
401    }
402
403    /**
404     * Tests that we get an error code when the server drops the connection during a download.
405     */
406    @LargeTest
407    public void testServerDropConnection_body() throws Exception {
408        byte[] blobData = generateData(25000, DataType.TEXT);  // file size = 25000 bytes
409
410        MockResponse response = enqueueResponse(HTTP_OK, blobData);
411        response.setCloseConnectionAfterXBytes(15382);
412        long dlRequest = doCommonStandardEnqueue();
413        waitForDownloadOrTimeout(dlRequest);
414
415        Cursor cursor = getCursor(dlRequest);
416        try {
417            verifyInt(cursor, DownloadManager.COLUMN_STATUS, DownloadManager.STATUS_FAILED);
418            verifyInt(cursor, DownloadManager.COLUMN_REASON,
419                    DownloadManager.ERROR_CANNOT_RESUME);
420        } finally {
421            cursor.close();
422        }
423        // Even tho the server drops the connection, we should still get a completed notification
424        assertEquals(1, mReceiver.numDownloadsCompleted());
425    }
426}
427