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