Fix GroupsDaoIntegrationTests on API 21

Track Uris created by tests for cleanup instead of creating a test account.

Change-Id: I5415368cfd2c20fb3b4d5d99bc5e8d86675f3a80
diff --git a/tests/src/com/android/contacts/GroupsDaoIntegrationTests.java b/tests/src/com/android/contacts/GroupsDaoIntegrationTests.java
index d2e4283..f6925ad 100644
--- a/tests/src/com/android/contacts/GroupsDaoIntegrationTests.java
+++ b/tests/src/com/android/contacts/GroupsDaoIntegrationTests.java
@@ -16,15 +16,16 @@
 
 package com.android.contacts;
 
-import android.accounts.Account;
-import android.accounts.AccountManager;
+import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.OperationApplicationException;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.provider.ContactsContract.Data;
@@ -32,24 +33,23 @@
 
 import com.android.contacts.common.model.account.AccountWithDataSet;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Tests of GroupsDaoImpl that perform DB operations directly against CP2
  */
 public class GroupsDaoIntegrationTests extends InstrumentationTestCase {
 
-    private Account mAccount;
-    private ContentResolver cr;
+    private ContentResolver mResolver;
+    private List<Uri> mTestRecords;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
-        mAccount = new Account(getClass().getSimpleName() + "_t" +
-                System.currentTimeMillis(), "com.android.contacts.tests.authtest.basic");
-        AccountManager accountManager = (AccountManager) getContext()
-                .getSystemService(Context.ACCOUNT_SERVICE);
-        accountManager.addAccountExplicitly(mAccount, null, null);
-        cr = getContext().getContentResolver();
+        mTestRecords = new ArrayList<>();
+        mResolver = getContext().getContentResolver();
     }
 
     @Override
@@ -57,63 +57,50 @@
         super.tearDown();
 
         // Cleanup anything leftover by the tests.
