phonebookengines_old/contactsmodel/tsrc/t_cnt_backup.cpp
changeset 40 b46a585f6909
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines_old/contactsmodel/tsrc/t_cnt_backup.cpp	Fri Jun 11 13:29:23 2010 +0300
@@ -0,0 +1,2213 @@
+// Copyright (c) 2004-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:
+//
+
+#include <e32test.h>
+#include <f32file.h>
+#include <s32file.h>
+#include <cntdb.h>
+#include <cntitem.h>
+#include <cntfield.h>
+#include <cntfldst.h>
+#include <coreappstest/testserver.h>
+
+#include <connect/sbeclient.h>
+
+#include "T_UTILS.H"
+#include "t_utils2.h"
+#include "t_cnt_backup.h"
+
+
+// cleanup version of test macro
+LOCAL_C void TestCondition(TBool aCondition, TInt aLineNumber);
+#define TEST_CONDITION(x) TestCondition(x, __LINE__)
+
+
+// test databases to create, for use by Contacts test clients
+_LIT(KBackupDatabaseFile1,"c:BackupTest1.cdb");
+_LIT(KBackupDatabaseFile2,"c:BackupTest2.cdb");
+_LIT(KBackupDatabaseFile3,"c:BackupTest3.cdb"); 
+
+
+// real location of Contacts db files
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+_LIT(KBackupDatabaseFileFullPath1,"c:\\private\\10003A73\\BackupTest1.cdb");
+_LIT(KBackupDatabaseFileFullPath2,"c:\\private\\10003A73\\BackupTest2.cdb");
+_LIT(KBackupDatabaseFileFullPath3,"c:\\private\\10003A73\\BackupTest3.cdb"); 
+_LIT(KBackupDestinationDatabasePath1,"c:\\t_cnt_backup\\BackupTest1.cdb");
+_LIT(KBackupDestinationDatabasePath2,"c:\\t_cnt_backup\\BackupTest2.cdb");
+_LIT(KBackupDestinationDatabasePath3,"c:\\t_cnt_backup\\BackupTest3.cdb"); 
+_LIT(KContactsBackupRegistrationDefaultDbFileFullPath, "c:\\private\\10003A73\\backup_registrationcontacts_cdb.xml");
+#else
+_LIT(KBackupDatabaseFileFullPath1,"c:\\private\\10003A73\\SQLite__BackupTest1.cdb");
+_LIT(KBackupDatabaseFileFullPath2,"c:\\private\\10003A73\\SQLite__BackupTest2.cdb");
+_LIT(KBackupDatabaseFileFullPath3,"c:\\private\\10003A73\\SQLite__BackupTest3.cdb"); 
+_LIT(KBackupDestinationDatabasePath1,"c:\\t_cnt_backup\\SQLite__BackupTest1.cdb");
+_LIT(KBackupDestinationDatabasePath2,"c:\\t_cnt_backup\\SQLite__BackupTest2.cdb");
+_LIT(KBackupDestinationDatabasePath3,"c:\\t_cnt_backup\\SQLite__BackupTest3.cdb"); 
+_LIT(KContactsBackupRegistrationDefaultDbFileFullPath, "c:\\private\\10003A73\\backup_registrationSQLite__contacts_cdb.xml");
+#endif
+
+
+// Contact model backup files
+_LIT(KContactsBackupRegistrationIniFileFullPath, "c:\\private\\10003A73\\backup_registration.xml");
+_LIT(KContactsIniBackupFileFullPath, "c:\\private\\10003A73\\Cntmodel.ini");
+_LIT(KBackupDestinationDirectory, "c:\\t_cnt_backup\\");
+_LIT(KBackupDestinationContactsIniPath,"c:\\t_cnt_backup\\Cntmodel.ini");
+_LIT(KRestoreDamagedDatabasePath,"z:\\t_cnt_backup_Corrupted_100065FF.cdb");
+
+// delays between Backup/Restoretest steps, to allow notifications to propagate to all components
+static const TInt KWaitForBackupNotification(15000000);
+static const TInt KWaitForClientToSettle(2000000);
+static const TInt KWaitForSystemToSettle(20000000);
+
+
+// Test databases have 10 contacts created, various contact Ids are used for different purposes
+static const TInt KNumContactsInDatabase= 10;
+static const TContactItemId KOpenContactId1 = 1;
+static const TContactItemId KOpenContactId2 = 2;
+static const TContactItemId KOpenContactId3 = 3;
+static const TContactItemId KSpeedDialContactId = 4;
+static const TContactItemId KReadContactId = 5;
+static const TInt KSpeedDialPositionOne = 1;
+
+
+_LIT(KAsyncFindMatch,"a");
+
+
+// global data for unit test
+_LIT(KTestName, "t_cnt_backup");
+static RTest test(KTestName);
+static RFs TheFsSession;
+
+
+/*
+ Class CBackupTestConductor drives the whole set of tests
+ 1. Check the Backup Registration file is present
+ 2. Check the Secure Backup Engine has processed it as we expect
+ 3. ... various Backup / Restore scenarios for contacts clients
+ */
+
+CBackupTestConductor* CBackupTestConductor::NewL()
+	{
+	CBackupTestConductor* self = new (ELeave) CBackupTestConductor();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CBackupTestConductor::~CBackupTestConductor()
+	{
+	// ensure test databases are deleted
+	CBackupTestConductor::DeleteDatabases();
+
+	// cleanup backup files
+	TheFsSession.Delete(KBackupDestinationContactsIniPath);
+	TheFsSession.Delete(KBackupDestinationDatabasePath1);
+	TheFsSession.Delete(KBackupDestinationDatabasePath2);
+	TheFsSession.Delete(KBackupDestinationDatabasePath3);
+	TheFsSession.RmDir(KBackupDestinationDirectory);
+	}
+
+
+CBackupTestConductor::CBackupTestConductor()
+	{
+	}
+
+
+void CBackupTestConductor::ConstructL()
+	{
+	const TInt err = TheFsSession.MkDirAll(KBackupDestinationDirectory);
+	if ((err != KErrNone) && (err != KErrAlreadyExists))
+		{
+		test.Printf(_L("Unable to create the directory %S\n"), &KBackupDestinationDirectory);
+		User::Leave(err);
+		}
+	}
+
+
+void CBackupTestConductor::RunTestsL()
+	{
+	// need databases for B&R testing
+	CreateDatabasesL();
+	// 1.x Check Backup Registration files
+	test.Start(_L("Backup registration files exist"));
+	TEST_CONDITION(CheckXMLBackupRegistrationExistsL());
+	test.End();
+
+	
+	// framework that runs a Backup & Restore test cycle
+	CBackupTestFramework* backupFramework = CBackupTestFramework::NewLC();
+	CleanupStack::Check(backupFramework);
+
+	// 2. ... run all Backup / Restore test situations
+	backupFramework->DoBackupRestoreTestsL();
+
+	// delete framework
+	CleanupStack::PopAndDestroy(backupFramework);
+	}
+
+
+// demonstrates that database is populated correctly
+#ifdef _DEBUG
+void CBackupTestConductor::ShowFieldsL(CContactDatabase* aDb)
+#else
+void CBackupTestConductor::ShowFieldsL(CContactDatabase* /*aDb*/)
+#endif
+	{
+#if _DEBUG
+	CContactItem* contact = aDb->ReadContactLC(iFirstContactId);
+	
+	CContactItemFieldSet& fields = contact->CardFields();
+	const TInt fieldCount = fields.Count();
+
+	for (TInt i = 0; i < fieldCount; i++)
+		{
+		CContactItemField &field = fields[i];
+		if (field.StorageType() == KStorageTypeText)
+			{
+			TPtrC fieldText = field.TextStorage()->Text();
+			TPtrC labelText = field.Label();
+		    test.Printf(_L("--Field(%d) %S: %S \n\r"), i, &labelText, &fieldText);
+			}
+		}
+	CleanupStack::PopAndDestroy(contact);	
+#endif
+	}
+
+
+/*
+ Populate the database - add TEN contacts, based on the default template,
+ setting FOUR fields. (Given name, Family name, phone number + Company name.)
+ Set the Company Name field to be the same as the name of the database.
+ 
+ @param aDb the CContactDatabase instance to add contacts to.
+ @param aFileName Database file name to put in the Company name field
+ */
+void CBackupTestConductor::PopulateDatabaseL(CContactDatabase* aDb,const TDesC& aFileName)
+	{
+	test.Printf(_L("Populating database %S\n"), &aFileName);
+	TInt index = 0;
+	TBool allDone = EFalse;
+
+	const TContactItemId templateId = aDb->TemplateId();
+	CContactItem* templateCard = aDb->ReadContactLC(templateId);
+
+	do
+	{
+		CContactCard* card = CContactCard::NewLC(templateCard);
+
+		CContactItemFieldSet& cardFields = card->CardFields();
+
+		TInt posLastName = cardFields.Find(KUidContactFieldGivenName);
+		TInt posFirstName = cardFields.Find(KUidContactFieldFamilyName);
+
+
+		switch (index)
+			{ // (famous writers on computer topics)
+			case 0:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test1"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name1"));
+				break;
+
+			case 1:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test2"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name2"));
+				break;
+
+			case 2:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Thompson10"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name3"));
+				break;
+
+			case 3:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test3"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name4"));
+				break;
+
+			case 4:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test4"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name5"));
+				break;
+
+			case 5:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test5"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name6"));
+				break;
+
+			case 6:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test6"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name7"));
+				break;
+
+			case 7:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test7"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name8"));
+				break;
+
+			case 8:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test8"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name9"));
+				break;
+
+			case 9:
+				cardFields[posLastName].TextStorage()->SetTextL(_L("Test9"));
+				cardFields[posFirstName].TextStorage()->SetTextL(_L("Name10"));
+				// last contact
+				allDone = ETrue;
+				break;
+			}
+
+
+		// Set the telephone number
+		TInt posNumber = cardFields.Find(KUidContactFieldPhoneNumber);
+		if (posNumber != KErrNotFound)
+			{
+			cardFields[posNumber].SetMapping(KUidContactFieldVCardMapTEL);
+			cardFields[posNumber].TextStorage()->SetTextL(_L("1234"));
+			}
+
+
+		// set database file name as company name
+		TInt posCompanyName = cardFields.Find(KUidContactFieldCompanyName);
+		if (posCompanyName != KErrNotFound)
+			{
+			cardFields[posCompanyName].TextStorage()->SetTextL(aFileName);
+			}
+
+
+		iLastContactId = aDb->AddNewContactL(*card);
+		if (index == 0)
+			{
+			iFirstContactId = iLastContactId;
+			}
+
+		CleanupStack::PopAndDestroy(card);
+		++index;
+		
+		test.Printf(_L("."));
+		}
+		while (!allDone);
+
+	CleanupStack::PopAndDestroy(templateCard);
+
+	ShowFieldsL(aDb);
+	}
+
+// create THREE empty contacts databases then populate each
+void CBackupTestConductor::CreateDatabasesL()
+	{
+	// Create & close databases
+	CContactDatabase* db;
+	// Need to create the default data base if it does not exist to enusre
+	// prescence of backup registration file.
+	if (!CContactDatabase::DefaultContactDatabaseExistsL())
+		{
+		db = CContactDatabase::CreateL();
+		delete db;		
+		}
+		
+	test.Printf(_L("Creating database %S\n"), &KBackupDatabaseFile1);
+	db = CContactDatabase::ReplaceL(KBackupDatabaseFile1);
+	PopulateDatabaseL(db, KBackupDatabaseFile1);
+	delete db;
+	
+	test.Printf(_L("Creating database %S\n"), &KBackupDatabaseFile2);
+	db = CContactDatabase::ReplaceL(KBackupDatabaseFile2);
+	PopulateDatabaseL(db, KBackupDatabaseFile2);
+	delete db;
+	
+	test.Printf(_L("Creating database %S\n"), &KBackupDatabaseFile3);
+	db = CContactDatabase::ReplaceL(KBackupDatabaseFile3);
+	PopulateDatabaseL(db, KBackupDatabaseFile3);
+	delete db;
+	}
+
+
+void CBackupTestConductor::DeleteDatabases()
+	{
+	// Delete databases
+	TRAP_IGNORE(CContactDatabase::DeleteDatabaseL(KBackupDatabaseFile1));
+	TRAP_IGNORE(CContactDatabase::DeleteDatabaseL(KBackupDatabaseFile2));
+	TRAP_IGNORE(CContactDatabase::DeleteDatabaseL(KBackupDatabaseFile3));
+	}
+
+
+/*
+ Check that the Contact Model's Backup Registration files are present and > 0 bytes length
+ */
+TBool CBackupTestConductor::CheckXMLBackupRegistrationExistsL()
+	{
+	// Check the Contacts private area for the expected registration files
+	TEntry entry;
+
+	// See if initialisation registration file is in the directory on drive Z:
+	TInt error = TheFsSession.Entry(KContactsBackupRegistrationIniFileFullPath, entry);
+
+	if (error == KErrNotFound)
+		{
+		return EFalse;
+		}
+		
+	User::LeaveIfError(error);
+
+	if(entry.iSize == 0)
+		{
+		// file is present but is empty
+		User::Leave(KErrCorrupt);
+		}
+
+	// See if default database registration file is in the directory on drive Z:
+	error = TheFsSession.Entry(KContactsBackupRegistrationDefaultDbFileFullPath, entry);
+
+	if (error == KErrNotFound)
+		{
+		return EFalse;
+		}
+		
+	User::LeaveIfError(error);
+
+	if(entry.iSize == 0)
+		{
+		// file is present but is empty
+		User::Leave(KErrCorrupt);
+		}
+
+	// Found the registration files
+	return ETrue;
+	}
+			
+
+//
+
+/*
+ Framework for simulating Contact Model clients
+ 
+ @param aDatabaseName database file name to open
+ @param aObserver Observer in Backup / Restore test framework to count Backup and Restore notifications
+ @param aContactViewObserver Observer in Backup / Restore test framework to count View Ready and Unavailable notifications
+ */
+CContactsClient* CContactsClient::NewLC(const TDesC& aDatabaseName, MBackupRestoreObserver* aObserver, MContactViewObserver& aContactViewObserver, TBool aCloseForBackup)
+	{
+	CContactsClient* self = new (ELeave) CContactsClient(aObserver, aContactViewObserver, aCloseForBackup);
+	CleanupStack::PushL(self);
+	self->ConstructL(aDatabaseName);
+	return self;
+	}
+	
+	
+CContactsClient::CContactsClient(MBackupRestoreObserver* aObserver, MContactViewObserver& aContactViewObserver, TBool aCloseForBackup)
+	: CActive(EPriorityStandard), iObserver(aObserver), iContactViewObserver(aContactViewObserver), iDatabaseIsOpen(EFalse), iCloseForBackup(aCloseForBackup), iOpenContacts(4)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CContactsClient::~CContactsClient()
+	{
+	Cancel();
+	CloseViews();
+	CloseDatabase();
+	iOpenContacts.ResetAndDestroy();
+
+	delete iDbName;
+	}
+
+
+void CContactsClient::StartActiveClose()
+	{
+	// start active object to close contact/view/database
+	// required as these can't be closed directly from the event handlers
+	if (!IsActive() && iDatabaseIsOpen)
+		{
+		TRequestStatus* pS = &iStatus;
+		User::RequestComplete(pS,0);
+		SetActive();
+		}
+	}
+	
+void CContactsClient::DoCancel()
+	{
+	}
+	
+
+void CContactsClient::RunL()
+	{
+	if (iStatus.Int() != KErrCancel)
+		{
+		CloseDatabase();
+		}
+	}
+	
+void CContactsClient::CloseDatabase()
+	{
+	CloseContacts();
+	CloseViews();
+	iDatabaseIsOpen = EFalse;
+
+	if (iIdleFinder)
+		{
+		delete iIdleFinder;
+		iIdleFinder = NULL;
+		}
+
+	if (iItemFieldDef)
+		{
+		delete iItemFieldDef;
+		iItemFieldDef = NULL;
+		}
+
+	if (iActiveCompress)
+		{
+		delete iActiveCompress;
+		iActiveCompress = NULL;
+		}
+
+	if (iActiveRecover)
+		{
+		delete iActiveRecover;
+		iActiveRecover = NULL;
+		}
+
+	delete iNotifier;
+	iNotifier = NULL;
+	delete iDb;
+	iDb = NULL;
+	}
+
+
+void CContactsClient::ConstructL(const TDesC& aDatabaseName)
+	{
+	// remember the database name
+	iDbName = aDatabaseName.AllocL();
+	// open it
+	OpenDatabaseL();
+	}
+
+
+void CContactsClient::OpenDatabaseL()
+	{
+	// can only open once
+	if (iDatabaseIsOpen)
+		{
+		User::Leave(KErrInUse);
+		}
+
+	test.Printf(_L("Open database %S\n"), iDbName);
+	iDb = CContactDatabase::OpenL(iDbName->Des());
+	iDatabaseIsOpen = ETrue;
+	iNotifier = CContactChangeNotifier::NewL(*iDb,this);
+	}
+
+
+const TDesC& CContactsClient::DatabaseName()
+	{
+	return *iDbName;
+	}
+
+
+TBool CContactsClient::IsOpen()
+	{
+	return iDatabaseIsOpen;
+	}
+
+TBool CContactsClient::IsCloseForBackup()
+	{
+	return iCloseForBackup;
+	}	
+
+void CContactsClient::OpenRemoteViewL()
+	{
+	if (iRemoteView != NULL)
+		{
+		User::Leave(KErrInUse);
+		}
+		
+	RContactViewSortOrder viewSortOrder;
+	
+	viewSortOrder.AppendL(KUidContactFieldFamilyName);
+	viewSortOrder.AppendL(KUidContactFieldGivenName);
+	viewSortOrder.AppendL(KUidContactFieldCompanyName);
+
+	iRemoteView = CContactRemoteView::NewL(iContactViewObserver, *iDb, viewSortOrder, EContactsOnly);
+
+	viewSortOrder.Close();
+	}
+
+
+void CContactsClient::OpenLocalViewL()
+	{
+	if (iLocalView != NULL)
+		{
+		User::Leave(KErrInUse);
+		}
+		
+	RContactViewSortOrder viewSortOrder;
+	
+	viewSortOrder.AppendL(KUidContactFieldFamilyName);
+	viewSortOrder.AppendL(KUidContactFieldGivenName);
+	viewSortOrder.AppendL(KUidContactFieldCompanyName);
+
+	iLocalView = CContactLocalView::NewL(iContactViewObserver, *iDb, viewSortOrder, EContactsOnly);
+
+	viewSortOrder.Close();
+	}
+
+
+void CContactsClient::CloseViews()
+	{
+	if (iLocalView)
+		{
+		iLocalView->Close(iContactViewObserver);
+		iLocalView = NULL;
+		}
+
+	if (iRemoteView)
+		{
+		iRemoteView->Close(iContactViewObserver);
+		iRemoteView = NULL;
+		}
+	}
+
+
+void CContactsClient::FindPhoneNumberL()
+	{
+	_LIT(KPhoneNumber, "1234");
+	const TInt KNumMatchDigit = 4;
+	CContactIdArray* array = iDb->MatchPhoneNumberL(KPhoneNumber, KNumMatchDigit);
+	CleanupStack::PushL(array);
+	TEST_CONDITION(array->Count() == 10);
+	CleanupStack::PopAndDestroy(array);
+	}
+
+
+// try to open a contact for edit
+void CContactsClient::OpenContactL(TContactItemId aContactId)
+	{
+	CContactItem* contact = iDb->OpenContactL(aContactId);
+	iOpenContacts.AppendL(contact);
+	}
+
+
+// try to commit an open contact
+void CContactsClient::CommitContactL(TContactItemId aContactId)
+	{
+	const TInt numOpenContacts = iOpenContacts.Count();
+	
+	for (TInt j = 0; j < numOpenContacts; ++j)
+		{
+		CContactItem* tempContact = iOpenContacts[j];
+		if (tempContact->Id() == aContactId)
+			{
+			iDb->CommitContactL(*tempContact);
+			iOpenContacts.Remove(j);
+			delete tempContact;
+			return;
+			}
+		}
+	// contact isn't in open list
+	TEST_CONDITION(EFalse);
+	}
+
+
+// close any open contacts
+void CContactsClient::CloseContacts()
+	{
+	while (iOpenContacts.Count())
+		{
+		CContactItem* tempContact = iOpenContacts[0];
+		TRAP_IGNORE(iDb->CloseContactL(tempContact->Id()));
+		iOpenContacts.Remove(0);
+		delete tempContact;
+		}
+	}
+
+// try to Read the template Contact from database
+// and also, check that one record exists with the Company Name field set 
+// to the clients database name 
+void CContactsClient::ReadContactL()
+	{
+	CContactItem* contact = iDb->ReadContactLC(KReadContactId);
+	CleanupStack::PopAndDestroy(contact);
+
+	// find records with the Company Name field set
+	CContactItemFieldDef* fieldDef = new(ELeave) CContactItemFieldDef;
+	CleanupStack::PushL(fieldDef);
+	TFieldType fieldtype = KUidContactFieldCompanyName;
+	fieldDef->AppendL(fieldtype);
+	CContactIdArray* matchList = iDb->FindLC(iDbName->Des(),fieldDef);
+  
+	// all added contacts should have this field initialised
+	TInt matchCount = matchList->Count();
+    TEST_CONDITION(matchCount == KNumContactsInDatabase);	
+
+    CleanupStack::PopAndDestroy(2, fieldDef);
+	}
+
+
+void CContactsClient::HandleDatabaseEventL(TContactDbObserverEvent aEvent)
+	{
+	/** Contacts DB about to be backed up  */
+	if (aEvent.iType == EContactDbObserverEventBackupBeginning)
+		{
+		iRestore = EFalse;
+		iObserver->ContactsBackupRestoreObserver(*this, iRestore, ETrue);
+		}
+	/** Contacts DB about to be restored */
+	else if (aEvent.iType == EContactDbObserverEventRestoreBeginning)
+		{
+		iRestore = ETrue;
+		iObserver->ContactsBackupRestoreObserver(*this, iRestore, ETrue);
+		}
+	/** The backup/restore operation has completed. */
+	else if (aEvent.iType == EContactDbObserverEventBackupRestoreCompleted)
+		{
+		iObserver->ContactsBackupRestoreObserver(*this, iRestore, EFalse);
+		}
+	/** The restore operation has completed but the database could not be opened. */
+	else if (aEvent.iType == EContactDbObserverEventRestoreBadDatabase)
+		{
+		iObserver->ContactsBackupRestoreObserver(*this, iRestore, EFalse);
+		}
+	}
+
+
+void CContactsClient::StartAsyncFindL()
+	{
+	if (!iItemFieldDef)
+		{
+		iItemFieldDef = new(ELeave) CContactItemFieldDef();
+		iItemFieldDef->AppendL(KUidContactFieldGivenName);
+		iItemFieldDef->AppendL(KUidContactFieldFamilyName);
+		iItemFieldDef->AppendL(KUidContactFieldCompanyName);
+		iItemFieldDef->AppendL(KUidContactFieldPhoneNumber);
+		iItemFieldDef->AppendL(KUidContactFieldFax);
+		iItemFieldDef->AppendL(KUidContactFieldEMail);
+		iItemFieldDef->AppendL(KUidContactFieldUrl);
+		iItemFieldDef->AppendL(KUidContactFieldAddress);
+		iItemFieldDef->AppendL(KUidContactFieldLocality);
+		iItemFieldDef->AppendL(KUidContactFieldRegion);
+		iItemFieldDef->AppendL(KUidContactFieldPostcode);
+		iItemFieldDef->AppendL(KUidContactFieldCountry);
+		iItemFieldDef->AppendL(KUidContactFieldNote);
+		}
+
+	iIdleFinder = iDb->FindAsyncL(KAsyncFindMatch, iItemFieldDef, this);
+	}
+
+
+void CContactsClient::StartActiveCompactL()
+	{
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+	if (! iActiveCompress)
+		{
+		iActiveCompress = iDb->CreateCompressorLC();
+		CleanupStack::Pop();
+		}
+	iActiveCompress->SetObserver(this);
+#endif
+	}
+
+
+void CContactsClient::StartActiveRecoverL()
+	{
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+	if (! iActiveRecover)
+		{
+		iActiveRecover = iDb->CreateRecoverLC();
+		CleanupStack::Pop();
+		}
+	iActiveRecover->SetObserver(this);
+#endif
+	}
+
+
+void CContactsClient::StartIdleSorterL(TRequestStatus& aStatus)
+	{
+	CArrayFix<CContactDatabase::TSortPref>* sortOrder = new(ELeave) CArrayFixFlat<CContactDatabase::TSortPref>(3);
+	CleanupStack::PushL(sortOrder);
+
+	// prepare a sort order
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldGivenName));
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldFamilyName));
+	sortOrder->AppendL(CContactDatabase::TSortPref(KUidContactFieldCompanyName));
+
+	// starts Contacts Model Idle Sorter
+	iDb->SortAsyncL(sortOrder, aStatus);
+
+
+	// sortOrder ownership was passed to the Contact Model
+	CleanupStack::Pop(sortOrder);
+	}
+
+
+void CContactsClient::CompleteAsyncFindL()
+	{
+	// nothing to do Async Find completes in its own time
+	}
+
+
+void CContactsClient::CompleteActiveCompactL()
+	{
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+	TInt step;
+	while(iActiveCompress->Step())
+		{
+		step = iActiveCompress->StepsTogo();
+		TEST_CONDITION(step > 0);
+		}
+	step = iActiveCompress->StepsTogo();
+	TEST_CONDITION(step == 0);
+	delete iActiveCompress;
+	iActiveCompress = NULL;
+#endif
+	}
+
+
+void CContactsClient::CompleteActiveRecoverL()
+	{
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+	TInt step;
+	while(iActiveRecover->Step())
+		{
+		step = iActiveRecover->StepsTogo();
+		TEST_CONDITION(step > 0);
+		}
+	step = iActiveRecover->StepsTogo();
+	TEST_CONDITION(step == 0);
+	delete iActiveRecover;
+	iActiveRecover = NULL;
+#endif
+	}
+
+
+// class MContactUiCompactObserver
+void CContactsClient::Step(TInt /*aStep*/)
+	{
+	}
+
+
+void CContactsClient::HandleError(TInt /*aError*/)
+	{
+	}
+
+
+// class MIdleFindObserver
+void CContactsClient::IdleFindCallback()
+	{
+	}
+
+
+// Speed Dial Check, Remove and Set - for testing cntmodel.ini is Backed up and Restored correctly
+void CContactsClient::CheckSpeedDialSetL(TContactItemId aContactId, TInt aSpeedDialPosition)
+	{
+	HBufC* buf = HBufC::NewLC(100);	
+	TPtr fieldContents = buf->Des();
+	
+	TContactItemId id = iDb->GetSpeedDialFieldL(aSpeedDialPosition, fieldContents);
+	CleanupStack::PopAndDestroy(buf);
+
+	TEST_CONDITION(id == aContactId);
+	}
+
+
+void CContactsClient::RemoveSpeedDialL(TContactItemId aContactId, TInt aSpeedDialPosition)
+	{
+	iDb->RemoveSpeedDialFieldL(aContactId, aSpeedDialPosition);
+	}
+
+
+void CContactsClient::SetSpeedDialL(TContactItemId aContactId, TInt aSpeedDialPosition)
+	{
+	CContactItem* speedDialItem = iDb->OpenContactLX(aContactId);
+	CleanupStack::PushL(speedDialItem);
+	CContactItemFieldSet& cardFields = speedDialItem->CardFields();
+
+	TInt posNumber = cardFields.Find(KUidContactFieldPhoneNumber);
+
+	iDb->SetFieldAsSpeedDialL(*speedDialItem, posNumber, aSpeedDialPosition);
+	CleanupStack::PopAndDestroy(speedDialItem);
+	CleanupStack::Pop(); // Lock Record
+	}
+
+
+//
+// Backup and Restore Test Framework class
+//
+
+CBackupHelper* CBackupHelper::NewL(RPIMTestServer& aTestServer)
+	{
+    CBackupHelper* self = new(ELeave) CBackupHelper(aTestServer);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+	
+CBackupHelper::CBackupHelper(RPIMTestServer& aTestServer) : 
+    iTestServ (aTestServer)
+	{
+	}
+	
+	
+void CBackupHelper::ConstructL()
+	{
+	/* Initialise the drive list to empty and then get drive list data from
+	 File Server.
+	 Required before Backup and Restore testing
+	 */
+	iDriveList.FillZ();
+	User::LeaveIfError(TheFsSession.DriveList(iDriveList));
+
+	iBackupClient = conn::CSBEClient::NewL();
+	}
+
+
+CBackupHelper::~CBackupHelper()
+	{
+	delete iBackupClient;
+	}
+	
+	
+void CBackupHelper::StartBackupL(conn::TBURPartType aBURPartType, conn::TBackupIncType aBackupIncType)
+	{
+	/* Use the Secure Backup Engine API to "start" a backup.  Ultimate effect
+	 is to cause CContactsClient::HandleDatabaseEventL() to be called.
+	 This happens indirectly through CLockSrvServer::BackupBeginningL()/
+	 BackupCompletedL()/RestoreBeginningL()/RestoreCompletedL() methods.
+	 These methods are implementations for MBackupRestoreNotificatioObserver
+	 which monitors changes in the P&S property conn::KUidBackupRestoreKey.
+	 This P&S property is changed by calling the Secure Backup Engine API
+	 below.
+	 */	
+	iBackupClient->SetBURModeL(iDriveList, aBURPartType, aBackupIncType);
+	}
+
+
+void CBackupHelper::EndBackupL()
+	{
+	/* Use the Secure Backup Engine API to "end" a backup.  Ultimate effect
+	 is to cause CContactsClient::HandleDatabaseEventL() to be called.
+	 This happens indirectly through CLockSrvServer::BackupBeginningL()/
+	 BackupCompletedL()/RestoreBeginningL()/RestoreCompletedL() methods.
+	 These methods are implementations for MBackupRestoreNotificatioObserver
+	 which monitors changes in the P&S property conn::KUidBackupRestoreKey.
+	 This P&S property is changed by calling the Secure Backup Engine API
+	 below.
+	 */
+	iBackupClient->SetBURModeL(iDriveList, conn::EBURNormal, conn::ENoBackup);
+	}
+
+
+void CBackupHelper::StartRestoreL()
+	{
+	/* Use the Secure Backup Engine API to "start" a restore.  Ultimate effect
+	 is to cause CContactsClient::HandleDatabaseEventL() to be called.
+	 This happens indirectly through CLockSrvServer::BackupBeginningL()/
+	 BackupCompletedL()/RestoreBeginningL()/RestoreCompletedL() methods.
+	 These methods are implementations for MBackupRestoreNotificatioObserver
+	 which monitors changes in the P&S property conn::KUidBackupRestoreKey.
+	 This P&S property is changed by calling the Secure Backup Engine API
+	 below.
+	 */
+	iBackupClient->SetBURModeL(iDriveList, conn::EBURRestoreFull, conn::EBackupBase);
+	}
+
+
+void CBackupHelper::EndRestoreL()
+	{
+	/* Use the Secure Backup Engine API to "end" a restore.  Ultimate effect
+	 is to cause CContactsClient::HandleDatabaseEventL() to be called.
+	 This happens indirectly through CLockSrvServer::BackupBeginningL()/
+	 BackupCompletedL()/RestoreBeginningL()/RestoreCompletedL() methods.
+	 These methods are implementations for MBackupRestoreNotificatioObserver
+	 which monitors changes in the P&S property conn::KUidBackupRestoreKey.
+	 This P&S property is changed by calling the Secure Backup Engine API
+	 below.
+	 */
+	iBackupClient->SetBURModeL(iDriveList, conn::EBURNormal, conn::ENoBackup);
+	}
+
+
+
+
+//
+// Simulate Backup of .ini file. Indicating if the operation was a success.
+//
+TBool CBackupHelper::SimulateIniBackup()
+	{
+    // Backup CntModel.ini file.
+    TRAPD(error, iTestServ.CopyFileL(KContactsIniBackupFileFullPath,
+        KBackupDestinationContactsIniPath))
+	
+	if (error != KErrNone)
+		{
+		test.Printf(_L("Copy failed with error %i"), error);
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+
+//
+// Simulate Backup of database(s). Indicating if the operation was a success.
+//
+TBool CBackupHelper::SimulateDbBackup()
+	{
+    // backup databases
+    TRAPD(error, iTestServ.CopyFileL(KBackupDatabaseFileFullPath1, KBackupDestinationDatabasePath1))
+
+	if (error == KErrNone)
+		{
+        TRAP(error, iTestServ.CopyFileL(KBackupDatabaseFileFullPath2, KBackupDestinationDatabasePath2))
+		}
+
+	if (error == KErrNone)
+		{
+        TRAP(error, iTestServ.CopyFileL(KBackupDatabaseFileFullPath3, KBackupDestinationDatabasePath3))
+		}
+
+	if (error != KErrNone)
+		{
+		test.Printf(_L("Copy failed with error %i"), error);
+		return EFalse;
+		}
+
+	return ETrue;
+	}
+
+
+//
+// Simulate restore of .ini file. Indicating if the operation was a success.
+//
+TBool CBackupHelper::SimulateIniRestore()
+	{
+	// Restore CntModel.ini file.
+    TRAPD(error, iTestServ.CopyFileL(KBackupDestinationContactsIniPath, KContactsIniBackupFileFullPath))
+
+	if (error != KErrNone)
+		{
+		test.Printf(_L("Copy failed with error %i"), error);
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+
+//
+// Simulate restore of database(s). Indicating if the operation was a success.
+//
+TBool CBackupHelper::SimulateDbRestore()
+	{
+	// restore databases
+    TRAPD(error, iTestServ.CopyFileL(KBackupDestinationDatabasePath1, KBackupDatabaseFileFullPath1))
+
+    if (error == KErrNone)
+		{
+        TRAP(error, iTestServ.CopyFileL(KBackupDestinationDatabasePath2, KBackupDatabaseFileFullPath2))
+		}
+
+	if (error == KErrNone)
+		{
+        TRAP(error, iTestServ.CopyFileL(KBackupDestinationDatabasePath3, KBackupDatabaseFileFullPath3))
+		}
+
+	if (error != KErrNone)
+		{
+		test.Printf(_L("Copy failed with error %i"), error);
+		return EFalse;
+		}
+
+	return ETrue;
+	}
+
+//
+// Simulate restoring a corrupted database.
+//
+TBool CBackupHelper::SimulateDamagedDbRestore()
+    {
+    // Restore first one from a damaged and the rest from a good copy.		
+    TRAPD(error, iTestServ.CopyFileL(KRestoreDamagedDatabasePath, KBackupDatabaseFileFullPath1))	
+
+    if (error == KErrNone)
+        {
+        TRAP(error, iTestServ.CopyFileL(KBackupDestinationDatabasePath2, KBackupDatabaseFileFullPath2))
+        }
+
+    if (error == KErrNone)
+        {
+        TRAP(error, iTestServ.CopyFileL(KBackupDestinationDatabasePath3, KBackupDatabaseFileFullPath3))
+        }
+	
+    if (error != KErrNone)
+        {
+        test.Printf(_L("Copy failed with error %i"), error);
+        return EFalse;
+        }
+
+    return ETrue;
+    }
+
+//
+// Backup and Restore Test Framework class
+//
+static const CBackupTestFramework::TBackupRestoreTestCase BackupTestCases[] =
+	{
+		/* iTestTitle, iNumDatabases, iClientsPerDatabase, iActivity, iCloseForBackup, iExpectedBackupSuccess */
+
+		/*
+		 Test client activities that DO NOT BLOCK Backup / Restore
+		 Backup and Restore should always succeed, tests are in pairs:
+		 1. does not respond to Backup
+		 2. closes all resources when Backup or Restore begin
+		*/
+
+		// Single client per database - Backup and Restore should always succeed
+		{
+		(TText*) L"Clients that keep CContactDatabase Open",
+		3, 1, CBackupTestFramework::EIdleClient, ETrue, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Clients that close CContactDatabase",
+		3, 1, CBackupTestFramework::EIdleClient, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+    	},
+
+        {
+		(TText*) L"Clients that keep CContactDatabase Open; Restore fails",
+		3, 1, CBackupTestFramework::ERestoreCorruptDbTest, ETrue, CBackupTestFramework::EAllOpenForBackup , conn::EBackupBase
+		},
+
+		// clients open a contact Local View - Backup and Restore should always succeed
+		{
+		(TText*) L"Clients that keep a Local View Open",
+		1, 1, CBackupTestFramework::EOpenLocalView, ETrue, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Clients that close Local View and database",
+		1, 1, CBackupTestFramework::EOpenLocalView, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+
+		// clients open a contact Remote View - Backup and Restore should always succeed
+		{
+		(TText*) L"Clients that keep a Remote View Open",
+		1, 1, CBackupTestFramework::EOpenRemoteView, ETrue, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Clients that close Remote View and database",
+		1, 1, CBackupTestFramework::EOpenRemoteView, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+
+		// Multiple clients per database - Backup and Restore should always succeed
+		{
+		(TText*) L"Multiple clients per database, all keep CContactDatabase Open",
+		3, 3, CBackupTestFramework::EIdleClient, ETrue, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Multiple clients per database, all close CContactDatabase",
+		3, 3, CBackupTestFramework::EIdleClient, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+		
+				
+		{
+		(TText*) L"Two clients per database, one close and one keep CContactDatabase open",
+		2, 2, CBackupTestFramework::EIdleClient, ETrue, CBackupTestFramework::EHalfCloseForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Two clients per database, one closes its contact item and one keeps its contact item open",
+		1, 2, CBackupTestFramework::EMultipleOpenOneContactForEdit, EFalse, CBackupTestFramework::EHalfCloseForBackup, conn::EBackupBase
+        },
+
+		/*
+		 Test client activities that should BLOCK Backup / Restore
+		 Tests are in pairs:
+		 1. does not respond to Backup or Restore - (tests that Backup & Restore fail)
+		 2. closes all resources when Backup or Restore begin - (tests that Backup & Restore succeed)
+		*/
+
+		// Client opens contact for edit - Backup and Restore succeed when resources are freed
+		{
+		(TText*) L"Client opens contact for edit, resources kept open",
+		1, 1, CBackupTestFramework::EOpenOneContactForEdit, EFalse, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Client opens contact for edit, resources released",
+		1, 1, CBackupTestFramework::EOpenOneContactForEdit, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+
+		// Open two contacts for edit - Backup and Restore succeed when resources are freed
+		{
+		(TText*) L"Open two contacts for edit, resources kept open",
+		1, 1, CBackupTestFramework::EOpenTwoContactsForEdit, EFalse, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Open two contacts for edit, resources released",
+		1, 1, CBackupTestFramework::EOpenTwoContactsForEdit, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+
+
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+		// Active Compact - Backup and Restore succeed when resources are free
+		{
+		(TText*) L"Active Compact, resources kept open",
+		1, 1, CBackupTestFramework::EContactsActiveCompact, EFalse, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Active Compact, resources released",
+		1, 1, CBackupTestFramework::EContactsActiveCompact, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+
+		// Active Recover - Backup and Restore succeed when resources are free
+		{
+		(TText*) L"Active Recover, resources kept open",
+		1, 1, CBackupTestFramework::EContactsActiveRecover, EFalse, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Active Recover, resources released",
+		1, 1, CBackupTestFramework::EContactsActiveRecover, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+#endif
+
+		// Async Find - Backup and Restore succeed when resources are freed
+		{
+		(TText*) L"Async Find - Blocks Backup / Restore until it completes",
+		1, 1, CBackupTestFramework::EContactsAsyncFind, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+
+		// Contacts Idle Sorter - Backup and Restore succeed when it completes and resources are freed
+		{
+		(TText*) L"Contacts Idle Sorter - Blocks Backup / Restore until it completes",
+		1, 1, CBackupTestFramework::EContactsIdleSorter, ETrue, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+
+		// Contacts client updates SpeedDial and checks this is Backed-up and Restored
+		{
+		(TText*) L"Contacts test for .Ini file Backup and Restore (clients don't close)",
+		1, 1, CBackupTestFramework::EContactsIniFileTest, ETrue, CBackupTestFramework::EAllOpenForBackup, conn::EBackupBase
+		},
+		// Open Remote View and open a contact - Backup and Restore succeed when it completes and resources are freed
+ 		{
+		(TText*) L"Multiple clients that create a remote view and open a contact(clients close)",
+		1, 2, CBackupTestFramework::EOpenRemoteViewOneContactForEdit, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+		{
+		(TText*) L"Contacts test for .Ini file Backup and Restore(clients close",
+		1, 1, CBackupTestFramework::EContactsIniFileTest, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupBase
+		},
+
+		//
+		// Incremental Backup and Restore. Should always succeed.
+		{
+		(TText*) L"INCREMENTAL: Clients that keep CContactDatabase Open",
+		3, 1, CBackupTestFramework::EIdleClient, ETrue, CBackupTestFramework::EAllOpenForBackup, conn::EBackupIncrement
+		},
+		{
+		(TText*) L"INCREMENTAL: Client opens contact for edit, resources released",
+		1, 1, CBackupTestFramework::EOpenOneContactForEdit, ETrue, CBackupTestFramework::EAllCloseForBackup, conn::EBackupIncrement
+ 		}
+	};
+
+
+CBackupTestFramework* CBackupTestFramework::NewLC()
+	{
+	CBackupTestFramework* self = new(ELeave) CBackupTestFramework();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+	
+	
+CBackupTestFramework::CBackupTestFramework() : CTimer(CActive::EPriorityStandard)
+	{
+	CActiveScheduler::Add(this);
+	}
+	
+	
+void CBackupTestFramework::ConstructL()
+	{
+	CTimer::ConstructL();
+	
+    // Test server used for copying files around.    
+    User::LeaveIfError(iTestServ.Connect());
+    iBackupHelper = CBackupHelper::NewL(iTestServ);
+	}
+
+
+CBackupTestFramework::~CBackupTestFramework()
+	{
+	// cleanup from current test case
+	CTimer::Cancel();
+
+    iTestServ.Close();
+
+	delete iBackupHelper;
+	iContactClientSession.ResetAndDestroy();
+	}
+	
+	
+void CBackupTestFramework::DoBackupRestoreTestsL()
+	{
+	const TInt testCount = sizeof(BackupTestCases) / sizeof(CBackupTestFramework::TBackupRestoreTestCase);
+
+	test.Printf(_L("Iterate through all %i Backup and Restore test cases"), testCount);
+
+	for (TInt testIndex = 0; testIndex < testCount; ++testIndex)
+		{
+		iTestCase = &BackupTestCases[testIndex];
+		BackupRestoreTestL();
+		}
+	}
+
+
+
+// Method to setup the Use Case under test
+// returns ETrue if TrequestStatus was used
+TBool CBackupTestFramework::PrepareBackupClientTestCaseL(TRequestStatus& aStatus)
+	{
+	TBool asyncRequest = EFalse;
+
+	// for every database we are required to open
+	for (TInt dbCount = 1; (dbCount <= iTestCase->iNumDatabases) && (!asyncRequest); ++dbCount)
+		{
+		switch (dbCount)
+			{
+			case 1:
+				asyncRequest = PrepareTestCaseL(KBackupDatabaseFile1(), aStatus);
+				break; 
+
+			case 2:
+				asyncRequest = PrepareTestCaseL(KBackupDatabaseFile2(), aStatus);
+				break;
+
+			case 3:
+				asyncRequest = PrepareTestCaseL(KBackupDatabaseFile3(), aStatus);
+				break;
+
+			default: // something is wrong with test code
+				User::Invariant();
+			}
+		}
+
+	return asyncRequest;
+	}
+	
+
+// Method to implement the Use Case under test
+TBool CBackupTestFramework::PrepareTestCaseL(const TDesC& aDatabaseName, TRequestStatus& aStatus)
+	{
+	TBool asyncRequest = EFalse;
+
+	// at least one, possibly more, clients per database
+	for (TInt clClient = 1; clClient <= iTestCase->iClientsPerDatabase; ++clClient)
+		{
+		// open database
+				TBool isCloseForBackup = ETrue;
+
+		switch(iTestCase->iCloseForBackup)
+			{
+			case EAllOpenForBackup:
+				isCloseForBackup = EFalse;
+				break;
+			case EHalfCloseForBackup:
+				if(clClient > iTestCase->iClientsPerDatabase/2)
+					{
+					isCloseForBackup = EFalse;
+					}
+				break;
+			case EAllCloseForBackup:
+			default:
+				break;
+			}
+
+		CContactsClient* db = NewDatabaseClientL(aDatabaseName, isCloseForBackup);
+
+
+		// specific test case behaviour
+		switch (iTestCase->iActivity)
+			{
+			// activities that do not block backup / restore
+			case EIdleClient:
+			case ERestoreCorruptDbTest:
+				// demonstrate database is open, read from it
+				test.Next(_L("Read a contact from database"));
+				db->ReadContactL();
+				break;
+
+			case EOpenLocalView:
+				test.Next(_L("open contact Local View"));
+				db->OpenLocalViewL();
+				break;
+
+			case EOpenRemoteView:
+				test.Next(_L("open contact Remote View"));
+				db->OpenRemoteViewL();
+				break;
+
+			// activities that can block backup / restore
+			case EOpenOneContactForEdit:
+				test.Next(_L("Open a contact from database"));
+				db->OpenContactL(KOpenContactId1);
+				break;
+
+			case EOpenTwoContactsForEdit:
+				test.Next(_L("Open 2 contacts from database"));
+				db->OpenContactL(KOpenContactId1);
+				db->OpenContactL(KOpenContactId2);
+				break;
+
+			case EContactsAsyncFind:
+				test.Next(_L("Start Async Find on database"));
+				db->StartAsyncFindL();
+				break;
+
+			case EContactsActiveCompact:
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+				test.Next(_L("Start Active Compact on database"));
+				db->StartActiveCompactL();
+#endif
+				break;
+
+			case EContactsActiveRecover:
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+				test.Next(_L("Start Active Recover on database"));
+				db->StartActiveRecoverL();
+#endif
+				break;
+
+			case EContactsIdleSorter:
+				test.Next(_L("Start Contacts Idle Sorter"));
+				db->StartIdleSorterL(aStatus);
+				asyncRequest = ETrue;
+				break;
+
+			case EContactsIniFileTest:
+				// demonstrate database is open, read from it
+				test.Next(_L("Read a contact from database"));
+				db->ReadContactL();
+				break;
+				
+						case EOpenRemoteViewOneContactForEdit:
+			    test.Next(_L("Open a contact from database & open contact Remote View"));
+			    if(clClient == 1) //There are two clients for this DB, first opens a view, second edits a contact
+			        {
+			    	db->OpenRemoteViewL();
+			        }
+			    else
+			        {
+			    	db->OpenContactL(KOpenContactId1);
+			        }
+			    break;
+			case EMultipleOpenOneContactForEdit:
+			    test.Next(_L("Multiple clients, one closes contact item one leaves open"));
+			    if (isCloseForBackup) //ETrue
+			        {
+			    	db->OpenContactL(KOpenContactId1);
+			        }  
+				else //EFalse
+				    {
+					db->OpenContactL(KOpenContactId2);
+				    }
+				    
+				break;
+
+			}
+		}
+
+	return asyncRequest;
+	}
+
+
+
+// Reconnect disconnected client after Backup/Restore
+void CBackupTestFramework::ReconnectBackupClientTestCaseL()
+	{
+	// check that databases can be re-opened and are still useable
+	const TInt numDatabases = iContactClientSession.Count();
+	for (TInt i = 0; i < numDatabases; i++)
+		{
+		if (!iContactClientSession[i]->IsOpen())
+			{
+			test.Printf(_L("reopen database client # %i after backup/restore\n\r"), i + 1);
+			iContactClientSession[i]->OpenDatabaseL();
+			}
+			
+		// read from db
+		test.Next(_L("Read a contact through database client"));
+		iContactClientSession[i]->ReadContactL();
+		}
+	}
+
+
+// test action if client didn't close database
+void CBackupTestFramework::CheckConnectionAfterBackupForTestCaseL()
+	{
+	const TInt numDatabases = iContactClientSession.Count();
+
+	// specific test case behaviour
+	switch (iTestCase->iActivity)
+		{
+		// activities that do not block backup / restore
+		case EIdleClient:
+		case EOpenLocalView:
+		case EOpenRemoteView:
+		case EContactsIniFileTest:
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				// read from each db
+				test.Next(_L("Read a contact through database client"));
+				iContactClientSession[i]->ReadContactL();
+				}
+			break;
+
+		case ERestoreCorruptDbTest:
+#ifndef __SYMBIAN_CNTMODEL_USE_SQLITE__
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				// read from each db
+				test.Next(_L("Read a contact through database client"));
+				TRAPD(err, iContactClientSession[i]->ReadContactL());
+				
+				// The restore is complete. The corrupted db file was damaged
+                // but should have been recovered after the restore completed. 
+                // However, the contact doesn't exist in the db. If the 
+                // corrupted db file was totally unrecognizable then the recover
+                // wouldn't have been attempted and the db would be closed. This
+                // would then return KErrNotReady.
+				if((iTestStep == EPostRestore) &&
+				    (iContactClientSession[i]->DatabaseName()==KBackupDatabaseFile1))
+					{
+					TEST_CONDITION(err==KErrNotFound);
+					}
+				else //others should not Leave, so propagate Leave if it occurs.
+					{
+					if(err != KErrNone)
+						{
+						User::Leave(err);
+						}
+					}
+				}
+#endif
+			break;
+
+		// activities that can block backup / restore
+		case EOpenOneContactForEdit:
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				test.Next(_L("Commit contact to database"));
+				iContactClientSession[i]->CommitContactL(KOpenContactId1);
+				}
+			break;
+
+		case EOpenTwoContactsForEdit:
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				test.Next(_L("Commit 2 contacts to database"));
+				iContactClientSession[i]->CommitContactL(KOpenContactId1);
+				iContactClientSession[i]->CommitContactL(KOpenContactId2);
+				}
+			break;
+
+		case EContactsAsyncFind:
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				test.Next(_L("Complete Async Find on database"));
+				iContactClientSession[i]->CompleteAsyncFindL();
+				}
+			break;
+
+		case EContactsActiveCompact:
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				test.Next(_L("Complete Active Compact on database"));
+				iContactClientSession[i]->CompleteActiveCompactL();
+				}
+			break;
+
+		case EContactsActiveRecover:
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				test.Next(_L("Complete Active Recover on database"));
+				iContactClientSession[i]->CompleteActiveRecoverL();
+				}
+			break;
+
+		case EContactsIdleSorter:
+			// nothing to do for this Use Case
+			break;
+		}
+	}
+
+
+
+// support methods for testing .Ini file Backup and Restore
+
+// any test case action required immediately before Backup start notifiction
+void CBackupTestFramework::PreBackupNotificationActionsL()
+	{
+	const TInt numDatabases = iContactClientSession.Count();
+
+	// specific test case behaviour
+	switch (iTestCase->iActivity)
+		{
+		case EIdleClient:
+        case ERestoreCorruptDbTest:
+		case EOpenLocalView:
+		case EOpenRemoteView:
+		case EOpenOneContactForEdit:
+		case EOpenTwoContactsForEdit:
+		case EContactsAsyncFind:
+		case EContactsActiveCompact:
+		case EContactsActiveRecover:
+		case EContactsIdleSorter:
+			// nothing to do for this Use Case
+			break;
+
+		case EContactsIniFileTest:
+			// make change to Contacts .ini file that should be Backed-up
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				// read from each db
+				test.Next(_L("Set Speed Dial 1 for database"));
+				iContactClientSession[i]->SetSpeedDialL(KSpeedDialContactId, KSpeedDialPositionOne);
+				}
+			break;
+		}
+	}
+
+
+// any test case action required after Backup completion
+void CBackupTestFramework::PostBackupActionsL()
+	{
+	const TInt numDatabases = iContactClientSession.Count();
+
+	// specific test case behaviour
+	switch (iTestCase->iActivity)
+		{
+		case EIdleClient:
+        case ERestoreCorruptDbTest:
+		case EOpenLocalView:
+		case EOpenRemoteView:
+		case EOpenOneContactForEdit:
+		case EOpenTwoContactsForEdit:
+		case EContactsAsyncFind:
+		case EContactsActiveCompact:
+		case EContactsActiveRecover:
+		case EContactsIdleSorter:
+		case EOpenRemoteViewOneContactForEdit:
+		case EMultipleOpenOneContactForEdit:
+
+			// nothing to do for this Use Case
+			break;
+
+		case EContactsIniFileTest:
+			// check Contacts .ini is correct
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				// read from each db
+				test.Next(_L("Check Speed Dial 1 still set for database"));
+				iContactClientSession[i]->CheckSpeedDialSetL(KSpeedDialContactId, KSpeedDialPositionOne);
+				}
+			break;
+		}
+	}
+
+
+// any test case action required immediately before Restore start notifiction
+void CBackupTestFramework::PreRestoreNotificationActionsL()
+	{
+	const TInt numDatabases = iContactClientSession.Count();
+
+	// specific test case behaviour
+	switch (iTestCase->iActivity)
+		{
+		case EIdleClient:
+        case ERestoreCorruptDbTest:
+		case EOpenLocalView:
+		case EOpenRemoteView:
+		case EOpenOneContactForEdit:
+		case EOpenTwoContactsForEdit:
+		case EContactsAsyncFind:
+		case EContactsActiveCompact:
+		case EContactsActiveRecover:
+		case EContactsIdleSorter:
+		case EOpenRemoteViewOneContactForEdit:
+		case EMultipleOpenOneContactForEdit:
+
+			// nothing to do for this Use Case
+			break;
+
+		case EContactsIniFileTest:
+			// make change to Contacts .ini file before Restore
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				// read from each db
+				test.Next(_L("Remove Speed Dial 1 from database"));
+				iContactClientSession[i]->RemoveSpeedDialL(KSpeedDialContactId, KSpeedDialPositionOne);
+				}
+			break;
+		}
+	}
+
+// any test case action required after Restore completion
+void CBackupTestFramework::PostRestoreActionsL()
+	{
+	const TInt numDatabases = iContactClientSession.Count();
+
+	// specific test case behaviour
+	switch (iTestCase->iActivity)
+		{
+		case EIdleClient:
+        case ERestoreCorruptDbTest:
+		case EOpenLocalView:
+		case EOpenRemoteView:
+		case EOpenOneContactForEdit:
+		case EOpenTwoContactsForEdit:
+		case EContactsAsyncFind:
+		case EContactsActiveCompact:
+		case EContactsActiveRecover:
+		case EContactsIdleSorter:
+		case EOpenRemoteViewOneContactForEdit:
+		case EMultipleOpenOneContactForEdit:
+
+			// nothing to do for this Use Case
+			break;
+
+		case EContactsIniFileTest:
+			// check Restored Contacts .ini file is the same as was Backed-up
+			for (TInt i = 0; i < numDatabases; i++)
+				{
+				// read from each db
+				test.Next(_L("Check Restored Speed Dial 1 from database"));
+				iContactClientSession[i]->CheckSpeedDialSetL(KSpeedDialContactId, KSpeedDialPositionOne);
+				}
+			break;
+		}
+	}
+
+
+
+
+// Backup and Restore test with chosen Use Case
+void CBackupTestFramework::BackupRestoreTestL()
+	{
+	// need to do type conversion in 2 steps
+	TPtrC title(iTestCase->iTestTitle);
+	test.Next(title);
+
+
+	// start backup & restore tests in Active Scheduler
+	iTestStep = EPreBackup;
+	After(0);
+	CActiveScheduler::Start();
+
+	// ensure databases closed & release resources
+	iContactClientSession.ResetAndDestroy();
+
+	// any error from active scheduler?
+	User::LeaveIfError(iTestError);
+	}
+
+
+
+void CBackupTestFramework::RunL()
+	{
+	TBool waitForAsyncRequest = EFalse;
+	
+	if (iStatus.Int() != KErrCancel)
+		{
+		switch (iTestStep)
+			{
+		// Backup test
+		case EPreBackup:
+			test.Start(_L("Backup test"));
+
+			test.Start(_L("Prepare Backup test case, open database(s) etc..."));
+			waitForAsyncRequest = PrepareBackupClientTestCaseL(iStatus);
+
+			// reset count number of Backup notifications
+			iClientNotifications = 0;
+			iViewUnavailableCount = 0;
+			break;
+				
+		case ENotifyBackupStart:
+			// any test case action required immediately before Backup start notifiction
+			PreBackupNotificationActionsL();
+
+			if(conn::EBackupIncrement == iTestCase->iBackupIncType)
+				{
+				test.Next(_L("notify start of incremental backup"));
+				iBackupHelper->StartBackupL(conn::EBURBackupPartial, conn::EBackupIncrement);
+				}
+			else
+				{
+				test.Next(_L("notify start of backup"));
+				iBackupHelper->StartBackupL(conn::EBURBackupFull, conn::EBackupBase);
+				}
+
+			break;
+
+		case ECheckBackupStartNotifications:
+			if(conn::EBackupIncrement == iTestCase->iBackupIncType)
+				{
+				test.Next(_L("check number of incremental backup start notifications"));					
+				}
+			else
+				{
+				test.Next(_L("check number of backup start notifications"));	
+				}
+			TEST_CONDITION(iContactClientSession.Count() == iClientNotifications);
+
+			// test case has views?
+			if ((iTestCase->iActivity == EOpenLocalView) || (iTestCase->iActivity == EOpenRemoteView))
+				{
+				if (iTestCase->iCloseForBackup)
+					{
+					// Contacts clients close for Backup or Restore
+					test.Next(_L("check not too many Contact View unavailable notifications"));
+					TEST_CONDITION((iTestCase->iNumDatabases * iTestCase->iClientsPerDatabase) >= iViewUnavailableCount);
+					}
+				else
+					{
+					// Contacts clients open for Backup or Restore
+					test.Next(_L("check the number of Contact View unavailable notifications"));
+					TEST_CONDITION((iTestCase->iNumDatabases * iTestCase->iClientsPerDatabase) == iViewUnavailableCount);
+					}
+				}
+			break;
+
+		case EDoBackup:
+			if(conn::EBackupIncrement == iTestCase->iBackupIncType)
+				{
+				test.Next(_L("attempt incremental backup of database(s)"));					
+				}
+			else
+				{
+				test.Next(_L("attempt backup of database(s)"));		
+				}
+
+			// Clients have not closed for Backup?
+			if (iTestCase->iCloseForBackup != EAllCloseForBackup)
+				{
+				const TInt numDatabases = iContactClientSession.Count();
+
+				// find open database sessions
+				test.Next(_L("Check that new Read and Open.(Write) operations cannot start"));
+				for (TInt i = 0; i < numDatabases; i++)
+					{
+					if (! iContactClientSession[i]->IsCloseForBackup())
+					    {
+					    test.Next(_L("check that database read is locked"));
+					    TRAPD(error, iContactClientSession[i]->ReadContactL());
+					    TEST_CONDITION(KErrLocked == error);
+
+					    test.Next(_L("check that database write is locked"));
+					    TRAP(error, iContactClientSession[i]->OpenContactL(KOpenContactId3));
+					    TEST_CONDITION(KErrLocked == error);
+
+					    test.Next(_L("check that phone number lookup (database read) is locked"));
+					    TRAP(error, iContactClientSession[i]->FindPhoneNumberL());
+					    TEST_CONDITION(KErrLocked == error);
+					    }
+					}
+				}
+
+			if(iTestCase->iActivity == EContactsIniFileTest)
+				{
+			    test.Next(_L("checking that backup of cntmodel.ini file succeeds"));
+		 	    TEST_CONDITION(iBackupHelper->SimulateIniBackup());
+				}
+
+			if (iTestCase->iExpectedBackupSuccess)
+				{
+				test.Next(_L("checking that backup of databases succeeds"));
+				TEST_CONDITION(iBackupHelper->SimulateDbBackup());
+				}
+			else
+				{
+				test.Next(_L("checking that backup of databases fails"));
+				TEST_CONDITION(! iBackupHelper->SimulateDbBackup());
+				}
+
+			// reset count for end of backup notifications		
+			iClientNotifications = 0;
+			iViewReadyCount = 0;
+			break;
+			
+		case ENotifyBackupEnd:
+			test.Next(_L("notify end of backup"));
+			iBackupHelper->EndBackupL();
+			break;
+
+		case ECheckBackupEndNotifications:
+			// if database connections are kept open
+			if (iTestCase->iCloseForBackup == EAllOpenForBackup)
+				{
+				test.Next(_L("check number of backup end notifications"));
+				TEST_CONDITION(iContactClientSession.Count() == iClientNotifications);
+
+				// test case kept views open?
+				if ((iTestCase->iActivity == EOpenLocalView) || (iTestCase->iActivity == EOpenRemoteView))
+					{
+					test.Next(_L("check the number of Contact View ready notifications"));
+					TEST_CONDITION((iTestCase->iNumDatabases * iTestCase->iClientsPerDatabase) == iViewReadyCount);
+					}
+				}
+			break;
+
+		case EPostBackup:
+			test.Next(_L("post backup verify database(s) useable"));
+			if (iTestCase->iCloseForBackup != EAllOpenForBackup)
+				{
+				ReconnectBackupClientTestCaseL();
+				}
+			else
+				{
+				CheckConnectionAfterBackupForTestCaseL();
+				}
+
+			// any test case action required after Backup completion
+			PostBackupActionsL();
+			break;
+			
+		case EFinishedBackup:
+			test.Next(_L("Cleanup all client resources for test case"));
+			// cleanup after backup test
+			iContactClientSession.ResetAndDestroy();
+			test.End();
+			break;
+
+		// Successful Restore test
+		case EPreRestore:
+			test.Next(_L("Restore test"));
+
+			test.Start(_L("pre-restore access database(s)"));
+			waitForAsyncRequest = PrepareBackupClientTestCaseL(iStatus);
+
+			// reset count of Restore notifications
+			iClientNotifications = 0;
+			iViewUnavailableCount = 0;
+			break;
+			
+		case ENotifyRestoreStart:
+			// any test case action required immediately before Restore start notifiction
+			PreRestoreNotificationActionsL();
+
+			test.Next(_L("notify start of restore"));
+			iBackupHelper->StartRestoreL();
+			break;
+
+		case ECheckRestoreStartNotifications:
+			test.Next(_L("check number of restore start notifications"));
+			TEST_CONDITION(iContactClientSession.Count() == iClientNotifications);
+
+			// test case has views?
+			if ((iTestCase->iActivity == EOpenLocalView) || (iTestCase->iActivity == EOpenRemoteView))
+				{
+				if (iTestCase->iCloseForBackup == EAllOpenForBackup)
+					{
+					// Contacts clients open for Backup or Restore
+					test.Next(_L("check the number of Contact View unavailable notifications"));
+					TEST_CONDITION((iTestCase->iNumDatabases * iTestCase->iClientsPerDatabase) == iViewUnavailableCount);
+					}
+				else
+					{
+					// Contacts clients close for Backup or Restore
+					test.Next(_L("check not too many Contact View unavailable notifications"));
+					TEST_CONDITION((iTestCase->iNumDatabases * iTestCase->iClientsPerDatabase) >= iViewUnavailableCount);
+					}
+				}
+			break;
+
+		case EDoRestore:
+			test.Next(_L("attempt restore of database(s)"));
+
+			// Clients have not closed for Backup?
+				if (iTestCase->iCloseForBackup == EAllOpenForBackup)
+
+				{
+				const TInt numDatabases = iContactClientSession.Count();
+
+				// find all open database sessions
+				for (TInt i = 0; i < numDatabases; i++)
+					{
+					test.Next(_L("check that database read is Locked"));
+					TRAPD(error, iContactClientSession[i]->ReadContactL());
+					TEST_CONDITION(KErrLocked == error);
+
+					test.Next(_L("check that database write is locked"));
+					TRAP(error, iContactClientSession[i]->OpenContactL(KOpenContactId3));
+					TEST_CONDITION(KErrLocked == error);
+
+				    test.Next(_L("check that phone number lookup (database read) is locked"));
+				    TRAP(error, iContactClientSession[i]->FindPhoneNumberL());
+				    TEST_CONDITION(KErrLocked == error);
+					}
+				}
+ 			if(iTestCase->iActivity == EContactsIniFileTest)
+				{
+			    test.Next(_L("checking that restore of ini file succeeds"));
+			    TEST_CONDITION(iBackupHelper->SimulateIniRestore());
+				}
+
+			if (iTestCase->iExpectedBackupSuccess)
+				{
+				if (iTestCase->iActivity == ERestoreCorruptDbTest)
+					{
+					test.Next(_L("checking that restore of databases fails on the corrupted one"));
+					TEST_CONDITION(iBackupHelper->SimulateDamagedDbRestore());
+					}
+				else
+					{
+    				test.Next(_L("checking that restore of databases succeeds"));
+    				TEST_CONDITION(iBackupHelper->SimulateDbRestore());
+                    }
+				}
+			else
+				{
+				test.Next(_L("checking that restore of databases fails"));
+				TEST_CONDITION(! iBackupHelper->SimulateDbRestore());
+				}
+
+			// reset count for end of Restore notifications
+			iClientNotifications = 0;
+			iViewReadyCount = 0;
+			break;
+			
+		case ENotifyRestoreEnd:
+			test.Next(_L("notify end of restore"));
+			iBackupHelper->EndRestoreL();
+			break;
+
+		case ECheckRestoreEndNotifications:
+			// if database connections are kept open
+			if (iTestCase->iCloseForBackup == EAllOpenForBackup)
+				{
+				test.Next(_L("check number of restore end notifications"));
+				TEST_CONDITION(iContactClientSession.Count() == iClientNotifications);
+
+				// test case kept views open?
+				if ((iTestCase->iActivity == EOpenLocalView) || (iTestCase->iActivity == EOpenRemoteView))
+					{
+					test.Next(_L("check the number of Contact View ready notifications"));
+					TEST_CONDITION((iTestCase->iNumDatabases * iTestCase->iClientsPerDatabase) == iViewReadyCount);
+					}
+				}
+			break;
+
+		case EPostRestore:
+			test.Next(_L("post-restore verify database(s) useable"));
+			if (iTestCase->iCloseForBackup)
+				{
+				ReconnectBackupClientTestCaseL();
+				}
+			else
+				{
+				CheckConnectionAfterBackupForTestCaseL();
+				}
+
+			// any test case action required after Restore completion
+			PostRestoreActionsL();
+			break;
+
+		case EFinishedRestore:
+			test.Next(_L("Cleanup all client resources for test case"));
+			// cleanup after backup test
+			iContactClientSession.ResetAndDestroy();
+			// end x.y.z restore test
+			test.End();
+			// end x.y test case
+			test.End();
+
+            // overwrite corrupted database, other tests don't use it
+            if(iTestCase->iActivity == ERestoreCorruptDbTest)
+                {			
+                // Copy a non-corrupted db over the corrupted one for other tests to use.
+                iBackupHelper->SimulateDbRestore();
+                }
+
+			// All Done
+			CActiveScheduler::Stop();
+			return;
+			}
+
+
+		// no pause required between steps?
+		if (waitForAsyncRequest)
+			// waits for an asynchronous request to complete
+			{
+			SetActive();
+			}
+		else if ((iTestStep == EPreBackup) || (iTestStep == EPreRestore))
+			{
+			// start of Backp or Restore test cycle - allow contacts client to settle (e.g. contacts view to sort)
+			test.Printf(_L("Wait %d ms to allow contacts client to settle (e.g. contacts view to sort)\n"), KWaitForClientToSettle);
+			After(KWaitForClientToSettle);
+			}
+		else if ((iTestStep == EPostBackup) || (iTestStep == EPostRestore))
+			{
+			// end of Backup or Restore test cycle - allow all system components to settle
+			test.Printf(_L("Wait %d ms to allow all system components to settle\n"), KWaitForSystemToSettle);
+			After(KWaitForSystemToSettle);
+			}
+		else if ((iTestStep == ENotifyBackupStart) || (iTestStep == ENotifyBackupEnd) || (iTestStep == ENotifyRestoreStart) || (iTestStep == ENotifyRestoreEnd))
+			{
+			// allow notification to propagate
+			test.Printf(_L("Wait %d ms to allow notification to propagate\n"), KWaitForBackupNotification);
+			After(KWaitForBackupNotification);
+			}
+		else
+			{
+			// minimum wait required
+			After(1);
+			}
+			
+		// next step
+		iTestStep = (TBackupRestoreSteps) (iTestStep + 1);
+		}
+	}
+
+
+TInt CBackupTestFramework::RunError(TInt aError)
+	{
+	// RunL is verbose and prints details of each step
+	// so just print error info
+	test.Printf(_L("Backup and Restore test error %d (at step %d)\n\r"), aError, iTestStep);
+	
+	// and state info
+	const TInt clientCount = iContactClientSession.Count();
+	for (TInt j = 0; j < clientCount; j++)
+		{
+		test.Printf(_L("client %i, IsOpen = %i, name \"%S\"\n\r"), 
+			j, iContactClientSession[j]->IsOpen(), &iContactClientSession[j]->DatabaseName());
+		}
+	
+	// propagate error
+	iTestError = aError;
+	
+	CActiveScheduler::Stop();
+	return KErrNone;
+	}
+
+
+//
+
+CContactsClient* CBackupTestFramework::NewDatabaseClientL(const TDesC& aDatabaseName, TBool aCloseForBackup)
+	{
+	test.Printf(_L("open database \"%S\"\n\r"), &aDatabaseName);
+
+	// open a Contacts Model client for test case
+	CContactsClient* newClient = CContactsClient::NewLC(aDatabaseName, this, *this, aCloseForBackup);
+	CleanupStack::Check(newClient);
+
+	// remember for later cleanup
+	iContactClientSession.AppendL(newClient);
+	CleanupStack::Pop(newClient);
+	return newClient;
+	}
+
+
+void CBackupTestFramework::ContactsBackupRestoreObserver(CContactsClient& aContactClient, const TBool aRestore, const TBool aStart)
+	{
+	iClientNotifications ++;
+	
+	// test case should respond to Backup / Restore notification ?
+	if (aStart && aContactClient.IsCloseForBackup())
+		{
+		test.Next(aRestore ? _L("Restore start notification - closing client") : _L("Backup start notification - closing client"));
+		aContactClient.CloseViews();
+		aContactClient.StartActiveClose();	
+		}
+	}
+
+
+
+/*
+ Contact Views become EUnavailable when Backup or Restore start,
+ if the View is kept open it becomes EReady again afterwards.
+ */
+void CBackupTestFramework::HandleContactViewEvent(const CContactViewBase& /*aView*/,const TContactViewEvent& aEvent)
+	{
+	if (aEvent.iEventType == TContactViewEvent::EUnavailable)
+		{
+		iViewUnavailableCount++;
+		// reset Ready count for end of Backup or Restore
+		iViewReadyCount = 0;
+		}
+	else if (aEvent.iEventType == TContactViewEvent::EReady)
+		{
+		iViewReadyCount++;
+		}
+	}
+
+
+
+
+//
+
+
+LOCAL_C void TestCondition(TBool aCondition, TInt aLineNumber)
+	{
+	// if the test is about to fail, cleanup files first
+	if (!aCondition)
+		{
+		CBackupTestConductor::DeleteDatabases();
+		}
+	test.operator()(aCondition, aLineNumber);
+	}
+
+
+LOCAL_C void DoMainL(CActiveScheduler* scheduler)
+    {
+	CActiveScheduler::Install(scheduler);
+
+	CBackupTestConductor* tester = CBackupTestConductor::NewL();
+	CleanupStack::PushL(tester);
+
+ 	tester->RunTestsL();
+	CleanupStack::PopAndDestroy(tester); 
+	}
+/**
+
+@SYMTestCaseID     PIM-T-CNT-BACKUP-0001
+
+*/
+
+GLDEF_C TInt E32Main()
+	{
+	__UHEAP_MARK;
+	test.Title();
+	test.Start(_L("SYMTestCaseID:PIM-T-CNT-BACKUP-0001 Contacts Backup and Restore"));
+	CActiveScheduler* scheduler = new CActiveScheduler;
+	test(scheduler != NULL);
+	CTrapCleanup* theCleanup = CTrapCleanup::New();
+	User::LeaveIfError(TheFsSession.Connect());
+
+	test.Printf(_L("SECURE_DATA mode\r\n"));
+	User::After(KWaitForSystemToSettle);
+
+	TRAPD(ret,DoMainL(scheduler));
+	if (ret != KErrNone)
+		{
+		test.Printf(_L("Something in the test left with error code %d\n"), ret);
+		}
+	TEST_CONDITION(ret == KErrNone);
+
+	TheFsSession.Close();
+	delete theCleanup;	
+	delete scheduler;
+	test.End();
+	test.Close();
+	__UHEAP_MARKEND;
+	return(KErrNone);
+    }