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