package mobisocial.musubi.sync; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Date; import java.util.List; import android.accounts.Account; import android.accounts.AccountManager; import android.content.ContentProviderResult; import android.content.ContentResolver; import android.content.ContentUris; import android.database.Cursor; import android.net.Uri; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.GroupMembership; import android.provider.ContactsContract.CommonDataKinds.Photo; import android.provider.ContactsContract.CommonDataKinds.StructuredName; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.RawContacts; import android.util.Log; import mobisocial.crypto.IBIdentity; import mobisocial.crypto.IBHashedIdentity.Authority; import mobisocial.musubi.model.MIdentity; import mobisocial.musubi.model.helpers.DatabaseFile; import mobisocial.musubi.model.helpers.IdentitiesManager; import mobisocial.musubi.syncadapter.MusubiProfile; import mobisocial.musubi.syncadapter.SyncAdapter; import mobisocial.musubi.util.Util; import mobisocial.test.TestBase; public class SyncAdapterTest extends TestBase { private DelegatedMockContext mProviderContext; public static final String TAG = "SyncAdapterTest"; public static final String ACCOUNT_NAME = "Me"; public static final String ACCOUNT_TYPE = "edu.stanford.mobisocial"; @Override protected void setUp() throws Exception { super.setUp(); mProviderContext = new DelegatedMockContext(getContext()); this.setContext(mProviderContext); final Account account = new Account(ACCOUNT_NAME, ACCOUNT_TYPE); AccountManager am = AccountManager.get(getContext()); Account[] acs = am.getAccountsByType(ACCOUNT_TYPE); if(acs.length == 0) { am.addAccountExplicitly(account, "", null); ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true); ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1); } } @Override protected void tearDown() throws Exception { // final Uri uri = RawContacts.CONTENT_URI.buildUpon() // .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build(); // final String selection = RawContacts.ACCOUNT_TYPE + "='edu.stanford.mobisocial'"; // // final ContentResolver resolver = getContext().getContentResolver(); // final int c = resolver.delete(uri, selection, null); // Log.i(TAG, "deleted " + String.valueOf(c) + " contacts"); } public void testGetUpdates() throws InterruptedException { SyncAdapter syncAdapter = new SyncAdapter(getContext(), true, ACCOUNT_TYPE, ACCOUNT_NAME); long lastUpdatedTime = new Date().getTime()/1000; Thread.sleep(1000); insertTestIdentity(); List<MIdentity> updated = syncAdapter.getUpdatedContacts(lastUpdatedTime); assertEquals(1, updated.size()); updated = syncAdapter.getUpdatedContacts(Long.MAX_VALUE); assertEquals(0, updated.size()); } public void testSyncUpdates() throws InterruptedException { SyncAdapter syncAdapter = new SyncAdapter(getContext(), true, ACCOUNT_TYPE, ACCOUNT_NAME); final long[] groupIds = syncAdapter.createGroups(); // test insert long lastUpdatedTime = new Date().getTime()/1000; Thread.sleep(1000); MIdentity insertedId = insertTestIdentity(); List<MIdentity> updated = syncAdapter.getUpdatedContacts(lastUpdatedTime); ContentProviderResult[] results = syncAdapter.syncUpdatedContacts(updated, groupIds, lastUpdatedTime); MIdentity retrievedId = getRawContact(ContentUris.parseId(results[0].uri), groupIds); assertTrue(retrievedId != null); // assertEquals(retrievedId.principal_, insertedId.principal_); assertEquals(retrievedId.name_, insertedId.name_); assertTrue(retrievedId.thumbnail_ != null); assertTrue(retrievedId.androidAggregatedContactId_ != null); assertEquals(retrievedId.blocked_, false); assertEquals(retrievedId.claimed_, true); for(int i = 0; i < retrievedId.principalHash_.length; i++) { assertEquals(retrievedId.principalHash_[i], insertedId.principalHash_[i]); } // test update // List<MIdentity> ids = new ArrayList<MIdentity>(); // retrievedId.musubiThumbnail_ = ""; // ids.add(retrievedId); // syncAdapter.syncUpdatedContacts(ids, groupIds); // // MIdentity updatedId = getRawContact(retrievedId); // assertTrue(updatedId != null); // assertEquals(retrievedId.principal_, updatedId.principal_); // assertEquals(retrievedId.name_, updatedId.name_); // assertTrue(updatedId.androidDataId_ != null); // // test delete // retrievedId.blocked_ = true; // syncAdapter.syncUpdatedContacts(ids); // MIdentity deletedId = getRawContact(retrievedId); // assertTrue(deletedId == null); } public void testInsertGroups() { SyncAdapter syncAdapter = new SyncAdapter(getContext(), true, ACCOUNT_TYPE, ACCOUNT_NAME); long[] groupIds = syncAdapter.createGroups(); assertTrue(groupIds[0] != 0 && groupIds[1] != 0); long[] newGroupIds = syncAdapter.createGroups(); assertEquals(groupIds[0], newGroupIds[0]); assertEquals(groupIds[1], newGroupIds[1]); } private MIdentity insertTestIdentity() { DatabaseFile dbh = new DatabaseFile(getContext()); IdentitiesManager idm = new IdentitiesManager(dbh); IBIdentity ibid0 = randomIBIdentity(); MIdentity id0 = new MIdentity(); id0.name_ = ibid0.principal_.substring(0, ibid0.principal_.length()-10); id0.type_ = ibid0.authority_; id0.principal_ = ibid0.principal_; id0.principalHash_ = ibid0.hashed_; id0.principalShortHash_ = Util.shortHash(id0.principalHash_); id0.owned_ = true; id0.claimed_ = true; id0.blocked_ = false; idm.insertIdentity(id0); return id0; } private MIdentity getRawContact(long rawId, long[] groupIds) { final Uri qUri = Data.CONTENT_URI; final String qSelection = Data.RAW_CONTACT_ID + "=?"; final String[] qProjection = new String[] {MusubiProfile.DATA_PID, Photo.PHOTO, StructuredName.DISPLAY_NAME, Data.RAW_CONTACT_ID, Data.MIMETYPE, GroupMembership.GROUP_ROW_ID, CommonDataKinds.Identity.IDENTITY }; final int COLUMN_ID = 0; final int COLUMN_PHOTO = 1; final int COLUMN_NAME = 2; final int COLUMN_RAW_ID = 3; final int COLUMN_MIME = 4; final int COLUMN_GROUP_ID = 5; final int COLUMN_PRINCIPAL_HASH = 6; long id = -1; long groupId = -1; byte[] photo = null; byte[] principalHash = null; String name = null; boolean isFound = false; final ContentResolver resolver = getContext().getContentResolver(); final Cursor c = resolver.query(qUri, qProjection, qSelection, new String[] {String.valueOf(rawId)} , null); try { while (c.moveToNext()) { String mime = c.getString(COLUMN_MIME); if(mime.equals(MusubiProfile.MIME_PROFILE)) { isFound = true; id = c.getLong(COLUMN_ID); } else if(mime.equals(Photo.CONTENT_ITEM_TYPE)) { photo = new byte[1]; } else if(mime.equals(StructuredName.CONTENT_ITEM_TYPE)) { name = c.getString(COLUMN_NAME); } else if(mime.equals(GroupMembership.CONTENT_ITEM_TYPE)) { groupId = c.getLong(COLUMN_GROUP_ID); } else if(mime.equals(CommonDataKinds.Identity.CONTENT_ITEM_TYPE)) { principalHash = c.getBlob(COLUMN_PRINCIPAL_HASH); } } // while } finally { c.close(); } MIdentity mId = null; if(isFound) { IBIdentity ibd = new IBIdentity(Authority.Email, "noemail", 0); mId = new MIdentity(); mId.id_ = id; mId.androidAggregatedContactId_ = rawId; mId.name_ = name; mId.type_ = ibd.authority_; mId.principal_ = ibd.principal_; mId.principalHash_ = principalHash; mId.principalShortHash_ = ByteBuffer.wrap(ibd.hashed_).getLong(); mId.thumbnail_ = photo; if(groupId == groupIds[SyncAdapter.CLAIMED_GROUP_ID]) { mId.claimed_ = true; mId.blocked_ = false; } else if(groupId == groupIds[SyncAdapter.WHITELIST_GROUP_ID]) { mId.claimed_ = false; mId.blocked_ = false; } } return mId; } }