-        // the ACCOUNT_NAME should be unique because it contains a timestamp
-        final Uri groupsUri = ContactsContract.Groups.CONTENT_URI.buildUpon()
-                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
-        final Uri rawContactsUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon()
-                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build();
-        getContext().getContentResolver().delete(groupsUri,
-                ContactsContract.Groups.ACCOUNT_NAME + "=?", new String[] { mAccount.name });
-        getContext().getContentResolver().delete(rawContactsUri,
-                ContactsContract.RawContacts.ACCOUNT_NAME + "=?", new String[] { mAccount.name });
-
-        if (mAccount != null) {
-            AccountManager accountManager = (AccountManager) getContext()
-                    .getSystemService(Context.ACCOUNT_SERVICE);
-            accountManager.removeAccountExplicitly(mAccount);
-            mAccount = null;
-        }
+        cleanupTestRecords();
+        mTestRecords.clear();
     }
 
     public void test_createGroup_createsGroupWithCorrectTitle() throws Exception {
-        ContactSaveService.GroupsDaoImpl sut = createDao();
-        Uri uri = sut.create("Test Create Group", getTestAccount());
+        final ContactSaveService.GroupsDao sut = createDao();
+        final Uri uri = sut.create("Test Create Group", getLocalAccount());
 
         assertNotNull(uri);
         assertGroupHasTitle(uri, "Test Create Group");
     }
 
     public void test_deleteEmptyGroup_marksRowDeleted() throws Exception {
-        ContactSaveService.GroupsDaoImpl sut = createDao();
-        Uri uri = sut.create("Test Delete Group", getTestAccount());
+        final ContactSaveService.GroupsDao sut = createDao();
+        final Uri uri = sut.create("Test Delete Group", getLocalAccount());
 
         assertEquals(1, sut.delete(uri));
 
-        Cursor cursor = cr.query(uri, null, null, null, null, null);
+        final Cursor cursor = mResolver.query(uri, null, null, null, null, null);
         try {
             cursor.moveToFirst();
-            assertEquals(1, cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Groups.DELETED)));
+            assertEquals(1, cursor.getInt(cursor.getColumnIndexOrThrow(
+                    ContactsContract.Groups.DELETED)));
         } finally {
             cursor.close();
         }
     }
 
     public void test_undoDeleteEmptyGroup_createsGroupWithMatchingTitle() throws Exception {
-        ContactSaveService.GroupsDaoImpl sut = createDao();
-        Uri uri = sut.create("Test Undo Delete Empty Group", getTestAccount());
+        final ContactSaveService.GroupsDao sut = createDao();
+        final Uri uri = sut.create("Test Undo Delete Empty Group", getLocalAccount());
 
-        Bundle undoData = sut.captureDeletionUndoData(uri);
+        final Bundle undoData = sut.captureDeletionUndoData(uri);
 
         assertEquals(1, sut.delete(uri));
 
-        Uri groupUri = sut.undoDeletion(undoData);
+        final Uri groupUri = sut.undoDeletion(undoData);
 
         assertGroupHasTitle(groupUri, "Test Undo Delete Empty Group");
     }
 
     public void test_deleteNonEmptyGroup_removesGroupAndMembers() throws Exception {
-        final ContactSaveService.GroupsDaoImpl sut = createDao();
-        final Uri groupUri = sut.create("Test delete non-empty group", getTestAccount());
+        final ContactSaveService.GroupsDao sut = createDao();
+        final Uri groupUri = sut.create("Test delete non-empty group", getLocalAccount());
 
         final long groupId = ContentUris.parseId(groupUri);
         addMemberToGroup(ContentUris.parseId(createRawContact()), groupId);
@@ -121,7 +108,7 @@
 
         assertEquals(1, sut.delete(groupUri));
 
-        final Cursor cursor = cr.query(Data.CONTENT_URI, null,
+        final Cursor cursor = mResolver.query(Data.CONTENT_URI, null,
                 Data.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?",
                 new String[] { GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(groupId) },
                 null, null);
@@ -138,14 +125,14 @@
     }
 
     public void test_undoDeleteNonEmptyGroup_restoresGroupAndMembers() throws Exception {
-        final ContactSaveService.GroupsDaoImpl sut = createDao();
-        final Uri groupUri = sut.create("Test undo delete non-empty group", getTestAccount());
+        final ContactSaveService.GroupsDao sut = createDao();
+        final Uri groupUri = sut.create("Test undo delete non-empty group", getLocalAccount());
 
         final long groupId = ContentUris.parseId(groupUri);
         addMemberToGroup(ContentUris.parseId(createRawContact()), groupId);
         addMemberToGroup(ContentUris.parseId(createRawContact()), groupId);
 
-        Bundle undoData = sut.captureDeletionUndoData(groupUri);
+        final Bundle undoData = sut.captureDeletionUndoData(groupUri);
 
         sut.delete(groupUri);
 
@@ -153,7 +140,7 @@
 
         final long newGroupId = ContentUris.parseId(recreatedGroup);
 
-        final Cursor cursor = cr.query(Data.CONTENT_URI, null,
+        final Cursor cursor = mResolver.query(Data.CONTENT_URI, null,
                 Data.MIMETYPE + "=? AND " + GroupMembership.GROUP_ROW_ID + "=?",
                 new String[] { GroupMembership.CONTENT_ITEM_TYPE, String.valueOf(newGroupId) },
                 null, null);
@@ -166,56 +153,45 @@
     }
 
     public void test_captureUndoDataForDeletedGroup_returnsEmptyBundle() {
-        final ContactSaveService.GroupsDaoImpl sut = createDao();
+        final ContactSaveService.GroupsDao sut = createDao();
 
-        Uri uri = sut.create("a deleted group", getTestAccount());
+        final Uri uri = sut.create("a deleted group", getLocalAccount());
         sut.delete(uri);
 
-        Bundle undoData = sut.captureDeletionUndoData(uri);
+        final Bundle undoData = sut.captureDeletionUndoData(uri);
 
         assertTrue(undoData.isEmpty());
     }
 
     public void test_captureUndoDataForNonExistentGroup_returnsEmptyBundle() {
-        final ContactSaveService.GroupsDaoImpl sut = createDao();
+        final ContactSaveService.GroupsDao sut = createDao();
 
         // This test could potentially be flaky if this ID exists for some reason. 10 is subtracted
         // to reduce the likelihood of this happening; some other test may use Integer.MAX_VALUE
         // or nearby values  to cover some special case or boundary condition.
         final long nonExistentId = Integer.MAX_VALUE - 10;
 
-        Bundle undoData = sut.captureDeletionUndoData(ContentUris
+        final Bundle undoData = sut.captureDeletionUndoData(ContentUris
                 .withAppendedId(ContactsContract.Groups.CONTENT_URI, nonExistentId));
 
         assertTrue(undoData.isEmpty());
     }
 
     public void test_undoWithEmptyBundle_doesNothing() {
-        final ContactSaveService.GroupsDaoImpl sut = createDao();
+        final ContactSaveService.GroupsDao sut = createDao();
 
-        Cursor cursor = queryGroupsForTestAccount();
-        try {
-            assertEquals(0, cursor.getCount());
-        } finally {
-            cursor.close();
-        }
+        final Uri uri = sut.undoDeletion(new Bundle());
 
-        sut.undoDeletion(new Bundle());
-
-        cursor = queryGroupsForTestAccount();
-        try {
-            assertEquals(0, cursor.getCount());
-        } finally {
-            cursor.close();
-        }
+        assertNull(uri);
     }
 
     public void test_undoDeleteEmptyGroupWithMissingMembersKey_shouldRecreateGroup() {
-        final ContactSaveService.GroupsDaoImpl sut = createDao();
-        final Uri groupUri = sut.create("Test undo delete null memberIds", getTestAccount());
+        final ContactSaveService.GroupsDao sut = createDao();
+        final Uri groupUri = sut.create("Test undo delete null memberIds", getLocalAccount());
 
-        Bundle undoData = sut.captureDeletionUndoData(groupUri);
+        final Bundle undoData = sut.captureDeletionUndoData(groupUri);
         undoData.remove(ContactSaveService.GroupsDaoImpl.KEY_GROUP_MEMBERS);
+        sut.delete(groupUri);
 
         sut.undoDeletion(undoData);
 
@@ -223,7 +199,8 @@
     }
 
     private void assertGroupHasTitle(Uri groupUri, String title) {
-        final Cursor cursor = cr.query(groupUri, new String[] { ContactsContract.Groups.TITLE },
+        final Cursor cursor = mResolver.query(groupUri,
+                new String[] { ContactsContract.Groups.TITLE },
                 ContactsContract.Groups.DELETED + "=?",
                 new String[] { "0" }, null, null);
         try {
@@ -236,11 +213,10 @@
     }
 
     private void assertGroupWithTitleExists(String title) {
-        final Cursor cursor = cr.query(ContactsContract.Groups.CONTENT_URI, null,
+        final Cursor cursor = mResolver.query(ContactsContract.Groups.CONTENT_URI, null,
                 ContactsContract.Groups.TITLE + "=? AND " +
-                        ContactsContract.Groups.DELETED + "=? AND " +
-                        ContactsContract.Groups.ACCOUNT_NAME + "=?",
-                new String[] { title, "0", mAccount.name }, null, null);
+                        ContactsContract.Groups.DELETED + "=?",
+                new String[] { title, "0" }, null, null);
         try {
             assertTrue("No group exists with title \"" + title + "\"", cursor.getCount() > 0);
         } finally {
@@ -248,36 +224,81 @@
         }
     }
 
-    private Cursor queryGroupsForTestAccount() {
-        return cr.query(ContactsContract.Groups.CONTENT_URI, null,
-                ContactsContract.Groups.ACCOUNT_NAME + "=?", new String[] { mAccount.name }, null);
-    }
-
-    public ContactSaveService.GroupsDaoImpl createDao() {
-        return new ContactSaveService.GroupsDaoImpl(getContext());
+    public ContactSaveService.GroupsDao createDao() {
+        return new GroupsDaoWrapper(new ContactSaveService.GroupsDaoImpl(getContext()));
     }
 
     private Uri createRawContact() {
-        ContentValues values = new ContentValues();
-        values.put(ContactsContract.RawContacts.ACCOUNT_NAME, mAccount.name);
-        values.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type);
-        return cr.insert(ContactsContract.RawContacts.CONTENT_URI, values);
+        final ContentValues values = new ContentValues();
+        values.putNull(ContactsContract.RawContacts.ACCOUNT_NAME);
+        values.putNull(ContactsContract.RawContacts.ACCOUNT_TYPE);
+        final Uri result = mResolver.insert(ContactsContract.RawContacts.CONTENT_URI, values);
+        mTestRecords.add(result);
+        return result;
     }
 
     private Uri addMemberToGroup(long rawContactId, long groupId) {
-        ContentValues values = new ContentValues();
+        final ContentValues values = new ContentValues();
         values.put(Data.RAW_CONTACT_ID, rawContactId);
         values.put(Data.MIMETYPE,
                 GroupMembership.CONTENT_ITEM_TYPE);
         values.put(GroupMembership.GROUP_ROW_ID, groupId);
-        return cr.insert(Data.CONTENT_URI, values);
-    }
 
-    private AccountWithDataSet getTestAccount() {
-        return new AccountWithDataSet(mAccount.name, mAccount.type, null);
+        // Dont' need to add to testRecords because it will be cleaned up when parent raw_contact
+        // is deleted.
+        return mResolver.insert(Data.CONTENT_URI, values);
     }
 
     private Context getContext() {
         return getInstrumentation().getTargetContext();
     }
+
+    private AccountWithDataSet getLocalAccount() {
+        return new AccountWithDataSet(null, null, null);
+    }
+
+    private void cleanupTestRecords() throws RemoteException, OperationApplicationException {
+        final ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+        for (Uri uri : mTestRecords) {
+            if (uri == null) continue;
+            ops.add(ContentProviderOperation
+                    .newDelete(uri.buildUpon()
+                            .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+                            .build())
+                    .build());
+        }
+        mResolver.applyBatch(ContactsContract.AUTHORITY, ops);
+    }
+
+    private class GroupsDaoWrapper implements ContactSaveService.GroupsDao {
+        private final ContactSaveService.GroupsDao mDelegate;
+
+        public GroupsDaoWrapper(ContactSaveService.GroupsDao delegate) {
+            mDelegate = delegate;
+        }
+
+        @Override
+        public Uri create(String title, AccountWithDataSet account) {
+            final Uri result = mDelegate.create(title, account);
+            mTestRecords.add(result);
+            return result;
+        }
+
+        @Override
+        public int delete(Uri groupUri) {
+            return mDelegate.delete(groupUri);
+        }
+
+        @Override
+        public Bundle captureDeletionUndoData(Uri groupUri) {
+            return mDelegate.captureDeletionUndoData(groupUri);
+        }
+
+        @Override
+        public Uri undoDeletion(Bundle undoData) {
+            final Uri result = mDelegate.undoDeletion(undoData);
+            mTestRecords.add(result);
+            return result;
+        }
+    }
 }