Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2019 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 android.content.cts;
     18 
     19 import static org.mockito.Mockito.doAnswer;
     20 import static org.mockito.Mockito.mock;
     21 import static org.mockito.Mockito.never;
     22 import static org.mockito.Mockito.spy;
     23 import static org.mockito.Mockito.verify;
     24 import static org.mockito.Mockito.when;
     25 
     26 import android.content.ContentProvider;
     27 import android.content.ContentProviderClient;
     28 import android.content.ContentProviderOperation;
     29 import android.content.ContentResolver;
     30 import android.content.ContentValues;
     31 import android.content.IContentProvider;
     32 import android.content.OperationApplicationException;
     33 import android.net.Uri;
     34 import android.os.Bundle;
     35 import android.os.CancellationSignal;
     36 import android.os.ICancellationSignal;
     37 import android.os.OperationCanceledException;
     38 import android.os.RemoteException;
     39 import android.test.AndroidTestCase;
     40 import android.test.mock.MockContentResolver;
     41 import android.test.mock.MockIContentProvider;
     42 
     43 import org.mockito.stubbing.Answer;
     44 
     45 import java.io.FileNotFoundException;
     46 import java.util.ArrayList;
     47 import java.util.concurrent.CountDownLatch;
     48 import java.util.concurrent.TimeUnit;
     49 
     50 /**
     51  * Simple delegation test for {@link ContentProviderClient}, checking the right methods are called.
     52  * Actual {@link ContentProvider} functionality is tested in {@link ContentProviderTest}.
     53  */
     54 public class ContentProviderClientTest extends AndroidTestCase {
     55 
     56     private static final Answer ANSWER_SLEEP = invocation -> {
     57         // Sleep long enough to trigger ANR
     58         Thread.sleep(100);
     59         return null;
     60     };
     61 
     62     private static final String PACKAGE_NAME = "android.content.cts";
     63     private static final String MODE = "mode";
     64     private static final String SELECTION = "selection";
     65     private static final String AUTHORITY = "authority";
     66     private static final String METHOD = "method";
     67     private static final String ARG = "arg";
     68     private static final Uri URI = Uri.parse("com.example.app://path");
     69     private static final Bundle ARGS = new Bundle();
     70     private static final ContentValues VALUES = new ContentValues();
     71     private static final ContentValues[] VALUES_ARRAY = {VALUES};
     72     private static final ArrayList<ContentProviderOperation> OPS = new ArrayList<>();
     73 
     74     private ContentResolver mContentResolver;
     75     private IContentProvider mIContentProvider;
     76     private ContentProviderClient mContentProviderClient;
     77 
     78     private CancellationSignal mCancellationSignal = new CancellationSignal();
     79     private ICancellationSignal mICancellationSignal;
     80     private boolean mCalledCancel = false;
     81 
     82     @Override
     83     public void setUp() throws Exception {
     84         super.setUp();
     85 
     86         mIContentProvider = mock(MockIContentProvider.class);
     87         mICancellationSignal = mock(ICancellationSignal.class);
     88 
     89         when(mIContentProvider.createCancellationSignal()).thenReturn(mICancellationSignal);
     90 
     91         mContentResolver = spy(new MockContentResolver(getContext()));
     92         mContentProviderClient = spy(new ContentProviderClient(mContentResolver, mIContentProvider,
     93                 false));
     94 
     95         mCalledCancel = false;
     96     }
     97 
     98     @Override
     99     protected void tearDown() throws Exception {
    100         super.tearDown();
    101         if (!mCalledCancel) {
    102             // Client should never cancel unless the test called cancel
    103             assertFalse(mCancellationSignal.isCanceled());
    104             verify(mICancellationSignal, never()).cancel();
    105         }
    106     }
    107 
    108     public void testQuery() throws RemoteException {
    109         mContentProviderClient.query(URI, null, ARGS, mCancellationSignal);
    110         verify(mIContentProvider).query(PACKAGE_NAME, URI, null, ARGS, mICancellationSignal);
    111     }
    112 
    113     public void testQueryTimeout() throws RemoteException, InterruptedException {
    114         when(mIContentProvider.query(PACKAGE_NAME, URI, null, ARGS, mICancellationSignal))
    115                 .thenAnswer(ANSWER_SLEEP);
    116 
    117         testTimeout(() -> mContentProviderClient.query(URI, null, ARGS, mCancellationSignal));
    118 
    119         verify(mIContentProvider).query(PACKAGE_NAME, URI, null, ARGS, mICancellationSignal);
    120     }
    121 
    122     public void testQueryAlreadyCancelled() throws Exception {
    123         testAlreadyCancelled(
    124                 () -> mContentProviderClient.query(URI, null, ARGS, mCancellationSignal));
    125         verify(mIContentProvider, never()).query(PACKAGE_NAME, URI, null, ARGS,
    126                 mICancellationSignal);
    127     }
    128 
    129     public void testGetType() throws RemoteException {
    130         mContentProviderClient.getType(URI);
    131         verify(mIContentProvider).getType(URI);
    132     }
    133 
    134     public void testGetTypeTimeout() throws RemoteException, InterruptedException {
    135         when(mIContentProvider.getType(URI))
    136                 .thenAnswer(ANSWER_SLEEP);
    137 
    138         testTimeout(() -> mContentProviderClient.getType(URI));
    139 
    140         verify(mIContentProvider).getType(URI);
    141     }
    142 
    143     public void testGetStreamTypes() throws RemoteException {
    144         mContentProviderClient.getStreamTypes(URI, "");
    145         verify(mIContentProvider).getStreamTypes(URI, "");
    146     }
    147 
    148     public void testGetStreamTypesTimeout() throws RemoteException, InterruptedException {
    149         when(mIContentProvider.getStreamTypes(URI, ""))
    150                 .thenAnswer(ANSWER_SLEEP);
    151 
    152         testTimeout(() -> mContentProviderClient.getStreamTypes(URI, ""));
    153 
    154         verify(mIContentProvider).getStreamTypes(URI, "");
    155     }
    156 
    157     public void testCanonicalize() throws RemoteException {
    158         mContentProviderClient.canonicalize(URI);
    159         verify(mIContentProvider).canonicalize(PACKAGE_NAME, URI);
    160     }
    161 
    162     public void testCanonicalizeTimeout() throws RemoteException, InterruptedException {
    163         when(mIContentProvider.canonicalize(PACKAGE_NAME, URI))
    164                 .thenAnswer(ANSWER_SLEEP);
    165 
    166         testTimeout(() -> mContentProviderClient.canonicalize(URI));
    167 
    168         verify(mIContentProvider).canonicalize(PACKAGE_NAME, URI);
    169     }
    170 
    171     public void testUncanonicalize() throws RemoteException {
    172         mContentProviderClient.uncanonicalize(URI);
    173         verify(mIContentProvider).uncanonicalize(PACKAGE_NAME, URI);
    174     }
    175 
    176     public void testUncanonicalizeTimeout() throws RemoteException, InterruptedException {
    177         when(mIContentProvider.uncanonicalize(PACKAGE_NAME, URI))
    178                 .thenAnswer(ANSWER_SLEEP);
    179 
    180         testTimeout(() -> mContentProviderClient.uncanonicalize(URI));
    181 
    182         verify(mIContentProvider).uncanonicalize(PACKAGE_NAME, URI);
    183     }
    184 
    185     public void testRefresh() throws RemoteException {
    186         mContentProviderClient.refresh(URI, ARGS, mCancellationSignal);
    187         verify(mIContentProvider).refresh(PACKAGE_NAME, URI, ARGS, mICancellationSignal);
    188     }
    189 
    190     public void testRefreshTimeout() throws RemoteException, InterruptedException {
    191         when(mIContentProvider.refresh(PACKAGE_NAME, URI, ARGS, mICancellationSignal))
    192                 .thenAnswer(ANSWER_SLEEP);
    193 
    194         testTimeout(() -> mContentProviderClient.refresh(URI, ARGS, mCancellationSignal));
    195 
    196         verify(mIContentProvider).refresh(PACKAGE_NAME, URI, ARGS, mICancellationSignal);
    197     }
    198 
    199     public void testRefreshAlreadyCancelled() throws Exception {
    200         testAlreadyCancelled(() -> mContentProviderClient.refresh(URI, ARGS, mCancellationSignal));
    201         verify(mIContentProvider, never()).refresh(PACKAGE_NAME, URI, ARGS, mICancellationSignal);
    202     }
    203 
    204     public void testInsert() throws RemoteException {
    205         mContentProviderClient.insert(URI, VALUES);
    206         verify(mIContentProvider).insert(PACKAGE_NAME, URI, VALUES);
    207     }
    208 
    209     public void testInsertTimeout() throws RemoteException, InterruptedException {
    210         when(mIContentProvider.insert(PACKAGE_NAME, URI, VALUES))
    211                 .thenAnswer(ANSWER_SLEEP);
    212 
    213         testTimeout(() -> mContentProviderClient.insert(URI, VALUES));
    214 
    215         verify(mIContentProvider).insert(PACKAGE_NAME, URI, VALUES);
    216     }
    217 
    218     public void testBulkInsert() throws RemoteException {
    219         mContentProviderClient.bulkInsert(URI, VALUES_ARRAY);
    220         verify(mIContentProvider).bulkInsert(PACKAGE_NAME, URI, VALUES_ARRAY);
    221     }
    222 
    223     public void testBulkInsertTimeout() throws RemoteException, InterruptedException {
    224         when(mIContentProvider.bulkInsert(PACKAGE_NAME, URI, VALUES_ARRAY))
    225                 .thenAnswer(ANSWER_SLEEP);
    226 
    227         testTimeout(() -> mContentProviderClient.bulkInsert(URI, VALUES_ARRAY));
    228 
    229         verify(mIContentProvider).bulkInsert(PACKAGE_NAME, URI, VALUES_ARRAY);
    230     }
    231 
    232     public void testDelete() throws RemoteException {
    233         mContentProviderClient.delete(URI, SELECTION, new String[0]);
    234         verify(mIContentProvider).delete(PACKAGE_NAME, URI, SELECTION, new String[0]);
    235     }
    236 
    237     public void testDeleteTimeout() throws RemoteException, InterruptedException {
    238         when(mIContentProvider.delete(PACKAGE_NAME, URI, SELECTION, new String[0]))
    239                 .thenAnswer(ANSWER_SLEEP);
    240 
    241         testTimeout(() -> mContentProviderClient.delete(URI, SELECTION, new String[0]));
    242 
    243         verify(mIContentProvider).delete(PACKAGE_NAME, URI, SELECTION, new String[0]);
    244     }
    245 
    246     public void testUpdate() throws RemoteException {
    247         mContentProviderClient.update(URI, VALUES, SELECTION, new String[0]);
    248         verify(mIContentProvider).update(PACKAGE_NAME, URI, VALUES, SELECTION,
    249                 new String[0]);
    250     }
    251 
    252     public void testUpdateTimeout() throws RemoteException, InterruptedException {
    253         when(mIContentProvider.update(PACKAGE_NAME, URI, VALUES, SELECTION,
    254                 new String[0]))
    255                 .thenAnswer(ANSWER_SLEEP);
    256 
    257         testTimeout(() -> mContentProviderClient.update(URI, VALUES, SELECTION,
    258                 new String[0]));
    259 
    260         verify(mIContentProvider).update(PACKAGE_NAME, URI, VALUES, SELECTION,
    261                 new String[0]);
    262     }
    263 
    264     public void testOpenFile() throws RemoteException, FileNotFoundException {
    265         mContentProviderClient.openFile(URI, MODE, mCancellationSignal);
    266 
    267         verify(mIContentProvider).openFile(PACKAGE_NAME, URI, MODE, mICancellationSignal, null);
    268     }
    269 
    270     public void testOpenFileTimeout()
    271             throws RemoteException, InterruptedException, FileNotFoundException {
    272         when(mIContentProvider.openFile(PACKAGE_NAME, URI, MODE, mICancellationSignal, null))
    273                 .thenAnswer(ANSWER_SLEEP);
    274 
    275         testTimeout(() -> mContentProviderClient.openFile(URI, MODE, mCancellationSignal));
    276 
    277         verify(mIContentProvider).openFile(PACKAGE_NAME, URI, MODE, mICancellationSignal, null);
    278     }
    279 
    280     public void testOpenFileAlreadyCancelled() throws Exception {
    281         testAlreadyCancelled(() -> mContentProviderClient.openFile(URI, MODE, mCancellationSignal));
    282 
    283         verify(mIContentProvider, never()).openFile(PACKAGE_NAME, URI, MODE,
    284                 mICancellationSignal, null);
    285     }
    286 
    287     public void testOpenAssetFile() throws RemoteException, FileNotFoundException {
    288         mContentProviderClient.openAssetFile(URI, MODE, mCancellationSignal);
    289 
    290         verify(mIContentProvider).openAssetFile(PACKAGE_NAME, URI, MODE, mICancellationSignal);
    291     }
    292 
    293     public void testOpenAssetFileTimeout()
    294             throws RemoteException, InterruptedException, FileNotFoundException {
    295         when(mIContentProvider.openAssetFile(PACKAGE_NAME, URI, MODE, mICancellationSignal))
    296                 .thenAnswer(ANSWER_SLEEP);
    297 
    298         testTimeout(() -> mContentProviderClient.openAssetFile(URI, MODE, mCancellationSignal));
    299 
    300         verify(mIContentProvider).openAssetFile(PACKAGE_NAME, URI, MODE, mICancellationSignal);
    301     }
    302 
    303     public void testOpenAssetFileAlreadyCancelled() throws Exception {
    304         testAlreadyCancelled(
    305                 () -> mContentProviderClient.openAssetFile(URI, MODE, mCancellationSignal));
    306 
    307         verify(mIContentProvider, never()).openAssetFile(PACKAGE_NAME, URI, MODE,
    308                 mICancellationSignal);
    309     }
    310 
    311     public void testOpenTypedAssetFile() throws RemoteException, FileNotFoundException {
    312         mContentProviderClient.openTypedAssetFile(URI, MODE, ARGS, mCancellationSignal);
    313 
    314         verify(mIContentProvider).openTypedAssetFile(PACKAGE_NAME, URI, MODE, ARGS,
    315                 mICancellationSignal);
    316     }
    317 
    318     public void testOpenTypedAssetFileTimeout()
    319             throws RemoteException, InterruptedException, FileNotFoundException {
    320         when(mIContentProvider.openTypedAssetFile(PACKAGE_NAME, URI, MODE, ARGS,
    321                 mICancellationSignal))
    322                 .thenAnswer(ANSWER_SLEEP);
    323 
    324         testTimeout(() -> mContentProviderClient.openTypedAssetFile(URI, MODE, ARGS,
    325                 mCancellationSignal));
    326 
    327         verify(mIContentProvider).openTypedAssetFile(PACKAGE_NAME, URI, MODE, ARGS,
    328                 mICancellationSignal);
    329     }
    330 
    331     public void testOpenTypedAssetFileAlreadyCancelled() throws Exception {
    332         testAlreadyCancelled(
    333                 () -> mContentProviderClient.openTypedAssetFile(URI, MODE, ARGS,
    334                         mCancellationSignal));
    335 
    336         verify(mIContentProvider, never()).openTypedAssetFile(PACKAGE_NAME, URI, MODE, ARGS,
    337                 mICancellationSignal);
    338     }
    339 
    340     public void testApplyBatch() throws RemoteException, OperationApplicationException {
    341         mContentProviderClient.applyBatch(AUTHORITY, OPS);
    342 
    343         verify(mIContentProvider).applyBatch(PACKAGE_NAME, AUTHORITY, OPS);
    344     }
    345 
    346     public void testApplyBatchTimeout()
    347             throws RemoteException, InterruptedException, OperationApplicationException {
    348         when(mIContentProvider.applyBatch(PACKAGE_NAME, AUTHORITY, OPS))
    349                 .thenAnswer(ANSWER_SLEEP);
    350 
    351         testTimeout(() -> mContentProviderClient.applyBatch(AUTHORITY, OPS));
    352 
    353         verify(mIContentProvider).applyBatch(PACKAGE_NAME, AUTHORITY, OPS);
    354     }
    355 
    356     public void testCall() throws RemoteException {
    357         mContentProviderClient.call(AUTHORITY, METHOD, ARG, ARGS);
    358 
    359         verify(mIContentProvider).call(PACKAGE_NAME, AUTHORITY, METHOD, ARG, ARGS);
    360     }
    361 
    362     public void testCallTimeout() throws RemoteException, InterruptedException {
    363         when(mIContentProvider.call(PACKAGE_NAME, AUTHORITY, METHOD, ARG, ARGS))
    364                 .thenAnswer(ANSWER_SLEEP);
    365 
    366         testTimeout(() -> mContentProviderClient.call(AUTHORITY, METHOD, ARG, ARGS));
    367 
    368         verify(mIContentProvider).call(PACKAGE_NAME, AUTHORITY, METHOD, ARG, ARGS);
    369     }
    370 
    371     private void testTimeout(Function function) throws InterruptedException {
    372         mContentProviderClient.setDetectNotResponding(1);
    373         CountDownLatch latch = new CountDownLatch(1);
    374         doAnswer(invocation -> {
    375             latch.countDown();
    376             return null;
    377         })
    378                 .when(mContentResolver)
    379                 .appNotRespondingViaProvider(mIContentProvider);
    380 
    381         new Thread(() -> {
    382             try {
    383                 function.run();
    384             } catch (Exception ignored) {
    385             } finally {
    386                 latch.countDown();
    387             }
    388         }).start();
    389 
    390         latch.await(100, TimeUnit.MILLISECONDS);
    391         assertEquals(0, latch.getCount());
    392 
    393         verify(mContentResolver).appNotRespondingViaProvider(mIContentProvider);
    394     }
    395 
    396     private void testAlreadyCancelled(Function function) throws Exception {
    397         mCancellationSignal.cancel();
    398         mCalledCancel = true;
    399 
    400         try {
    401             function.run();
    402             fail("Expected OperationCanceledException");
    403         } catch (OperationCanceledException expected) {
    404         }
    405     }
    406 
    407     private interface Function {
    408         void run() throws Exception;
    409     }
    410 }
    411