phonebookengines_old/contactsmodel/tsrc/T_MULTS.CPP
changeset 40 b46a585f6909
equal deleted inserted replaced
37:fd64c38c277d 40:b46a585f6909
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32test.h>
       
    17 #include <f32file.h>
       
    18 #include <s32file.h>
       
    19 #include <cntdb.h>
       
    20 #include <cntitem.h>
       
    21 #include <cntfield.h>
       
    22 #include <cntfldst.h>
       
    23 #include "t_utils.h"
       
    24 #include "t_utils2.h"
       
    25 
       
    26 RFs fs;
       
    27 CCntTest* CntTest=NULL;
       
    28 #define xtest(x) TestErr(x,__LINE__)
       
    29 
       
    30 _LIT(KDataBaseName, "c:T_MultReq.cdb");
       
    31 
       
    32 const TInt KDeleteGranularity=16;	// Must be kept in step with KDeleteTransactionGranularity in CNTDB.CPP
       
    33 
       
    34 struct TUpdatingResults
       
    35 	{
       
    36 public:
       
    37 	TUpdatingResults();
       
    38 	void ProcessErrorL(TInt aError);
       
    39 	void ProcessErrorL(TInt aError, TUpdatingResults &aMoreResults);
       
    40 	void PrintResults(const TDesC &aTitle) const;
       
    41 	void AppendResults(TDes &aBuf) const;
       
    42 public:
       
    43 	TInt iTotalCount;
       
    44 	TInt iLockedCount;
       
    45 	TInt iNotFoundCount;
       
    46 	TInt iModifiedErr;
       
    47 	};
       
    48 
       
    49 struct SDbmsErrParams
       
    50 	{
       
    51 	inline SDbmsErrParams(TBool *aRemoteThreadFinished,TUpdatingResults *aResults) : iRemoteThreadFinished(aRemoteThreadFinished),iResults(aResults) {};
       
    52 	TBool *iRemoteThreadFinished;
       
    53 	TUpdatingResults *iResults;
       
    54 	};
       
    55 
       
    56 LOCAL_D RTest test(_L("T_MULTS"));
       
    57 LOCAL_D CContactDatabase* TheDb1;
       
    58 LOCAL_D CContactDatabase* TheDb2;
       
    59 LOCAL_D CArrayFix<TContactItemId>* TheIds;
       
    60 void DoDEF022709TestL();
       
    61 
       
    62 const TPtrC KDatabaseFileName=_L("C:T_MULTS");
       
    63 
       
    64 // Note long names needed to push record size of 255 bytes to trigger problems with DBMS locking
       
    65 const TPtrC KTestName1=_L("Test Name No%d, plus some padding to make the data over 255 bytes, 0123456789, 0123456789, 0123456789, 0123456789");
       
    66 const TPtrC KTestName2=_L("Test Name 2 No%d, plus some padding to make the data over 255 bytes, 0123456789, 0123456789, 0123456789, 0123456789");
       
    67 const TPtrC KTestName3=_L("Test Name 3 No%d, plus some padding to make the data over 255 bytes, 0123456789, 0123456789, 0123456789, 0123456789");
       
    68 const TInt KTotalNumRecords=20;
       
    69 
       
    70 struct TOpenBaseParams
       
    71 	{
       
    72 	TFileName iDbName;
       
    73 	TInt iParam1;
       
    74 	TInt iParam2;
       
    75 	};
       
    76 
       
    77 enum TTestFuncs
       
    78 	{
       
    79 	EThreadFuncHoldOpenForAWhile,
       
    80 	EThreadFuncHoldOpenForever,
       
    81 	EThreadFuncHoldOpenRangeForAWhile,
       
    82 	EThreadFuncHoldOpenRangeForever,
       
    83 	EThreadFuncKeepUpdatingContacts,
       
    84 	};
       
    85 
       
    86 enum TThreadFuncs
       
    87 	{
       
    88 	EFuncOpenContact,
       
    89 	EFuncDeleteContact,
       
    90 	EFuncKeepReadingContacts,
       
    91 	};
       
    92 
       
    93 class CFred2 : public CBase
       
    94 	{
       
    95 public:
       
    96 	~CFred2();
       
    97 	void ConstructL(TInt aFunc, const TDesC8 &aParams);
       
    98 	inline TInt Func() {return(iFunc);};
       
    99 	inline const HBufC8 *Params() {return(iParams);};
       
   100 	void WaitForLogon();
       
   101 	void Kill();
       
   102 // Other thread funcs
       
   103 	void DoTestL();
       
   104 protected:
       
   105 	void OpenDbEtcL();
       
   106 	void RunTestL();
       
   107 	void CloseDbEtcL();
       
   108 	void KeepUpdatingContactsL(TInt aNumTimesToLoop,SDbmsErrParams *aResults);
       
   109 protected:
       
   110 	CContactDatabase* iDb;
       
   111 	TInt iFunc;
       
   112 	HBufC8* iParams;
       
   113 	RThread iThread;
       
   114 	TRequestStatus iLogonStatus;
       
   115 	};
       
   116 
       
   117 class CNotificationRec : public CBase, public MContactDbObserver
       
   118 	{
       
   119 public:
       
   120 	static CNotificationRec* NewLC();
       
   121 	~CNotificationRec();
       
   122 	void Wait(TContactItemId aTestId, TContactDbObserverEventType aEventType, const CContactDatabase* aDatabase);
       
   123 	static TInt TimerCallBackL(TAny* aSelf);
       
   124 	void Purge();
       
   125 public: // from MContactDbObserver
       
   126 	void HandleDatabaseEventL(TContactDbObserverEvent aEvent);
       
   127 private:
       
   128 	void ConstructL();
       
   129 private:
       
   130 	CPeriodic* iTimer;
       
   131 	TBool iWaiting;
       
   132 	TContactItemId iTestId;
       
   133 	TUint iConnectionId;
       
   134 	TContactDbObserverEventType iEventType;
       
   135 	};
       
   136 
       
   137 //
       
   138 // TUpdatingResults
       
   139 //
       
   140 
       
   141 TUpdatingResults::TUpdatingResults()
       
   142 	{
       
   143 	iTotalCount=0;
       
   144 	iLockedCount=0;
       
   145 	iNotFoundCount=0;
       
   146 	iModifiedErr=0;
       
   147 	}
       
   148 
       
   149 void TUpdatingResults::ProcessErrorL(TInt aError)
       
   150 	{
       
   151 	if (aError==KErrLocked)
       
   152 		iLockedCount++;
       
   153 	else if (aError==KErrNotFound)
       
   154 		iNotFoundCount++;
       
   155 	else if (aError==KErrCommsLineFail)
       
   156 		iModifiedErr++;
       
   157 	else
       
   158 		User::LeaveIfError(aError);
       
   159 	iTotalCount++;
       
   160 	}
       
   161 
       
   162 void TUpdatingResults::ProcessErrorL(TInt aError, TUpdatingResults &aMoreResults)
       
   163 	{
       
   164 	ProcessErrorL(aError);
       
   165 	aMoreResults.ProcessErrorL(aError);
       
   166 	}
       
   167 
       
   168 void TUpdatingResults::PrintResults(const TDesC &aTitle) const
       
   169 	{
       
   170 	test.Printf(aTitle);
       
   171 	test.Printf(_L("-Locked/Not Found/Debug/Total[1] %d/%d/%d/%d\n"),iLockedCount,iNotFoundCount,iModifiedErr,iTotalCount);
       
   172 	}
       
   173 
       
   174 void TUpdatingResults::AppendResults(TDes &aBuf) const
       
   175 	{
       
   176 	aBuf.AppendFormat(_L("%d/%d/%d/%d"),iLockedCount,iNotFoundCount,iModifiedErr,iTotalCount);
       
   177 	}
       
   178 
       
   179 //
       
   180 
       
   181 LOCAL_C CFred2 *LaunchFred2L(TInt aFunc, const TDesC8 &aParams)
       
   182 	{
       
   183 	CFred2 *fred2=new(ELeave) CFred2;
       
   184 	fred2->ConstructL(aFunc, aParams);
       
   185 	return(fred2);
       
   186 	}
       
   187 
       
   188 CNotificationRec* CNotificationRec::NewLC()
       
   189 	{ // static
       
   190 	CNotificationRec* self=new(ELeave) CNotificationRec;
       
   191 	CleanupStack::PushL(self);
       
   192 	self->ConstructL();
       
   193 	return self;
       
   194 	}
       
   195 
       
   196 CNotificationRec::~CNotificationRec()
       
   197 	{
       
   198 	delete iTimer;
       
   199 	}
       
   200 
       
   201 void CNotificationRec::ConstructL()
       
   202 	{
       
   203 	iTimer=CPeriodic::NewL(0);
       
   204 	}
       
   205 
       
   206 void CNotificationRec::Wait(TContactItemId aTestId, TContactDbObserverEventType aEventType, const CContactDatabase* aDatabase)
       
   207 	{
       
   208 	iWaiting=ETrue;
       
   209 	iTestId=aTestId;
       
   210 	iEventType=aEventType;
       
   211 	iConnectionId=aDatabase->ConnectionId();
       
   212 	iTimer->Start(5000000,5000000,TCallBack(TimerCallBackL,NULL)); // wait for 5 seconds for notification
       
   213 	CActiveScheduler::Start();
       
   214 	}
       
   215 
       
   216 void CNotificationRec::Purge()
       
   217 	{
       
   218 	iWaiting=EFalse;
       
   219 	iTimer->Start(2000000,2000000,TCallBack(TimerCallBackL,this)); // wait for 2 seconds for notification
       
   220 	CActiveScheduler::Start();
       
   221 	}
       
   222 
       
   223 TInt CNotificationRec::TimerCallBackL(TAny* aSelf)
       
   224 	{ // static
       
   225 	// if this gets called, notification hasn't happened
       
   226 	if (((CNotificationRec*)aSelf)->iWaiting)
       
   227 		User::Leave(KErrGeneral);
       
   228 	else
       
   229 		{
       
   230 		((CNotificationRec*)aSelf)->iTimer->Cancel();
       
   231 		CActiveScheduler::Stop();
       
   232 		}
       
   233 	return 0;
       
   234 	}
       
   235 
       
   236 void CNotificationRec::HandleDatabaseEventL(TContactDbObserverEvent aEvent)
       
   237 	{
       
   238 	if (!iWaiting || aEvent.iType==EContactDbObserverEventRollback)
       
   239 		return;
       
   240 	if (iEventType!=EContactDbObserverEventUnknownChanges)
       
   241 		test(aEvent.iContactId==iTestId);
       
   242 	test(iEventType==aEvent.iType);
       
   243 	switch(iEventType)
       
   244 		{
       
   245 		case EContactDbObserverEventRecover:
       
   246 		case EContactDbObserverEventTablesClosed:
       
   247 		case EContactDbObserverEventTablesOpened:
       
   248 			test(aEvent.iConnectionId==0);
       
   249 			break;
       
   250 		default:
       
   251 			test(iConnectionId==aEvent.iConnectionId);
       
   252 			break;
       
   253 		}
       
   254 	iWaiting=EFalse;
       
   255 	iTimer->Cancel();
       
   256 	CActiveScheduler::Stop();
       
   257 	}
       
   258 
       
   259 
       
   260 LOCAL_C void PopulateDatabaseL()
       
   261 //
       
   262 // Create and populate the database
       
   263 //
       
   264 	{
       
   265 	TheIds=new(ELeave) CArrayFixFlat<TContactItemId>(5);
       
   266 	CContactDatabase* db=CntTest->CreateDatabaseL();
       
   267 	CntTest->DeleteAllTemplateFieldsL();
       
   268 	TContactItemId id;
       
   269 	for (TInt ii=0;ii<KTotalNumRecords;ii++)
       
   270 		{
       
   271 		CContactItem* item=CContactCard::NewLC();
       
   272 		TBuf<256> name;
       
   273 		name.Format(KTestName1,ii);
       
   274 		SetNameL(*item,KUidContactFieldCompanyName,KUidContactFieldVCardMapUnusedN,name,ETrue);
       
   275 		name.Format(KTestName2,ii);
       
   276 		SetNameL(*item,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,name,ETrue);
       
   277 		name.Format(KTestName3,ii);
       
   278 		SetNameL(*item,KUidContactFieldGivenName,KUidContactFieldVCardMapUnusedN,name,ETrue);
       
   279 		id=db->AddNewContactL(*item);
       
   280 		TheIds->AppendL(id);
       
   281 		CleanupStack::PopAndDestroy(); // item
       
   282 		}
       
   283 	CntTest->CloseDatabase();
       
   284 	}
       
   285 	
       
   286 LOCAL_C TPtrC Name(CContactItem& aItem,TUid aType)
       
   287 	{
       
   288 	CContactItemFieldSet& fieldSet=aItem.CardFields();
       
   289 	const TInt pos=fieldSet.Find(aType);
       
   290 	if (pos==KErrNotFound)
       
   291 		return _L("");
       
   292 	return fieldSet[pos].TextStorage()->Text();
       
   293 	}
       
   294 
       
   295 LOCAL_C void ReadL()
       
   296 //
       
   297 // Access the database with two clients running in the same thread
       
   298 //
       
   299 	{
       
   300 	CContactItem* item1=NULL;
       
   301 	CContactItem* item2=NULL;
       
   302 	for (TInt ii=0;ii<KTotalNumRecords;ii++)
       
   303 		{
       
   304 		TContactItemId id=(*TheIds)[ii];
       
   305 		item1=TheDb1->ReadContactLC(id);
       
   306 		item2=TheDb2->ReadContactLC(id);
       
   307 		test(Name(*item1,KUidContactFieldCompanyName)==Name(*item2,KUidContactFieldCompanyName));
       
   308 		TBuf<256> testName;
       
   309 		testName.Format(KTestName1,ii);
       
   310 		test(Name(*item1,KUidContactFieldCompanyName)==testName);
       
   311 		CleanupStack::PopAndDestroy(2); // item2, item1
       
   312 		}
       
   313 	}
       
   314 
       
   315 LOCAL_C void EditL()
       
   316 	{
       
   317 	CContactItem* item1=NULL;
       
   318 	CContactItem* item2=NULL;
       
   319 	for (TInt ii=0;ii<KTotalNumRecords;ii++)
       
   320 		{
       
   321 		TContactItemId id=(*TheIds)[ii];
       
   322 		// edit items in db1
       
   323 		item1=TheDb1->OpenContactL(id);
       
   324 		CleanupStack::PushL(item1);
       
   325 		SetNameL(*item1,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,_L("Family"),EFalse);
       
   326 		TheDb1->CommitContactL(*item1);
       
   327 		CleanupStack::PopAndDestroy(); // item1
       
   328 		// test db2 picks up changes and re-edit items
       
   329 		item2=TheDb2->OpenContactL(id);
       
   330 		CleanupStack::PushL(item2);
       
   331 		test(Name(*item2,KUidContactFieldFamilyName)==_L("Family"));
       
   332 		SetNameL(*item2,KUidContactFieldGivenName,KUidContactFieldVCardMapUnusedN,_L(""),EFalse);
       
   333 		TheDb2->CommitContactL(*item2);
       
   334 		CleanupStack::PopAndDestroy(); // item2
       
   335 		// check db1 notices changes
       
   336 		item1=TheDb1->ReadContactL(id);
       
   337 		test(Name(*item1,KUidContactFieldGivenName)==_L(""));
       
   338 		delete item1;
       
   339 		}
       
   340 	// test each one can lock records
       
   341 	TContactItemId id=(*TheIds)[0];
       
   342 	item1=TheDb1->OpenContactL(id);
       
   343 	CleanupStack::PushL(item1);
       
   344 	TRAPD(err,TheDb2->OpenContactL(id));
       
   345 	test(err==KErrInUse);
       
   346 	TheDb1->CloseContactL(id);
       
   347 	CleanupStack::PopAndDestroy(); // item1
       
   348 
       
   349 	item2=TheDb2->OpenContactL(id);
       
   350 	CleanupStack::PushL(item2);
       
   351 	TRAP(err,TheDb1->OpenContactL(id));
       
   352 	test(err==KErrInUse);
       
   353 	TheDb2->CloseContactL(id);
       
   354 	CleanupStack::PopAndDestroy(); // item2
       
   355 	}
       
   356 
       
   357 LOCAL_C void AddL()
       
   358 	{
       
   359 	CContactItem* item=CContactCard::NewLC();
       
   360 	TContactItemId id1=TheDb1->AddNewContactL(*item);
       
   361 	TContactItemId id2=TheDb2->AddNewContactL(*item);
       
   362 	CleanupStack::PopAndDestroy(); // item
       
   363 	delete TheDb1->ReadContactL(id2);
       
   364 	delete TheDb2->ReadContactL(id1);
       
   365 	TheDb1->DeleteContactL(id2);
       
   366 	TheDb2->DeleteContactL(id1);
       
   367 	}
       
   368 
       
   369 LOCAL_C void TouchContactL(CContactDatabase* aDb, TContactItemId aId)
       
   370 	{
       
   371 	CContactItem* item=aDb->OpenContactL(aId);
       
   372 	SetNameL(*item,KUidContactFieldGivenName,KUidContactFieldVCardMapUnusedN,_L(""),EFalse);
       
   373 	aDb->CommitContactL(*item);
       
   374 	delete item;
       
   375 	}
       
   376 
       
   377 LOCAL_C void AdjustContactAccessCountL(CContactDatabase* aDb, TContactItemId aItemId, TInt aCount)
       
   378 	{
       
   379 	CContactItem *incItem=aDb->OpenContactLX(aItemId);
       
   380 	CleanupStack::PushL(incItem);
       
   381 	while(aCount>0)
       
   382 		{
       
   383 		incItem->IncAccessCount();
       
   384 		aCount--;
       
   385 		}
       
   386 	while(aCount<0)
       
   387 		{
       
   388 		incItem->DecAccessCount();
       
   389 		aCount++;
       
   390 		}
       
   391 	aDb->CommitContactL(*incItem);
       
   392 	CleanupStack::PopAndDestroy(2);	// incItem, Close(incItem)
       
   393 	}
       
   394 
       
   395 LOCAL_C void WaitAndCheckEvent(CNotificationRec* aRec1,CNotificationRec* aRec2,TContactItemId aTestId, TContactDbObserverEventType aEventType, const CContactDatabase* aDatabase)
       
   396 	{
       
   397 	aRec1->Wait(aTestId,aEventType,aDatabase);
       
   398 	if (aRec2)
       
   399 		aRec2->Wait(aTestId,aEventType,aDatabase);
       
   400 	}
       
   401 
       
   402 LOCAL_C void SetSortOrderL(CContactDatabase* aDb, TFieldType aFieldType)
       
   403 	{
       
   404 	CArrayFix<CContactDatabase::TSortPref>* sortOrder=new(ELeave) CArrayFixFlat<CContactDatabase::TSortPref>(3);
       
   405 	CleanupStack::PushL(sortOrder);
       
   406 	sortOrder->AppendL(CContactDatabase::TSortPref(aFieldType,CContactDatabase::TSortPref::EAsc));
       
   407 	aDb->SortL(sortOrder);
       
   408 	CleanupStack::Pop();	// sortOrder
       
   409 	}
       
   410 
       
   411 LOCAL_C void TestDeleteContactsErrorL(CContactDatabase* aDb, CContactDatabase* aDb2, CNotificationRec* aRec, CNotificationRec* aRec2, TInt aErrorPos, TBool aChangedMessage)
       
   412 	{
       
   413 	aRec2->Purge();
       
   414 	SetSortOrderL(aDb,KUidContactFieldGivenName);
       
   415 	CContactIdArray *deleteIds=CContactIdArray::NewLC();
       
   416 	CContactItem *openItem=NULL;
       
   417 	TInt startCount=aDb->SortedItemsL()->Count();
       
   418 	TInt startCount2=aDb2->SortedItemsL()->Count();
       
   419 	for(TInt loop=0;loop<(aErrorPos+10);loop++)
       
   420 		{
       
   421 		TContactItemId add=AddContactL(aDb,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,_L("Add1"));
       
   422 		deleteIds->AddL(add);
       
   423 		aRec->Wait(add,EContactDbObserverEventContactAdded,aDb);
       
   424 		aRec2->Wait(add,EContactDbObserverEventContactAdded,aDb);
       
   425 		if (loop==aErrorPos)
       
   426 			{
       
   427 			openItem=aDb2->OpenContactLX(add);
       
   428 			CleanupStack::PushL(openItem);
       
   429 			}
       
   430 		TInt db2Count=aDb2->SortedItemsL()->Count();
       
   431 		test(db2Count==(startCount2+loop+1));
       
   432 		}
       
   433 	test(openItem!=NULL);
       
   434 	TRAPD(delErr,aDb->DeleteContactsL(*deleteIds));
       
   435 	test(delErr==KErrInUse);
       
   436 	User::After(500000);	// Let rollback event arrive
       
   437 	if (aChangedMessage)
       
   438 		aRec->Wait(0,EContactDbObserverEventUnknownChanges,aDb);
       
   439 //
       
   440 	CleanupStack::PopAndDestroy(3); // deleteIds, openItem, openItem->Close()
       
   441 //
       
   442 	aDb2->RecoverL();
       
   443 //
       
   444 	if (aChangedMessage)
       
   445 		{
       
   446 		aRec->Wait(0,EContactDbObserverEventTablesClosed,aDb);
       
   447 //		aRec->Wait(0,EContactDbObserverEventUnknownChanges,aDb);
       
   448 		}
       
   449 //
       
   450 	aDb->OpenTablesL();
       
   451 	aRec->Purge();
       
   452 	aRec2->Purge();
       
   453 	SetSortOrderL(aDb,KUidContactFieldFamilyName);
       
   454 	TInt db1Count=aDb->SortedItemsL()->Count();
       
   455 	TInt db2Count=aDb2->SortedItemsL()->Count();
       
   456 	test(db1Count==db2Count);
       
   457 	if (aChangedMessage)
       
   458 		test(db1Count==(startCount+10+aErrorPos-KDeleteGranularity));
       
   459 	else
       
   460 		test(db1Count==(startCount+10+aErrorPos));
       
   461 //
       
   462 	deleteIds=CContactIdArray::NewLC(aDb->SortedItemsL());
       
   463 	aDb->DeleteContactsL(*deleteIds);
       
   464 	aRec->Wait(0,EContactDbObserverEventUnknownChanges,aDb);
       
   465 	CleanupStack::PopAndDestroy(); // deleteIds
       
   466 	}
       
   467 
       
   468 LOCAL_C void WaitForNotificationL()
       
   469 	{
       
   470 	CNotificationRec* rec1=CNotificationRec::NewLC();
       
   471 	CNotificationRec* rec2=CNotificationRec::NewLC();
       
   472 	CContactDatabase* db1=CContactDatabase::OpenL(CntTest->DatabaseName());
       
   473 	CleanupStack::PushL(db1);
       
   474 	CContactChangeNotifier *notify1=CContactChangeNotifier::NewL(*db1,rec1);
       
   475 	CleanupStack::PushL(notify1);
       
   476 	CContactDatabase* db2=CContactDatabase::OpenL(CntTest->DatabaseName());
       
   477 	CleanupStack::PushL(db2);
       
   478 	CContactChangeNotifier *notify2=CContactChangeNotifier::NewL(*db2,rec2);
       
   479 	CleanupStack::PushL(notify2);
       
   480 	TContactItemId touchId=(*TheIds)[0];
       
   481 	TouchContactL(db1,touchId);
       
   482 	WaitAndCheckEvent(rec1,rec2,touchId,EContactDbObserverEventContactChanged,db1); // shouldn't return until the change is notified
       
   483 //
       
   484 	touchId=(*TheIds)[1];
       
   485 	TouchContactL(db2,touchId);
       
   486 	WaitAndCheckEvent(rec1,rec2,touchId,EContactDbObserverEventContactChanged,db2);
       
   487 //
       
   488 	TouchContactL(db2,(*TheIds)[0]);
       
   489 	TouchContactL(db2,(*TheIds)[1]);
       
   490 	TouchContactL(db2,(*TheIds)[2]);
       
   491 	db2->DeleteContactL((*TheIds)[1]);
       
   492 	TouchContactL(db2,(*TheIds)[3]);
       
   493 	TouchContactL(db2,(*TheIds)[0]);
       
   494 // zzz Beef up test code to have a queue of expected events and read rec & rec2 in parallel
       
   495 	WaitAndCheckEvent(rec1,NULL,(*TheIds)[0],EContactDbObserverEventContactChanged,db2);
       
   496 	WaitAndCheckEvent(rec1,NULL,(*TheIds)[1],EContactDbObserverEventContactChanged,db2);
       
   497 	WaitAndCheckEvent(rec1,NULL,(*TheIds)[2],EContactDbObserverEventContactChanged,db2);
       
   498 	WaitAndCheckEvent(rec1,NULL,(*TheIds)[1],EContactDbObserverEventContactDeleted,db2);
       
   499 	WaitAndCheckEvent(rec1,NULL,(*TheIds)[3],EContactDbObserverEventContactChanged,db2);
       
   500 	WaitAndCheckEvent(rec1,NULL,(*TheIds)[0],EContactDbObserverEventContactChanged,db2);
       
   501 //
       
   502 	AdjustContactAccessCountL(db2,(*TheIds)[2],1);
       
   503 	rec1->Wait((*TheIds)[2],EContactDbObserverEventContactChanged,db2);
       
   504 	db2->DeleteContactL((*TheIds)[2]);
       
   505 	rec1->Wait((*TheIds)[2],EContactDbObserverEventContactDeleted,db2);
       
   506 	AdjustContactAccessCountL(db2,(*TheIds)[2],-1);
       
   507 	TouchContactL(db2,(*TheIds)[0]);
       
   508 	rec1->Wait((*TheIds)[0],EContactDbObserverEventContactChanged,db2);
       
   509 //
       
   510 	TContactItemId add1=AddContactL(db1,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,_L("Add1"));
       
   511 	TContactItemId add2=AddContactL(db2,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,_L("Add2"));
       
   512 	TContactItemId add3=AddContactL(db1,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,_L("Add3"));
       
   513 	rec1->Wait(add1,EContactDbObserverEventContactAdded,db1);
       
   514 	rec1->Wait(add2,EContactDbObserverEventContactAdded,db2);
       
   515 	rec1->Wait(add3,EContactDbObserverEventContactAdded,db1);
       
   516 //
       
   517 	CContactIdArray* deleteIds=CContactIdArray::NewLC();
       
   518 	deleteIds->AddL(add2);
       
   519 	deleteIds->AddL(add1);
       
   520 	deleteIds->AddL(add3);
       
   521 	db1->DeleteContactsL(*deleteIds);
       
   522 	rec1->Wait(0,EContactDbObserverEventUnknownChanges,db1);
       
   523 	CleanupStack::PopAndDestroy(); // deleteIds
       
   524 //
       
   525 	TestDeleteContactsErrorL(db1,db2,rec1,rec2,KDeleteGranularity-4,EFalse);	// Count lower than delete granularity
       
   526 	TestDeleteContactsErrorL(db1,db2,rec1,rec2,KDeleteGranularity+4,ETrue);		// Count Higher than delete granularity
       
   527 //
       
   528 	CleanupStack::PopAndDestroy(6); // db2, db1, notify2, notify1, rec2, rec1
       
   529 	}
       
   530 
       
   531 void TestErr(TInt aErr,TInt aLineNum)
       
   532     {
       
   533 	if (aErr!=KErrNone)
       
   534 		{
       
   535 		test.Printf(_L("Error %d, line %d\n"),aErr,aLineNum);
       
   536 		test(EFalse);
       
   537 		}
       
   538 	}
       
   539 
       
   540 LOCAL_C void KeepReadingContactsL(TInt ,SDbmsErrParams *aParams)
       
   541 	{
       
   542 	const CContactIdArray* idarray=CContactIdArray::NewLC(TheDb1->SortedItemsL());
       
   543 	User::After(200000);	// Synch with other thread
       
   544 	while(!(*aParams->iRemoteThreadFinished))
       
   545 		{
       
   546 		for(TInt idIndex=idarray->Count();idIndex>0;)
       
   547 			{
       
   548 			CContactItem *readItem=NULL;
       
   549 			TContactItemId id=(*idarray)[--idIndex];
       
   550 			TRAPD(err,readItem=TheDb1->ReadContactL(id));
       
   551 			CleanupStack::PushL(readItem);
       
   552 			aParams->iResults->ProcessErrorL(err);
       
   553 			if (err==KErrLocked)
       
   554 				test.Printf(_L("*"));
       
   555 			else if (err==KErrNotFound)
       
   556 				test.Printf(_L("#"));
       
   557 			else if (err==KErrCommsLineFail)
       
   558 				test.Printf(_L("%"));
       
   559 			else
       
   560 				test.Printf(_L("."));
       
   561 			CleanupStack::PopAndDestroy();	// readItem
       
   562 			}
       
   563 		}
       
   564 	test.Printf(_L("\n"));
       
   565 	CleanupStack::PopAndDestroy();	// idArray
       
   566 	}
       
   567 
       
   568 LOCAL_C void MultiAccessTestL(TInt aFredFunc,TInt aFredParam1,TInt aFredParam2,TInt aFunc,TInt aParam1,TInt aParam2)
       
   569 	{
       
   570 	TOpenBaseParams params;
       
   571 	params.iDbName.Copy(CntTest->DatabaseName());
       
   572 	params.iParam1=aFredParam1;
       
   573 	params.iParam2=aFredParam2;
       
   574 	CFred2* fred2=LaunchFred2L(aFredFunc,TPtrC8((TUint8 *)&params,sizeof(params)));
       
   575 	User::After(600000);	// Let Fred2 get going
       
   576 //
       
   577 	switch(aFunc)
       
   578 		{
       
   579 		case EFuncOpenContact:
       
   580 			{
       
   581 			CContactItem *item=NULL;
       
   582 			TRAPD(openErr,item=TheDb1->OpenContactL((*TheIds)[aParam1]));
       
   583 			CleanupStack::PushL(item);
       
   584 			xtest(openErr);
       
   585 			TheDb1->CommitContactL(*item);
       
   586 			CleanupStack::PopAndDestroy();
       
   587 			}
       
   588 			break;
       
   589 		case EFuncDeleteContact:
       
   590 			TheDb1->DeleteContactL((*TheIds)[aParam1]);
       
   591 			break;
       
   592 		case EFuncKeepReadingContacts:
       
   593 			KeepReadingContactsL(aParam1,(SDbmsErrParams *)aParam2);
       
   594 			break;
       
   595 		}
       
   596 //
       
   597 	if (aFredFunc==EThreadFuncHoldOpenForever || aFredFunc==EThreadFuncHoldOpenRangeForever)
       
   598 		fred2->Kill();
       
   599 	fred2->WaitForLogon();
       
   600 	delete fred2;
       
   601 	User::After(400000);	// Let Fred2 shutdown properly
       
   602 	}
       
   603 
       
   604 /**
       
   605 
       
   606 @SYMTestCaseID     PIM-T-MULTS-0001
       
   607 
       
   608 */
       
   609 
       
   610 LOCAL_C void MultiAccessTestL()
       
   611 	{
       
   612 	test.Start(_L("@SYMTestCaseID:PIM-T-MULTS-0001 Multi 1"));
       
   613 //
       
   614 	MultiAccessTestL(EThreadFuncHoldOpenForAWhile,1,0,EFuncOpenContact,1,0);
       
   615 	test.Next(_L("Multi 2"));
       
   616 	MultiAccessTestL(EThreadFuncHoldOpenForever,2,0,EFuncOpenContact,3,0);
       
   617 //
       
   618 	test.Next(_L("Multi 3"));
       
   619 	MultiAccessTestL(EThreadFuncHoldOpenRangeForAWhile,8,9,EFuncOpenContact,5,0);
       
   620 	test.Next(_L("Multi 4"));
       
   621 	MultiAccessTestL(EThreadFuncHoldOpenRangeForever,2,16,EFuncOpenContact,18,0);
       
   622 //
       
   623 	test.Next(_L("Multi 5"));
       
   624 	MultiAccessTestL(EThreadFuncHoldOpenForAWhile,1,0,EFuncDeleteContact,1,0);
       
   625 	test.Next(_L("Multi 6"));
       
   626 	MultiAccessTestL(EThreadFuncHoldOpenForever,0,0,EFuncDeleteContact,3,0);
       
   627 //
       
   628 	test.Next(_L("Multi 7"));
       
   629 	TUpdatingResults updateResults1;
       
   630 	TUpdatingResults updateResults2[4];
       
   631 	TBool remoteThreadFinished=EFalse;
       
   632 	SDbmsErrParams params1(&remoteThreadFinished,&updateResults1);
       
   633 	SDbmsErrParams params2(&remoteThreadFinished,&updateResults2[0]);
       
   634 	MultiAccessTestL(EThreadFuncKeepUpdatingContacts,5,(TInt)&params2,EFuncKeepReadingContacts,0,(TInt)&params1);
       
   635 	updateResults1.PrintResults(_L("Reading"));
       
   636 	updateResults2[0].PrintResults(_L("Open/Commit"));
       
   637 	updateResults2[1].PrintResults(_L("Export"));
       
   638 	updateResults2[2].PrintResults(_L("Import"));
       
   639 	updateResults2[3].PrintResults(_L("Delete"));
       
   640 //
       
   641 	test.End();
       
   642 	}
       
   643 
       
   644 void InitialiseDatabaseEtcL()
       
   645 	{
       
   646 	TRAPD(err,PopulateDatabaseL());
       
   647 	xtest(err);
       
   648 	TheDb1=CContactDatabase::OpenL(CntTest->DatabaseName());
       
   649 	TheDb2=CContactDatabase::OpenL(CntTest->DatabaseName());
       
   650 	}
       
   651 
       
   652 void DeleteDatabaseEtc()
       
   653 	{
       
   654 	delete TheDb1;
       
   655 	delete TheDb2;
       
   656 	delete TheIds;
       
   657 	TheDb1=NULL;
       
   658 	TheDb2=NULL;
       
   659 	TheIds=NULL;
       
   660 	}
       
   661 
       
   662 class RTestSession : public RSessionBase
       
   663 	{
       
   664 public:
       
   665 	TInt CreateSession();
       
   666 	};
       
   667 
       
   668 TInt RTestSession::CreateSession()
       
   669 	{
       
   670 	TVersion version;
       
   671 	return(RSessionBase::CreateSession(_L("CntLockServer"),version,1));
       
   672 	}
       
   673 
       
   674 void TestServerGoneL()
       
   675 	{
       
   676 	test(CntTest->LockServerProcessCount(ETrue,EFalse,ETrue)==0);
       
   677 	if (CntTest->LockServerSessionExists())
       
   678 		{
       
   679 		test.Printf(_L("Warning - Lock server still exists"));
       
   680 		test.Getch();
       
   681 		}
       
   682 	}
       
   683 
       
   684 void DoTestsL()
       
   685     {
       
   686 	User::LeaveIfError(fs.Connect());
       
   687 	CleanupClosePushL(fs);
       
   688 	CTestRegister* TempFiles = CTestRegister::NewLC();
       
   689 	TempFiles->RegisterL(KDataBaseName, EFileTypeCnt);
       
   690 	TempFiles->RegisterL(KDatabaseFileName, EFileTypeCnt);
       
   691 
       
   692 	CntTest->SelectDriveL();
       
   693 	test.Start(_L("Create new database"));
       
   694 	TInt err;
       
   695 //
       
   696 	TRAP(err,InitialiseDatabaseEtcL());
       
   697 	test.Next(_L("Wait for change notification"));
       
   698 	TRAP(err,WaitForNotificationL());
       
   699 	xtest(err);
       
   700 	DeleteDatabaseEtc();
       
   701 //
       
   702 	TRAP(err,InitialiseDatabaseEtcL());
       
   703 	xtest(err);
       
   704 	test.Next(_L("Lock tests"));
       
   705 	TRAP(err,MultiAccessTestL());
       
   706 	xtest(err);
       
   707 	DeleteDatabaseEtc();
       
   708 //
       
   709 	TRAP(err,InitialiseDatabaseEtcL());
       
   710 	xtest(err);
       
   711 	test.Next(_L("Read items"));
       
   712 	TRAP(err,ReadL());
       
   713 	xtest(err);
       
   714 	test.Next(_L("Edit items"));
       
   715 	TRAP(err,EditL());
       
   716 	xtest(err);
       
   717 	test.Next(_L("Add / delete items"));
       
   718 	TRAP(err,AddL());
       
   719 	xtest(err);
       
   720 	test.Next(_L("Wait for change notification"));
       
   721 	TRAP(err,WaitForNotificationL());
       
   722 	xtest(err);
       
   723 	DeleteDatabaseEtc();
       
   724 	TestServerGoneL();
       
   725 
       
   726 	// Now do test for DEF022709  (Propagated) Contact DB Monitoring Error Messages 
       
   727 	TRAP(err,DoDEF022709TestL());
       
   728 	xtest(err);
       
   729 
       
   730 	CleanupStack::PopAndDestroy(2); // TempFiles, close fs
       
   731     }
       
   732 
       
   733 LOCAL_C TInt FredIIFunc(TAny *aParam);
       
   734 
       
   735 GLDEF_C TInt E32Main()
       
   736 	{
       
   737     CntTest=new(ELeave) CCntTest;
       
   738 	CntTest->ConstructL(test,KDatabaseFileName);
       
   739 	TRAPD(err,DoTestsL());
       
   740 	CntTest->EndTestLib(err);
       
   741 	return KErrNone;
       
   742     }
       
   743 
       
   744 //
       
   745 // CFred2
       
   746 //
       
   747 
       
   748 CFred2::~CFred2()
       
   749 	{
       
   750 	iThread.Close();
       
   751 	delete iParams;
       
   752 	}
       
   753 
       
   754 void CFred2::ConstructL(TInt aFunc, const TDesC8 &aParams)
       
   755 	{
       
   756 	iFunc=aFunc;
       
   757 	iParams=aParams.AllocL();
       
   758 	User::LeaveIfError(iThread.Create(_L("FredII"),FredIIFunc,KDefaultStackSize,0x2000,0x20000,this,EOwnerThread));
       
   759 	iThread.Logon(iLogonStatus);
       
   760 	iThread.Resume();
       
   761 	}
       
   762 
       
   763 void CFred2::Kill()
       
   764 	{
       
   765 	iThread.Kill(0);
       
   766 	}
       
   767 
       
   768 void CFred2::WaitForLogon()
       
   769 	{
       
   770 	User::WaitForRequest(iLogonStatus);
       
   771 	xtest(iLogonStatus.Int());
       
   772 	}
       
   773 
       
   774 //
       
   775 // Fred II from here on
       
   776 // 
       
   777 
       
   778 LOCAL_C TInt FredIIFunc(TAny *aParam)
       
   779 	{
       
   780 	CActiveScheduler::Install(new(ELeave) CActiveScheduler);
       
   781     CTrapCleanup* cleanup=CTrapCleanup::New();
       
   782 	TRAPD(err,((CFred2 *)aParam)->DoTestL());
       
   783     delete cleanup;
       
   784 	delete CActiveScheduler::Current();
       
   785 	return(err);
       
   786 	}
       
   787 
       
   788 void CFred2::OpenDbEtcL()
       
   789 	{
       
   790 	switch(Func())
       
   791 		{
       
   792 		case EThreadFuncHoldOpenForAWhile:
       
   793 		case EThreadFuncHoldOpenForever:
       
   794 		case EThreadFuncHoldOpenRangeForAWhile:
       
   795 		case EThreadFuncHoldOpenRangeForever:
       
   796 		case EThreadFuncKeepUpdatingContacts:
       
   797 			iDb=CContactDatabase::OpenL(((TOpenBaseParams *)Params()->Ptr())->iDbName);
       
   798 			break;
       
   799 		}
       
   800 	}
       
   801 
       
   802 void CFred2::CloseDbEtcL()
       
   803 	{
       
   804 	delete iDb;
       
   805 	}
       
   806 
       
   807 void CFred2::KeepUpdatingContactsL(TInt aNumTimesToLoop,SDbmsErrParams *aParams)
       
   808 	{
       
   809 	TUpdatingResults *openResults=aParams->iResults;
       
   810 	TUpdatingResults *exportResults=aParams->iResults+1;
       
   811 	TUpdatingResults *importResults=aParams->iResults+2;
       
   812 	TUpdatingResults *deleteResults=aParams->iResults+3;
       
   813 	TUpdatingResults totalResults;
       
   814 	const CContactIdArray* idarray=CContactIdArray::NewLC(iDb->SortedItemsL());
       
   815 	for(TInt mode=0;mode<2;mode++)
       
   816 		{
       
   817 		for(TInt loop=0;loop<aNumTimesToLoop;loop++)
       
   818 			{
       
   819 			TInt err=KErrNone;
       
   820 			switch(mode)
       
   821 				{
       
   822 				case 0:
       
   823 					{
       
   824 					for(TInt idIndex=0;idIndex<idarray->Count();idIndex++)
       
   825 						{
       
   826 						CContactItem *openItem=NULL;
       
   827 						TContactItemId id=(*idarray)[idIndex];
       
   828 						TRAP(err,openItem=iDb->OpenContactL(id));
       
   829 						CleanupStack::PushL(openItem);
       
   830 						if (err==KErrNone)
       
   831 							{
       
   832 							TRAP(err,iDb->CommitContactL(*openItem));
       
   833 							iDb->CloseContactL(id);
       
   834 							}
       
   835 						CleanupStack::PopAndDestroy();	// openItem
       
   836 						openResults->ProcessErrorL(err,totalResults);
       
   837 						}
       
   838 					break;
       
   839 					}
       
   840 				case 1:
       
   841 					{
       
   842 					CVCardTestStore* store=NULL;
       
   843 					TRAP(err,store=ExportContactsL(iDb,idarray,CContactDatabase::EExcludeUid,KVCardStoreTypeBuf,NULL,1000));
       
   844 					exportResults->ProcessErrorL(err,totalResults);
       
   845 					if (err==KErrNone)
       
   846 						{
       
   847 						CleanupStack::PushL(store);
       
   848 						CArrayPtr<CContactItem>* items=NULL;
       
   849 						TRAP(err,items=ImportContactsL(iDb,store,CContactDatabase::EExcludeUid));
       
   850 						importResults->ProcessErrorL(err,totalResults);
       
   851 						if (err==KErrNone)
       
   852 							{
       
   853 							CleanupStack::PushL(TCleanupItem(CleanUpResetAndDestroy,items));
       
   854 							for(TInt delLoop=0;delLoop<items->Count();delLoop++)
       
   855 								{
       
   856 								TRAP(err,iDb->DeleteContactL((*items)[delLoop]->Id()));
       
   857 								deleteResults->ProcessErrorL(err,totalResults);
       
   858 								}
       
   859 							CleanupStack::PopAndDestroy();	// items
       
   860 							}
       
   861 						CleanupStack::PopAndDestroy();	// store
       
   862 						}
       
   863 					}
       
   864 					break;
       
   865 				}
       
   866 			TBuf<128> buf;
       
   867 			buf.Format(_L("M:%d,C:%d "),mode,loop);
       
   868 			totalResults.AppendResults(buf);
       
   869 			User::InfoPrint(buf);
       
   870 			}
       
   871 		}
       
   872 	CleanupStack::PopAndDestroy();	// idArray
       
   873 	*aParams->iRemoteThreadFinished=ETrue;
       
   874 	}
       
   875 
       
   876 void CFred2::RunTestL()
       
   877 	{
       
   878 	switch(Func())
       
   879 		{
       
   880 		case EThreadFuncHoldOpenForever:
       
   881 		case EThreadFuncHoldOpenForAWhile:
       
   882 			{
       
   883 			TContactItemId id=(*TheIds)[((TOpenBaseParams *)(Params()->Ptr()))->iParam1];
       
   884 			CContactItem *item=iDb->OpenContactL(id);
       
   885 			CleanupStack::PushL(item);
       
   886 			if (Func()==EThreadFuncHoldOpenForAWhile)
       
   887 				{
       
   888 				User::After(1000000);
       
   889 				iDb->CommitContactL(*item);
       
   890 				CleanupStack::PopAndDestroy(); // item
       
   891 				}
       
   892 			else
       
   893 				{
       
   894 				TRequestStatus request;
       
   895 				User::WaitForRequest(request);	// Wait forever
       
   896 				}
       
   897 			}
       
   898 			break;
       
   899 		case EThreadFuncHoldOpenRangeForAWhile:
       
   900 		case EThreadFuncHoldOpenRangeForever:
       
   901 			{
       
   902 			TInt start=((TOpenBaseParams *)(Params()->Ptr()))->iParam1;
       
   903 			TInt end=((TOpenBaseParams *)(Params()->Ptr()))->iParam2;
       
   904 			CContactItem *items[KTotalNumRecords];
       
   905 			for(TInt loop=start;loop<end;loop++)
       
   906 				{
       
   907 				TContactItemId id=(*TheIds)[loop];
       
   908 				items[loop]=iDb->OpenContactL(id);
       
   909 /*			Weird MARM Death
       
   910 			TRAPD(x,items[loop]=iDb->OpenContactL(id));
       
   911 			TBuf<32> buf;
       
   912 			buf.Format(_L("oc-%d"),x);
       
   913 			test.Printf(buf);*/
       
   914 				CleanupStack::PushL(items[loop]);
       
   915 				}
       
   916 			if (Func()==EThreadFuncHoldOpenRangeForAWhile)
       
   917 				{
       
   918 				User::After(100000);
       
   919 				for(TInt loop=start;loop<end;loop++)
       
   920 					iDb->CommitContactL(*items[loop]);
       
   921 				CleanupStack::PopAndDestroy(end-start);
       
   922 				}
       
   923 			else
       
   924 				{
       
   925 				TRequestStatus request;
       
   926 				User::WaitForRequest(request);	// Wait forever
       
   927 				}
       
   928 			}
       
   929 			break;
       
   930 		case EThreadFuncKeepUpdatingContacts:
       
   931 			{
       
   932 			TOpenBaseParams *params=(TOpenBaseParams *)(Params()->Ptr());
       
   933 			KeepUpdatingContactsL(params->iParam1,(SDbmsErrParams *)params->iParam2);
       
   934 			}
       
   935 			break;
       
   936 		}
       
   937 	}
       
   938 
       
   939 void CFred2::DoTestL()
       
   940 	{
       
   941 	OpenDbEtcL();
       
   942 	RunTestL();
       
   943 	CloseDbEtcL();
       
   944 	}
       
   945 
       
   946 //
       
   947 // Test code for DEF022709  (Propagated) Contact DB Monitoring Error Messages //
       
   948 //
       
   949 
       
   950 const TInt32	KNumContactsToAdd=50;
       
   951 // If there are many contacts, it is worth using the #define below.
       
   952 // This will compact the database when necessary.
       
   953 #define __KEEP_DB_SMALL__
       
   954 
       
   955 // CWaitForCompletion implementation
       
   956 class CWaitForCompletion : public CActive
       
   957 	{
       
   958 	public:
       
   959 		CWaitForCompletion() : CActive(EPriorityStandard)
       
   960 			{
       
   961 			CActiveScheduler::Add(this);
       
   962 			}
       
   963 		virtual ~CWaitForCompletion() {}
       
   964 
       
   965 		void Activate() { SetActive(); }
       
   966 		TRequestStatus& RequestStatus() { return iStatus; }
       
   967 	protected:
       
   968 		// From CActive
       
   969 		virtual void DoCancel() { ; }
       
   970 		virtual void RunL() { CActiveScheduler::Stop(); }
       
   971 	};
       
   972 
       
   973 class CTestMultipleRequests : public CBase
       
   974 	{
       
   975     public:
       
   976         static CTestMultipleRequests* NewLC(TRequestStatus& aRequest);
       
   977         void ConstructL(TRequestStatus& aRequest);
       
   978         TContactItemId CreateTestContactL(const TDesC& aFamilyName, TBool aWithPhoneNumber);
       
   979 		CTestMultipleRequests();
       
   980         ~CTestMultipleRequests();
       
   981 	    TBool Synchronize();
       
   982 		static TInt OnIdle(TAny* aObject);
       
   983 		TInt DoIdle();
       
   984 		void Complete();
       
   985 	private:
       
   986 //		CPbkContactEngine* iPbkEngine;
       
   987 		CContactDatabase* iContactDatabase;
       
   988 		CContactChangeNotifier* iContactChangeNotifier;
       
   989 		TBool iRepeat;
       
   990 		CContactIdArray* iContactDbIdArray;
       
   991 		CIdle* iIdleTask;
       
   992 		TInt iContactIdCount;
       
   993 		TInt iCount;
       
   994 		TInt iTimesThrough;
       
   995 		TRequestStatus* iClientRequest;
       
   996 		TBool iFinished;
       
   997 	};
       
   998 
       
   999 CTestMultipleRequests::CTestMultipleRequests()
       
  1000 	{
       
  1001 	}
       
  1002 
       
  1003 CTestMultipleRequests::~CTestMultipleRequests()
       
  1004 	{
       
  1005 //	delete iPbkEngine;
       
  1006     delete iContactChangeNotifier;
       
  1007     delete iContactDbIdArray;
       
  1008 	delete iIdleTask;
       
  1009 	delete iContactDatabase;
       
  1010 	}
       
  1011 
       
  1012 CTestMultipleRequests* CTestMultipleRequests::NewLC(TRequestStatus& aRequest)
       
  1013 	{
       
  1014 	CTestMultipleRequests* self=new(ELeave) CTestMultipleRequests();
       
  1015 	CleanupStack::PushL(self);
       
  1016 	self->ConstructL(aRequest);
       
  1017 	return self;
       
  1018 	}
       
  1019 
       
  1020 void CTestMultipleRequests::ConstructL(TRequestStatus& aRequest)
       
  1021 	{
       
  1022 	iCount = 0;
       
  1023     iTimesThrough = 0;
       
  1024     iIdleTask = CIdle::NewL(-20);
       
  1025     iRepeat = EFalse;
       
  1026 	iFinished=EFalse;
       
  1027 	iClientRequest=&aRequest;
       
  1028 	*iClientRequest=KRequestPending;
       
  1029 //    BaseConstructL();
       
  1030 //    iPbkEngine = CPbkContactEngine::NewL();
       
  1031 
       
  1032 //    iContactDatabase = CContactDatabase::CreateL(KDatabaseFileName);
       
  1033     iContactDatabase = CContactDatabase::ReplaceL(KDataBaseName);
       
  1034 
       
  1035 	CRandomContactGenerator* randomGenerator=CRandomContactGenerator::NewL();
       
  1036 	CleanupStack::PushL(randomGenerator);
       
  1037 	randomGenerator->SetDbL(*iContactDatabase);
       
  1038 	for (TInt i=0; i<KNumContactsToAdd; i++)
       
  1039 		randomGenerator->AddTypicalRandomContactL();
       
  1040 	CleanupStack::PopAndDestroy(randomGenerator);
       
  1041     
       
  1042 	const CContactIdArray* contactDbIdArray = iContactDatabase->SortedItemsL();
       
  1043     iContactDbIdArray = CContactIdArray::NewL(contactDbIdArray);
       
  1044     iContactIdCount = iContactDbIdArray->Count();
       
  1045 
       
  1046     User::After(15000000); // 15 seconds
       
  1047     iIdleTask->Start(TCallBack(OnIdle,this));            // sync the VoCoS and Contact DB using CIdle
       
  1048 	}
       
  1049 
       
  1050 TBool CTestMultipleRequests::Synchronize()
       
  1051 	{
       
  1052 
       
  1053 	if (iTimesThrough == 5)
       
  1054 		return EFalse;
       
  1055 	if (iCount == iContactIdCount)
       
  1056 		{
       
  1057 		iCount = 0;
       
  1058 		iTimesThrough++;
       
  1059 		}
       
  1060  	CContactItem* item = iContactDatabase->OpenContactLX((*iContactDbIdArray)[iCount]);
       
  1061 	CleanupStack::PushL(item);
       
  1062 	iContactDatabase->CommitContactL( *item ); 
       
  1063 	CleanupStack::PopAndDestroy(item);
       
  1064 	CleanupStack::PopAndDestroy(); // lock
       
  1065 #ifdef __KEEP_DB_SMALL__
       
  1066 	if (iContactDatabase->CompressRequired())
       
  1067 		iContactDatabase->CompactL(); // keep the database to a sensible size.
       
  1068 #endif
       
  1069 	iCount++;
       
  1070 	return ETrue;
       
  1071 	}
       
  1072 
       
  1073 
       
  1074 TInt CTestMultipleRequests::OnIdle(TAny* aObject)
       
  1075 	{
       
  1076 	TBool ret = ((CTestMultipleRequests*)aObject)->DoIdle();
       
  1077 	if (!ret)
       
  1078 		((CTestMultipleRequests*)aObject)->Complete();
       
  1079 	return ret;
       
  1080 	}
       
  1081 
       
  1082 TInt CTestMultipleRequests::DoIdle()
       
  1083 	{
       
  1084 	TBool ret=EFalse;
       
  1085 	if (!iFinished)
       
  1086 		{
       
  1087 		ret = Synchronize();
       
  1088 		if (!ret)
       
  1089 			{
       
  1090 			iFinished=ETrue;
       
  1091 			}
       
  1092 		}
       
  1093 	return ret;
       
  1094 	}
       
  1095 
       
  1096 void CTestMultipleRequests::Complete()
       
  1097 	{
       
  1098     if (iIdleTask)
       
  1099 		{
       
  1100         iIdleTask->Cancel();
       
  1101 		}
       
  1102 	User::RequestComplete(iClientRequest, KErrNone);
       
  1103 	}
       
  1104 
       
  1105 
       
  1106 void DoDEF022709TestL()
       
  1107 	{
       
  1108 	test.Start(_L("Test for defect DEF022709"));
       
  1109 
       
  1110 	// Create test resources
       
  1111 	CWaitForCompletion* transactionWait=new (ELeave)CWaitForCompletion();
       
  1112 	CleanupStack::PushL(transactionWait);
       
  1113 	CTestMultipleRequests* res = CTestMultipleRequests::NewLC(transactionWait->RequestStatus());
       
  1114 	transactionWait->Activate();
       
  1115 	CActiveScheduler::Start();
       
  1116 
       
  1117 	// Cleanup
       
  1118     CleanupStack::PopAndDestroy(res);
       
  1119 	CleanupStack::PopAndDestroy(transactionWait);
       
  1120 
       
  1121     test.End();
       
  1122 	}