1 /*
2  * Copyright (C) 2007 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.calendar;
18 
19 import com.android.calendar.AsyncQueryService.Operation;
20 import com.android.calendar.AsyncQueryServiceHelper.OperationInfo;
21 
22 import android.content.ComponentName;
23 import android.content.ContentProvider;
24 import android.content.ContentProviderOperation;
25 import android.content.ContentProviderResult;
26 import android.content.ContentResolver;
27 import android.content.ContentValues;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.res.Resources;
31 import android.database.Cursor;
32 import android.net.Uri;
33 import android.os.Handler;
34 import android.os.HandlerThread;
35 import android.os.Message;
36 import android.test.IsolatedContext;
37 import android.test.RenamingDelegatingContext;
38 import android.test.ServiceTestCase;
39 import android.test.mock.MockContentResolver;
40 import android.test.mock.MockContext;
41 import android.test.mock.MockCursor;
42 import android.test.suitebuilder.annotation.LargeTest;
43 import android.test.suitebuilder.annotation.SmallTest;
44 import android.test.suitebuilder.annotation.Smoke;
45 import android.util.Log;
46 
47 import java.io.File;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.concurrent.Semaphore;
51 import java.util.concurrent.TimeUnit;
52 
53 /**
54  * Unit tests for {@link android.text.format.DateUtils#formatDateRange}.
55  */
56 public class AsyncQueryServiceTest extends ServiceTestCase<AsyncQueryServiceHelper> {
57     private static final String TAG = "AsyncQueryServiceTest";
58 
59     private static final String AUTHORITY_URI = "content://AsyncQueryAuthority/";
60 
61     private static final String AUTHORITY = "AsyncQueryAuthority";
62 
63     private static final int MIN_DELAY = 50;
64 
65     private static final int BASE_TEST_WAIT_TIME = MIN_DELAY * 5;
66 
67     private static int mId = 0;
68 
69     private static final String[] TEST_PROJECTION = new String[] {
70             "col1", "col2", "col3"
71     };
72 
73     private static final String TEST_SELECTION = "selection";
74 
75     private static final String[] TEST_SELECTION_ARGS = new String[] {
76             "arg1", "arg2", "arg3"
77     };
78 
AsyncQueryServiceTest()79     public AsyncQueryServiceTest() {
80         super(AsyncQueryServiceHelper.class);
81     }
82 
83     @Override
setUp()84     protected void setUp() throws Exception {
85         super.setUp();
86     }
87 
88     private class MockContext2 extends MockContext {
89         @Override
getResources()90         public Resources getResources() {
91             return getContext().getResources();
92         }
93 
94         @Override
getDir(String name, int mode)95         public File getDir(String name, int mode) {
96             return getContext().getDir("mockcontext2_+" + name, mode);
97         }
98 
99         @Override
getApplicationContext()100         public Context getApplicationContext() {
101             return this;
102         }
103     }
104 
105     @Smoke
106     @SmallTest
testQuery()107     public void testQuery() throws Exception {
108         int index = 0;
109         final OperationInfo[] work = new OperationInfo[1];
110         work[index] = new OperationInfo();
111         work[index].op = Operation.EVENT_ARG_QUERY;
112 
113         work[index].token = ++mId;
114         work[index].cookie = ++mId;
115         work[index].uri = Uri.parse(AUTHORITY_URI + "blah");
116         work[index].projection = TEST_PROJECTION;
117         work[index].selection = TEST_SELECTION;
118         work[index].selectionArgs = TEST_SELECTION_ARGS;
119         work[index].orderBy = "order";
120 
121         work[index].delayMillis = 0;
122         work[index].result = new TestCursor();
123 
124         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
125         aqs.startQuery(work[index].token, work[index].cookie, work[index].uri,
126                 work[index].projection, work[index].selection, work[index].selectionArgs,
127                 work[index].orderBy);
128 
129         Log.d(TAG, "testQuery Waiting >>>>>>>>>>>");
130         assertEquals("Not all operations were executed.", work.length, aqs
131                 .waitForCompletion(BASE_TEST_WAIT_TIME));
132         Log.d(TAG, "testQuery Done <<<<<<<<<<<<<<");
133     }
134 
135     @SmallTest
testInsert()136     public void testInsert() throws Exception {
137         int index = 0;
138         final OperationInfo[] work = new OperationInfo[1];
139         work[index] = new OperationInfo();
140         work[index].op = Operation.EVENT_ARG_INSERT;
141 
142         work[index].token = ++mId;
143         work[index].cookie = ++mId;
144         work[index].uri = Uri.parse(AUTHORITY_URI + "blah");
145         work[index].values = new ContentValues();
146         work[index].values.put("key", ++mId);
147 
148         work[index].delayMillis = 0;
149         work[index].result = Uri.parse(AUTHORITY_URI + "Result=" + ++mId);
150 
151         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
152         aqs.startInsert(work[index].token, work[index].cookie, work[index].uri, work[index].values,
153                 work[index].delayMillis);
154 
155         Log.d(TAG, "testInsert Waiting >>>>>>>>>>>");
156         assertEquals("Not all operations were executed.", work.length, aqs
157                 .waitForCompletion(BASE_TEST_WAIT_TIME));
158         Log.d(TAG, "testInsert Done <<<<<<<<<<<<<<");
159     }
160 
161     @SmallTest
testUpdate()162     public void testUpdate() throws Exception {
163         int index = 0;
164         final OperationInfo[] work = new OperationInfo[1];
165         work[index] = new OperationInfo();
166         work[index].op = Operation.EVENT_ARG_UPDATE;
167 
168         work[index].token = ++mId;
169         work[index].cookie = ++mId;
170         work[index].uri = Uri.parse(AUTHORITY_URI + ++mId);
171         work[index].values = new ContentValues();
172         work[index].values.put("key", ++mId);
173         work[index].selection = TEST_SELECTION;
174         work[index].selectionArgs = TEST_SELECTION_ARGS;
175 
176         work[index].delayMillis = 0;
177         work[index].result = ++mId;
178 
179         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
180         aqs.startUpdate(work[index].token, work[index].cookie, work[index].uri, work[index].values,
181                 work[index].selection, work[index].selectionArgs, work[index].delayMillis);
182 
183         Log.d(TAG, "testUpdate Waiting >>>>>>>>>>>");
184         assertEquals("Not all operations were executed.", work.length, aqs
185                 .waitForCompletion(BASE_TEST_WAIT_TIME));
186         Log.d(TAG, "testUpdate Done <<<<<<<<<<<<<<");
187     }
188 
189     @SmallTest
testDelete()190     public void testDelete() throws Exception {
191         int index = 0;
192         final OperationInfo[] work = new OperationInfo[1];
193         work[index] = new OperationInfo();
194         work[index].op = Operation.EVENT_ARG_DELETE;
195 
196         work[index].token = ++mId;
197         work[index].cookie = ++mId;
198         work[index].uri = Uri.parse(AUTHORITY_URI + "blah");
199         work[index].selection = TEST_SELECTION;
200         work[index].selectionArgs = TEST_SELECTION_ARGS;
201 
202         work[index].delayMillis = 0;
203         work[index].result = ++mId;
204 
205         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
206         aqs.startDelete(work[index].token,
207                 work[index].cookie,
208                 work[index].uri,
209                 work[index].selection,
210                 work[index].selectionArgs,
211                 work[index].delayMillis);
212 
213         Log.d(TAG, "testDelete Waiting >>>>>>>>>>>");
214         assertEquals("Not all operations were executed.", work.length, aqs
215                 .waitForCompletion(BASE_TEST_WAIT_TIME));
216         Log.d(TAG, "testDelete Done <<<<<<<<<<<<<<");
217     }
218 
219     @SmallTest
testBatch()220     public void testBatch() throws Exception {
221         int index = 0;
222         final OperationInfo[] work = new OperationInfo[1];
223         work[index] = new OperationInfo();
224         work[index].op = Operation.EVENT_ARG_BATCH;
225 
226         work[index].token = ++mId;
227         work[index].cookie = ++mId;
228         work[index].authority = AUTHORITY;
229         work[index].cpo = new ArrayList<ContentProviderOperation>();
230         work[index].cpo.add(ContentProviderOperation.newInsert(Uri.parse(AUTHORITY_URI + ++mId))
231                 .build());
232 
233         work[index].delayMillis = 0;
234         ContentProviderResult[] resultArray = new ContentProviderResult[1];
235         resultArray[0] = new ContentProviderResult(++mId);
236         work[index].result = resultArray;
237 
238         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(work), work);
239         aqs.startBatch(work[index].token,
240                 work[index].cookie,
241                 work[index].authority,
242                 work[index].cpo,
243                 work[index].delayMillis);
244 
245         Log.d(TAG, "testBatch Waiting >>>>>>>>>>>");
246         assertEquals("Not all operations were executed.", work.length, aqs
247                 .waitForCompletion(BASE_TEST_WAIT_TIME));
248         Log.d(TAG, "testBatch Done <<<<<<<<<<<<<<");
249     }
250 
251     @LargeTest
testDelay()252     public void testDelay() throws Exception {
253         // Tests the ordering of the workqueue
254         int index = 0;
255         OperationInfo[] work = new OperationInfo[5];
256         work[index++] = generateWork(MIN_DELAY * 2);
257         work[index++] = generateWork(0);
258         work[index++] = generateWork(MIN_DELAY * 1);
259         work[index++] = generateWork(0);
260         work[index++] = generateWork(MIN_DELAY * 3);
261 
262         OperationInfo[] sorted = generateSortedWork(work, work.length);
263 
264         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(sorted), sorted);
265         startWork(aqs, work);
266 
267         Log.d(TAG, "testDelay Waiting >>>>>>>>>>>");
268         assertEquals("Not all operations were executed.", work.length, aqs
269                 .waitForCompletion(BASE_TEST_WAIT_TIME));
270         Log.d(TAG, "testDelay Done <<<<<<<<<<<<<<");
271     }
272 
273     @LargeTest
testCancel_simpleCancelLastTest()274     public void testCancel_simpleCancelLastTest() throws Exception {
275         int index = 0;
276         OperationInfo[] work = new OperationInfo[5];
277         work[index++] = generateWork(MIN_DELAY * 2);
278         work[index++] = generateWork(0);
279         work[index++] = generateWork(MIN_DELAY);
280         work[index++] = generateWork(0);
281         work[index] = generateWork(MIN_DELAY * 3);
282 
283         // Not part of the expected as it will be canceled
284         OperationInfo toBeCancelled1 = work[index];
285         OperationInfo[] expected = generateSortedWork(work, work.length - 1);
286 
287         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected);
288         startWork(aqs, work);
289         Operation lastOne = aqs.getLastCancelableOperation();
290         // Log.d(TAG, "lastOne = " + lastOne.toString());
291         // Log.d(TAG, "toBeCancelled1 = " + toBeCancelled1.toString());
292         assertTrue("1) delay=3 is not last", toBeCancelled1.equivalent(lastOne));
293         assertEquals("Can't cancel delay 3", 1, aqs.cancelOperation(lastOne.token));
294 
295         Log.d(TAG, "testCancel_simpleCancelLastTest Waiting >>>>>>>>>>>");
296         assertEquals("Not all operations were executed.", expected.length, aqs
297                 .waitForCompletion(BASE_TEST_WAIT_TIME));
298         Log.d(TAG, "testCancel_simpleCancelLastTest Done <<<<<<<<<<<<<<");
299     }
300 
301     @LargeTest
testCancel_cancelSecondToLast()302     public void testCancel_cancelSecondToLast() throws Exception {
303         int index = 0;
304         OperationInfo[] work = new OperationInfo[5];
305         work[index++] = generateWork(MIN_DELAY * 2);
306         work[index++] = generateWork(0);
307         work[index++] = generateWork(MIN_DELAY);
308         work[index++] = generateWork(0);
309         work[index] = generateWork(MIN_DELAY * 3);
310 
311         // Not part of the expected as it will be canceled
312         OperationInfo toBeCancelled1 = work[index];
313         OperationInfo[] expected = new OperationInfo[4];
314         expected[0] = work[1]; // delay = 0
315         expected[1] = work[3]; // delay = 0
316         expected[2] = work[2]; // delay = MIN_DELAY
317         expected[3] = work[4]; // delay = MIN_DELAY * 3
318 
319         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected);
320         startWork(aqs, work);
321 
322         Operation lastOne = aqs.getLastCancelableOperation(); // delay = 3
323         assertTrue("2) delay=3 is not last", toBeCancelled1.equivalent(lastOne));
324         assertEquals("Can't cancel delay 2", 1, aqs.cancelOperation(work[0].token));
325         assertEquals("Delay 2 should be gone", 0, aqs.cancelOperation(work[0].token));
326 
327         Log.d(TAG, "testCancel_cancelSecondToLast Waiting >>>>>>>>>>>");
328         assertEquals("Not all operations were executed.", expected.length, aqs
329                 .waitForCompletion(BASE_TEST_WAIT_TIME));
330         Log.d(TAG, "testCancel_cancelSecondToLast Done <<<<<<<<<<<<<<");
331     }
332 
333     @LargeTest
testCancel_multipleCancels()334     public void testCancel_multipleCancels() throws Exception {
335         int index = 0;
336         OperationInfo[] work = new OperationInfo[5];
337         work[index++] = generateWork(MIN_DELAY * 2);
338         work[index++] = generateWork(0);
339         work[index++] = generateWork(MIN_DELAY);
340         work[index++] = generateWork(0);
341         work[index] = generateWork(MIN_DELAY * 3);
342 
343         // Not part of the expected as it will be canceled
344         OperationInfo[] expected = new OperationInfo[3];
345         expected[0] = work[1]; // delay = 0
346         expected[1] = work[3]; // delay = 0
347         expected[2] = work[2]; // delay = MIN_DELAY
348 
349         TestAsyncQueryService aqs = new TestAsyncQueryService(buildTestContext(expected), expected);
350         startWork(aqs, work);
351 
352         Operation lastOne = aqs.getLastCancelableOperation(); // delay = 3
353         assertTrue("3) delay=3 is not last", work[4].equivalent(lastOne));
354         assertEquals("Can't cancel delay 2", 1, aqs.cancelOperation(work[0].token));
355         assertEquals("Delay 2 should be gone", 0, aqs.cancelOperation(work[0].token));
356         assertEquals("Can't cancel delay 3", 1, aqs.cancelOperation(work[4].token));
357         assertEquals("Delay 3 should be gone", 0, aqs.cancelOperation(work[4].token));
358 
359         Log.d(TAG, "testCancel_multipleCancels Waiting >>>>>>>>>>>");
360         assertEquals("Not all operations were executed.", expected.length, aqs
361                 .waitForCompletion(BASE_TEST_WAIT_TIME));
362         Log.d(TAG, "testCancel_multipleCancels Done <<<<<<<<<<<<<<");
363     }
364 
generateWork(long delayMillis)365     private OperationInfo generateWork(long delayMillis) {
366         OperationInfo work = new OperationInfo();
367         work.op = Operation.EVENT_ARG_DELETE;
368 
369         work.token = ++mId;
370         work.cookie = 100 + work.token;
371         work.uri = Uri.parse(AUTHORITY_URI + "blah");
372         work.selection = TEST_SELECTION;
373         work.selectionArgs = TEST_SELECTION_ARGS;
374 
375         work.delayMillis = delayMillis;
376         work.result = 1000 + work.token;
377         return work;
378     }
379 
startWork(TestAsyncQueryService aqs, OperationInfo[] work)380     private void startWork(TestAsyncQueryService aqs, OperationInfo[] work) {
381         for (OperationInfo w : work) {
382             if (w != null) {
383                 aqs.startDelete(w.token, w.cookie, w.uri, w.selection, w.selectionArgs,
384                         w.delayMillis);
385             }
386         }
387     }
388 
generateSortedWork(OperationInfo[] work, int length)389     OperationInfo[] generateSortedWork(OperationInfo[] work, int length) {
390         OperationInfo[] sorted = new OperationInfo[length];
391         System.arraycopy(work, 0, sorted, 0, length);
392 
393         // Set the scheduled time so they get sorted properly
394         for (OperationInfo w : sorted) {
395             if (w != null) {
396                 w.calculateScheduledTime();
397             }
398         }
399 
400         // Stable sort by scheduled time
401         Arrays.sort(sorted);
402 
403         Log.d(TAG, "Unsorted work: " + work.length);
404         for (OperationInfo w : work) {
405             if (w != null) {
406                 Log.d(TAG, "Token#" + w.token + " delay=" + w.delayMillis);
407             }
408         }
409         Log.d(TAG, "Sorted work: " + sorted.length);
410         for (OperationInfo w : sorted) {
411             if (w != null) {
412                 Log.d(TAG, "Token#" + w.token + " delay=" + w.delayMillis);
413             }
414         }
415 
416         return sorted;
417     }
418 
buildTestContext(final OperationInfo[] work)419     private Context buildTestContext(final OperationInfo[] work) {
420         MockContext context = new MockContext() {
421             MockContentResolver mResolver;
422 
423             @Override
424             public ContentResolver getContentResolver() {
425                 if (mResolver == null) {
426                     mResolver = new MockContentResolver();
427 
428                     final String filenamePrefix = "test.";
429                     RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
430                             new MockContext2(), getContext(), filenamePrefix);
431                     IsolatedContext providerContext =
432                             new IsolatedContext(mResolver, targetContextWrapper);
433 
434                     ContentProvider provider = new TestProvider(work);
435                     provider.attachInfo(providerContext, null);
436 
437                     mResolver.addProvider(AUTHORITY, provider);
438                 }
439                 return mResolver;
440             }
441 
442             @Override
443             public String getPackageName() {
444                 return AsyncQueryServiceTest.class.getPackage().getName();
445             }
446 
447             @Override
448             public ComponentName startService(Intent service) {
449                 AsyncQueryServiceTest.this.startService(service);
450                 return service.getComponent();
451             }
452         };
453 
454         return context;
455     }
456 
457     private final class TestCursor extends MockCursor {
458         int mUnique = ++mId;
459 
460         @Override
getCount()461         public int getCount() {
462             return mUnique;
463         }
464     }
465 
466     /**
467      * TestAsyncQueryService takes the expected results in the constructor. They
468      * are used to verify the data passed to the callbacks.
469      */
470     class TestAsyncQueryService extends AsyncQueryService {
471         int mIndex = 0;
472 
473         private OperationInfo[] mWork;
474 
475         private Semaphore mCountingSemaphore;
476 
TestAsyncQueryService(Context context, OperationInfo[] work)477         public TestAsyncQueryService(Context context, OperationInfo[] work) {
478             super(context);
479             mCountingSemaphore = new Semaphore(0);
480 
481             // run in a separate thread but call the same code
482             HandlerThread thread = new HandlerThread("TestAsyncQueryService");
483             thread.start();
484             super.setTestHandler(new Handler(thread.getLooper()) {
485                 @Override
486                 public void handleMessage(Message msg) {
487                     TestAsyncQueryService.this.handleMessage(msg);
488                 }
489             });
490 
491             mWork = work;
492         }
493 
494         @Override
onQueryComplete(int token, Object cookie, Cursor cursor)495         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
496             Log.d(TAG, "onQueryComplete tid=" + Thread.currentThread().getId());
497             Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
498 
499             assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_QUERY);
500             assertEquals(mWork[mIndex].token, token);
501             /*
502              * Even though our TestProvider returned mWork[mIndex].result, it is
503              * wrapped with new'ed CursorWrapperInner and there's no equal() in
504              * CursorWrapperInner. assertEquals the two cursor will always fail.
505              * So just compare the count which will be unique in our TestCursor;
506              */
507             assertEquals(((Cursor) mWork[mIndex].result).getCount(), cursor.getCount());
508 
509             mIndex++;
510             mCountingSemaphore.release();
511         }
512 
513         @Override
onInsertComplete(int token, Object cookie, Uri uri)514         protected void onInsertComplete(int token, Object cookie, Uri uri) {
515             Log.d(TAG, "onInsertComplete tid=" + Thread.currentThread().getId());
516             Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
517 
518             assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_INSERT);
519             assertEquals(mWork[mIndex].token, token);
520             assertEquals(mWork[mIndex].result, uri);
521 
522             mIndex++;
523             mCountingSemaphore.release();
524         }
525 
526         @Override
onUpdateComplete(int token, Object cookie, int result)527         protected void onUpdateComplete(int token, Object cookie, int result) {
528             Log.d(TAG, "onUpdateComplete tid=" + Thread.currentThread().getId());
529             Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
530 
531             assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_UPDATE);
532             assertEquals(mWork[mIndex].token, token);
533             assertEquals(mWork[mIndex].result, result);
534 
535             mIndex++;
536             mCountingSemaphore.release();
537         }
538 
539         @Override
onDeleteComplete(int token, Object cookie, int result)540         protected void onDeleteComplete(int token, Object cookie, int result) {
541             Log.d(TAG, "onDeleteComplete tid=" + Thread.currentThread().getId());
542             Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
543 
544             assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_DELETE);
545             assertEquals(mWork[mIndex].token, token);
546             assertEquals(mWork[mIndex].result, result);
547 
548             mIndex++;
549             mCountingSemaphore.release();
550         }
551 
552         @Override
onBatchComplete(int token, Object cookie, ContentProviderResult[] results)553         protected void onBatchComplete(int token, Object cookie, ContentProviderResult[] results) {
554             Log.d(TAG, "onBatchComplete tid=" + Thread.currentThread().getId());
555             Log.d(TAG, "mWork.length=" + mWork.length + " mIndex=" + mIndex);
556 
557             assertEquals(mWork[mIndex].op, Operation.EVENT_ARG_BATCH);
558             assertEquals(mWork[mIndex].token, token);
559 
560             ContentProviderResult[] expected = (ContentProviderResult[]) mWork[mIndex].result;
561             assertEquals(expected.length, results.length);
562             for (int i = 0; i < expected.length; ++i) {
563                 assertEquals(expected[i].count, results[i].count);
564                 assertEquals(expected[i].uri, results[i].uri);
565             }
566 
567             mIndex++;
568             mCountingSemaphore.release();
569         }
570 
waitForCompletion(long timeoutMills)571         public int waitForCompletion(long timeoutMills) {
572             Log.d(TAG, "waitForCompletion tid=" + Thread.currentThread().getId());
573             int count = 0;
574             try {
575                 while (count < mWork.length) {
576                     if (!mCountingSemaphore.tryAcquire(timeoutMills, TimeUnit.MILLISECONDS)) {
577                         break;
578                     }
579                     count++;
580                 }
581             } catch (InterruptedException e) {
582             }
583             return count;
584         }
585     }
586 
587     /**
588      * This gets called by AsyncQueryServiceHelper to read or write the data. It
589      * also verifies the data against the data passed in the constructor
590      */
591     class TestProvider extends ContentProvider {
592         OperationInfo[] mWork;
593 
594         int index = 0;
595 
TestProvider(OperationInfo[] work)596         public TestProvider(OperationInfo[] work) {
597             mWork = work;
598         }
599 
600         @Override
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy)601         public final Cursor query(Uri uri, String[] projection, String selection,
602                 String[] selectionArgs, String orderBy) {
603             Log.d(TAG, "Provider query index=" + index);
604             assertEquals(mWork[index].op, Operation.EVENT_ARG_QUERY);
605             assertEquals(mWork[index].uri, uri);
606             assertEquals(mWork[index].projection, projection);
607             assertEquals(mWork[index].selection, selection);
608             assertEquals(mWork[index].selectionArgs, selectionArgs);
609             assertEquals(mWork[index].orderBy, orderBy);
610             return (Cursor) mWork[index++].result;
611         }
612 
613         @Override
insert(Uri uri, ContentValues values)614         public Uri insert(Uri uri, ContentValues values) {
615             Log.d(TAG, "Provider insert index=" + index);
616             assertEquals(mWork[index].op, Operation.EVENT_ARG_INSERT);
617             assertEquals(mWork[index].uri, uri);
618             assertEquals(mWork[index].values, values);
619             return (Uri) mWork[index++].result;
620         }
621 
622         @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)623         public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
624             Log.d(TAG, "Provider update index=" + index);
625             assertEquals(mWork[index].op, Operation.EVENT_ARG_UPDATE);
626             assertEquals(mWork[index].uri, uri);
627             assertEquals(mWork[index].values, values);
628             assertEquals(mWork[index].selection, selection);
629             assertEquals(mWork[index].selectionArgs, selectionArgs);
630             return (Integer) mWork[index++].result;
631         }
632 
633         @Override
delete(Uri uri, String selection, String[] selectionArgs)634         public int delete(Uri uri, String selection, String[] selectionArgs) {
635             Log.d(TAG, "Provider delete index=" + index);
636             assertEquals(mWork[index].op, Operation.EVENT_ARG_DELETE);
637             assertEquals(mWork[index].uri, uri);
638             assertEquals(mWork[index].selection, selection);
639             assertEquals(mWork[index].selectionArgs, selectionArgs);
640             return (Integer) mWork[index++].result;
641         }
642 
643         @Override
applyBatch(ArrayList<ContentProviderOperation> operations)644         public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) {
645             Log.d(TAG, "Provider applyBatch index=" + index);
646             assertEquals(mWork[index].op, Operation.EVENT_ARG_BATCH);
647             assertEquals(mWork[index].cpo, operations);
648             return (ContentProviderResult[]) mWork[index++].result;
649         }
650 
651         @Override
getType(Uri uri)652         public String getType(Uri uri) {
653             return null;
654         }
655 
656         @Override
onCreate()657         public boolean onCreate() {
658             return false;
659         }
660     }
661 }
662