/tests/src/com/android/email/provider/ContentCacheTests.java
Java | 299 lines | 185 code | 32 blank | 82 comment | 1 complexity | 164e83f9b5c3dfde7bba635e5402f82d MD5 | raw file
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.android.email.provider;
- import com.android.email.provider.ContentCache.CacheToken;
- import com.android.email.provider.ContentCache.CachedCursor;
- import com.android.email.provider.ContentCache.TokenList;
- import com.android.emailcommon.provider.Account;
- import com.android.emailcommon.provider.EmailContent;
- import com.android.emailcommon.provider.Mailbox;
- import android.content.ContentResolver;
- import android.content.ContentUris;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.CursorWrapper;
- import android.database.MatrixCursor;
- import android.net.Uri;
- import android.test.ProviderTestCase2;
- /**
- * Tests of ContentCache
- *
- * You can run this entire test case with:
- * runtest -c com.android.email.provider.ContentCacheTests email
- */
- public class ContentCacheTests extends ProviderTestCase2<EmailProvider> {
- EmailProvider mProvider;
- Context mMockContext;
- public ContentCacheTests() {
- super(EmailProvider.class, EmailContent.AUTHORITY);
- }
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mMockContext = getMockContext();
- }
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- }
- public void testCounterMap() {
- ContentCache.CounterMap<String> map = new ContentCache.CounterMap<String>(4);
- // Make sure we can find added items
- map.add("1");
- assertTrue(map.contains("1"));
- map.add("2");
- map.add("2");
- // Make sure we can remove once for each add
- map.subtract("2");
- assertTrue(map.contains("2"));
- map.subtract("2");
- // Make sure that over-removing throws an exception
- try {
- map.subtract("2");
- fail("Removing a third time should throw an exception");
- } catch (IllegalStateException e) {
- }
- try {
- map.subtract("3");
- fail("Removing object never added should throw an exception");
- } catch (IllegalStateException e) {
- }
- // There should only be one item in the map ("1")
- assertEquals(1, map.size());
- assertTrue(map.contains("1"));
- }
- public void testTokenList() {
- TokenList list = new TokenList("Name");
- // Add two tokens for "1"
- CacheToken token1a = list.add("1");
- assertTrue(token1a.isValid());
- assertEquals("1", token1a.getId());
- assertEquals(1, list.size());
- CacheToken token1b = list.add("1");
- assertTrue(token1b.isValid());
- assertEquals("1", token1b.getId());
- assertTrue(token1a.equals(token1b));
- assertEquals(2, list.size());
- // Add a token for "2"
- CacheToken token2 = list.add("2");
- assertFalse(token1a.equals(token2));
- assertEquals(3, list.size());
- // Invalidate "1"; there should be two tokens invalidated
- assertEquals(2, list.invalidateTokens("1"));
- assertFalse(token1a.isValid());
- assertFalse(token1b.isValid());
- // Token2 should still be valid
- assertTrue(token2.isValid());
- // Only token2 should be in the list now (invalidation removes tokens)
- assertEquals(1, list.size());
- assertEquals(token2, list.get(0));
- // Add 3 tokens for "3"
- CacheToken token3a = list.add("3");
- CacheToken token3b = list.add("3");
- CacheToken token3c = list.add("3");
- // Remove two of them
- assertTrue(list.remove(token3a));
- assertTrue(list.remove(token3b));
- // Removing tokens doesn't invalidate them
- assertTrue(token3a.isValid());
- assertTrue(token3b.isValid());
- assertTrue(token3c.isValid());
- // There should be two items left "3" and "2"
- assertEquals(2, list.size());
- }
- public void testCachedCursors() {
- final ContentResolver resolver = mMockContext.getContentResolver();
- final Context context = mMockContext;
- // Create account and two mailboxes
- Account acct = ProviderTestUtils.setupAccount("account", true, context);
- ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
- Mailbox box = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context);
- // We need to test with a query that only returns one row (others can't be put in a
- // CachedCursor)
- Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box.mId);
- Cursor cursor =
- resolver.query(uri, Mailbox.CONTENT_PROJECTION, null, null, null);
- // ContentResolver gives us back a wrapper
- assertTrue(cursor instanceof CursorWrapper);
- // The wrappedCursor should be a CachedCursor
- Cursor wrappedCursor = ((CursorWrapper)cursor).getWrappedCursor();
- assertTrue(wrappedCursor instanceof CachedCursor);
- CachedCursor cachedCursor = (CachedCursor)wrappedCursor;
- // The cursor wrapped in cachedCursor is the underlying cursor
- Cursor activeCursor = cachedCursor.getWrappedCursor();
- // The cursor should be in active cursors
- int activeCount = ContentCache.sActiveCursors.getCount(activeCursor);
- assertEquals(1, activeCount);
- // Some basic functionality that shouldn't throw exceptions and should otherwise act as the
- // underlying cursor would
- String[] columnNames = cursor.getColumnNames();
- assertEquals(Mailbox.CONTENT_PROJECTION.length, columnNames.length);
- for (int i = 0; i < Mailbox.CONTENT_PROJECTION.length; i++) {
- assertEquals(Mailbox.CONTENT_PROJECTION[i], columnNames[i]);
- }
- assertEquals(1, cursor.getCount());
- cursor.moveToNext();
- assertEquals(0, cursor.getPosition());
- cursor.moveToPosition(0);
- assertEquals(0, cursor.getPosition());
- assertFalse(cursor.moveToPosition(1));
- cursor.close();
- // We've closed the cached cursor; make sure
- assertTrue(cachedCursor.isClosed());
- // The underlying cursor shouldn't be closed because it's in a cache (we'll test
- // that in testContentCache)
- assertFalse(activeCursor.isClosed());
- // Our cursor should no longer be in the active cursors map
- assertFalse(ContentCache.sActiveCursors.contains(activeCursor));
- // TODO - change the code or the test to enforce the assertion that a cached cursor
- // should have only zero or one rows. We cannot test this in the constructor, however,
- // due to potential for deadlock.
- // // Make sure that we won't accept cursors with multiple rows
- // cursor = resolver.query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, null, null, null);
- // try {
- // cursor = new CachedCursor(cursor, null, "Foo");
- // fail("Mustn't accept cursor with more than one row");
- // } catch (IllegalArgumentException e) {
- // // Correct
- // }
- }
- private static final String[] SIMPLE_PROJECTION = new String[] {"Foo"};
- private static final Object[] SIMPLE_ROW = new Object[] {"Bar"};
- private Cursor getOneRowCursor() {
- MatrixCursor cursor = new MatrixCursor(SIMPLE_PROJECTION, 1);
- cursor.addRow(SIMPLE_ROW);
- return cursor;
- }
- public void testContentCacheRemoveEldestEntry() {
- // Create a cache of size 2
- ContentCache cache = new ContentCache("Name", SIMPLE_PROJECTION, 2);
- // Random cursor; what's in it doesn't matter
- Cursor cursor1 = getOneRowCursor();
- // Get a token for arbitrary object named "1"
- CacheToken token = cache.getCacheToken("1");
- // Put the cursor in the cache
- cache.putCursor(cursor1, "1", SIMPLE_PROJECTION, token);
- assertEquals(1, cache.size());
- // Add another random cursor; what's in it doesn't matter
- Cursor cursor2 = getOneRowCursor();
- // Get a token for arbitrary object named "2"
- token = cache.getCacheToken("2");
- // Put the cursor in the cache
- cache.putCursor(cursor1, "2", SIMPLE_PROJECTION, token);
- assertEquals(2, cache.size());
- // We should be able to find both now in the cache
- Cursor cachedCursor = cache.getCachedCursor("1", SIMPLE_PROJECTION);
- assertNotNull(cachedCursor);
- assertTrue(cachedCursor instanceof CachedCursor);
- cachedCursor = cache.getCachedCursor("2", SIMPLE_PROJECTION);
- assertNotNull(cachedCursor);
- assertTrue(cachedCursor instanceof CachedCursor);
- // Both cursors should be open
- assertFalse(cursor1.isClosed());
- assertFalse(cursor2.isClosed());
- // Add another random cursor; what's in it doesn't matter
- Cursor cursor3 = getOneRowCursor();
- // Get a token for arbitrary object named "3"
- token = cache.getCacheToken("3");
- // Put the cursor in the cache
- cache.putCursor(cursor1, "3", SIMPLE_PROJECTION, token);
- // We should never have more than 2 entries in the cache
- assertEquals(2, cache.size());
- // The first cursor we added should no longer be in the cache (it's the eldest)
- cachedCursor = cache.getCachedCursor("1", SIMPLE_PROJECTION);
- assertNull(cachedCursor);
- // The cursors for 2 and 3 should be cached
- cachedCursor = cache.getCachedCursor("2", SIMPLE_PROJECTION);
- assertNotNull(cachedCursor);
- assertTrue(cachedCursor instanceof CachedCursor);
- cachedCursor = cache.getCachedCursor("3", SIMPLE_PROJECTION);
- assertNotNull(cachedCursor);
- assertTrue(cachedCursor instanceof CachedCursor);
- // Even cursor1 should be open, since all cached cursors are in mActiveCursors until closed
- assertFalse(cursor1.isClosed());
- assertFalse(cursor2.isClosed());
- assertFalse(cursor3.isClosed());
- }
- public void testCloseCachedCursor() {
- // Create a cache of size 2
- ContentCache cache = new ContentCache("Name", SIMPLE_PROJECTION, 2);
- // Random cursor; what's in it doesn't matter
- Cursor underlyingCursor = getOneRowCursor();
- Cursor cachedCursor1 = new CachedCursor(underlyingCursor, cache, "1");
- Cursor cachedCursor2 = new CachedCursor(underlyingCursor, cache, "1");
- assertEquals(2, ContentCache.sActiveCursors.getCount(underlyingCursor));
- cachedCursor1.close();
- assertTrue(cachedCursor1.isClosed());
- // Underlying cursor should be open (still one cached cursor open)
- assertFalse(underlyingCursor.isClosed());
- cachedCursor2.close();
- assertTrue(cachedCursor2.isClosed());
- assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
- // Underlying cursor should be closed (no cached cursors open)
- assertTrue(underlyingCursor.isClosed());
- underlyingCursor = getOneRowCursor();
- cachedCursor1 = cache.putCursor(
- underlyingCursor, "2", SIMPLE_PROJECTION, cache.getCacheToken("2"));
- cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2");
- assertEquals(2, ContentCache.sActiveCursors.getCount(underlyingCursor));
- cachedCursor1.close();
- cachedCursor2.close();
- assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
- // Underlying cursor should still be open; it's in the cache
- assertFalse(underlyingCursor.isClosed());
- // Cache a new cursor
- cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2");
- assertEquals(1, ContentCache.sActiveCursors.getCount(underlyingCursor));
- // Remove "2" from the cache and close the cursor
- cache.invalidate();
- cachedCursor2.close();
- // The underlying cursor should now be closed (not in the cache and no cached cursors)
- assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
- assertTrue(underlyingCursor.isClosed());
- }
- }