Home | History | Annotate | Download | only in calendar
      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 
     79     public AsyncQueryServiceTest() {
     80         super(AsyncQueryServiceHelper.class);
     81     }
     82 
     83     @Override
     84     protected void setUp() throws Exception {
     85         super.setUp();
     86     }
     87 
     88     private class MockContext2 extends MockContext {
     89         @Override
     90         public Resources getResources() {
     91             return getContext().getResources();
     92         }
     93 
     94         @Override
     95         public File getDir(String name, int mode) {
     96             return getContext().getDir("mockcontext2_+" + name, mode);
     97         }
     98 
     99         @Override
    100         public Context getApplicationContext() {
    101             return this;
    102         }
    103     }
    104 
    105     @Smoke
    106     @SmallTest
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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 
    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 
    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 
    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
    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 
    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
    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
    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
    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
    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
    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 
    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 
    596         public TestProvider(OperationInfo[] work) {
    597             mWork = work;
    598         }
    599 
    600         @Override
    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
    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
    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
    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
    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
    652         public String getType(Uri uri) {
    653             return null;
    654         }
    655 
    656         @Override
    657         public boolean onCreate() {
    658             return false;
    659         }
    660     }
    661 }
    662