/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at
* src/com/vodafone360/people/VODAFONE.LICENSE.txt or
* http://github.com/360/360-Engine-for-Android
* See the License for the specific language governing permissions and
* limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each file and
* include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the fields
* enclosed by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2010 Vodafone Sales & Services Ltd. All rights reserved.
* Use is subject to license terms.
*/
package com.vodafone360.people.tests.engine.contactsync;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import junit.framework.TestCase;
import android.test.suitebuilder.annotation.Suppress;
import com.vodafone360.people.database.DatabaseHelper;
import com.vodafone360.people.engine.contactsync.ContactChange;
import com.vodafone360.people.engine.contactsync.NativeExporter;
import com.vodafone360.people.engine.contactsync.NativeContactsApi.Account;
import com.vodafone360.people.tests.engine.contactsync.NativeImporterTest.NativeContactsApiMockup;
import com.vodafone360.people.utils.VersionUtils;
public class NativeExporterTest extends TestCase {
/**
* Tests multiple exports to native with only new contacts.
*/
@Suppress
public void testMultipleExportsToNativeWithNewContacts() {
final int NEW_CONTACTS_COUNT = 30;
final NativeContactsApiMockup nativeMockup = new NativeContactsApiMockup();
final PeopleContactsApiMockup peopleMockup = new PeopleContactsApiMockup(null);
// add new contacts syncable contact on People side
feedPeopleContactsApiWithNewSyncableContacts(peopleMockup, NEW_CONTACTS_COUNT);
long[] nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(null, nativeIdsFromPeople); // shall be null because our PeopleContactsApiMockup will add them once synced
long[] localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(NEW_CONTACTS_COUNT, localIds.length);
long[] nativeIds = nativeMockup.getContactIds(null);
assertEquals(null, nativeIds);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are updated correctly
nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(NEW_CONTACTS_COUNT, nativeIdsFromPeople.length);
nativeIds = nativeMockup.getContactIds(null);
assertEquals(NEW_CONTACTS_COUNT, nativeIds.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
}
/**
* Tests multiple exports to native with deleted contacts.
*/
@Suppress
public void testMultipleExportsToNativeWithDeletedContacts() {
// add contacts on People side and sync them to native side
final int NEW_CONTACTS_COUNT = 30;
final NativeContactsApiMockup nativeMockup = new NativeContactsApiMockup();
final PeopleContactsApiMockup peopleMockup = new PeopleContactsApiMockup(null);
// add new contacts syncable contact on People side
feedPeopleContactsApiWithNewSyncableContacts(peopleMockup, NEW_CONTACTS_COUNT);
long[] nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(null, nativeIdsFromPeople); // shall be null because our PeopleContactsApiMockup will add them once synced
long[] localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(NEW_CONTACTS_COUNT, localIds.length);
long[] nativeIds = nativeMockup.getContactIds(null);
assertEquals(null, nativeIds);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are updated correctly
nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(NEW_CONTACTS_COUNT, nativeIdsFromPeople.length);
nativeIds = nativeMockup.getContactIds(null);
assertEquals(NEW_CONTACTS_COUNT, nativeIds.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
// delete half of contacts on People side
peopleMockup.setSyncableDeletedContact(1);
peopleMockup.setSyncableDeletedContact(2);
peopleMockup.setSyncableDeletedContact(5);
peopleMockup.setSyncableDeletedContact(8);
peopleMockup.setSyncableDeletedContact(9);
peopleMockup.setSyncableDeletedContact(13);
peopleMockup.setSyncableDeletedContact(18);
peopleMockup.setSyncableDeletedContact(19);
peopleMockup.setSyncableDeletedContact(22);
peopleMockup.setSyncableDeletedContact(23);
peopleMockup.setSyncableDeletedContact(24);
peopleMockup.setSyncableDeletedContact(25);
peopleMockup.setSyncableDeletedContact(26);
peopleMockup.setSyncableDeletedContact(28);
peopleMockup.setSyncableDeletedContact(30);
nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(NEW_CONTACTS_COUNT/2, nativeIdsFromPeople.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(NEW_CONTACTS_COUNT/2, localIds.length);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are updated correctly
nativeIds = nativeMockup.getContactIds(null);
assertEquals(NEW_CONTACTS_COUNT/2, nativeIds.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
}
/**
* Tests export to native with added details to a existing contacts.
*/
@Suppress
public void testExportToNativeWithUpdatedContacts_addedDetails() {
// add contacts on People side and sync them to native side
final int NEW_CONTACTS_COUNT = 30;
final NativeContactsApiMockup nativeMockup = new NativeContactsApiMockup();
final PeopleContactsApiMockup peopleMockup = new PeopleContactsApiMockup(null);
// add new contacts syncable contact on People side
feedPeopleContactsApiWithNewSyncableContacts(peopleMockup, NEW_CONTACTS_COUNT);
long[] nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(null, nativeIdsFromPeople); // shall be null because our PeopleContactsApiMockup will add them once synced
long[] localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(NEW_CONTACTS_COUNT, localIds.length);
long[] nativeIds = nativeMockup.getContactIds(null);
assertEquals(null, nativeIds);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are updated correctly
nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(NEW_CONTACTS_COUNT, nativeIdsFromPeople.length);
nativeIds = nativeMockup.getContactIds(null);
assertEquals(NEW_CONTACTS_COUNT, nativeIds.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
// pick few contacts and add details to them
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 1));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 2));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 5));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 10));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 12));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 18));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 19));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 21));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 23));
peopleMockup.updateNativeContact(getNewDetails(peopleMockup, 24));
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are equivalent
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
}
/**
* Tests export to native with updated details to existing contacts.
*/
@Suppress
public void testExportToNativeWithUpdatedContacts_updatedDetails() {
// add contacts on People side and sync them to native side
final int NEW_CONTACTS_COUNT = 30;
final NativeContactsApiMockup nativeMockup = new NativeContactsApiMockup();
final PeopleContactsApiMockup peopleMockup = new PeopleContactsApiMockup(null);
// add new contacts syncable contact on People side
feedPeopleContactsApiWithNewSyncableContacts(peopleMockup, NEW_CONTACTS_COUNT);
long[] nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(null, nativeIdsFromPeople); // shall be null because our PeopleContactsApiMockup will add them once synced
long[] localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(NEW_CONTACTS_COUNT, localIds.length);
long[] nativeIds = nativeMockup.getContactIds(null);
assertEquals(null, nativeIds);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are updated correctly
nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(NEW_CONTACTS_COUNT, nativeIdsFromPeople.length);
nativeIds = nativeMockup.getContactIds(null);
assertEquals(NEW_CONTACTS_COUNT, nativeIds.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
// pick contacts and modify all their details
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 1));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 2));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 5));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 10));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 12));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 18));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 19));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 21));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 23));
peopleMockup.updateNativeContact(getUpdatedDetails(peopleMockup, 24));
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are equivalent
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
}
/**
* Tests export to native with added details to a existing contacts.
*/
@Suppress
public void testExportToNativeWithUpdatedContacts_deletedDetails() {
// add contacts on People side and sync them to native side
final int NEW_CONTACTS_COUNT = 30;
final NativeContactsApiMockup nativeMockup = new NativeContactsApiMockup();
final PeopleContactsApiMockup peopleMockup = new PeopleContactsApiMockup(null);
// add new contacts syncable contact on People side
feedPeopleContactsApiWithNewSyncableContacts(peopleMockup, NEW_CONTACTS_COUNT);
long[] nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(null, nativeIdsFromPeople); // shall be null because our PeopleContactsApiMockup will add them once synced
long[] localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(NEW_CONTACTS_COUNT, localIds.length);
long[] nativeIds = nativeMockup.getContactIds(null);
assertEquals(null, nativeIds);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are updated correctly
nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(NEW_CONTACTS_COUNT, nativeIdsFromPeople.length);
nativeIds = nativeMockup.getContactIds(null);
assertEquals(NEW_CONTACTS_COUNT, nativeIds.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
// pick few contacts and add details to them
ContactChange[][] addedDetails = new ContactChange[3][];
addedDetails[0] = getNewDetails(peopleMockup, 1);
peopleMockup.updateNativeContact(addedDetails[0]);
addedDetails[1] = getNewDetails(peopleMockup, 2);
peopleMockup.updateNativeContact(addedDetails[1]);
addedDetails[2] = getNewDetails(peopleMockup, 5);
peopleMockup.updateNativeContact(addedDetails[2]);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are equivalent
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
// remove the previously added details
for (int i = 0; i < addedDetails.length; i++) {
forceDetailsAsDeleteType(addedDetails[i]);
peopleMockup.updateNativeContact(addedDetails[i]);
}
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are equivalent
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
}
/**
* Tests that the export is performed on the correct account depending on the Android platform.
*/
public void testExportAccount() {
final int NEW_CONTACTS_COUNT = 30;
final NativeContactsApiMockup nativeMockup = new NativeContactsApiMockup();
final PeopleContactsApiMockup peopleMockup = new PeopleContactsApiMockup(null);
nativeMockup.feedAccount(NativeImporterTest.GMAIL_ACCOUNT_1);
nativeMockup.feedAccount(NativeImporterTest.GMAIL_ACCOUNT_2);
nativeMockup.feedAccount(NativeImporterTest.THIRD_PARTY_ACCOUNT);
nativeMockup.feedAccount(NativeImporterTest.PEOPLE_ACCOUNT);
// add new contacts syncable contact on People side
feedPeopleContactsApiWithNewSyncableContacts(peopleMockup, NEW_CONTACTS_COUNT);
long[] nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(null, nativeIdsFromPeople); // shall be null because our PeopleContactsApiMockup will add them once synced
long[] localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(NEW_CONTACTS_COUNT, localIds.length);
long[] nativeIds = nativeMockup.getContactIds(null);
assertEquals(null, nativeIds);
// perform the export to native
runNativeExporter(nativeMockup, peopleMockup);
// check both sides are updated correctly
nativeIdsFromPeople = peopleMockup.getNativeContactsIds();
assertEquals(NEW_CONTACTS_COUNT, nativeIdsFromPeople.length);
nativeIds = nativeMockup.getContactIds(null);
assertEquals(NEW_CONTACTS_COUNT, nativeIds.length);
localIds = peopleMockup.getNativeSyncableContactIds();
assertEquals(null, localIds);
if (VersionUtils.is2XPlatform()) {
// on Android 2.X, the contacts shall be present in the People Account
final Account[] accounts = { NativeImporterTest.PEOPLE_ACCOUNT };
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, accounts, peopleMockup));
} else {
// on Android 1.X, the contacts shall be present in the "null" account
assertTrue(NativeImporterTest.compareNativeAndPeopleContactsList(nativeMockup, null, peopleMockup));
}
}
/**
* Sets the ContactChange.TYPE_DELETE_DETAIL to all the provided ContactChange
* @param changes the array of ContactChange
*/
private void forceDetailsAsDeleteType(ContactChange[] changes) {
for (int i = 0; i < changes.length; i++) {
changes[0].setType(ContactChange.TYPE_DELETE_DETAIL);
}
}
/**
* Runs the NativeExporter until it finishes synchronizing.
*
* @param ncam the NativeContactsApiMockup instance
* @param pcam the PeopleContactsApiMockup instance
*/
private void runNativeExporter(NativeContactsApiMockup ncam, PeopleContactsApiMockup pcam) {
final NativeExporter nativeExporter = new NativeExporter(pcam, ncam);
// run the NativeExporter until the export to native is over
while (!nativeExporter.tick());
}
/**
* Gets an array for ContatChange updates for the provided Contact
* @param pcam the PeopleContactsApiMockup instance
* @param nativeContactId the contact native id
* @return an array for ContatChange updates
*/
private ContactChange[] getUpdatedDetails(PeopleContactsApiMockup pcam, long nativeContactId) {
final ContactChange[] contact = pcam.getContact(nativeContactId);
final ContactChange[] copy = new ContactChange[contact.length];
for (int i = 0; i < contact.length; i++) {
copy[i] = NativeImporterTest.alterContactChangeValue(contact[i], contact[i].getValue() + "x9x");
copy[i].setType(ContactChange.TYPE_UPDATE_DETAIL);
}
return copy;
}
/**
* Gets an array of ContatChange new details for the provided Contact
* @param pcam the PeopleContactsApiMockup instance
* @param nativeContactId the contact native id
* @return an array for ContatChange updates
*/
private ContactChange[] getNewDetails(PeopleContactsApiMockup pcam, long nativeContactId) {
final ContactChange[] contact = pcam.getContact(nativeContactId);
final long localContactId = contact[0].getInternalContactId();
final ContactChange[] addedDetails = new ContactChange[2];
int index = 0;
// add extra details
addedDetails[index] = new ContactChange(ContactChange.KEY_VCARD_EMAIL, "xxxxx@xxxxx.xx", ContactChange.FLAG_WORK);
addedDetails[index].setNabContactId(nativeContactId);
addedDetails[index].setInternalContactId(localContactId);
addedDetails[index].setType(ContactChange.TYPE_ADD_DETAIL);
index++;
addedDetails[index] = new ContactChange(ContactChange.KEY_VCARD_PHONE, "+9912345678", ContactChange.FLAG_WORK);
addedDetails[index].setNabContactId(nativeContactId);
addedDetails[index].setInternalContactId(localContactId);
addedDetails[index].setType(ContactChange.TYPE_ADD_DETAIL);
index++;
return addedDetails;
}
/**
* Feeds the PeopleContactApiMockup with new Contacts to sync.
* @param pcam the PeopleContactsApiMockup instance
* @param contactsCount the number of new contacts
*/
private void feedPeopleContactsApiWithNewSyncableContacts(PeopleContactsApiMockup pcam, int contactsCount) {
for (int i = 0; i < contactsCount; i++) {
final ContactChange[] contact = ContactChangeHelper.randomContact(ContactChange.INVALID_ID, ContactChange.INVALID_ID, ContactChange.INVALID_ID);
pcam.addSyncableContact(contact);
}
}
/**
* A specifically modified version of the PeopleContactsApiMockup for the NativeExporter tests.
*/
private static class PeopleContactsApiMockup extends com.vodafone360.people.tests.engine.contactsync.NativeImporterTest.PeopleContactsApiMockup {
/**
* Holds all the syncable changes.
*/
protected Hashtable<Long, ContactChange[]> mPeopleContactsToSync = new Hashtable<Long, ContactChange[]>();
public PeopleContactsApiMockup(DatabaseHelper dbh) {
super(dbh);
// TODO Auto-generated constructor stub
}
public void addSyncableContact(ContactChange[] contact) {
contact[0].setType(ContactChange.TYPE_ADD_CONTACT);
// set the local ids
for (int i = 0; i < contact.length; i++) {
contact[i].setInternalContactId(mLocalContactId);
contact[i].setInternalDetailId(mLocalDetailId++);
}
mLocalContactId++;
// add the contact to the hashtable of contacts to sync
mPeopleContactsToSync.put(contact[0].getInternalContactId(), contact);
}
/**
* Deletes a contact and adds it to the syncable hashtable
*
* @param nativeContactId
*/
public void setSyncableDeletedContact(long nativeContactId) {
ContactChange[] contact = mPeopleContacts.get(nativeContactId);
if (contact != null) {
mPeopleContacts.remove(nativeContactId);
final ContactChange[] change = { contact[0] };
change[0].setType(ContactChange.TYPE_DELETE_CONTACT);
mPeopleContactsToSync.put(change[0].getInternalContactId(), change);
}
}
@Override
public ContactChange[] getNativeSyncableContactChanges(long localId) {
// return a copy, the NativeExporter may mess with it
final ContactChange[] original = mPeopleContactsToSync.get(localId);
ContactChange[] copy = null;
copy = new ContactChange[original.length];
for (int i = 0; i < original.length; i++) {
copy[i] = NativeImporterTest.copyContactChange(original[i]);
}
return copy;
}
@Override
public long[] getNativeSyncableContactIds() {
if (mPeopleContactsToSync.size() > 0) {
final Enumeration<ContactChange[]> e = mPeopleContactsToSync.elements();
final long[] ids = new long[mPeopleContactsToSync.size()];
int idIndex = 0;
while (e.hasMoreElements()) {
final ContactChange[] contact = e.nextElement();
ids[idIndex++] = contact[0].getInternalContactId();
}
Arrays.sort(ids);
return ids;
} else {
return null;
}
}
@Override
public void updateNativeContact(ContactChange[] contact) {
super.updateNativeContact(contact);
// add the updates to the syncable hashtable
mPeopleContactsToSync.put(contact[0].getInternalContactId(), contact);
}
@Override
public boolean syncBackDeletedNativeContact(ContactChange deletedContact) {
mPeopleContactsToSync.remove(deletedContact.getInternalContactId());
return true;
}
@Override
public boolean syncBackNewNativeContact(ContactChange[] contact, ContactChange[] nativeIds) {
mPeopleContactsToSync.remove(contact[0].getInternalContactId());
// set the native ids
final long nativeContactId = nativeIds[0].getNabContactId();
for (int i = 0; i < contact.length; i++) {
contact[i].setNabContactId(nativeContactId);
contact[i].setNabDetailId(nativeIds[i+1] != null ? nativeIds[i+1].getNabDetailId() : nativeContactId);
}
mPeopleContacts.put(contact[0].getNabContactId(), contact);
return true;
}
@Override
public boolean syncBackUpdatedNativeContact(ContactChange[] contact, ContactChange[] nativeIds) {
mPeopleContactsToSync.remove(contact[0].getInternalContactId());
return true;
}
}
}