326d9fff61265b9e6f006c080fdede08fa226608
[android/platform/packages/providers/DownloadProvider.git] / tests / src / com / android / providers / downloads / AbstractDownloadManagerFunctionalTest.java
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
17 package com.android.providers.downloads;
18
19 import android.content.ComponentName;
20 import android.content.ContentResolver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.database.Cursor;
24 import android.provider.Downloads;
25 import android.test.MoreAsserts;
26 import android.test.RenamingDelegatingContext;
27 import android.test.ServiceTestCase;
28 import android.test.mock.MockContentResolver;
29 import android.util.Log;
30 import tests.http.MockResponse;
31 import tests.http.MockWebServer;
32 import tests.http.RecordedRequest;
33
34 import java.io.BufferedReader;
35 import java.io.File;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.net.MalformedURLException;
40 import java.util.Arrays;
41 import java.util.HashSet;
42 import java.util.Set;
43
44 public abstract class AbstractDownloadManagerFunctionalTest extends
45         ServiceTestCase<DownloadService> {
46
47     protected static final String LOG_TAG = "DownloadManagerFunctionalTest";
48     private static final String PROVIDER_AUTHORITY = "downloads";
49     protected static final long REQUEST_TIMEOUT_MILLIS = 10 * 1000;
50     protected static final long RETRY_DELAY_MILLIS = 61 * 1000;
51     protected static final String FILE_CONTENT = "hello world";
52     protected static final int HTTP_OK = 200;
53     protected static final int HTTP_PARTIAL_CONTENT = 206;
54     protected static final int HTTP_NOT_FOUND = 404;
55     protected static final int HTTP_SERVICE_UNAVAILABLE = 503;
56     protected MockWebServer mServer;
57     protected MockContentResolver mResolver;
58     protected TestContext mTestContext;
59     protected FakeSystemFacade mSystemFacade;
60
61     static interface StatusReader {
62         public int getStatus();
63         public boolean isComplete(int status);
64     }
65
66     /**
67      * Context passed to the provider and the service.  Allows most methods to pass through to the
68      * real Context (this is a LargeTest), with a few exceptions, including renaming file operations
69      * to avoid file and DB conflicts (via RenamingDelegatingContext).
70      */
71     static class TestContext extends RenamingDelegatingContext {
72         private static final String FILENAME_PREFIX = "test.";
73
74         private Context mRealContext;
75         private Set<String> mAllowedSystemServices;
76         private ContentResolver mResolver;
77
78         boolean mHasServiceBeenStarted = false;
79
80         public TestContext(Context realContext) {
81             super(realContext, FILENAME_PREFIX);
82             mRealContext = realContext;
83             mAllowedSystemServices = new HashSet<String>(Arrays.asList(new String[] {
84                     Context.NOTIFICATION_SERVICE,
85                     Context.POWER_SERVICE,
86             }));
87         }
88
89         public void setResolver(ContentResolver resolver) {
90             mResolver = resolver;
91         }
92
93         /**
94          * Direct DownloadService to our test instance of DownloadProvider.
95          */
96         @Override
97         public ContentResolver getContentResolver() {
98             assert mResolver != null;
99             return mResolver;
100         }
101
102         /**
103          * Stub some system services, allow access to others, and block the rest.
104          */
105         @Override
106         public Object getSystemService(String name) {
107             if (mAllowedSystemServices.contains(name)) {
108                 return mRealContext.getSystemService(name);
109             }
110             return super.getSystemService(name);
111         }
112
113         /**
114          * Record when DownloadProvider starts DownloadService.
115          */
116         @Override
117         public ComponentName startService(Intent service) {
118             if (service.getComponent().getClassName().equals(DownloadService.class.getName())) {
119                 mHasServiceBeenStarted = true;
120                 return service.getComponent();
121             }
122             throw new UnsupportedOperationException("Unexpected service: " + service);
123         }
124     }
125
126     public AbstractDownloadManagerFunctionalTest() {
127         super(DownloadService.class);
128     }
129
130     @Override
131     protected void setUp() throws Exception {
132         super.setUp();
133
134         mSystemFacade = new FakeSystemFacade();
135         Context realContext = getContext();
136         mTestContext = new TestContext(realContext);
137         setupProviderAndResolver();
138         assert isDatabaseEmpty(); // ensure we're not messing with real data
139
140         mTestContext.setResolver(mResolver);
141         setContext(mTestContext);
142         setupService();
143         getService().mSystemFacade = mSystemFacade;
144
145         mServer = new MockWebServer();
146         mServer.play();
147     }
148
149     @Override
150     protected void tearDown() throws Exception {
151         cleanUpDownloads();
152         super.tearDown();
153     }
154
155     private boolean isDatabaseEmpty() {
156         Cursor cursor = mResolver.query(Downloads.CONTENT_URI, null, null, null, null);
157         try {
158             return cursor.getCount() == 0;
159         } finally {
160             cursor.close();
161         }
162     }
163
164     void setupProviderAndResolver() {
165         DownloadProvider provider = new DownloadProvider();
166         provider.mSystemFacade = mSystemFacade;
167         provider.attachInfo(mTestContext, null);
168         mResolver = new MockContentResolver();
169         mResolver.addProvider(PROVIDER_AUTHORITY, provider);
170     }
171
172     /**
173      * Remove any downloaded files and delete any lingering downloads.
174      */
175     void cleanUpDownloads() {
176         if (mResolver == null) {
177             return;
178         }
179         String[] columns = new String[] {Downloads._DATA};
180         Cursor cursor = mResolver.query(Downloads.CONTENT_URI, columns, null, null, null);
181         try {
182             for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
183                 String filePath = cursor.getString(0);
184                 if (filePath == null) continue;
185                 Log.d(LOG_TAG, "Deleting " + filePath);
186                 new File(filePath).delete();
187             }
188         } finally {
189             cursor.close();
190         }
191         mResolver.delete(Downloads.CONTENT_URI, null, null);
192     }
193
194     /**
195      * Enqueue a response from the MockWebServer.
196      */
197     MockResponse enqueueResponse(int status, String body) {
198         MockResponse response = new MockResponse()
199                         .setResponseCode(status)
200                         .setBody(body)
201                         .addHeader("Content-type", "text/plain");
202         mServer.enqueue(response);
203         return response;
204     }
205
206     MockResponse enqueueEmptyResponse(int status) {
207         return enqueueResponse(status, "");
208     }
209
210     /**
211      * Wait for a request to come to the MockWebServer and return it.
212      */
213     RecordedRequest takeRequest() throws InterruptedException {
214         RecordedRequest request = mServer.takeRequestWithTimeout(REQUEST_TIMEOUT_MILLIS);
215         assertNotNull("Timed out waiting for request", request);
216         return request;
217     }
218
219     String getServerUri(String path) throws MalformedURLException {
220         return mServer.getUrl(path).toString();
221     }
222
223     /**
224      * Run the service and wait for a request and for the download to reach the given status.
225      * @return the request received
226      */
227     protected RecordedRequest runUntilStatus(StatusReader reader, int status) throws Exception {
228         startService(null);
229         RecordedRequest request = takeRequest();
230         waitForDownloadToStop(reader, status);
231         return request;
232     }
233
234     /**
235      * Wait for a download to given a given status, with a timeout.  Fails if the download reaches
236      * any other final status.
237      */
238     protected void waitForDownloadToStop(StatusReader reader, int expectedStatus)
239             throws Exception {
240         // TODO(showard): find a better way to accomplish this
241         long startTimeMillis = System.currentTimeMillis();
242         int status = reader.getStatus();
243         while (status != expectedStatus) {
244             if (reader.isComplete(status)) {
245                 fail("Download completed with unexpected status: " + status);
246             }
247             if (System.currentTimeMillis() > startTimeMillis + REQUEST_TIMEOUT_MILLIS) {
248                 fail("Download timed out with status " + status);
249             }
250             Thread.sleep(100);
251             mServer.checkForExceptions();
252             status = reader.getStatus();
253         }
254
255         long delta = System.currentTimeMillis() - startTimeMillis;
256         Log.d(LOG_TAG, "Status " + status + " reached after " + delta + "ms");
257     }
258
259     protected String readStream(InputStream inputStream) throws IOException {
260         BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
261         try {
262             char[] buffer = new char[1024];
263             int length = reader.read(buffer);
264             assertTrue("Failed to read anything from input stream", length > -1);
265             return String.valueOf(buffer, 0, length);
266         } finally {
267             reader.close();
268         }
269     }
270
271     protected void assertStartsWith(String expectedPrefix, String actual) {
272         String regex = "^" + expectedPrefix + ".*";
273         MoreAsserts.assertMatchesRegex(regex, actual);
274     }
275 }