pimprotocols/phonebooksync/Test/TE_cntsync/te_cntsyncview.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 10:12:17 +0200
changeset 0 e686773b3f54
permissions -rw-r--r--
Revision: 201003 Kit: 201005

// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Tests that PhBkSync adds contacts from USIM address books to the contacts database,
// and that they appear correctly in the Contacts Model local view.
// 
//

#include <e32test.h>
#include "te_cntsyncbase.h"
#include "te_cntsyncview.h"
#include <cntview.h>

// Values for User::After()
const TInt	K1SecondWait(1000000);
const TInt	K5SecondWait(5*K1SecondWait);
const TInt	K20SecondWait(20*K1SecondWait);

// Test config numbers...
const TInt  KNormalSIMTestConfig(0);
const TInt  KLockedSIMTestConfig(8);

// Number of contacts on SIM cards
const TInt	KNumContactsNormalSIM(5);
const TInt	KNumContactsLockedSIM(25);

class TViewCleanup
	{
	public:
		TViewCleanup(CContactLocalView* aLocalView, CContactViewEventWait* aViewWaitEvent)
			{
			iLocalView = aLocalView;
			iViewWaitEvent = aViewWaitEvent;
			}
		CContactViewEventWait* iViewWaitEvent;
		CContactLocalView* iLocalView;
	};

static void ViewCleanup(TAny* aPointer)
	{
	TViewCleanup* cleanup = static_cast<TViewCleanup*> (aPointer);
	CContactLocalView* iLocalView = cleanup->iLocalView;
	CContactViewEventWait* iViewWaitEvent = cleanup->iViewWaitEvent;
	iLocalView->Close(*iViewWaitEvent);
	delete iViewWaitEvent;
	}

/** 
 * Factory construction method.
 * @return Pointer to CPhbkViewICCSyncTest object
 */
CPhbkViewICCSyncTest* CPhbkViewICCSyncTest::NewL()
	{
	CPhbkViewICCSyncTest* self = new(ELeave) CPhbkViewICCSyncTest();
	return self;
	}

/**
 *  Default constructor.  Each test step initialises it's own name.
 */
CPhbkViewICCSyncTest::CPhbkViewICCSyncTest()
	{
	SetTestStepName(_L("ViewICCSyncTest"));
	}

/**
 * Synchronisation of normal, unlocked, ICC.  Creates a Contacts View
 * with ICC entries only.
 */
enum TVerdict CPhbkViewICCSyncTest::doTestStepL()
	{
	SetSimTsyTestNumberL(0);
	DoSyncL();
	
	// all View tests use Manual Sync mode
	User::LeaveIfError(iSession.SetSyncMode(RPhoneBookSession::EManual)); // Set mode to manual to avoid getting KErrInUse
	CheckSyncModeL(RPhoneBookSession::EManual);
	
	// ICC unlocked
	SetSimTsyTestNumberL(KNormalSIMTestConfig);
	CleanupClosePushL(iViewSortOrder);

	// A sort order (only Family Name is present in ADN phonebooks)
    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
    iViewSortOrder.AppendL(KUidContactFieldGivenName);
    iViewSortOrder.AppendL(KUidContactFieldCompanyName);

	// Helper class that gives timed wait for View events
	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
	CleanupStack::PushL(viewEventWait);

	// View with just ICC entries
	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesOnly);

	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
	TViewCleanup cleanup(iIccView, viewEventWait);
	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));

	INFO_PRINTF1(_L("  Manual Sync"));
	// do manual synchronisation
	DoSyncL();
	WaitForSyncToCompleteL();

	// let view catch up, waits 2s
	INFO_PRINTF1(_L("  Wait for ICC view to become ready"));
	// Wait 30s for View Event: EReady or ESortOrderChanged only
	TBool eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
	// check that event was received
	TESTCHECKCONDITIONL(eventReceived);
	TESTCHECKL(iEvent.iEventType, TContactViewEvent::EReady);

	INFO_PRINTF1(_L("  Check all PhoneBook entries are in view"));
	TInt count = iIccView->CountL();
	if (count != KNumContactsNormalSIM)
		{
		INFO_PRINTF3(_L("  Expecting %d entries in View but found %d:"),
			KNumContactsNormalSIM, count);
		DumpICCViewL();
		}
	TESTCHECK(count, KNumContactsNormalSIM);

	User::After(K5SecondWait);
	CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder

	return TestStepResult();
	}
	
	
/** 
 * Factory construction method.
 * @return Pointer to CPhbkViewICCLockedICCTest object
 */
CPhbkViewICCLockedICCTest* CPhbkViewICCLockedICCTest::NewL()
	{
	CPhbkViewICCLockedICCTest* self = new(ELeave) CPhbkViewICCLockedICCTest();
	return self;
	}

