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