1fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank/*
2fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * Copyright (C) 2010 The Android Open Source Project
3fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank *
4fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * Licensed under the Apache License, Version 2.0 (the "License");
5fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * you may not use this file except in compliance with the License.
6fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * You may obtain a copy of the License at
7fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank *
8fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank *      http://www.apache.org/licenses/LICENSE-2.0
9fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank *
10fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * Unless required by applicable law or agreed to in writing, software
11fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * distributed under the License is distributed on an "AS IS" BASIS,
12fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * See the License for the specific language governing permissions and
14fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * limitations under the License.
15fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank */
16fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
17fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankpackage com.android.email.provider;
18fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
19fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport com.android.email.provider.ContentCache.CacheToken;
20fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport com.android.email.provider.ContentCache.CachedCursor;
21fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport com.android.email.provider.ContentCache.TokenList;
22f5418f1f93b02e7fab9f15eb201800b65510998eMarc Blankimport com.android.emailcommon.provider.Account;
2331d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.provider.EmailContent;
2453ea83ebf91f820692e8fa8e781f5cc982dd94dbBen Komaloimport com.android.emailcommon.provider.Mailbox;
25fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
26fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.content.ContentResolver;
27fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.content.ContentUris;
28fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.content.Context;
29fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.database.Cursor;
30fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.database.CursorWrapper;
31fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.database.MatrixCursor;
32fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.net.Uri;
33fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankimport android.test.ProviderTestCase2;
34fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
35fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank/**
36fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * Tests of ContentCache
37fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank *
38fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank * You can run this entire test case with:
39fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank *   runtest -c com.android.email.provider.ContentCacheTests email
40fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank */
41fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blankpublic class ContentCacheTests extends ProviderTestCase2<EmailProvider> {
42fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
43fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    EmailProvider mProvider;
44fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    Context mMockContext;
45fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
46fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    public ContentCacheTests() {
4731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank        super(EmailProvider.class, EmailContent.AUTHORITY);
48fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
49fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
50fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    @Override
51fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    public void setUp() throws Exception {
52fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        super.setUp();
53fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        mMockContext = getMockContext();
54fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
55fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
56fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    @Override
57fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    public void tearDown() throws Exception {
58fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        super.tearDown();
59fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
60fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
61fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    public void testCounterMap() {
62fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        ContentCache.CounterMap<String> map = new ContentCache.CounterMap<String>(4);
63fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Make sure we can find added items
64fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        map.add("1");
65fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(map.contains("1"));
66fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        map.add("2");
67fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        map.add("2");
68fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Make sure we can remove once for each add
692199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        map.subtract("2");
70fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(map.contains("2"));
712199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        map.subtract("2");
72fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Make sure that over-removing throws an exception
73fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        try {
742199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler            map.subtract("2");
75fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank            fail("Removing a third time should throw an exception");
76fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        } catch (IllegalStateException e) {
77fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        }
78fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        try {
792199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler            map.subtract("3");
80fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank            fail("Removing object never added should throw an exception");
81fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        } catch (IllegalStateException e) {
82fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        }
83fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // There should only be one item in the map ("1")
84fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(1, map.size());
85fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(map.contains("1"));
86fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
87fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
88fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    public void testTokenList() {
89fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        TokenList list = new TokenList("Name");
90fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
91fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Add two tokens for "1"
92fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CacheToken token1a = list.add("1");
93fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(token1a.isValid());
94fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals("1", token1a.getId());
95fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(1, list.size());
96fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CacheToken token1b = list.add("1");
97fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(token1b.isValid());
98fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals("1", token1b.getId());
99fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(token1a.equals(token1b));
100fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(2, list.size());
101fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
102fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Add a token for "2"
103fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CacheToken token2 = list.add("2");
104fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(token1a.equals(token2));
105fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(3, list.size());
106fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
107fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Invalidate "1"; there should be two tokens invalidated
108fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(2, list.invalidateTokens("1"));
109fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(token1a.isValid());
110fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(token1b.isValid());
111fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Token2 should still be valid
112fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(token2.isValid());
113fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Only token2 should be in the list now (invalidation removes tokens)
114fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(1, list.size());
115fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(token2, list.get(0));
116fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
117fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Add 3 tokens for "3"
118fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CacheToken token3a = list.add("3");
119fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CacheToken token3b = list.add("3");
120fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CacheToken token3c = list.add("3");
121fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Remove two of them
122fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(list.remove(token3a));
123fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(list.remove(token3b));
124fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Removing tokens doesn't invalidate them
125fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(token3a.isValid());
126fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(token3b.isValid());
127fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(token3c.isValid());
128fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // There should be two items left "3" and "2"
129fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(2, list.size());
130fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
131fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
132fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    public void testCachedCursors() {
133fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        final ContentResolver resolver = mMockContext.getContentResolver();
134fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        final Context context = mMockContext;
135fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
136fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Create account and two mailboxes
137fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Account acct = ProviderTestUtils.setupAccount("account", true, context);
138fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
139fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Mailbox box = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context);
140fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
141fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // We need to test with a query that only returns one row (others can't be put in a
142fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // CachedCursor)
143fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box.mId);
144fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Cursor cursor =
145fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank            resolver.query(uri, Mailbox.CONTENT_PROJECTION, null, null, null);
146fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // ContentResolver gives us back a wrapper
147fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(cursor instanceof CursorWrapper);
148fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // The wrappedCursor should be a CachedCursor
149fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Cursor wrappedCursor = ((CursorWrapper)cursor).getWrappedCursor();
150fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(wrappedCursor instanceof CachedCursor);
151fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CachedCursor cachedCursor = (CachedCursor)wrappedCursor;
152fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // The cursor wrapped in cachedCursor is the underlying cursor
153fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Cursor activeCursor = cachedCursor.getWrappedCursor();
154fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
155fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // The cursor should be in active cursors
1562199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        int activeCount = ContentCache.sActiveCursors.getCount(activeCursor);
1572199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        assertEquals(1, activeCount);
158fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
159fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Some basic functionality that shouldn't throw exceptions and should otherwise act as the
160fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // underlying cursor would
161fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        String[] columnNames = cursor.getColumnNames();
162fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(Mailbox.CONTENT_PROJECTION.length, columnNames.length);
163fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        for (int i = 0; i < Mailbox.CONTENT_PROJECTION.length; i++) {
164fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank            assertEquals(Mailbox.CONTENT_PROJECTION[i], columnNames[i]);
165fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        }
166fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
167fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(1, cursor.getCount());
168fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cursor.moveToNext();
169fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(0, cursor.getPosition());
170fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cursor.moveToPosition(0);
171fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(0, cursor.getPosition());
17268dc380d62b29b4b6733bc1b20e44b8931c1d341Marc Blank        assertFalse(cursor.moveToPosition(1));
173fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
174fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cursor.close();
175fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // We've closed the cached cursor; make sure
176fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(cachedCursor.isClosed());
177fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // The underlying cursor shouldn't be closed because it's in a cache (we'll test
178fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // that in testContentCache)
179fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(activeCursor.isClosed());
180fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Our cursor should no longer be in the active cursors map
1812199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        assertFalse(ContentCache.sActiveCursors.contains(activeCursor));
1822199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler
1832199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        // TODO - change the code or the test to enforce the assertion that a cached cursor
1842199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        // should have only zero or one rows.  We cannot test this in the constructor, however,
1852199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler        // due to potential for deadlock.
1862199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//        // Make sure that we won't accept cursors with multiple rows
1872199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//        cursor = resolver.query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, null, null, null);
1882199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//        try {
1892199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//            cursor = new CachedCursor(cursor, null, "Foo");
1902199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//            fail("Mustn't accept cursor with more than one row");
1912199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//        } catch (IllegalArgumentException e) {
1922199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//            // Correct
1932199c7ddf5d497e816bef1a1b7473098369a1bdfAndy Stadler//        }
194fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
195fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
196fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    private static final String[] SIMPLE_PROJECTION = new String[] {"Foo"};
197fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    private static final Object[] SIMPLE_ROW = new Object[] {"Bar"};
198fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    private Cursor getOneRowCursor() {
199fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        MatrixCursor cursor = new MatrixCursor(SIMPLE_PROJECTION, 1);
200fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cursor.addRow(SIMPLE_ROW);
201fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        return cursor;
202fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
203fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
204fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    public void testContentCacheRemoveEldestEntry() {
205fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Create a cache of size 2
206fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        ContentCache cache = new ContentCache("Name", SIMPLE_PROJECTION, 2);
207fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Random cursor; what's in it doesn't matter
208fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Cursor cursor1 = getOneRowCursor();
209fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Get a token for arbitrary object named "1"
210fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        CacheToken token = cache.getCacheToken("1");
211fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Put the cursor in the cache
212fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cache.putCursor(cursor1, "1", SIMPLE_PROJECTION, token);
213fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(1, cache.size());
214fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
215fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Add another random cursor; what's in it doesn't matter
216fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Cursor cursor2 = getOneRowCursor();
217fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Get a token for arbitrary object named "2"
218fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        token = cache.getCacheToken("2");
219fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Put the cursor in the cache
220fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cache.putCursor(cursor1, "2", SIMPLE_PROJECTION, token);
221fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(2, cache.size());
222fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
223fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // We should be able to find both now in the cache
224fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Cursor cachedCursor = cache.getCachedCursor("1", SIMPLE_PROJECTION);
225fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertNotNull(cachedCursor);
226fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(cachedCursor instanceof CachedCursor);
227fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cachedCursor = cache.getCachedCursor("2", SIMPLE_PROJECTION);
228fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertNotNull(cachedCursor);
229fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(cachedCursor instanceof CachedCursor);
230fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
231fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Both cursors should be open
232fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(cursor1.isClosed());
233fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(cursor2.isClosed());
234fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
235fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Add another random cursor; what's in it doesn't matter
236fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        Cursor cursor3 = getOneRowCursor();
237fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Get a token for arbitrary object named "3"
238fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        token = cache.getCacheToken("3");
239fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Put the cursor in the cache
240fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cache.putCursor(cursor1, "3", SIMPLE_PROJECTION, token);
241fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // We should never have more than 2 entries in the cache
242fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertEquals(2, cache.size());
243fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
244fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // The first cursor we added should no longer be in the cache (it's the eldest)
245fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cachedCursor = cache.getCachedCursor("1", SIMPLE_PROJECTION);
246fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertNull(cachedCursor);
247fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // The cursors for 2 and 3 should be cached
248fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cachedCursor = cache.getCachedCursor("2", SIMPLE_PROJECTION);
249fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertNotNull(cachedCursor);
250fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(cachedCursor instanceof CachedCursor);
251fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        cachedCursor = cache.getCachedCursor("3", SIMPLE_PROJECTION);
252fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertNotNull(cachedCursor);
253fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertTrue(cachedCursor instanceof CachedCursor);
254fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank
255fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        // Even cursor1 should be open, since all cached cursors are in mActiveCursors until closed
256fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(cursor1.isClosed());
257fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(cursor2.isClosed());
258fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank        assertFalse(cursor3.isClosed());
259fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank    }
2603aee641aab491a3da53364aafb9074ae69dd2212Jesse Wilson
261c159d32be05ee744f3726579d9cd8eed39545137Marc Blank    public void testCloseCachedCursor() {
262c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // Create a cache of size 2
263c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        ContentCache cache = new ContentCache("Name", SIMPLE_PROJECTION, 2);
264c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // Random cursor; what's in it doesn't matter
265c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        Cursor underlyingCursor = getOneRowCursor();
266c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        Cursor cachedCursor1 = new CachedCursor(underlyingCursor, cache, "1");
267c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        Cursor cachedCursor2 = new CachedCursor(underlyingCursor, cache, "1");
268c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertEquals(2, ContentCache.sActiveCursors.getCount(underlyingCursor));
269c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        cachedCursor1.close();
270c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertTrue(cachedCursor1.isClosed());
271c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // Underlying cursor should be open (still one cached cursor open)
272c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertFalse(underlyingCursor.isClosed());
273c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        cachedCursor2.close();
274c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertTrue(cachedCursor2.isClosed());
275c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
276c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // Underlying cursor should be closed (no cached cursors open)
277c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertTrue(underlyingCursor.isClosed());
2783aee641aab491a3da53364aafb9074ae69dd2212Jesse Wilson
279c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        underlyingCursor = getOneRowCursor();
2803aee641aab491a3da53364aafb9074ae69dd2212Jesse Wilson        cachedCursor1 = cache.putCursor(
2813aee641aab491a3da53364aafb9074ae69dd2212Jesse Wilson                underlyingCursor, "2", SIMPLE_PROJECTION, cache.getCacheToken("2"));
282c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2");
283c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertEquals(2, ContentCache.sActiveCursors.getCount(underlyingCursor));
284c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        cachedCursor1.close();
285c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        cachedCursor2.close();
286c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
287c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // Underlying cursor should still be open; it's in the cache
288c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertFalse(underlyingCursor.isClosed());
289c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // Cache a new cursor
290c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2");
291c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertEquals(1, ContentCache.sActiveCursors.getCount(underlyingCursor));
292c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // Remove "2" from the cache and close the cursor
2933aee641aab491a3da53364aafb9074ae69dd2212Jesse Wilson        cache.invalidate();
294c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        cachedCursor2.close();
295c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        // The underlying cursor should now be closed (not in the cache and no cached cursors)
296c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
297c159d32be05ee744f3726579d9cd8eed39545137Marc Blank        assertTrue(underlyingCursor.isClosed());
298c159d32be05ee744f3726579d9cd8eed39545137Marc Blank    }
299fab77f147f85766d2f75d8aece0aaa4ffb3838e8Marc Blank}
300