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 com.android.providers.downloads;
18
19import static android.text.format.DateUtils.SECOND_IN_MILLIS;
20import static java.net.HttpURLConnection.HTTP_OK;
21
22import android.content.ContentValues;
23import android.database.Cursor;
24import android.net.ConnectivityManager;
25import android.net.Uri;
26import android.os.Environment;
27import android.os.SystemClock;
28import android.provider.Downloads;
29import android.test.suitebuilder.annotation.LargeTest;
30
31import com.google.mockwebserver.MockWebServer;
32import com.google.mockwebserver.RecordedRequest;
33
34import java.io.InputStream;
35import java.net.MalformedURLException;
36import java.net.UnknownHostException;
37import java.util.concurrent.TimeoutException;
38
39/**
40 * This test exercises the entire download manager working together -- it requests downloads through
41 * the {@link DownloadProvider}, just like a normal client would, and runs the
42 * {@link DownloadService} with start intents.  It sets up a {@link MockWebServer} running on the
43 * device to serve downloads.
44 */
45@LargeTest
46public class DownloadProviderFunctionalTest extends AbstractDownloadProviderFunctionalTest {
47    private static final String TAG = "DownloadManagerFunctionalTest";
48
49    public DownloadProviderFunctionalTest() {
50        super(new FakeSystemFacade());
51    }
52
53    public void testDownloadTextFile() throws Exception {
54        enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
55
56        String path = "/download_manager_test_path";
57        Uri downloadUri = requestDownload(path);
58        assertEquals(Downloads.Impl.STATUS_PENDING, getDownloadStatus(downloadUri));
59        assertTrue(mTestContext.mHasServiceBeenStarted);
60
61        runUntilStatus(downloadUri, Downloads.Impl.STATUS_SUCCESS);
62        RecordedRequest request = takeRequest();
63        assertEquals("GET", request.getMethod());
64        assertEquals(path, request.getPath());
65        assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
66        assertStartsWith(Environment.getExternalStorageDirectory().getPath(),
67                         getDownloadFilename(downloadUri));
68    }
69
70    public void testDownloadToCache() throws Exception {
71        enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
72
73        Uri downloadUri = requestDownload("/path");
74        updateDownload(downloadUri, Downloads.Impl.COLUMN_DESTINATION,
75                       Integer.toString(Downloads.Impl.DESTINATION_CACHE_PARTITION));
76        runUntilStatus(downloadUri, Downloads.Impl.STATUS_SUCCESS);
77        assertEquals(FILE_CONTENT, getDownloadContents(downloadUri));
78        assertStartsWith(getContext().getCacheDir().getAbsolutePath(),
79                         getDownloadFilename(downloadUri));
80    }
81
82    public void testRoaming() throws Exception {
83        enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
84        enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
85
86        mSystemFacade.mActiveNetworkType = ConnectivityManager.TYPE_MOBILE;
87        mSystemFacade.mIsRoaming = true;
88
89        // for a normal download, roaming is fine
90        Uri downloadUri = requestDownload("/path");
91        runUntilStatus(downloadUri, Downloads.Impl.STATUS_SUCCESS);
92
93        // when roaming is disallowed, the download should pause...
94        downloadUri = requestDownload("/path");
95        updateDownload(downloadUri, Downloads.Impl.COLUMN_DESTINATION,
96                       Integer.toString(Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING));
97        runUntilStatus(downloadUri, Downloads.Impl.STATUS_WAITING_FOR_NETWORK);
98
99        // ...and pick up when we're off roaming
100        mSystemFacade.mIsRoaming = false;
101        runUntilStatus(downloadUri, Downloads.Impl.STATUS_SUCCESS);
102    }
103
104    public void testCleartextTrafficPermittedFlagHonored() throws Exception {
105        enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
106        enqueueResponse(buildResponse(HTTP_OK, FILE_CONTENT));
107
108        // Assert that HTTP request succeeds when cleartext traffic is permitted
109        mSystemFacade.mCleartextTrafficPermitted = true;
110        Uri downloadUri = requestDownload("/path");
111        assertEquals("http", downloadUri.getScheme());
112        runUntilStatus(downloadUri, Downloads.Impl.STATUS_SUCCESS);
113
114        // Assert that HTTP request fails when cleartext traffic is not permitted
115        mSystemFacade.mCleartextTrafficPermitted = false;
116        downloadUri = requestDownload("/path");
117        assertEquals("http", downloadUri.getScheme());
118        runUntilStatus(downloadUri, Downloads.Impl.STATUS_BAD_REQUEST);
119    }
120
121    /**
122     * Read a downloaded file from disk.
123     */
124    private String getDownloadContents(Uri downloadUri) throws Exception {
125        InputStream inputStream = mResolver.openInputStream(downloadUri);
126        try {
127            return readStream(inputStream);
128        } finally {
129            inputStream.close();
130        }
131    }
132
133    private void runUntilStatus(Uri downloadUri, int expected) throws Exception {
134        startService(null);
135
136        int actual = -1;
137
138        final long timeout = SystemClock.elapsedRealtime() + (15 * SECOND_IN_MILLIS);
139        while (SystemClock.elapsedRealtime() < timeout) {
140            actual = getDownloadStatus(downloadUri);
141            if (expected == actual) {
142                return;
143            }
144
145            SystemClock.sleep(100);
146        }
147
148        throw new TimeoutException("Expected status " + expected + "; only reached " + actual);
149    }
150
151    protected int getDownloadStatus(Uri downloadUri) {
152        return Integer.valueOf(getDownloadField(downloadUri, Downloads.Impl.COLUMN_STATUS));
153    }
154
155    private String getDownloadFilename(Uri downloadUri) {
156        return getDownloadField(downloadUri, Downloads.Impl._DATA);
157    }
158
159    private String getDownloadField(Uri downloadUri, String column) {
160        final String[] columns = new String[] {column};
161        Cursor cursor = mResolver.query(downloadUri, columns, null, null, null);
162        try {
163            assertEquals(1, cursor.getCount());
164            cursor.moveToFirst();
165            return cursor.getString(0);
166        } finally {
167            cursor.close();
168        }
169    }
170
171    /**
172     * Request a download from the Download Manager.
173     */
174    private Uri requestDownload(String path) throws MalformedURLException, UnknownHostException {
175        ContentValues values = new ContentValues();
176        values.put(Downloads.Impl.COLUMN_URI, getServerUri(path));
177        values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_EXTERNAL);
178        return mResolver.insert(Downloads.Impl.CONTENT_URI, values);
179    }
180
181    /**
182     * Update one field of a download in the provider.
183     */
184    private void updateDownload(Uri downloadUri, String column, String value) {
185        ContentValues values = new ContentValues();
186        values.put(column, value);
187        int numChanged = mResolver.update(downloadUri, values, null, null);
188        assertEquals(1, numChanged);
189    }
190}
191