Home | History | Annotate | Download | only in downloads
      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 static org.mockito.Mockito.mock;
     20 
     21 import android.app.NotificationManager;
     22 import android.content.ComponentName;
     23 import android.content.ContentResolver;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.database.ContentObserver;
     27 import android.database.Cursor;
     28 import android.net.Uri;
     29 import android.provider.Downloads;
     30 import android.test.MoreAsserts;
     31 import android.test.RenamingDelegatingContext;
     32 import android.test.ServiceTestCase;
     33 import android.test.mock.MockContentResolver;
     34 import android.util.Log;
     35 
     36 import com.google.mockwebserver.MockResponse;
     37 import com.google.mockwebserver.MockWebServer;
     38 import com.google.mockwebserver.RecordedRequest;
     39 import com.google.mockwebserver.SocketPolicy;
     40 
     41 import java.io.BufferedReader;
     42 import java.io.File;
     43 import java.io.IOException;
     44 import java.io.InputStream;
     45 import java.io.InputStreamReader;
     46 import java.net.MalformedURLException;
     47 import java.net.UnknownHostException;
     48 
     49 public 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 MockContentResolverWithNotify(Context context) {
     78             super(context);
     79         }
     80 
     81         public synchronized void resetNotified() {
     82             mNotifyWasCalled = false;
     83         }
     84 
     85         @Override
     86         public synchronized void notifyChange(
     87                 Uri uri, ContentObserver observer, boolean syncToNetwork) {
     88             mNotifyWasCalled = true;
     89         }
     90     }
     91 
     92     /**
     93      * Context passed to the provider and the service.  Allows most methods to pass through to the
     94      * real Context (this is a LargeTest), with a few exceptions, including renaming file operations
     95      * to avoid file and DB conflicts (via RenamingDelegatingContext).
     96      */
     97     static class TestContext extends RenamingDelegatingContext {
     98         private static final String FILENAME_PREFIX = "test.";
     99 
    100         private final ContentResolver mResolver;
    101         private final NotificationManager mNotifManager;
    102 
    103         boolean mHasServiceBeenStarted = false;
    104 
    105         public TestContext(Context realContext) {
    106             super(realContext, FILENAME_PREFIX);
    107             mResolver = new MockContentResolverWithNotify(this);
    108             mNotifManager = mock(NotificationManager.class);
    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 
    160         mTestContext = new TestContext(realContext);
    161         mResolver = (MockContentResolverWithNotify) mTestContext.getContentResolver();
    162 
    163         final DownloadProvider provider = new DownloadProvider();
    164         provider.mSystemFacade = mSystemFacade;
    165         provider.attachInfo(mTestContext, null);
    166 
    167         mResolver.addProvider(PROVIDER_AUTHORITY, provider);
    168 
    169         setContext(mTestContext);
    170         setupService();
    171         getService().mSystemFacade = mSystemFacade;
    172 
    173         mSystemFacade.setUp();
    174         assertTrue(isDatabaseEmpty()); // ensure we're not messing with real data
    175         mServer = new MockWebServer();
    176         mServer.play();
    177     }
    178 
    179     @Override
    180     protected void tearDown() throws Exception {
    181         cleanUpDownloads();
    182         mServer.shutdown();
    183         mMockitoHelper.tearDown();
    184         super.tearDown();
    185     }
    186 
    187     private boolean isDatabaseEmpty() {
    188         Cursor cursor = mResolver.query(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
    189                 null, null, null, null);
    190         try {
    191             return cursor.getCount() == 0;
    192         } finally {
    193             cursor.close();
    194         }
    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