• 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.doAnswer;
20 import static org.mockito.Mockito.doReturn;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.spy;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.RETURNS_DEFAULTS;
26 
27 import android.content.AttributionSource;
28 import android.content.ContentProvider;
29 import android.content.ContentProviderClient;
30 import android.content.ContentProviderOperation;
31 import android.content.ContentResolver;
32 import android.content.ContentValues;
33 import android.content.Context;
34 import android.content.ContextParams;
35 import android.content.IContentProvider;
36 import android.content.OperationApplicationException;
37 import android.net.Uri;
38 import android.os.Bundle;
39 import android.os.CancellationSignal;
40 import android.os.ICancellationSignal;
41 import android.os.OperationCanceledException;
42 import android.os.Process;
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).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(URI);
146     }
147 
testGetTypeTimeout()148     public void testGetTypeTimeout() throws RemoteException, InterruptedException {
149         doAnswer(ANSWER_SLEEP).when(mIContentProvider).getType(URI);
150 
151         testTimeout(() -> mContentProviderClient.getType(URI));
152 
153         verify(mIContentProvider).getType(URI);
154     }
155 
testGetStreamTypes()156     public void testGetStreamTypes() throws RemoteException {
157         mContentProviderClient.getStreamTypes(URI, "");
158         verify(mIContentProvider).getStreamTypes(URI, "");
159     }
160 
testGetStreamTypesTimeout()161     public void testGetStreamTypesTimeout() throws RemoteException, InterruptedException {
162         doAnswer(ANSWER_SLEEP).when(mIContentProvider).getStreamTypes(URI, "");
163 
164         testTimeout(() -> mContentProviderClient.getStreamTypes(URI, ""));
165 
166         verify(mIContentProvider).getStreamTypes(URI, "");
167     }
168 
testCanonicalize()169     public void testCanonicalize() throws RemoteException {
170         mContentProviderClient.canonicalize(URI);
171         verify(mIContentProvider).canonicalize(mAttributionSource, URI);
172     }
173 
testCanonicalizeTimeout()174     public void testCanonicalizeTimeout() throws RemoteException, InterruptedException {
175         doAnswer(ANSWER_SLEEP).when(mIContentProvider).canonicalize(mAttributionSource, URI);
176 
177         testTimeout(() -> mContentProviderClient.canonicalize(URI));
178 
179         verify(mIContentProvider).canonicalize(mAttributionSource, URI);
180     }
181 
testUncanonicalize()182     public void testUncanonicalize() throws RemoteException {
183         mContentProviderClient.uncanonicalize(URI);
184         verify(mIContentProvider).uncanonicalize(mAttributionSource, URI);
185     }
186 
testUncanonicalizeTimeout()187     public void testUncanonicalizeTimeout() throws RemoteException, InterruptedException {
188         doAnswer(ANSWER_SLEEP).when(mIContentProvider).uncanonicalize(mAttributionSource, URI);
189 
190         testTimeout(() -> mContentProviderClient.uncanonicalize(URI));
191 
192         verify(mIContentProvider).uncanonicalize(mAttributionSource, URI);
193     }
194 
testRefresh()195     public void testRefresh() throws RemoteException {
196         mContentProviderClient.refresh(URI, ARGS, mCancellationSignal);
197         verify(mIContentProvider).refresh(mAttributionSource, URI, ARGS,
198                 mICancellationSignal);
199     }
200 
testRefreshTimeout()201     public void testRefreshTimeout() throws RemoteException, InterruptedException {
202         doAnswer(ANSWER_SLEEP).when(mIContentProvider).refresh(mAttributionSource, URI, ARGS,
203                 mICancellationSignal);
204 
205         testTimeout(() -> mContentProviderClient.refresh(URI, ARGS, mCancellationSignal));
206 
207         verify(mIContentProvider).refresh(mAttributionSource, URI, ARGS,
208                 mICancellationSignal);
209     }
210 
testRefreshAlreadyCancelled()211     public void testRefreshAlreadyCancelled() throws Exception {
212         testAlreadyCancelled(() -> mContentProviderClient.refresh(URI, ARGS, mCancellationSignal));
213         verify(mIContentProvider, never()).refresh(mAttributionSource, URI, ARGS,
214                 mICancellationSignal);
215     }
216 
testInsert()217     public void testInsert() throws RemoteException {
218         mContentProviderClient.insert(URI, VALUES, EXTRAS);
219         verify(mIContentProvider).insert(mAttributionSource, URI, VALUES, EXTRAS);
220     }
221 
testInsertTimeout()222     public void testInsertTimeout() throws RemoteException, InterruptedException {
223         doAnswer(ANSWER_SLEEP).when(mIContentProvider).insert(mAttributionSource, URI,
224                 VALUES, EXTRAS);
225 
226         testTimeout(() -> mContentProviderClient.insert(URI, VALUES, EXTRAS));
227 
228         verify(mIContentProvider).insert(mAttributionSource, URI, VALUES, EXTRAS);
229     }
230 
testBulkInsert()231     public void testBulkInsert() throws RemoteException {
232         mContentProviderClient.bulkInsert(URI, VALUES_ARRAY);
233         verify(mIContentProvider).bulkInsert(mAttributionSource, URI, VALUES_ARRAY);
234     }
235 
testBulkInsertTimeout()236     public void testBulkInsertTimeout() throws RemoteException, InterruptedException {
237         doAnswer(ANSWER_SLEEP).when(mIContentProvider).bulkInsert(mAttributionSource, URI,
238                 VALUES_ARRAY);
239 
240         testTimeout(() -> mContentProviderClient.bulkInsert(URI, VALUES_ARRAY));
241 
242         verify(mIContentProvider).bulkInsert(mAttributionSource, URI, VALUES_ARRAY);
243     }
244 
testDelete()245     public void testDelete() throws RemoteException {
246         mContentProviderClient.delete(URI, EXTRAS);
247         verify(mIContentProvider).delete(mAttributionSource, URI, EXTRAS);
248     }
249 
testDeleteTimeout()250     public void testDeleteTimeout() throws RemoteException, InterruptedException {
251         doAnswer(ANSWER_SLEEP).when(mIContentProvider).delete(mAttributionSource, URI, EXTRAS);
252 
253         testTimeout(() -> mContentProviderClient.delete(URI, EXTRAS));
254 
255         verify(mIContentProvider).delete(mAttributionSource, URI, EXTRAS);
256     }
257 
testUpdate()258     public void testUpdate() throws RemoteException {
259         mContentProviderClient.update(URI, VALUES, EXTRAS);
260         verify(mIContentProvider).update(mAttributionSource, URI, VALUES, EXTRAS);
261     }
262 
testUpdateTimeout()263     public void testUpdateTimeout() throws RemoteException, InterruptedException {
264         doAnswer(ANSWER_SLEEP).when(mIContentProvider).update(mAttributionSource, URI,
265                 VALUES, EXTRAS);
266 
267         testTimeout(() -> mContentProviderClient.update(URI, VALUES, EXTRAS));
268 
269         verify(mIContentProvider).update(mAttributionSource, URI, VALUES, EXTRAS);
270     }
271 
testOpenFile()272     public void testOpenFile() throws RemoteException, FileNotFoundException {
273         mContentProviderClient.openFile(URI, MODE, mCancellationSignal);
274 
275         verify(mIContentProvider).openFile(mAttributionSource, URI, MODE, mICancellationSignal);
276     }
277 
testOpenFileTimeout()278     public void testOpenFileTimeout()
279             throws RemoteException, InterruptedException, FileNotFoundException {
280         doAnswer(ANSWER_SLEEP).when(mIContentProvider).openFile(mAttributionSource,
281                 URI, MODE, mICancellationSignal);
282 
283         testTimeout(() -> mContentProviderClient.openFile(URI, MODE, mCancellationSignal));
284 
285         verify(mIContentProvider).openFile(mAttributionSource, URI, MODE, mICancellationSignal);
286     }
287 
testOpenFileAlreadyCancelled()288     public void testOpenFileAlreadyCancelled() throws Exception {
289         testAlreadyCancelled(() -> mContentProviderClient.openFile(URI, MODE, mCancellationSignal));
290 
291         verify(mIContentProvider, never()).openFile(mAttributionSource, URI, MODE,
292                 mICancellationSignal);
293     }
294 
testOpenAssetFile()295     public void testOpenAssetFile() throws RemoteException, FileNotFoundException {
296         mContentProviderClient.openAssetFile(URI, MODE, mCancellationSignal);
297 
298         verify(mIContentProvider).openAssetFile(mAttributionSource, URI, MODE, mICancellationSignal);
299     }
300 
testOpenAssetFileTimeout()301     public void testOpenAssetFileTimeout()
302             throws RemoteException, InterruptedException, FileNotFoundException {
303         doAnswer(ANSWER_SLEEP).when(mIContentProvider).openAssetFile(mAttributionSource,
304                 URI, MODE, mICancellationSignal);
305 
306         testTimeout(() -> mContentProviderClient.openAssetFile(URI, MODE, mCancellationSignal));
307 
308         verify(mIContentProvider).openAssetFile(mAttributionSource, URI, MODE,
309                 mICancellationSignal);
310     }
311 
testOpenAssetFileAlreadyCancelled()312     public void testOpenAssetFileAlreadyCancelled() throws Exception {
313         testAlreadyCancelled(
314                 () -> mContentProviderClient.openAssetFile(URI, MODE, mCancellationSignal));
315 
316         verify(mIContentProvider, never()).openAssetFile(mAttributionSource, URI, MODE,
317                 mICancellationSignal);
318     }
319 
testOpenTypedAssetFileDescriptor()320     public void testOpenTypedAssetFileDescriptor() throws RemoteException, FileNotFoundException {
321         mContentProviderClient.openTypedAssetFileDescriptor(URI, MODE, ARGS, mCancellationSignal);
322 
323         verify(mIContentProvider).openTypedAssetFile(mAttributionSource, URI, MODE, ARGS,
324                 mICancellationSignal);
325     }
326 
testOpenTypedAssetFile()327     public void testOpenTypedAssetFile() throws RemoteException, FileNotFoundException {
328         mContentProviderClient.openTypedAssetFile(URI, MODE, ARGS, mCancellationSignal);
329 
330         verify(mIContentProvider).openTypedAssetFile(mAttributionSource, URI, MODE, ARGS,
331                 mICancellationSignal);
332     }
333 
testOpenTypedAssetFileTimeout()334     public void testOpenTypedAssetFileTimeout()
335             throws RemoteException, InterruptedException, FileNotFoundException {
336         doAnswer(ANSWER_SLEEP).when(mIContentProvider).openTypedAssetFile(mAttributionSource,
337                 URI, MODE, ARGS, mICancellationSignal);
338 
339         testTimeout(() -> mContentProviderClient.openTypedAssetFile(URI, MODE, ARGS,
340                 mCancellationSignal));
341 
342         verify(mIContentProvider).openTypedAssetFile(mAttributionSource, URI, MODE, ARGS,
343                 mICancellationSignal);
344     }
345 
testOpenTypedAssetFileAlreadyCancelled()346     public void testOpenTypedAssetFileAlreadyCancelled() throws Exception {
347         testAlreadyCancelled(
348                 () -> mContentProviderClient.openTypedAssetFile(URI, MODE, ARGS,
349                         mCancellationSignal));
350 
351         verify(mIContentProvider, never()).openTypedAssetFile(mAttributionSource, URI, MODE,
352                 ARGS, mICancellationSignal);
353     }
354 
testApplyBatch()355     public void testApplyBatch() throws RemoteException, OperationApplicationException {
356         mContentProviderClient.applyBatch(AUTHORITY, OPS);
357 
358         verify(mIContentProvider).applyBatch(mAttributionSource, AUTHORITY, OPS);
359     }
360 
testApplyBatchTimeout()361     public void testApplyBatchTimeout()
362             throws RemoteException, InterruptedException, OperationApplicationException {
363         doAnswer(ANSWER_SLEEP).when(mIContentProvider).applyBatch(mAttributionSource,
364                 AUTHORITY, OPS);
365 
366         testTimeout(() -> mContentProviderClient.applyBatch(AUTHORITY, OPS));
367 
368         verify(mIContentProvider).applyBatch(mAttributionSource, AUTHORITY, OPS);
369     }
370 
testCall()371     public void testCall() throws RemoteException {
372         mContentProviderClient.call(AUTHORITY, METHOD, ARG, ARGS);
373 
374         verify(mIContentProvider).call(mAttributionSource, AUTHORITY, METHOD, ARG, ARGS);
375     }
376 
testCallTimeout()377     public void testCallTimeout() throws RemoteException, InterruptedException {
378         doAnswer(ANSWER_SLEEP).when(mIContentProvider).call(mAttributionSource, AUTHORITY,
379                 METHOD, ARG, ARGS);
380 
381         testTimeout(() -> mContentProviderClient.call(AUTHORITY, METHOD, ARG, ARGS));
382 
383         verify(mIContentProvider).call(mAttributionSource, AUTHORITY, METHOD, ARG, ARGS);
384     }
385 
testTimeout(Function function)386     private void testTimeout(Function function) throws InterruptedException {
387         mContentProviderClient.setDetectNotResponding(1);
388         CountDownLatch latch = new CountDownLatch(1);
389         doAnswer(invocation -> {
390             latch.countDown();
391             return null;
392         })
393                 .when(mContentResolver)
394                 .appNotRespondingViaProvider(mIContentProvider);
395 
396         new Thread(() -> {
397             try {
398                 function.run();
399             } catch (Exception ignored) {
400             } finally {
401                 latch.countDown();
402             }
403         }).start();
404 
405         latch.await(100, TimeUnit.MILLISECONDS);
406         assertEquals(0, latch.getCount());
407 
408         verify(mContentResolver).appNotRespondingViaProvider(mIContentProvider);
409     }
410 
testAlreadyCancelled(Function function)411     private void testAlreadyCancelled(Function function) throws Exception {
412         mCancellationSignal.cancel();
413         mCalledCancel = true;
414 
415         try {
416             function.run();
417             fail("Expected OperationCanceledException");
418         } catch (OperationCanceledException expected) {
419         }
420     }
421 
422     private interface Function {
run()423         void run() throws Exception;
424     }
425 }
426