/**
 *  Default constructor.  Each test step initialises it's own name.
 */
CPhbkViewICCLockedICCTest::CPhbkViewICCLockedICCTest()
	{
	SetTestStepName(_L("ViewICCLockedICCTest"));
	}

/**
 * Synchronisation when ICC is locked.  Creates a Contacts View of ICC entries
 * only.
 *
 * Synchroniser is initially unable to perform synchronisation because ICC is locked. The
 * Local View class recognises that the ICC is locked, and creates an empty View.
 *
 * When ICC becomes unlocked the synchronisation completes successfully. The Contacts Local 
 * View sees this, and re-sorts itself making the ICC entries appear in the View.
 */
enum TVerdict CPhbkViewICCLockedICCTest::doTestStepL()
	{
	// ICC locked, so initial Synchronisation is not carried out 
	SetSimTsyTestNumberL(KLockedSIMTestConfig);
	CleanupClosePushL(iViewSortOrder);
	// A sort order (only Family Name is present in ADN phonebooks)
    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
    iViewSortOrder.AppendL(KUidContactFieldGivenName);
    iViewSortOrder.AppendL(KUidContactFieldCompanyName);

	// Helper class that gives timed wait for View events
	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
	CleanupStack::PushL(viewEventWait);

	// View with just ICC entries
	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesOnly);
	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
	TViewCleanup cleanup(iIccView, viewEventWait);
	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));

	INFO_PRINTF1(_L("  Initial Sync Failure"));
	// check that ICC is locked
	TRAPD(err, DoSyncFailL());
	if(err == KErrGeneral)
		{
		INFO_PRINTF1(_L("The view has already been created before we attempt to sync, so sync won't fail. We should finsh test here"));
		SetTestStepResult(EPass);
		CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
		return TestStepResult(); 
		}
	TESTCHECKL(err, KErrNone);
	User::After(K1SecondWait);

	RPhoneBookSession::TSyncState state;
	iSession.GetPhoneBookCacheState(state);

	TESTCHECKL(state, RPhoneBookSession::EErrorDuringSync); // Cache not in valid state 

	iSession.GetLastSyncError(err);
	TESTCHECKL(err, KErrAccessDenied); // ICC locked

	// initially ready with no entries as ICC (SIM) card is not ready, waits 2s
	INFO_PRINTF1(_L("  Check View becomes ready with no entries"));
	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
	TBool eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
	// check that event was received
	TESTCHECKCONDITIONL(eventReceived);

	TESTCHECKL(iEvent.iEventType, TContactViewEvent::EReady);
	TESTCHECKL(iIccView->CountL(), 0); // view should be empty

	// wait for ICC to become unlocked
	INFO_PRINTF1(_L("  Start Sync when ICC becomes unlocked"));
	User::After(K20SecondWait); // ICC should become unlocked now 
	DoSyncL();
	WaitForSyncToCompleteL();

	// let the view catch up, waits 2s
	INFO_PRINTF1(_L("  Wait for View to Re-Sort with ICC entries"));
	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
	eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
	// check that event was received
	TESTCHECKCONDITIONL(eventReceived);

	INFO_PRINTF1(_L("  Contacts View should be resorted"));
	TESTCHECKL(iEvent.iEventType, TContactViewEvent::ESortOrderChanged);

	INFO_PRINTF1(_L("  Check all PhoneBook entries are in view"));
	TInt count = iIccView->CountL();
	if (count != KNumContactsLockedSIM)
		{
		INFO_PRINTF3(_L("  Expecting %d entries in View but found %d:"),
			KNumContactsLockedSIM, count);
		DumpICCViewL();
		}
	TESTCHECK(count, KNumContactsLockedSIM);

	User::After(K5SecondWait);
	CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder

	return TestStepResult();
	}
	
	
/** 
 * Factory construction method.
 * @return Pointer to CPhbkViewICCLockedMixedTest object
 */
CPhbkViewICCLockedMixedTest* CPhbkViewICCLockedMixedTest::NewL()
	{
	CPhbkViewICCLockedMixedTest* self = new(ELeave) CPhbkViewICCLockedMixedTest();
	return self;
	}

/**
 *  Default constructor.  Each test step initialises it's own name.
 */
CPhbkViewICCLockedMixedTest::CPhbkViewICCLockedMixedTest()
	{
	SetTestStepName(_L("ViewICCLockedMixedTest"));
	}

