phonebookengines_old/contactsmodel/tsrc/T_FERROR.CPP
changeset 40 b46a585f6909
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines_old/contactsmodel/tsrc/T_FERROR.CPP	Fri Jun 11 13:29:23 2010 +0300
@@ -0,0 +1,541 @@
+// Copyright (c) 1997-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 <e32math.h>
+#include <f32file.h>
+#include <s32file.h>
+#include <cntdb.h>
+#include <cntitem.h>
+#include <cntfield.h>
+#include <cntfldst.h>
+#include "T_UTILS.H"
+
+// Type definitions
+CCntTest* CntTest=NULL;
+LOCAL_D RTest test(_L("T_FERROR"));
+LOCAL_D RFile logFile;
+LOCAL_D RFile threadLogFile;
+
+const TPtrC KDatabaseFileName=_L("C:T_FERROR");
+const TPtrC KDatabaseRemoveableFileName=_L("D:T_FERROR2");
+
+const TPtrC KLogFileName=_L("C:\\T_FERROR.LOG");
+const TPtrC KThreadLogFileName=_L("C:\\T_FERROR2.LOG");
+const TInt KNumTestContacts=5;
+
+class CFred2 : public CBase
+	{
+public:
+	~CFred2();
+	void ConstructL();
+	void WaitForLogon();
+	void Kill();
+	void DoDamageL();
+protected:
+	RThread iThread;
+	TRequestStatus iLogonStatus;
+	};
+
+class CContactReadWriter : public CIdle, public MContactDbObserver
+	{
+public:
+	static CContactReadWriter *NewLC();
+	static TInt CallbackL(TAny *xThis);
+private:
+	TInt DoWorkL();
+	CContactReadWriter();
+	~CContactReadWriter();
+	void SetNameL(CContactItem& aItem,TUid aVcardType,const TDesC& aName);
+	TPtrC Name(CContactItem& aItem);
+	TBool AddNewContactsL();
+	TBool EditContactsL();
+	TBool DeleteContactsL();
+	void PrintRecovering() const;
+	void PrintErr(TInt aErr) const;
+public: // from MContactDbObserver
+	void HandleDatabaseEventL(TContactDbObserverEvent aEvent);
+private:
+	TBool iSuspendWork;
+	TInt iSubState;
+	TInt iState;
+	CContactDatabase* iDb;
+	CArrayFix<TContactItemId>* iIdList;
+	CContactChangeNotifier *iNotify;
+	};
+
+LOCAL_C void doWriteToLogL(RFile &aFile, const TDesC &aLog, TInt aParam, TInt aParam2)
+	{
+	TBuf<128> buf;
+	TTime time;
+	time.UniversalTime();
+	time.FormatL(buf,_L("%T:%S.%*C3-"));
+	TFileText textFile;
+	textFile.Set(aFile);
+	User::LeaveIfError(textFile.Write(buf));
+	buf.Format(aLog,aParam,aParam2);
+	User::LeaveIfError(textFile.Write(buf));
+	aFile.Flush();
+	}
+
+LOCAL_C void WriteToLogL(const TDesC &aLog, TInt aParam=0, TInt aParam2=0)
+	{
+	doWriteToLogL(logFile,aLog,aParam,aParam2);
+	}
+
+LOCAL_C void WriteToThreadLogL(const TDesC &aLog, TInt aParam=0, TInt aParam2=0)
+	{
+	doWriteToLogL(threadLogFile,aLog,aParam,aParam2);
+	}
+
+//
+// CContactReadWriter
+//
+
+void CContactReadWriter::HandleDatabaseEventL(TContactDbObserverEvent aEvent)
+	{
+	if (aEvent.iType==EContactDbObserverEventTablesClosed)
+		iSuspendWork=ETrue;
+	else if (aEvent.iType==EContactDbObserverEventTablesOpened)
+		iSuspendWork=EFalse;
+	else if (aEvent.iType==EContactDbObserverEventRollback)
+		{
+		PrintRecovering();
+		TRAP_IGNORE(iDb->RecoverL());
+		}
+	WriteToLogL(_L("Event(%d,%d)"),aEvent.iType,aEvent.iContactId);
+	}
+
+void CContactReadWriter::SetNameL(CContactItem& aItem,TUid aVcardType,const TDesC& aName)
+//
+// Set the contents of a text field, creating the field if required
+//
+	{
+	CContactItemFieldSet& fieldSet=aItem.CardFields();
+	const TInt pos=fieldSet.Find(KUidContactFieldFamilyName);
+	if (pos!=KErrNotFound)
+		fieldSet[pos].TextStorage()->SetTextL(aName);
+	else
+		{
+		CContactItemField* field=CContactItemField::NewLC(KStorageTypeText,KUidContactFieldFamilyName);
+		field->SetMapping(aVcardType);
+		field->TextStorage()->SetTextL(aName);
+		aItem.AddFieldL(*field);
+		CleanupStack::Pop(); // item
+		}
+	}
+
+TPtrC CContactReadWriter::Name(CContactItem& aItem)
+	{
+	CContactItemFieldSet& fieldSet=aItem.CardFields();
+	const TInt pos=fieldSet.Find(KUidContactFieldFamilyName);
+	if (pos==KErrNotFound)
+		return _L("");
+	return fieldSet[pos].TextStorage()->Text();
+	}
+
+TBool CContactReadWriter::AddNewContactsL()
+	{
+	CContactCard* card=CContactCard::NewL();
+	CleanupStack::PushL(card);
+	TBuf<16> name;
+	name.Format(_L("NAME #%d"),iSubState);
+	SetNameL(*card,KUidContactFieldVCardMapUnusedN,name);
+	CContactItemField* field=CContactItemField::NewLC(KStorageTypeText);
+	card->AddFieldL(*field);
+	CleanupStack::Pop(); // field
+	iIdList->AppendL(iDb->AddNewContactL(*card));
+	CleanupStack::PopAndDestroy(); // card
+	iSubState++;
+	return(iSubState==KNumTestContacts);
+	}
+
+TBool CContactReadWriter::EditContactsL()
+//
+// Check then edit contact names
+//
+	{
+	if (iSubState<KNumTestContacts)
+		{
+		const TInt index=(*iIdList)[iSubState];
+		CContactItem* item=iDb->OpenContactLX(index);
+		CleanupStack::PushL(item);
+		TBuf<16> name;
+		name.Format(_L("NAME #%d"),iSubState);
+		test(name==Name(*item));
+		name.Format(_L("NEW NAME #%d"),index);
+		SetNameL(*item,KUidContactFieldVCardMapUnusedN,name);
+		iDb->CommitContactL(*item);
+		CleanupStack::PopAndDestroy(); // item;
+		CleanupStack::Pop(); // Close from OpenContactLX
+		}
+	else if (iSubState<(2*KNumTestContacts))
+		{
+		const TInt index=(*iIdList)[iSubState-KNumTestContacts];
+		CContactItem* item=iDb->ReadContactL(index);
+		TBuf<16> name;
+		name.Format(_L("NEW NAME #%d"),index);
+		test(name==Name(*item));
+		delete item;
+		}
+	return(++iSubState==2*KNumTestContacts);
+	}
+
+TBool CContactReadWriter::DeleteContactsL()
+//
+// Delete all contacts
+//
+	{
+	if (iDb->CountL()==0)
+		return(ETrue);
+	iDb->DeleteContactL((*iDb->SortedItemsL())[0]);
+	return(EFalse);
+	}
+
+//
+
+CContactReadWriter::CContactReadWriter() : CIdle(CActive::EPriorityIdle)
+	{
+	}
+
+CContactReadWriter *CContactReadWriter::NewLC()
+	{
+	CContactReadWriter *rw=new(ELeave) CContactReadWriter();
+	CleanupStack::PushL(rw);
+	CActiveScheduler::Add(rw);
+	rw->Start(TCallBack(CContactReadWriter::CallbackL,rw));
+	return(rw);
+	}
+
+CContactReadWriter::~CContactReadWriter()
+	{
+	delete iNotify;
+	delete iIdList;
+	delete iDb;
+	}
+
+TInt CContactReadWriter::DoWorkL()
+	{
+	if (iSuspendWork)
+		{
+		WriteToLogL(_L("Suspended"));
+		User::After(100000);
+		return(ETrue);
+		}
+	WriteToLogL(_L("DoWork(%d,%d)"),iState,iSubState);
+	TBool moveToNextState=ETrue;
+	switch(iState)
+		{
+		case 0:
+			test(iDb==NULL);
+			User::After(200000);	// Increase the chance of a damage hit here
+			iDb=CContactDatabase::OpenL(KDatabaseFileName);
+			while(iDb->IsDamaged())
+				{
+				WriteToLogL(_L("Recovering"));
+				TRAP_IGNORE(iDb->RecoverL());
+				}
+			iNotify=CContactChangeNotifier::NewL(*iDb,this);
+			iIdList=new(ELeave) CArrayFixFlat<TContactItemId>(5);
+			break;
+		case 1:
+			moveToNextState=AddNewContactsL();
+			break;
+		case 2:
+			moveToNextState=EditContactsL();
+			break;
+		case 3:
+			moveToNextState=DeleteContactsL();
+			break;
+		case 4:
+			CActiveScheduler::Stop();
+			return(EFalse);
+		}
+	if (moveToNextState)
+		{
+		iState++;
+		iSubState=0;
+		}
+	return(ETrue);
+	}
+
+void CContactReadWriter::PrintRecovering() const
+	{
+	test.Printf(_L("Recovering:"));
+	}
+
+void CContactReadWriter::PrintErr(TInt aErr) const
+	{
+	TBuf<64> errText;
+	errText.Format(_L("Err %d:"),aErr);
+	test.Printf(errText);
+	}
+
+TInt CContactReadWriter::CallbackL(TAny *aThis)
+	{
+	CContactReadWriter *xthis=(CContactReadWriter *)aThis;
+	TInt ret=ETrue;
+	TRAPD(err,ret=xthis->DoWorkL());
+	if (err!=KErrNone)
+		{
+		xthis->PrintErr(err);
+/*		if (xthis->iDb)
+			{
+			TRAP_IGNORE(xthis->iDb->RecoverL());
+			}*/
+		}
+	return(ret);
+	}
+
+//
+
+LOCAL_C void CreateDatabaseL()
+//
+// Create a database in a store
+//
+	{
+	CntTest->CreateDatabaseL();
+	CntTest->DeleteAllTemplateFieldsL();
+	CntTest->CloseDatabase();
+	}
+	
+void TestLoop(TInt aNumLoops)
+    {
+	CFred2 *fred2=new(ELeave) CFred2;
+	CleanupStack::PushL(fred2);
+	fred2->ConstructL();
+	for(TInt loop=0;loop<aNumLoops;loop++)
+		{
+		CContactReadWriter::NewLC();
+		CActiveScheduler::Start();
+		CleanupStack::PopAndDestroy();	// CContactReadWriter
+		test.Printf(_L("."));
+		}
+	test.Printf(_L("\n"));
+	CleanupStack::PopAndDestroy();	// fred2
+	}
+
+LOCAL_C void DriveErrMsg()
+	{
+	test.Printf(_L("Error: For this test to run properly "));
+#if defined(__WINS__)
+	test.Printf(_L("_EPOC_DRIVE_D must be set up as a removable drive for this test\n"));
+#else
+	test.Printf(_L("a removable/writable D: must exist\n"));
+#endif
+	test.Getch();
+	}
+
+void RemovePackTestL()
+	{
+	RFs fs;
+	test(fs.Connect()==KErrNone);
+//
+	TDriveInfo driveInfo;
+	if (fs.Drive(driveInfo,EDriveD)!=KErrNone || driveInfo.iType==EMediaNotPresent || driveInfo.iMediaAtt&KMediaAttWriteProtected)
+		DriveErrMsg();
+	else
+		{
+		TInt err=fs.MkDirAll(_L("D:\\___t___\\"));
+		if (err!=KErrNone)
+			DriveErrMsg();
+		else
+			{
+			fs.RmDir(_L("D:\\___t___\\"));
+			CContactDatabase *remDb=CContactDatabase::ReplaceL(KDatabaseRemoveableFileName);
+			CleanupStack::PushL(remDb);
+			test.Printf(_L("Remove pack and press a key\n"));
+			test.Getch();
+			TInt addErr=KErrNone;
+			do
+				{
+				if (addErr!=KErrNone)
+					{
+					test.Printf(_L("Add error %d,"),addErr);
+					TRAP(addErr,remDb->RecoverL());
+					test.Printf(_L("Recover error %d"),addErr);
+					TRAP(addErr,remDb->OpenTablesL());
+					test.Printf(_L("Open tables error %d\n"),addErr);
+					test.Printf(_L("Press a key to try again\n"));
+					test.Getch();
+					}
+				if (addErr==KErrNone)
+					{
+					TRAP(addErr,AddContactL(remDb,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,_L("x")));
+					}
+				} while(addErr!=KErrNone);
+			CleanupStack::PopAndDestroy();	// remDb
+			}
+		}
+	}
+
+/**
+
+@SYMTestCaseID     PIM-T-FERROR-0001
+
+*/
+
+void DoTestsL()
+    {
+	test.Start(_L("@SYMTESTCaseID:PIM-T-FERROR-0001 Remove pack test"));
+
+	RemovePackTestL();
+
+	test.Next(_L("File error tests"));
+
+	User::LeaveIfError(logFile.Replace(CntTest->Fs(),KLogFileName,EFileStreamText|EFileWrite));
+	CleanupClosePushL(logFile);
+//
+	test.Next(_L("Create new database"));
+
+	WriteToLogL(_L("Starting Logging"));
+	TRAPD(ret,CreateDatabaseL());
+	test(ret==KErrNone);
+	test.Next(_L("Starting fail loop"));
+
+	TestLoop(50);
+	test.Next(_L("Delete database"));
+
+	TInt retDel=KErrNone;
+	do
+		{
+		TRAP(retDel,CntTest->DeleteDatabaseL());
+		if (retDel==KErrInUse)
+			{
+			User::After(200000);
+			}
+		else
+			{
+			test(retDel==KErrNone);
+			}
+		} while(retDel!=KErrNone);
+	WriteToLogL(_L("Close log"));
+	CleanupStack::PopAndDestroy();	// logfile
+    }
+
+GLDEF_C TInt E32Main()
+	{
+    CntTest=new(ELeave) CCntTest;
+	CntTest->ConstructL(test,KDatabaseFileName);
+    TRAPD(err,DoTestsL());
+	CntTest->EndTestLib(err);
+	return KErrNone;
+    }
+
+//
+// CFred2
+//
+
+LOCAL_C TInt FredIIFunc(TAny *aParam);
+
+CFred2::~CFred2()
+	{
+	Kill();
+	iThread.Close();
+	}
+
+void CFred2::ConstructL()
+	{
+	User::LeaveIfError(iThread.Create(_L("FredII"),FredIIFunc,KDefaultStackSize,0x2000,0x20000,this,EOwnerThread));
+	iThread.Logon(iLogonStatus);
+	iThread.Resume();
+	}
+
+void CFred2::Kill()
+	{
+	iThread.Kill(0);
+	}
+
+void CFred2::WaitForLogon()
+	{
+	User::WaitForRequest(iLogonStatus);
+	test(iLogonStatus.Int()==KErrNone);
+	}
+
+//
+// Fred II from here on
+// 
+
+LOCAL_C TInt FredIIFunc(TAny *aParam)
+	{
+	CActiveScheduler::Install(new(ELeave) CActiveScheduler);
+    CTrapCleanup* cleanup=CTrapCleanup::New();
+	TRAPD(err,((CFred2 *)aParam)->DoDamageL());
+	test(EFalse);
+    delete cleanup;
+	delete CActiveScheduler::Current();
+	return(err);
+	}
+
+#if defined(__WINS__)
+ const TInt KMaxDamageWait=500000;	// up to a half a second
+#else
+# if defined(_UNICODE)
+ const TInt KMaxDamageWait=1500000;	// up to a one second
+# else
+ const TInt KMaxDamageWait=1000000;	// up to one and a half a second
+# endif
+#endif
+
+void CFred2::DoDamageL()
+	{
+	RFs fs;
+	test(fs.Connect()==KErrNone);
+	CleanupClosePushL(fs);
+	User::LeaveIfError(threadLogFile.Replace(fs,KThreadLogFileName,EFileStreamText|EFileWrite));
+	CleanupClosePushL(threadLogFile);
+	WriteToThreadLogL(_L("test1"));
+//
+	WriteToThreadLogL(_L("test2"));
+	CContactDatabase* db=CContactDatabase::OpenL(KDatabaseFileName);
+	WriteToThreadLogL(_L("test3"));
+	CleanupStack::PushL(db);
+	TBool doRecover=EFalse;
+	TInt64 seed=0;
+	User::After(1000000);
+	TInt damageCount=0;
+	TInt error1=KErrNone;
+	TInt error2=KErrNone;
+	WriteToThreadLogL(_L("test4"));
+	FOREVER
+		{
+		TInt after=(Math::Rand(seed)%KMaxDamageWait);
+		User::After(after);
+		WriteToThreadLogL(_L("Doing damage"));
+		TRAP(error1,db->DamageDatabaseL(0x666));
+		damageCount++;
+		FOREVER
+			{
+			if (doRecover)
+				{
+				WriteToThreadLogL(_L("Start Recover"));
+				TRAP(error2,db->RecoverL());
+				WriteToThreadLogL(_L("Finished Recover"));
+				}
+			else
+				{
+				WriteToThreadLogL(_L("Close tables"));
+				db->CloseTables();
+				TRAP(error2,db->OpenTablesL());
+				WriteToThreadLogL(_L("Open tables %d"),error2);
+				}
+			if (error2==KErrNone)
+				break;
+			User::After(100000);
+			}
+		doRecover=!doRecover;
+		}
+//unreachable at the mo'	CleanupStack::PopAndDestroy(3);	// db, log file, fs
+	}