PageRenderTime 172ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/src/com/android/email/provider/ContentCacheTests.java

https://bitbucket.org/camcory/android_packages_apps_email
Java | 299 lines | 185 code | 32 blank | 82 comment | 1 complexity | 164e83f9b5c3dfde7bba635e5402f82d MD5 | raw file
  1. /*
  2. * Copyright (C) 2010 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. package com.android.email.provider;
  17. import com.android.email.provider.ContentCache.CacheToken;
  18. import com.android.email.provider.ContentCache.CachedCursor;
  19. import com.android.email.provider.ContentCache.TokenList;
  20. import com.android.emailcommon.provider.Account;
  21. import com.android.emailcommon.provider.EmailContent;
  22. import com.android.emailcommon.provider.Mailbox;
  23. import android.content.ContentResolver;
  24. import android.content.ContentUris;
  25. import android.content.Context;
  26. import android.database.Cursor;
  27. import android.database.CursorWrapper;
  28. import android.database.MatrixCursor;
  29. import android.net.Uri;
  30. import android.test.ProviderTestCase2;
  31. /**
  32. * Tests of ContentCache
  33. *
  34. * You can run this entire test case with:
  35. * runtest -c com.android.email.provider.ContentCacheTests email
  36. */
  37. public class ContentCacheTests extends ProviderTestCase2<EmailProvider> {
  38. EmailProvider mProvider;
  39. Context mMockContext;
  40. public ContentCacheTests() {
  41. super(EmailProvider.class, EmailContent.AUTHORITY);
  42. }
  43. @Override
  44. public void setUp() throws Exception {
  45. super.setUp();
  46. mMockContext = getMockContext();
  47. }
  48. @Override
  49. public void tearDown() throws Exception {
  50. super.tearDown();
  51. }
  52. public void testCounterMap() {
  53. ContentCache.CounterMap<String> map = new ContentCache.CounterMap<String>(4);
  54. // Make sure we can find added items
  55. map.add("1");
  56. assertTrue(map.contains("1"));
  57. map.add("2");
  58. map.add("2");
  59. // Make sure we can remove once for each add
  60. map.subtract("2");
  61. assertTrue(map.contains("2"));
  62. map.subtract("2");
  63. // Make sure that over-removing throws an exception
  64. try {
  65. map.subtract("2");
  66. fail("Removing a third time should throw an exception");
  67. } catch (IllegalStateException e) {
  68. }
  69. try {
  70. map.subtract("3");
  71. fail("Removing object never added should throw an exception");
  72. } catch (IllegalStateException e) {
  73. }
  74. // There should only be one item in the map ("1")
  75. assertEquals(1, map.size());
  76. assertTrue(map.contains("1"));
  77. }
  78. public void testTokenList() {
  79. TokenList list = new TokenList("Name");
  80. // Add two tokens for "1"
  81. CacheToken token1a = list.add("1");
  82. assertTrue(token1a.isValid());
  83. assertEquals("1", token1a.getId());
  84. assertEquals(1, list.size());
  85. CacheToken token1b = list.add("1");
  86. assertTrue(token1b.isValid());
  87. assertEquals("1", token1b.getId());
  88. assertTrue(token1a.equals(token1b));
  89. assertEquals(2, list.size());
  90. // Add a token for "2"
  91. CacheToken token2 = list.add("2");
  92. assertFalse(token1a.equals(token2));
  93. assertEquals(3, list.size());
  94. // Invalidate "1"; there should be two tokens invalidated
  95. assertEquals(2, list.invalidateTokens("1"));
  96. assertFalse(token1a.isValid());
  97. assertFalse(token1b.isValid());
  98. // Token2 should still be valid
  99. assertTrue(token2.isValid());
  100. // Only token2 should be in the list now (invalidation removes tokens)
  101. assertEquals(1, list.size());
  102. assertEquals(token2, list.get(0));
  103. // Add 3 tokens for "3"
  104. CacheToken token3a = list.add("3");
  105. CacheToken token3b = list.add("3");
  106. CacheToken token3c = list.add("3");
  107. // Remove two of them
  108. assertTrue(list.remove(token3a));
  109. assertTrue(list.remove(token3b));
  110. // Removing tokens doesn't invalidate them
  111. assertTrue(token3a.isValid());
  112. assertTrue(token3b.isValid());
  113. assertTrue(token3c.isValid());
  114. // There should be two items left "3" and "2"
  115. assertEquals(2, list.size());
  116. }
  117. public void testCachedCursors() {
  118. final ContentResolver resolver = mMockContext.getContentResolver();
  119. final Context context = mMockContext;
  120. // Create account and two mailboxes
  121. Account acct = ProviderTestUtils.setupAccount("account", true, context);
  122. ProviderTestUtils.setupMailbox("box1", acct.mId, true, context);
  123. Mailbox box = ProviderTestUtils.setupMailbox("box2", acct.mId, true, context);
  124. // We need to test with a query that only returns one row (others can't be put in a
  125. // CachedCursor)
  126. Uri uri = ContentUris.withAppendedId(Mailbox.CONTENT_URI, box.mId);
  127. Cursor cursor =
  128. resolver.query(uri, Mailbox.CONTENT_PROJECTION, null, null, null);
  129. // ContentResolver gives us back a wrapper
  130. assertTrue(cursor instanceof CursorWrapper);
  131. // The wrappedCursor should be a CachedCursor
  132. Cursor wrappedCursor = ((CursorWrapper)cursor).getWrappedCursor();
  133. assertTrue(wrappedCursor instanceof CachedCursor);
  134. CachedCursor cachedCursor = (CachedCursor)wrappedCursor;
  135. // The cursor wrapped in cachedCursor is the underlying cursor
  136. Cursor activeCursor = cachedCursor.getWrappedCursor();
  137. // The cursor should be in active cursors
  138. int activeCount = ContentCache.sActiveCursors.getCount(activeCursor);
  139. assertEquals(1, activeCount);
  140. // Some basic functionality that shouldn't throw exceptions and should otherwise act as the
  141. // underlying cursor would
  142. String[] columnNames = cursor.getColumnNames();
  143. assertEquals(Mailbox.CONTENT_PROJECTION.length, columnNames.length);
  144. for (int i = 0; i < Mailbox.CONTENT_PROJECTION.length; i++) {
  145. assertEquals(Mailbox.CONTENT_PROJECTION[i], columnNames[i]);
  146. }
  147. assertEquals(1, cursor.getCount());
  148. cursor.moveToNext();
  149. assertEquals(0, cursor.getPosition());
  150. cursor.moveToPosition(0);
  151. assertEquals(0, cursor.getPosition());
  152. assertFalse(cursor.moveToPosition(1));
  153. cursor.close();
  154. // We've closed the cached cursor; make sure
  155. assertTrue(cachedCursor.isClosed());
  156. // The underlying cursor shouldn't be closed because it's in a cache (we'll test
  157. // that in testContentCache)
  158. assertFalse(activeCursor.isClosed());
  159. // Our cursor should no longer be in the active cursors map
  160. assertFalse(ContentCache.sActiveCursors.contains(activeCursor));
  161. // TODO - change the code or the test to enforce the assertion that a cached cursor
  162. // should have only zero or one rows. We cannot test this in the constructor, however,
  163. // due to potential for deadlock.
  164. // // Make sure that we won't accept cursors with multiple rows
  165. // cursor = resolver.query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, null, null, null);
  166. // try {
  167. // cursor = new CachedCursor(cursor, null, "Foo");
  168. // fail("Mustn't accept cursor with more than one row");
  169. // } catch (IllegalArgumentException e) {
  170. // // Correct
  171. // }
  172. }
  173. private static final String[] SIMPLE_PROJECTION = new String[] {"Foo"};
  174. private static final Object[] SIMPLE_ROW = new Object[] {"Bar"};
  175. private Cursor getOneRowCursor() {
  176. MatrixCursor cursor = new MatrixCursor(SIMPLE_PROJECTION, 1);
  177. cursor.addRow(SIMPLE_ROW);
  178. return cursor;
  179. }
  180. public void testContentCacheRemoveEldestEntry() {
  181. // Create a cache of size 2
  182. ContentCache cache = new ContentCache("Name", SIMPLE_PROJECTION, 2);
  183. // Random cursor; what's in it doesn't matter
  184. Cursor cursor1 = getOneRowCursor();
  185. // Get a token for arbitrary object named "1"
  186. CacheToken token = cache.getCacheToken("1");
  187. // Put the cursor in the cache
  188. cache.putCursor(cursor1, "1", SIMPLE_PROJECTION, token);
  189. assertEquals(1, cache.size());
  190. // Add another random cursor; what's in it doesn't matter
  191. Cursor cursor2 = getOneRowCursor();
  192. // Get a token for arbitrary object named "2"
  193. token = cache.getCacheToken("2");
  194. // Put the cursor in the cache
  195. cache.putCursor(cursor1, "2", SIMPLE_PROJECTION, token);
  196. assertEquals(2, cache.size());
  197. // We should be able to find both now in the cache
  198. Cursor cachedCursor = cache.getCachedCursor("1", SIMPLE_PROJECTION);
  199. assertNotNull(cachedCursor);
  200. assertTrue(cachedCursor instanceof CachedCursor);
  201. cachedCursor = cache.getCachedCursor("2", SIMPLE_PROJECTION);
  202. assertNotNull(cachedCursor);
  203. assertTrue(cachedCursor instanceof CachedCursor);
  204. // Both cursors should be open
  205. assertFalse(cursor1.isClosed());
  206. assertFalse(cursor2.isClosed());
  207. // Add another random cursor; what's in it doesn't matter
  208. Cursor cursor3 = getOneRowCursor();
  209. // Get a token for arbitrary object named "3"
  210. token = cache.getCacheToken("3");
  211. // Put the cursor in the cache
  212. cache.putCursor(cursor1, "3", SIMPLE_PROJECTION, token);
  213. // We should never have more than 2 entries in the cache
  214. assertEquals(2, cache.size());
  215. // The first cursor we added should no longer be in the cache (it's the eldest)
  216. cachedCursor = cache.getCachedCursor("1", SIMPLE_PROJECTION);
  217. assertNull(cachedCursor);
  218. // The cursors for 2 and 3 should be cached
  219. cachedCursor = cache.getCachedCursor("2", SIMPLE_PROJECTION);
  220. assertNotNull(cachedCursor);
  221. assertTrue(cachedCursor instanceof CachedCursor);
  222. cachedCursor = cache.getCachedCursor("3", SIMPLE_PROJECTION);
  223. assertNotNull(cachedCursor);
  224. assertTrue(cachedCursor instanceof CachedCursor);
  225. // Even cursor1 should be open, since all cached cursors are in mActiveCursors until closed
  226. assertFalse(cursor1.isClosed());
  227. assertFalse(cursor2.isClosed());
  228. assertFalse(cursor3.isClosed());
  229. }
  230. public void testCloseCachedCursor() {
  231. // Create a cache of size 2
  232. ContentCache cache = new ContentCache("Name", SIMPLE_PROJECTION, 2);
  233. // Random cursor; what's in it doesn't matter
  234. Cursor underlyingCursor = getOneRowCursor();
  235. Cursor cachedCursor1 = new CachedCursor(underlyingCursor, cache, "1");
  236. Cursor cachedCursor2 = new CachedCursor(underlyingCursor, cache, "1");
  237. assertEquals(2, ContentCache.sActiveCursors.getCount(underlyingCursor));
  238. cachedCursor1.close();
  239. assertTrue(cachedCursor1.isClosed());
  240. // Underlying cursor should be open (still one cached cursor open)
  241. assertFalse(underlyingCursor.isClosed());
  242. cachedCursor2.close();
  243. assertTrue(cachedCursor2.isClosed());
  244. assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
  245. // Underlying cursor should be closed (no cached cursors open)
  246. assertTrue(underlyingCursor.isClosed());
  247. underlyingCursor = getOneRowCursor();
  248. cachedCursor1 = cache.putCursor(
  249. underlyingCursor, "2", SIMPLE_PROJECTION, cache.getCacheToken("2"));
  250. cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2");
  251. assertEquals(2, ContentCache.sActiveCursors.getCount(underlyingCursor));
  252. cachedCursor1.close();
  253. cachedCursor2.close();
  254. assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
  255. // Underlying cursor should still be open; it's in the cache
  256. assertFalse(underlyingCursor.isClosed());
  257. // Cache a new cursor
  258. cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2");
  259. assertEquals(1, ContentCache.sActiveCursors.getCount(underlyingCursor));
  260. // Remove "2" from the cache and close the cursor
  261. cache.invalidate();
  262. cachedCursor2.close();
  263. // The underlying cursor should now be closed (not in the cache and no cached cursors)
  264. assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));
  265. assertTrue(underlyingCursor.isClosed());
  266. }
  267. }