• 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.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
setUp()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
tearDown()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 
testQuery()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 
testQueryTimeout()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 
testQueryAlreadyCancelled()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 
testGetType()129     public void testGetType() throws RemoteException {
130         mContentProviderClient.getType(URI);
131         verify(mIContentProvider).getType(URI);
132     }
133 
testGetTypeTimeout()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 
testGetStreamTypes()143     public void testGetStreamTypes() throws RemoteException {
144         mContentProviderClient.getStreamTypes(URI, "");
145         verify(mIContentProvider).getStreamTypes(URI, "");
146     }
147 
testGetStreamTypesTimeout()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 
testCanonicalize()157     public void testCanonicalize() throws RemoteException {
158         mContentProviderClient.canonicalize(URI);
159         verify(mIContentProvider).canonicalize(PACKAGE_NAME, URI);
160     }
161 
testCanonicalizeTimeout()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 
testUncanonicalize()171     public void testUncanonicalize() throws RemoteException {
172         mContentProviderClient.uncanonicalize(URI);
173         verify(mIContentProvider).uncanonicalize(PACKAGE_NAME, URI);
174     }
175 
testUncanonicalizeTimeout()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 
testRefresh()185     public void testRefresh() throws RemoteException {
186         mContentProviderClient.refresh(URI, ARGS, mCancellationSignal);
187         verify(mIContentProvider).refresh(PACKAGE_NAME, URI, ARGS, mICancellationSignal);
188     }
189 
testRefreshTimeout()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 
testRefreshAlreadyCancelled()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 
testInsert()204     public void testInsert() throws RemoteException {
205         mContentProviderClient.insert(URI, VALUES);
206         verify(mIContentProvider).insert(PACKAGE_NAME, URI, VALUES);
207     }
208 
testInsertTimeout()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 
testBulkInsert()218     public void testBulkInsert() throws RemoteException {
219         mContentProviderClient.bulkInsert(URI, VALUES_ARRAY);
220         verify(mIContentProvider).bulkInsert(PACKAGE_NAME, URI, VALUES_ARRAY);
221     }
222 
testBulkInsertTimeout()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 
testDelete()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 
testDeleteTimeout()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 
testUpdate()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 
testUpdateTimeout()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 
testOpenFile()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 
testOpenFileTimeout()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 
testOpenFileAlreadyCancelled()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 
testOpenAssetFile()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 
testOpenAssetFileTimeout()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 
testOpenAssetFileAlreadyCancelled()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 
testOpenTypedAssetFile()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 
testOpenTypedAssetFileTimeout()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 
testOpenTypedAssetFileAlreadyCancelled()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 
testApplyBatch()340     public void testApplyBatch() throws RemoteException, OperationApplicationException {
341         mContentProviderClient.applyBatch(AUTHORITY, OPS);
342 
343         verify(mIContentProvider).applyBatch(PACKAGE_NAME, AUTHORITY, OPS);
344     }
345 
testApplyBatchTimeout()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 
testCall()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 
testCallTimeout()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 
testTimeout(Function function)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 
testAlreadyCancelled(Function function)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 {
run()408         void run() throws Exception;
409     }
410 }
411