AbstractDownloadProviderFunctionalTest.java revision 323f5ae0cafdc72f61defefaa5ba938f1b4d0dda
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 org.mockito.Mockito.mock;
20
21import android.app.NotificationManager;
22import android.content.ComponentName;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.database.ContentObserver;
27import android.database.Cursor;
28import android.net.Uri;
29import android.provider.Downloads;
30import android.test.MoreAsserts;
31import android.test.RenamingDelegatingContext;
32import android.test.ServiceTestCase;
33import android.test.mock.MockContentResolver;
34import android.util.Log;
35
36import com.google.mockwebserver.MockResponse;
37import com.google.mockwebserver.MockWebServer;
38import com.google.mockwebserver.RecordedRequest;
39import com.google.mockwebserver.SocketPolicy;
40
41import java.io.BufferedReader;
42import java.io.File;
43import java.io.IOException;
44import java.io.InputStream;
45import java.io.InputStreamReader;
46import java.net.MalformedURLException;
47import java.net.UnknownHostException;
48
49public abstract class AbstractDownloadProviderFunctionalTest extends
50        ServiceTestCase<DownloadService> {
51
52    protected static final String LOG_TAG = "DownloadProviderFunctionalTest";
53    private static final String PROVIDER_AUTHORITY = "downloads";
54    protected static final long RETRY_DELAY_MILLIS = 61 * 1000;
55
56    protected static final String
57            FILE_CONTENT = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
58
59    private final MockitoHelper mMockitoHelper = new MockitoHelper();
60
61    protected MockWebServer mServer;
62    protected MockContentResolverWithNotify mResolver;
63    protected TestContext mTestContext;
64    protected FakeSystemFacade mSystemFacade;
65    protected static String STRING_1K;
66    static {
67        StringBuilder buff = new StringBuilder();
68        for (int i = 0; i < 1024; i++) {
69            buff.append("a" + i % 26);
70        }
71        STRING_1K = buff.toString();
72    }
73
74    static class MockContentResolverWithNotify extends MockContentResolver {
75        public boolean mNotifyWasCalled = false;
76
77        public synchronized void resetNotified() {
78            mNotifyWasCalled = false;
79        }
80
81        @Override
82        public synchronized void notifyChange(Uri uri, ContentObserver observer,
83                boolean syncToNetwork) {
84            mNotifyWasCalled = true;
85            notifyAll();
86        }
87    }
88
89    /**
90     * Context passed to the provider and the service.  Allows most methods to pass through to the
91     * real Context (this is a LargeTest), with a few exceptions, including renaming file operations
92     * to avoid file and DB conflicts (via RenamingDelegatingContext).
93     */
94    static class TestContext extends RenamingDelegatingContext {
95        private static final String FILENAME_PREFIX = "test.";
96
97        private ContentResolver mResolver;
98        private final NotificationManager mNotifManager;
99
100        boolean mHasServiceBeenStarted = false;
101
102        public TestContext(Context realContext) {
103            super(realContext, FILENAME_PREFIX);
104            mNotifManager = mock(NotificationManager.class);
105        }
106
107        public void setResolver(ContentResolver resolver) {
108            mResolver = resolver;
109        }
110
111        /**
112         * Direct DownloadService to our test instance of DownloadProvider.
113         */
114        @Override
115        public ContentResolver getContentResolver() {
116            return mResolver;
117        }
118
119        /**
120         * Stub some system services, allow access to others, and block the rest.
121         */
122        @Override
123        public Object getSystemService(String name) {
124            if (Context.NOTIFICATION_SERVICE.equals(name)) {
125                return mNotifManager;
126            }
127
128            return super.getSystemService(name);
129        }
130
131        /**
132         * Record when DownloadProvider starts DownloadService.
133         */
134        @Override
135        public ComponentName startService(Intent service) {
136            if (service.getComponent().getClassName().equals(DownloadService.class.getName())) {
137                mHasServiceBeenStarted = true;
138                return service.getComponent();
139            }
140            throw new UnsupportedOperationException("Unexpected service: " + service);
141        }
142    }
143
144    public AbstractDownloadProviderFunctionalTest(FakeSystemFacade systemFacade) {
145        super(DownloadService.class);
146        mSystemFacade = systemFacade;
147    }
148
149    @Override
150    protected void setUp() throws Exception {
151        super.setUp();
152        mMockitoHelper.setUp(getClass());
153
154        // Since we're testing a system app, AppDataDirGuesser doesn't find our
155        // cache dir, so set it explicitly.
156        System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
157
158        final Context realContext = getContext();
159        mTestContext = new TestContext(realContext);
160        setupProviderAndResolver();
161        mTestContext.setResolver(mResolver);
162        setContext(mTestContext);
163        setupService();
164        getService().mSystemFacade = mSystemFacade;
165        mSystemFacade.setUp();
166        assertTrue(isDatabaseEmpty()); // ensure we're not messing with real data
167        mServer = new MockWebServer();
168        mServer.play();
169    }
170
171    @Override
172    protected void tearDown() throws Exception {
173        cleanUpDownloads();
174        mServer.shutdown();
175        mMockitoHelper.tearDown();
176        super.tearDown();
177    }
178
179    private boolean isDatabaseEmpty() {
180        Cursor cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
181                null, null, null, null);
182        try {
183            return cursor.getCount() == 0;
184        } finally {
185            cursor.close();
186        }
187    }
188
189    void setupProviderAndResolver() {
190        DownloadProvider provider = new DownloadProvider();
191        provider.mSystemFacade = mSystemFacade;
192        provider.attachInfo(mTestContext, null);
193        mResolver = new MockContentResolverWithNotify();
194        mResolver.addProvider(PROVIDER_AUTHORITY, provider);
195    }
196
197    /**
198     * Remove any downloaded files and delete any lingering downloads.
199     */
200    void cleanUpDownloads() {
201        if (mResolver == null) {
202            return;
203        }
204        String[] columns = new String[] {Downloads.Impl._DATA};
205        Cursor cursor = mResolver.query(Downloads.Impl.CONTENT_URI, columns, null, null, null);
206        try {
207            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
208                String filePath = cursor.getString(0);
209                if (filePath == null) continue;
210                Log.d(LOG_TAG, "Deleting " + filePath);
211                new File(filePath).delete();
212            }
213        } finally {
214            cursor.close();
215        }
216        mResolver.delete(Downloads.Impl.CONTENT_URI, null, null);
217    }
218
219    void enqueueResponse(MockResponse resp) {
220        mServer.enqueue(resp);
221    }
222
223    MockResponse buildResponse(int status, String body) {
224        return new MockResponse().setResponseCode(status).setBody(body)
225                .setHeader("Content-type", "text/plain")
226                .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END);
227    }
228
229    MockResponse buildResponse(int status, byte[] body) {
230        return new MockResponse().setResponseCode(status).setBody(body)
231                .setHeader("Content-type", "text/plain")
232                .setSocketPolicy(SocketPolicy.DISCONNECT_AT_END);
233    }
234
235    MockResponse buildEmptyResponse(int status) {
236        return buildResponse(status, "");
237    }
238
239    /**
240     * Fetch the last request received by the MockWebServer.
241     */
242    protected RecordedRequest takeRequest() throws InterruptedException {
243        RecordedRequest request = mServer.takeRequest();
244        assertNotNull("Expected request was not made", request);
245        return request;
246    }
247
248    String getServerUri(String path) throws MalformedURLException, UnknownHostException {
249        return mServer.getUrl(path).toString();
250    }
251
252    protected String readStream(InputStream inputStream) throws IOException {
253        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
254        try {
255            char[] buffer = new char[1024];
256            int length = reader.read(buffer);
257            assertTrue("Failed to read anything from input stream", length > -1);
258            return String.valueOf(buffer, 0, length);
259        } finally {
260            reader.close();
261        }
262    }
263
264    protected void assertStartsWith(String expectedPrefix, String actual) {
265        String regex = "^" + expectedPrefix + ".*";
266        MoreAsserts.assertMatchesRegex(regex, actual);
267    }
268}
269