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