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    /**
105     * Read a downloaded file from disk.
106     */
107    private String getDownloadContents(Uri downloadUri) throws Exception {
108        InputStream inputStream = mResolver.openInputStream(downloadUri);
109        try {
110            return readStream(inputStream);
111        } finally {
112            inputStream.close();
113        }
114    }
115
116    private void runUntilStatus(Uri downloadUri, int expected) throws Exception {
117        startService(null);
118
119        int actual = -1;
120
121        final long timeout = SystemClock.elapsedRealtime() + (15 * SECOND_IN_MILLIS);
122        while (SystemClock.elapsedRealtime() < timeout) {
123            actual = getDownloadStatus(downloadUri);
124            if (expected == actual) {
125                return;
126            }
127
128            SystemClock.sleep(100);
129        }
130
131        throw new TimeoutException("Expected status " + expected + "; only reached " + actual);
132    }
133
134    protected int getDownloadStatus(Uri downloadUri) {
135        return Integer.valueOf(getDownloadField(downloadUri, Downloads.Impl.COLUMN_STATUS));
136    }
137
138    private String getDownloadFilename(Uri downloadUri) {
139        return getDownloadField(downloadUri, Downloads.Impl._DATA);
140    }
141
142    private String getDownloadField(Uri downloadUri, String column) {
143        final String[] columns = new String[] {column};
144        Cursor cursor = mResolver.query(downloadUri, columns, null, null, null);
145        try {
146            assertEquals(1, cursor.getCount());
147            cursor.moveToFirst();
148            return cursor.getString(0);
149        } finally {
150            cursor.close();
151        }
152    }
153
154    /**
155     * Request a download from the Download Manager.
156     */
157    private Uri requestDownload(String path) throws MalformedURLException, UnknownHostException {
158        ContentValues values = new ContentValues();
159        values.put(Downloads.Impl.COLUMN_URI, getServerUri(path));
160        values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_EXTERNAL);
161        return mResolver.insert(Downloads.Impl.CONTENT_URI, values);
162    }
163
164    /**
165     * Update one field of a download in the provider.
166     */
167    private void updateDownload(Uri downloadUri, String column, String value) {
168        ContentValues values = new ContentValues();
169        values.put(column, value);
170        int numChanged = mResolver.update(downloadUri, values, null, null);
171        assertEquals(1, numChanged);
172    }
173}
174