diff -r d4f567ce2e7c -r 5b6f26637ad3 phonebookengines_old/contactsmodel/tsrc/t_cnt_backup.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/phonebookengines_old/contactsmodel/tsrc/t_cnt_backup.cpp Tue Aug 31 15:05:21 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#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* sortOrder = new(ELeave) CArrayFixFlat(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); + }