/**
 * Synchronisation when ICC is locked.  Creates a Contacts View of Contacts
 * and ICC entries.  This is similar to the ICC entries only test, but timing
 * and behaviour of Contacts model is different.
 *
 * Synchroniser is initially unable to perform synchronisation because ICC is locked. The
 * Local View class recognises that the ICC is locked, and creates a View without ICC entries.
 *
 * When ICC becomes unlocked the synchronisation completes successfully. The Contacts Local 
 * View sees this, and re-sorts itself making the ICC entries appear in the View.
 */
enum TVerdict CPhbkViewICCLockedMixedTest::doTestStepL()
	{
	// ICC locked, so initial Synchronisation is not carried out
	SetSimTsyTestNumberL(KLockedSIMTestConfig);
	CleanupClosePushL(iViewSortOrder);

	// A sort order (only Family Name is present in ADN phonebooks)
    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
    iViewSortOrder.AppendL(KUidContactFieldGivenName);
    iViewSortOrder.AppendL(KUidContactFieldCompanyName);

	// Helper class that gives timed wait for View events
	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
	CleanupStack::PushL(viewEventWait);

	// View with ICC entries and contacts
	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesAndContacts);
	
	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
	TViewCleanup cleanup(iIccView, viewEventWait);
	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));

	INFO_PRINTF1(_L("  Initial Sync Failure"));
	// check that ICC is locked
	TRAPD(err, DoSyncFailL());
	if(err == KErrGeneral)
		{
		INFO_PRINTF1(_L("The view has already been created before we attempt to sync, so sync won't fail. We should finsh test here"));		
		SetTestStepResult(EPass);
		CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
		return TestStepResult(); 
		}
	TESTCHECKL(err, KErrNone);
	User::After(K1SecondWait);

	RPhoneBookSession::TSyncState state;
	iSession.GetPhoneBookCacheState(state);

	TESTCHECKL(state, RPhoneBookSession::EErrorDuringSync); // Cache not in valid state 

	iSession.GetLastSyncError(err);
	TESTCHECKL(err, KErrAccessDenied); // ICC locked

	// initially ready with no entries as ICC (SIM) card is not ready, waits 2s
	INFO_PRINTF1(_L("  Check View becomes ready without ICC entries"));
	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
	TBool eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
	// check that event was received
	TESTCHECKCONDITIONL(eventReceived);

	TESTCHECKL(iEvent.iEventType, TContactViewEvent::EReady);
	TESTCHECKL(iIccView->CountL(), 0); // view should be empty

	// wait for ICC to become unlocked
	INFO_PRINTF1(_L("  Start Sync when ICC becomes unlocked"));
	User::After(K20SecondWait); // ICC should become unlocked now 
	DoSyncL();
	WaitForSyncToCompleteL();

	// let the view catch up, waits 2s
	INFO_PRINTF1(_L("  Wait for View to Re-Sort with ICC entries"));
	// Wait 30seconds at max for View Event: EReady or ESortOrderChanged only
	eventReceived = viewEventWait->WaitForViewEvent(iIccView, 30, iEvent, EFalse);
	// check that event was received
	TESTCHECKCONDITIONL(eventReceived);

	INFO_PRINTF1(_L("  Contacts View should be resorted"));
	TESTCHECKL(iEvent.iEventType, TContactViewEvent::ESortOrderChanged);

	INFO_PRINTF1(_L("  Check all PhoneBook entries are in view"));
	TInt count = iIccView->CountL();
	if (count != KNumContactsLockedSIM)
		{
		INFO_PRINTF3(_L("  Expecting %d entries in View but found %d:"),
			KNumContactsLockedSIM, count);
		DumpICCViewL();
		}
	TESTCHECK(count, KNumContactsLockedSIM);

	User::After(K5SecondWait);
	CleanupStack::PopAndDestroy(2);//iIccView, viewEventWait and iViewSortOrder
	return TestStepResult();
	}


/**
 *  Synchronisation and create a view when just one phonebook exists. Previously
 *  a defect existed which would fail if no FDN phonebook was defined.
 */
