Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d1de54e authored by Marcus Hagerott's avatar Marcus Hagerott
Browse files

Fix GroupsDaoIntegrationTests on API 21

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

Change-Id: I5415368cfd2c20fb3b4d5d99bc5e8d86675f3a80
parent d73db0fa
Loading
Loading
Loading
Loading
+108 −87
Original line number Diff line number Diff line
@@ -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 android.test.InstrumentationTestCase;

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 @@ public class GroupsDaoIntegrationTests extends InstrumentationTestCase {
        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 @@ public class GroupsDaoIntegrationTests extends InstrumentationTestCase {

        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 class GroupsDaoIntegrationTests extends InstrumentationTestCase {
    }

    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 @@ public class GroupsDaoIntegrationTests extends InstrumentationTestCase {

        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 class GroupsDaoIntegrationTests extends InstrumentationTestCase {
    }

    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();

        Cursor cursor = queryGroupsForTestAccount();
        try {
            assertEquals(0, cursor.getCount());
        } finally {
            cursor.close();
        }
        final ContactSaveService.GroupsDao sut = createDao();

        sut.undoDeletion(new Bundle());
        final Uri uri = 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 @@ public class GroupsDaoIntegrationTests extends InstrumentationTestCase {
    }

    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 @@ public class GroupsDaoIntegrationTests extends InstrumentationTestCase {
    }

    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 @@ public class GroupsDaoIntegrationTests extends InstrumentationTestCase {
        }
    }

    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;
        }
    }
}