loggingservices/eventlogger/test/src/t_logutil2.cpp
branchRCL_3
changeset 9 667e88a979d7
child 23 26645d81f48d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loggingservices/eventlogger/test/src/t_logutil2.cpp	Mon Mar 15 12:46:30 2010 +0200
@@ -0,0 +1,937 @@
+// Copyright (c) 2004-2010 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 <bautils.h>
+#include "t_logutil2.h"
+
+_LIT(KHelperExeName, "t_LogHiCapHelper.exe");
+
+//======================================================================================================
+
+#ifdef LOGGING_ENABLED
+
+void Log::New()
+	{
+	_LIT(KNewLogText, "===== NEW LOG =====");
+	//
+	RFileLogger logger;
+	TInt ret=logger.Connect();
+	if	(ret==KErrNone)
+		{
+		logger.CreateLog(KLogFolder, KLogFileName, EFileLoggingModeOverwrite);
+		logger.Write(KNewLogText);
+		}
+	logger.Close();
+	}
+
+void Log::Write(const TDesC& aText)
+	{
+	PruneLogFile();
+
+	RFileLogger logger;
+	TInt ret=logger.Connect();
+	if (ret==KErrNone)
+		{
+		logger.SetDateAndTime(EFalse,EFalse);
+		logger.CreateLog(KLogFolder, KLogFileName,EFileLoggingModeAppend);
+		TBuf<KLogEngLogBufferSize> buf;
+		TTime now;
+		now.HomeTime();
+		TDateTime dateTime;
+		dateTime = now.DateTime();
+		buf.Format(KTimeFormat,dateTime.Hour(),dateTime.Minute(),dateTime.Second(),dateTime.MicroSecond());
+		buf.AppendFormat(KTextFormat,&aText);
+
+		logger.Write(buf);
+		}
+
+	logger.Close();
+	}
+
+void Log::WriteFormat(TRefByValue<const TDesC> aFmt, ...)
+	{
+	VA_LIST list;
+	VA_START(list,aFmt);
+
+	PruneLogFile();
+
+	TBuf<2*KLogEngLogBufferSize> buf;
+	buf.SetMax();
+	buf.FillZ();
+	TTime now;
+	now.HomeTime();
+	TDateTime dateTime;
+	dateTime = now.DateTime();
+	buf.Format(KTimeFormat,dateTime.Hour(),dateTime.Minute(),dateTime.Second(),dateTime.MicroSecond());
+	buf.AppendFormatList(aFmt, list );
+
+	RFileLogger logger;
+	TInt ret=logger.Connect();
+	if (ret==KErrNone)
+		{
+		logger.SetDateAndTime(EFalse,EFalse);
+		logger.CreateLog(KLogFolder, KLogFileName,EFileLoggingModeAppend);
+		logger.Write(buf);
+		}
+
+	logger.Close();
+	}
+
+void Log::PruneLogFile()
+  	{
+	const TInt KMaxLogSize = 1024 * 500;
+	_LIT(KDriveLetter, "C:\\Logs\\");
+	//
+	TFileName fileName(KDriveLetter);
+	fileName.Append(KLogFolder);
+	fileName.Append(KLogFileName);
+	//
+	RFs fsSession;
+	if	(fsSession.Connect() == KErrNone)
+		{
+		TEntry entry;
+		if	(fsSession.Entry(fileName, entry) == KErrNone)
+			{
+			// Check size and delete if its too big
+			if	(entry.iSize >= KMaxLogSize)
+				fsSession.Delete(fileName); // ignore error
+			}
+		}
+	fsSession.Close();
+	}
+
+#endif
+
+// Globals 
+GLDEF_D CTrapCleanup* theCleanup;
+GLDEF_D CActiveScheduler *testScheduler;
+GLDEF_D RFs theFs;
+GLDEF_D TFileName theLogName;
+GLDEF_D RFile theLog;
+GLDEF_D RLogTestSession theLogServ;
+
+//**********************************
+// CTestActive
+//**********************************
+
+CTestActive::CTestActive(TInt aPriority)
+:	CActive(aPriority)
+	{
+	CActiveScheduler::Add(this);
+	iDelayTime=0;
+	}
+
+CTestActive::~CTestActive()
+	{
+	Cancel();
+	}
+
+void CTestActive::DoCancel()
+	{
+	TRequestStatus* s=&iStatus;
+	User::RequestComplete(s, KErrNone);
+	}
+
+void CTestActive::StartL()
+	{
+	iDelayCompletion=EFalse;
+	iDelayTime=0;
+	iStatus = KRequestPending;
+	SetActive();
+	}
+
+void CTestActive::StartL(TInt aDelay)
+	{
+	iDelayCompletion=ETrue;
+	iDelayTime=aDelay;
+	iStatus = KRequestPending;
+	SetActive();
+	}
+
+void CTestActive::RunL() 
+	{
+	if(iDelayCompletion && iDelayTime)
+		{
+		// Wait for events in other threads to have a go....
+		User::After(iDelayTime);
+		iDelayTime=0;
+		iStoredStatus=iStatus;
+		SetActive();
+		TRequestStatus* s=&iStatus;
+		User::RequestComplete(s, KErrNone);
+		}
+	else
+		{
+		if(iDelayCompletion)
+			iStatus=iStoredStatus;
+
+		LOGTEXT("CTestActive::RunL() - Stopping the scheduler");
+		CActiveScheduler::Stop();
+		}
+	}
+
+//**********************************
+// CTestTimer
+//**********************************
+
+CTestTimer::CTestTimer()
+: CTimer(EPriorityLow)
+	{}
+
+void CTestTimer::RunL()
+	{
+	LOGTEXT("CTestTimer::RunL() - Stopping the scheduler");
+	CActiveScheduler::Stop();
+	}
+
+CTestTimer* CTestTimer::NewL()
+	{
+	CTestTimer* self = new(ELeave) CTestTimer();
+	CleanupStack::PushL(self);
+	self->ConstructL(); // CTimer
+	CActiveScheduler::Add(self);
+	CleanupStack::Pop();
+	return self;
+	}
+
+//**********************************
+// TestUtils
+//**********************************
+
+void TestUtils::Initialize(const TDesC& aName)
+	{
+	TheTest.Title();
+	TheTest.Printf(_L("%S\r\n"), &aName);
+    User::RenameThread(aName);
+	}
+
+TBool TestUtils::FileExists(const TDesC& aFile)
+	{
+	TEntry entry;
+	return theFs.Entry(aFile, entry) == KErrNone;
+	}
+
+//Loads t_loghihelper process and passes for execution to t_loghihelper "aCommandLineArg" command line.
+//t_loghihelper will run, execute the command and die, returning the result of the command execution.
+//TestUtils::ExecuteRemoteL() will leave if error and return the result of the remote cmd execution to the caller.
+TInt TestUtils::ExecuteRemoteL(const TDesC& aCommandLineArg)
+	{
+	RProcess process;
+	LEAVE_IF_ERROR(process.Create(KHelperExeName, aCommandLineArg));
+	
+	TRequestStatus status;
+	process.Logon(status);
+	process.Resume();
+
+	User::WaitForRequest(status);
+	TInt exitReason = process.ExitReason();
+	
+	process.Close();
+	LEAVE_IF_ERROR(exitReason);
+
+	return exitReason;
+	}
+	
+//Runs t_loghihelper. t_loghihelper will execute the "delete LogEng database" command.
+//The "delete LogEng database" is a complex operation. The request is sent via the backup server
+//which will send a request to the LogEng server to release the LogEng database file locks and close the file.
+//After that the database will be deleted. 
+//In the same call the LogEng server will restarted and the LogEng server will re-create the database during the 
+//server startup.
+//
+//If "aCloseBeforeDelete" flag is false, then the database wil be only deleted.
+//The default value of "aCloseBeforeDelete" is true: the database will be closed, deleted and re-created.
+//But some of the LogEng tests create a CBaBackupSessionWrapper object and call CloseFileL() with the logeng
+//database name as a parameter. In this case, if another process, as t_loghicaphelper for example, attempts
+//to call CloseFileL() with the same file name as a parameter, then the caller will get KErrServerBusy error.
+//See how CBaBackupSessionWrapper::CloseFileL() is implemented on the server side.
+void TestUtils::DeleteDatabaseL(TBool aCloseBeforeDelete)
+	{
+    _LIT(KCmdLine1, "-delete_db1");
+    _LIT(KCmdLine2, "-delete_db2");
+    (void)ExecuteRemoteL(aCloseBeforeDelete ? KCmdLine1 : KCmdLine2);
+	}
+	
+//Runs t_loghihelper. t_loghihelper will check and return whether the LogEng database is open or not.  
+TBool TestUtils::IsDatabaseOpenL()
+	{
+	_LIT(KCmdLine, "-db_is_open");
+	TInt result = ExecuteRemoteL(KCmdLine);
+	return result != 0;
+	}
+	
+//Runs t_loghihelper. t_loghihelper will add an event type to the LogEng database.  
+void TestUtils::AddEventTypeL()
+	{
+	_LIT(KCmdLine, "-add_event_type");
+	(void)ExecuteRemoteL(KCmdLine);
+	}
+	
+//Runs t_loghihelper. t_loghihelper will add an event to the LogEng database.  
+TInt TestUtils::AddEventL()
+	{
+	_LIT(KCmdLine, "-add_event");
+	return ExecuteRemoteL(KCmdLine);		
+	}
+	
+//Runs t_loghihelper. t_loghihelper will add events to the LogEng database.  
+void TestUtils::AddViewTestEventsL()
+	{
+	_LIT(KCmdLine, "-add_view_test_events");
+	(void)ExecuteRemoteL(KCmdLine);
+	}
+
+//Runs t_loghihelper. t_loghihelper will return the size of the LogEng database.  
+TInt TestUtils::DatabaseSizeL()
+	{
+	_LIT(KCmdLine, "-db_size");
+	return ExecuteRemoteL(KCmdLine);		
+	}	
+	
+//Runs t_loghihelper. t_loghihelper will replace the LogEng database with a corrupted database (for testing purposes).
+//The LogEng server will be stopped before that. The function can be used only in debug mode.
+#ifdef _DEBUG
+void TestUtils::CopyCorruptDbL()
+	{
+
+	_LIT(KCmdLine, "-copy_corrupt");
+	(void)ExecuteRemoteL(KCmdLine);
+	}
+	
+//Runs t_loghihelper. t_loghihelper will replace the LogEng database with a corrupted database (for testing purposes).
+//The LogEng server will be stopped before that. The function can be used only in debug mode.
+void  TestUtils::CopyCorruptDamagedDbL()
+	{
+
+	_LIT(KCmdLine, "-copy_corrupt_damaged");
+	(void)ExecuteRemoteL(KCmdLine);
+	}
+	
+//Runs t_loghihelper. t_loghihelper will replace the LogEng database with an old format database 
+//(no SimId column, phone number length is different). The LogEng server will be stopped before that.
+//The function can be used only in debug mode.
+void TestUtils::CopyOldDbL()
+	{
+	_LIT(KCmdLine, "-copy_old");
+	(void)ExecuteRemoteL(KCmdLine);
+	}
+#else //_DEBUG
+void TestUtils::CopyCorruptDbL()
+	{
+	TheTest.Printf(_L("TestUtils::CopyCorruptDbL() has a meaningfull implementation in debug builds only.\n"));
+	}
+
+void TestUtils::CopyCorruptDamagedDbL()
+	{
+	TheTest.Printf(_L("TestUtils::CopyCorruptDamagedDbL() has a meaningfull implementation in debug builds only.\n"));
+	}
+
+void TestUtils::CopyOldDbL()
+	{
+	TheTest.Printf(_L("TestUtils::CopyOldDbL() has a meaningfull implementation in debug builds only.\n"));
+	}
+
+#endif//_DEBUG
+
+//Runs t_loghihelper. t_loghihelper will re-create the LogEng database and check whether LogEng client can connect to the server.   
+void TestUtils::TestInvalidSchemaL()
+	{
+	_LIT(KCmdLine, "-invalid_schema");
+	(void)ExecuteRemoteL(KCmdLine);
+	}
+
+//Runs t_loghihelper. t_loghihelper checks whether the phone number mathcing is enabled.   
+TBool TestUtils::MatchingEnabledL()
+	{
+	_LIT(KCmdLine, "-is_matching_enabled");
+	return ExecuteRemoteL(KCmdLine) != 0;
+	}
+
+//Creates HBufC object and puts it on the cleanup stack.
+//The buffer will be filled with (' ' + pos) characters, where pos is the character position in the buffer. 
+HBufC* TestUtils::CreateBufLC(TInt aLength)
+	{
+	HBufC* buf = HBufC::NewLC(aLength);
+	TPtr ptr = buf->Des();
+	for(TInt pos=0;pos<aLength;++pos)
+		{
+		ptr.Append(TChar(' ' + pos));
+		}
+	return buf;
+	}
+
+//Returns whether the two filters are equal or not.
+TBool TestUtils::FiltersEqual(const CLogFilter& aFilter1, const CLogFilter& aFilter2)
+	{
+	return aFilter1.EventType() == aFilter2.EventType() &&
+		   aFilter1.RemoteParty() == aFilter2.RemoteParty() &&
+		   aFilter1.Direction() == aFilter2.Direction() &&
+		   aFilter1.DurationType() == aFilter2.DurationType() &&
+		   aFilter1.Status() == aFilter2.Status() &&
+		   aFilter1.Contact() == aFilter2.Contact() &&
+		   aFilter1.Number() == aFilter2.Number() 
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+		   &&
+		   aFilter1.SimId() == aFilter2.SimId()
+#endif		   
+		   ;
+	}
+
+//Creates HBufC8 object and puts it on the cleanup stack.
+//The buffer will be filled with (' ' + pos % (0xff - 32)) characters, where pos is the character position in the buffer. 
+HBufC8* TestUtils::CreateBuf8LC(TInt aLength)
+	{
+	HBufC8* buf = HBufC8::NewLC(aLength);
+	TPtr8 ptr = buf->Des();
+	for(TInt pos=0;pos<aLength;++pos)
+		{
+		ptr.Append(TChar(' ' + pos % (0xff - 32)));
+		}
+	return buf;
+	}
+
+//Returns whether the two events are equal or not.
+TBool TestUtils::EventsEqual(const CLogEvent& aEvent1, const CLogEvent& aEvent2)
+	{
+	return 	aEvent1.Id() == aEvent2.Id() &&
+			aEvent1.EventType() == aEvent2.EventType() &&
+			aEvent1.RemoteParty() == aEvent2.RemoteParty() &&
+			aEvent1.Direction() == aEvent2.Direction() &&
+			aEvent1.Time() == aEvent2.Time() &&
+			aEvent1.DurationType() == aEvent2.DurationType() &&
+			aEvent1.Duration() == aEvent2.Duration() &&
+			aEvent1.Status() == aEvent2.Status() &&
+			aEvent1.Subject() == aEvent2.Subject() &&
+			aEvent1.Number() == aEvent2.Number() &&
+			aEvent1.Contact() == aEvent2.Contact() &&
+			aEvent1.Link() == aEvent2.Link() &&
+			aEvent1.Description() == aEvent2.Description() &&
+			aEvent1.Data() == aEvent2.Data() 
+#ifdef SYMBIAN_ENABLE_EVENTLOGGER_DUALSIM	
+			&& 
+			aEvent1.SimId() == aEvent2.SimId()
+#endif			
+			; 
+	}
+
+//Returns whether the two event types are equal or not.
+TBool TestUtils::TypesEqual(const CLogEventType& aType1, const CLogEventType& aType2)
+	{
+	return	aType1.Uid() == aType2.Uid() &&
+			aType1.Description() == aType2.Description() &&
+			aType1.LoggingEnabled() == aType2.LoggingEnabled();
+	}
+
+//Waits for a key to be pressed.
+TBool TestUtils::WaitForKeyL(TTimeIntervalMicroSeconds32 aDelay, TKeyCode& aKeyCode)
+	{
+	TEST(TheTest.Console() != NULL);
+
+	// Create timer
+	CTestTimer* timer = CTestTimer::NewL();
+	CleanupStack::PushL(timer);
+	timer->After(aDelay);
+
+	CTestActive* wait = new(ELeave)CTestActive;
+	CleanupStack::PushL(wait);
+	wait->StartL();
+
+	// Wait for key press
+	TheTest.Console()->Read(wait->iStatus);
+	CActiveScheduler::Start();
+
+	// If timer still active a key was pressed
+	TBool keyPressed = timer->IsActive();
+
+	if (keyPressed)
+		{
+		// Get the key pressed
+		aKeyCode = TheTest.Console()->KeyCode();
+
+		// Cancel timer
+		timer->Cancel();
+		}
+	else
+		{
+		// Cancel wait for character
+		TheTest.Console()->ReadCancel();
+		User::WaitForRequest(wait->iStatus);
+		}
+
+	CleanupStack::PopAndDestroy(2); // wait, timer
+	return keyPressed;
+	}
+
+//Used for LogEng server side heap failure testing.
+#ifdef _DEBUG
+void TestUtils::SetLogServHeapFailureL(RHeap::TAllocFail aType, TInt aRate)
+	{
+	//this function doesn't have any effect on UREL builds 
+ 	//get rid of warnings in release builds
+ 	aType = aType;
+ 	aRate = aRate;
+	if (!theLogServ.Handle())
+	    LEAVE_IF_ERROR(theLogServ.Connect());
+
+	TIpcArgs  ipcArgs(aType,aRate) ;
+	LEAVE_IF_ERROR(theLogServ.Send(ELogSetHeapFail, ipcArgs));
+	}
+#else
+void TestUtils::SetLogServHeapFailureL(RHeap::TAllocFail, TInt)
+	{
+	}
+#endif//_DEBUG
+
+//**********************************
+// CLogViewChangeObserver
+//**********************************
+
+CLogViewChangeObserver* CLogViewChangeObserver::NewLC()
+	{
+	CLogViewChangeObserver* self = new(ELeave) CLogViewChangeObserver();
+	CleanupStack::PushL(self);
+	return self;
+	}
+
+CLogViewChangeObserver::~CLogViewChangeObserver()
+	{
+	Cancel();
+	delete iChanges;
+	}
+
+CLogViewChangeObserver::CLogViewChangeObserver()
+:	CActive(EPriorityStandard)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+CLogChangeDefinition* CLogViewChangeObserver::WaitForChangesLC(TStopType aType, TInt aCount)
+	{
+	__ASSERT_ALWAYS(!iSchedulerStarted, User::Invariant());
+	Reset();
+	//
+	iExpectedChangeCount = aCount;
+	iType = aType;
+	if	(aType != EStopOnChanges)
+		SetActive();
+	//
+	iSchedulerStarted = ETrue;
+	CActiveScheduler::Start();
+	iSchedulerStarted = EFalse;
+	//
+	CLogChangeDefinition* ret = iChanges;
+	TEST(iChanges != NULL);
+	iChanges = NULL;
+	CleanupStack::PushL(ret);
+	return ret;
+	}
+
+CLogChangeDefinition* CLogViewChangeObserver::WaitForChangesLC(TCallBack aCallBack, TStopType aType, TInt aCount)
+	{
+	iHaveCallBack = ETrue;
+	iCallBack = aCallBack;
+	return WaitForChangesLC(aType, aCount);
+	}
+
+void CLogViewChangeObserver::HandleLogViewChangeEventAddedL(TLogId aId, TInt aViewIndex, TInt aChangeIndex, TInt aTotalChangeCount)
+	{
+	AddChangeL(ELogChangeTypeEventAdded, aId, aViewIndex);
+	if	(aChangeIndex == aTotalChangeCount-1)
+		CheckForSchedulerStop();
+	}
+
+void CLogViewChangeObserver::HandleLogViewChangeEventChangedL(TLogId aId, TInt aViewIndex, TInt aChangeIndex, TInt aTotalChangeCount)
+	{
+	AddChangeL(ELogChangeTypeEventChanged, aId, aViewIndex);
+	if	(aChangeIndex == aTotalChangeCount-1)
+		CheckForSchedulerStop();
+	}
+
+void CLogViewChangeObserver::HandleLogViewChangeEventDeletedL(TLogId aId, TInt aViewIndex, TInt aChangeIndex, TInt aTotalChangeCount)
+	{
+	AddChangeL(ELogChangeTypeEventDeleted, aId, aViewIndex);
+	if	(aChangeIndex == aTotalChangeCount-1)
+		CheckForSchedulerStop();
+	}
+
+void CLogViewChangeObserver::RunL()
+	{
+	__ASSERT_ALWAYS(iType == EStopOnRunL || iType == EStopOnBoth, User::Invariant());
+	iHaveFinishedOperation = ETrue;
+	CheckForSchedulerStop();
+	}
+
+void CLogViewChangeObserver::DoCancel()
+	{
+	TRequestStatus* s=&iStatus;
+	User::RequestComplete(s, KErrCancel);
+	}
+
+void CLogViewChangeObserver::Reset()
+	{
+	iExpectedChangeCount = 0;
+	iHaveFinishedOperation = EFalse;
+	iHaveObtainedChanges = EFalse;
+	iSchedulerStarted = EFalse;
+	iType = EStopOnChanges;
+	delete iChanges;
+	iChanges = NULL;
+	}
+
+void CLogViewChangeObserver::CheckForSchedulerStop()
+	{
+	if(iSchedulerStarted)
+		{
+		if	(iHaveCallBack)
+			{
+			iCallBack.CallBack();
+			iCallBack.iFunction = NULL;
+			iCallBack.iPtr = NULL;
+			iHaveCallBack = EFalse;
+			}
+		//
+		TBool stopScheduler = EFalse;
+		switch(iType)
+			{
+		case EStopOnChanges:
+			stopScheduler = iHaveObtainedChanges;
+			break;
+		case EStopOnRunL:
+			stopScheduler = iHaveFinishedOperation;
+			break;
+		case EStopOnBoth:
+			stopScheduler = (iHaveObtainedChanges && iHaveFinishedOperation);
+			break;
+		case EStopOnCount:
+			if	(iChanges)
+				{
+				TEST(iChanges->Count() <= iExpectedChangeCount);
+				stopScheduler = (iChanges->Count() == iExpectedChangeCount);
+				}
+		case EDontStopScheduler:
+			break;
+			}
+
+		if	(stopScheduler)
+			{
+			LOGTEXT("CLogViewChangeObserver::CheckForSchedulerStop() - Stopping the scheduler");
+			CActiveScheduler::Stop();
+			}
+		}
+	}
+
+void CLogViewChangeObserver::AddChangeL(TLogDatabaseChangeType aType, TLogId aId, TInt aViewIndex)
+	{
+	CLogChangeDefinition* changes;
+
+	if	(iChanges)
+		changes = iChanges;
+	else
+		{
+		changes = CLogChangeDefinition::NewL();
+		CleanupStack::PushL(changes);
+		}
+	//
+	changes->AddL(aId, aType, aViewIndex);
+	//
+	if	(!iChanges)
+		{
+		delete iChanges;
+		iChanges = changes;
+		CleanupStack::Pop(changes);
+		}
+	//
+	iHaveObtainedChanges = ETrue;
+	}
+
+//**********************************
+// CLogViewChangeObserverErrorTest
+//**********************************
+CLogViewChangeObserverErrorTest* CLogViewChangeObserverErrorTest::NewLC()
+	{
+	CLogViewChangeObserverErrorTest* self = new(ELeave) CLogViewChangeObserverErrorTest();
+	CleanupStack::PushL(self);
+	return self;
+	}	
+
+CLogViewChangeObserverErrorTest::CLogViewChangeObserverErrorTest()
+	{}
+	 
+void CLogViewChangeObserverErrorTest::HandleLogViewChangeEventAddedL(TLogId aId, TInt aViewIndex, TInt aChangeIndex, TInt aTotalChangeCount)
+	{
+  	// DEF108741L - the error condition tested here is that a leave is dealt with 
+  	// gracefully without any panics.
+ 
+ 	// Add a new event to the log
+	AddChangeL(ELogChangeTypeEventAdded, aId, aViewIndex);
+	if	(aChangeIndex == aTotalChangeCount-1)
+		CheckForSchedulerStop();
+	
+	// In the test case for DEF108741L this method will be effectively
+	// invoked 3 times. This code forces a leave on the middle event to 
+	// ensure that the leave is dealt with and the rest of the test 
+	// completes successfully.
+	if (aId == 1)
+		{	
+		LEAVE(KErrGeneral);
+		} 
+	}
+ 
+//**********************************
+// CLogSchedulerTimer
+//**********************************
+
+CLogSchedulerTimer* CLogSchedulerTimer::NewLC()
+	{
+	CLogSchedulerTimer* self = new(ELeave) CLogSchedulerTimer();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CLogSchedulerTimer::~CLogSchedulerTimer()
+	{
+	Cancel();
+	}
+
+CLogSchedulerTimer::CLogSchedulerTimer()
+:	CTimer(0)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CLogSchedulerTimer::ConstructL()
+	{
+	CTimer::ConstructL();
+	}
+
+void CLogSchedulerTimer::Wait(TTimeIntervalMicroSeconds32 aTime)
+	{
+	After(aTime);
+	CActiveScheduler::Start();
+	}
+
+void CLogSchedulerTimer::RunL()
+	{
+	LOGTEXT("CLogSchedulerTimer::RunL() - Stopping the scheduler");
+	CActiveScheduler::Stop();
+	}
+
+
+
+
+//**********************************
+// CLogChangeNotifier
+//**********************************
+
+CLogChangeNotifier* CLogChangeNotifier::NewL()
+	{
+	CLogChangeNotifier* self = new(ELeave)CLogChangeNotifier();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CLogChangeNotifier::~CLogChangeNotifier()
+	{
+	Cancel();
+	delete iClient;
+	}
+
+CLogChangeNotifier::CLogChangeNotifier()
+: CActive(EPriorityStandard)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CLogChangeNotifier::ConstructL()
+	{
+	iClient = CLogClient::NewL(theFs);
+
+	iStart.UniversalTime();
+	iClient->NotifyChange(10000000, iStatus);
+	SetActive();
+	}
+
+void CLogChangeNotifier::RunL()
+	{
+	TTime now;
+	now.UniversalTime();
+	TTimeIntervalSeconds seconds;
+	now.SecondsFrom(iStart, seconds);
+
+	TBuf<256> buf;
+ 	const TInt error = iStatus.Int();
+ 	if (error == KErrServerTerminated)
+ 		{
+ 		buf.Format(_L("KErrServerTerminated"));
+		User::InfoPrint(buf);
+		return;
+ 		}
+ 		
+	buf.Format(_L("%d seconds"), seconds.Int());
+	User::InfoPrint(buf);
+	
+	iStart.UniversalTime();
+	iClient->NotifyChange(10000000, iStatus);
+	SetActive();
+	}
+
+void CLogChangeNotifier::DoCancel()
+	{
+	iClient->NotifyChangeCancel();	
+	}
+
+//**********************************
+// Global
+//**********************************
+
+void SetupSchedulerL()
+	{
+	testScheduler = new (ELeave) CActiveScheduler;
+	CleanupStack::PushL( testScheduler );
+	CActiveScheduler::Install( testScheduler );
+	}
+
+void CloseScheduler()
+	{
+    CleanupStack::PopAndDestroy(); // Scheduler
+    testScheduler = NULL;
+	}
+
+static void CreateLogL()
+    {
+    LEAVE_IF_ERROR(theFs.Connect());
+
+    theLogName.Copy(RProcess().FileName());
+    TInt start = theLogName.LocateReverse('\\');
+    TInt end = theLogName.LocateReverse('.');
+    theLogName = theLogName.Mid(start + 1, end - start - 1);
+
+    // create the log filename
+    theLogName.Insert(0, _L("C:\\"));
+#if defined(__WINS__)
+    theLogName.Append(_L(".WINS."));
+#else
+    theLogName.Append(_L(".MARM."));
+#endif
+#if defined(_UNICODE)
+    theLogName.Append(_L("UNICODE."));
+#else
+    theLogName.Append(_L("ASCII."));
+#endif
+#if defined(_DEBUG)
+    theLogName.Append(_L("DEB."));
+#else
+    theLogName.Append(_L("REL."));
+#endif
+    theLogName.Append(_L("LOG"));
+
+    // create the logfile
+    LEAVE_IF_ERROR(theLog.Replace(theFs, theLogName, EFileWrite|EFileShareExclusive));
+    TBuf8<256> text;
+    text.Copy(theLogName);
+    theLog.Write(text);
+    theLog.Write(_L8("\nTest results\n"));
+    }
+
+static void CloseLog()
+    {
+    theLog.Write(_L8("Tests completed\n"));
+    TheTest.Printf(_L("Results saved in %S\n"), &theLogName);
+    theLog.Close();
+    theFs.Close();
+    }
+
+void DeleteDataFile(const TDesC& aFullName)
+	{
+	RFs fsSession;
+	TInt err = fsSession.Connect();
+	if(err == KErrNone)
+		{
+		TEntry entry;
+		if(fsSession.Entry(aFullName, entry) == KErrNone)
+			{
+			TheTest.Printf(_L("Deleting \"%S\" file.\n"), &aFullName);
+			err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly);
+			if(err != KErrNone) 
+				{
+				TheTest.Printf(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName);
+				}
+			err = fsSession.Delete(aFullName);
+			if(err != KErrNone) 
+				{
+				TheTest.Printf(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName);
+				}
+			}
+		fsSession.Close();
+		}
+	else
+		{
+		TheTest.Printf(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName);
+		}
+	}
+
+static void Cleanup(void*)
+	{
+	TRAP_IGNORE(TestUtils::DeleteDatabaseL());
+	_LIT(KCntModelFileName, "c:\\system\\data\\CntModel.ini");
+	::DeleteDataFile(KCntModelFileName);
+	_LIT(KContactsFileName, "c:\\system\\data\\Contacts.cdb");
+	::DeleteDataFile(KContactsFileName);
+	::DeleteDataFile(theLogName);
+	}
+
+static void DoMainL()
+	{
+	::SetupSchedulerL();
+	TCleanupItem cleanup(&Cleanup, NULL);
+	CleanupStack::PushL(cleanup);
+	CreateLogL();
+	::doTestsL();
+	CloseLog();
+    CleanupStack::PopAndDestroy();//cleanup
+	::CloseScheduler();
+	}
+
+TInt E32Main()
+	{	
+	__UHEAP_MARK;
+
+	theCleanup = CTrapCleanup::New();
+    if(!theCleanup)
+       {
+       _LIT(KLogHiCapHelperPanic, "LogTestPanic");
+        User::Panic(KLogHiCapHelperPanic, KErrNoMemory);
+       }
+
+	TRAPD(err, ::DoMainL());	
+	TEST2(err, KErrNone);
+
+	delete theCleanup;	
+
+	TheTest.Console()->SetPos(0, 13);
+
+	TheTest.End();
+	TheTest.Close();
+
+	__UHEAP_MARKEND;
+
+	return KErrNone;
+	}
+
+