enum TVerdict CPhbkViewICCSinglePhonebookTest::doTestStepL()
	{
	SetSimTsyTestNumberL(30);

	//
	// Setup a sort order (only Family Name is present in ADN phonebooks)
    //
	INFO_PRINTF1(_L("Setup a sort order (only Family Name is present in ADN phonebooks)"));
	CleanupClosePushL(iViewSortOrder);
    iViewSortOrder.AppendL(KUidContactFieldFamilyName);
    iViewSortOrder.AppendL(KUidContactFieldGivenName);
    iViewSortOrder.AppendL(KUidContactFieldCompanyName);
	
	//
    // Helper class that gives timed wait for View events
	//
	CContactViewEventWait *viewEventWait = CContactViewEventWait::NewL();
	CleanupStack::PushL(viewEventWait);

	//
	// Create a view with ICC entries and contacts
	//
	INFO_PRINTF1(_L("Create a view with ICC entries and contacts"));
	iIccView = CContactLocalView::NewL(*viewEventWait, *iDb, iViewSortOrder, EICCEntriesAndContacts);
	
	CleanupStack::Pop();//viewEventWait will be deleted with cleanup below
	TViewCleanup cleanup(iIccView, viewEventWait);
	CleanupStack::PushL(TCleanupItem(ViewCleanup, &cleanup));	

	//
	// Sync ADN phonebook...
	//
	INFO_PRINTF1(_L(" Sync ADN phonebook..."));
	TRequestStatus  status; 

	iSession.DoSynchronisation(status, KUidIccGlobalAdnPhonebook);
	User::WaitForRequest(status);
	TESTCHECKL(status.Int(), KErrNone);

	//
	// Close view and clean up...
	//
	INFO_PRINTF1(_L(" Close view and clean up..."));
	CleanupStack::PopAndDestroy(2);

	return TestStepResult();
	} // CPhbkViewICCSinglePhonebookTest::doTestStepL


void CPhbkSyncViewIntegrationTestBase::DumpICCViewL()
	{
	const TInt count = iIccView->CountL();

	if (count == 0)
		{
		INFO_PRINTF1(_L("  No contacts to list."));
		return;
		}

	CContactItem* contact = NULL;
	TInt  index;

	for (index = 0;  index < count;  index++)
		{
		const CViewContact&  viewContact = iIccView->ContactAtL(index);
		const TInt  id = viewContact.Id();
		
		// get actual Contact from DB
		contact = iDb->ReadMinimalContactLC(id);

		// Get & print Contact's phone number
		CContactItemFieldSet& fieldset = contact->CardFields();
		// look for Phone Number field in record
		const TInt pos = fieldset.Find(KUidContactFieldPhoneNumber);	
		User::LeaveIfError(pos);	// field must be present
		CContactItemField& field = fieldset[pos];
		CContactTextField* textfield = field.TextStorage();

		TBuf<128>  outputString;
		outputString.AppendFormat(_L("    [%04i]  Id=%04i Name=\""), index+1, id);
		outputString.Append(viewContact.Field(0));
		outputString.AppendFormat(_L("\" Number=\""));
		outputString.Append(textfield->Text());
		outputString.AppendFormat(_L("\""));
		INFO_PRINTF1(outputString);

		CleanupStack::PopAndDestroy(contact);
		contact = NULL;
		}
	}

// support class implementation, timed wait for View Event; (based on CContactViewEventQueue)

CContactViewEventWait* CContactViewEventWait::NewL()
    {
    CContactViewEventWait* self = new(ELeave) CContactViewEventWait;
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }


CContactViewEventWait::~CContactViewEventWait()
    {
    CTimer::Cancel();
    if (iView) iView->Close(*this);
    }


/**
 *  Waits for an event from the database.
 *
 *  @param aView        Contact view to listen for events.
 *  @param aTimeOut     Max time to wait for an event.
 *  @param aEvent       The received event, undefined if this function returns false.
 *  @param aWaitForAny  ETrue if wait is for any event, EFalse for view ready events only
 *
 *  @return true if an event was received, false if timeout expired first.
 */
TBool CContactViewEventWait::WaitForViewEvent(CContactViewBase* aView,
											  TTimeIntervalSeconds aTimeOut, 
											  TContactViewEvent& aEvent, 
											  TBool aWaitForAny)
    {
	iView = aView;
	iWaitForAny = aWaitForAny;
	iTimedOut = EFalse;
    CTimer::After(aTimeOut.Int() * 1000000);

	// wait for timer to finish or desired View event
    CActiveScheduler::Start();

    if (!iTimedOut)
        {
        aEvent = iEvent;
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }


void CContactViewEventWait::RunL()
    {
    // Timer expired
	iTimedOut = ETrue;
    CActiveScheduler::Stop();
    }


void CContactViewEventWait::HandleContactViewEvent(const CContactViewBase& aView,
												   const TContactViewEvent& aEvent)
    {
	__ASSERT_ALWAYS(iView == &aView, User::Invariant());

	// either waiting for Any event, or Ready or Ready after Re-sort
	if(iWaitForAny || aEvent.iEventType == TContactViewEvent::EReady || 
			aEvent.iEventType == TContactViewEvent::ESortOrderChanged)
		{
		iEvent = aEvent;

	    CTimer::Cancel();
	    CActiveScheduler::Stop();
		}
    }


CContactViewEventWait::CContactViewEventWait()
    : CTimer(CActive::EPriorityStandard)
    {
    }


void CContactViewEventWait::ConstructL()
    {
    CTimer::ConstructL();
    CActiveScheduler::Add(this);
	iView = NULL;
    }