--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/bench/t_notify_perf_impl.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1664 @@
+// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// f32test\bench\t_notify_perf_impl.cpp
+//
+//
+
+#include "t_notify_perf.h"
+#include "t_server.h"
+
+extern void FileNameGen(TFileName& aName, TInt aNum, TBool aIsFile = ETrue);
+extern TInt FileOperationThread(TAny* aSetting);
+extern TInt NotificationOperationThread(TAny* aSetting);
+extern TInt KillerThread(TAny*);
+extern TUint OpNotifyMapping(TUint16& aOption, TInt aOperation);
+extern TBool CompareEntryName(const TEntry& aEntry1, const TEntry& aEntry2);
+extern void SafeTestL(TBool aResult, TInt aId, TInt aLine, TText* aFile);
+extern void SafeTestL(TInt aResult, TInt aExpected, TInt aId, TInt aLine, TText* aFile);
+
+const TInt KNotificationHeaderSize = (sizeof(TUint16)*2)+(sizeof(TUint));
+const TInt KMinNotificationBufferSize = 2*KNotificationHeaderSize + 2*KMaxFileName;
+
+TBool gPerfMeasure;
+TFileName gTestPath;
+TFileName gLogFilePath;
+RArray<RThread> gNotiThreads;
+RThread gFileThread;
+TBuf<50> gLogPostFix;
+
+// Prints out the filename
+#define ExpandMe(X) L ## X
+#define Expand(X) ExpandMe(X)
+
+// Safe test, so that sub-threads are not hanging after check fail
+#define SAFETEST0(a) SafeTestL(a,KNoThreadId,__LINE__,(TText*)Expand("t_notify_perf_impl.cpp"))
+#define SAFETEST1(a,b) SafeTestL(a,b,__LINE__,(TText*)Expand("t_notify_perf_impl.cpp"))
+#define SAFETEST2(a,b,c) SafeTestL(a,b,c,__LINE__,(TText*)Expand("t_notify_perf_impl.cpp"))
+
+
+TTestSetting::TTestSetting()
+: iNumFiles(0), iNumCli(0), iOption(0), iOperationList(NULL)
+ {
+ }
+
+TTestSetting::TTestSetting(TInt aNumFiles, TInt aNumCli, TUint16 aOpt, const TUint* aOpList)
+: iNumFiles(aNumFiles), iNumCli(aNumCli), iOption(aOpt), iOperationList(aOpList)
+ {
+ }
+
+//===========================================================
+
+CTimerLogger* CTimerLogger::NewL(const TFileName& aLogFile)
+ {
+ CTimerLogger* self = new(ELeave) CTimerLogger();
+ CleanupStack::PushL(self);
+ self->ConstructL(aLogFile);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CTimerLogger::ConstructL(const TFileName& aLogFile)
+ {
+ User::LeaveIfError(HAL::Get(HALData::ENanoTickPeriod, iTickPeriod));
+ iLogFile.Copy(aLogFile);
+ }
+
+CTimerLogger::CTimerLogger()
+: iTiming(EFalse), iTickNumber(0), iTimeScale(KDefaultTimeScale)
+ {
+ iFs.Connect();
+ }
+
+CTimerLogger::~CTimerLogger()
+ {
+ iFs.Close();
+ }
+
+// Write Logs
+TInt CTimerLogger::Log(const TDesC& aDes, TBool aIsLine)
+ {
+ RFile file;
+ iFs.Connect();
+
+ TInt err = file.Open(iFs,iLogFile,EFileShareExclusive|EFileWrite);
+ SAFETEST0(err == KErrNone || err == KErrNotFound || err == KErrPathNotFound);
+
+ if (err != KErrNone)
+ {
+ err = iFs.MkDirAll(iLogFile);
+ SAFETEST0(err == KErrNone || err == KErrAlreadyExists);
+ err = file.Create(iFs,iLogFile,EFileShareExclusive|EFileWrite);
+ SAFETEST0(err == KErrNone);
+ }
+
+ TBuf8<240> data;
+ data.Copy(aDes);
+ if (aIsLine)
+ {
+ data.Append(_L8("\r\n"));
+ }
+
+ TInt offset = 0;
+ err = file.Seek(ESeekEnd, offset);
+ SAFETEST0(err == KErrNone);
+ err = file.Write(data);
+ SAFETEST0(err == KErrNone);
+
+ file.Close();
+ iFs.Close();
+ return err;
+ }
+
+// Write Logs and also print the line written in the console
+TInt CTimerLogger::LogAndPrint(const TDesC& aDes, TBool aIsLine)
+ {
+ TInt err = KErrNone;
+ RDebug::Print(aDes);
+ if (gPerfMeasure)
+ err = Log(aDes, aIsLine);
+ return err;
+ }
+
+// Write and print the time result
+TInt CTimerLogger::LogTestStepTime(TUint aOp, TInt aNum)
+ {
+ if (iTiming)
+ return KErrGeneral;
+
+ TBuf<100> buf;
+ switch (aOp)
+ {
+ case EOpCreate:
+ buf.Append(_L("Create - "));
+ break;
+ case EOpReplace:
+ buf.Append(_L("Replace - "));
+ break;
+ case EOpChgAttr:
+ buf.Append(_L("Change Attribute - "));
+ break;
+ case EOpRename:
+ buf.Append(_L("Rename - "));
+ break;
+ case EOpWrite:
+ buf.Append(_L("Write - "));
+ break;
+ case EOpResize:
+ buf.Append(_L("Resize - "));
+ break;
+ case EOpDelete:
+ buf.Append(_L("Delete - "));
+ break;
+ case EOpManyChanges:
+ buf.AppendFormat(_L("%d Changes on Single File - "), aNum);
+ break;
+ case EOpManyFiles:
+ buf.AppendFormat(_L("Small Changes on %d Files - "), aNum);
+ break;
+ case EOpCreateDir:
+ buf.Append(_L("Create(dir) - "));
+ break;
+ case EOpRenameDir:
+ buf.Append(_L("Rename(dir) - "));
+ break;
+ case EOpDeleteDir:
+ buf.Append(_L("Delete(dir) - "));
+ break;
+ case EOpMixed:
+ buf.AppendFormat(_L("%d Mixed Operations - "), aNum*18);
+ default:
+ break;
+ }
+
+ TReal time = (static_cast<TReal>(iTickNumber) * iTickPeriod) / iTimeScale;
+ buf.AppendFormat(_L("time: %d ms"), static_cast<TInt>(time));
+ return LogAndPrint(buf);
+ }
+
+// write and print the test case discription
+TInt CTimerLogger::LogSettingDescription(const TInt aNumFile, const TInt aNumCli, const TUint16 aOption, TBool aNumOpVaries)
+ {
+ LogAndPrint(_L("===================================================="));
+
+ TBuf<120> buf;
+ buf.Append(_L("Test: "));
+ if (!aNumOpVaries)
+ {
+ buf.AppendFormat(_L("%d files/directories, %d Clients, "), aNumFile, aNumCli);
+ }
+
+ // Notification Type
+ switch(aOption & KNotifyOptionMask)
+ {
+ case ENoNotify:
+ buf.Append(_L("No Notification"));
+ break;
+ case EEnhanced:
+ buf.Append(_L("Enhanced"));
+ break;
+ case EOriginal:
+ buf.Append(_L("Original"));
+ break;
+ case EPlugin:
+ buf.Append(_L("Nokia Plug-in"));
+ break;
+ default:
+ return KErrArgument;
+ }
+
+ if (aOption & EBigFilter)
+ {
+ buf.Append(_L(", 100 Filters"));
+ }
+
+ if (aOption & EReportChg)
+ {
+ buf.Append(_L(", Change Reporting"));
+ }
+ else
+ {
+ buf.Append(_L(", Not Report Changes"));
+ }
+
+ if (aOption & EEnhanced)
+ {
+ if (aOption & EBigBuffer)
+ {
+ buf.Append(_L(", Big Buffer"));
+ }
+ else
+ {
+ buf.Append(_L(", Small Buffer"));
+ }
+
+ if (aOption & EMultiNoti1)
+ {
+ buf.Append(_L(", Multi Notification Mode 1"));
+ }
+ else if (aOption & EMultiNoti2)
+ {
+ buf.Append(_L(", Multi Notification Mode 2"));
+ }
+ }
+
+ LogAndPrint(buf);
+ LogAndPrint(_L("----------------------------------------------------"));
+
+ return KErrNone;
+ }
+
+//===========================================================
+
+CTestExecutor::CTestExecutor(TTestSetting& aSetting)
+: iTestSetting(aSetting)
+ {
+ }
+
+CTestExecutor::~CTestExecutor()
+ {
+ }
+
+void CTestExecutor::KillAllTestThreads()
+ {
+ RThread killer;
+ killer.Create(_L("KillerThread"), KillerThread, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, NULL);
+ killer.Resume();
+
+ TRequestStatus status;
+ killer.Logon(status);
+ User::WaitForRequest(status);
+ TInt err = killer.ExitReason();
+ test(err == KErrNone);
+ }
+
+// start run a test case
+void CTestExecutor::RunTestCaseL()
+ {
+ RSemaphore smphF;
+ smphF.CreateLocal(0);
+ RSemaphore smphN;
+ smphN.CreateLocal(0);
+
+ RArray<RThread> notiThreads; // list of handles of notification threads
+ RPointerArray<CTimerLogger> loggerList;
+
+ TUint16 count = 0;
+ TUint16 option = iTestSetting.iOption;
+ while (count < iTestSetting.iNumCli)
+ {
+ test(count < 16);
+ iTestSetting.iOption = (TUint16)(option + count); // Put Thread ID in option
+
+ TThreadParam param;
+ param.iSetting = iTestSetting;
+ param.iSmphFT = &smphF;
+ param.iSmphNT = &smphN;
+
+ TFileName logName;
+ logName.FillZ();
+
+ if (gPerfMeasure)
+ {
+ logName.Append(gLogFilePath);
+ if (iTestSetting.iNumCli == 1)
+ logName.Append(_L("SingleClient"));
+ else
+ logName.AppendFormat(_L("MultiClient%02d"), count);
+
+ logName.Append(gLogPostFix);
+ }
+
+ CTimerLogger* logger = CTimerLogger::NewL(logName);
+ CleanupStack::PushL(logger);
+
+ param.iLogger = logger;
+ param.iLoggerArray = NULL;
+
+ TUint operation = *iTestSetting.iOperationList;
+ TBool numFilesVaries = EFalse;
+
+ if (operation == EOpManyFiles || operation == EOpManyChanges || operation == EOpMixed)
+ {
+ numFilesVaries = ETrue;
+ }
+ logger->LogSettingDescription(iTestSetting.iNumFiles, iTestSetting.iNumCli, iTestSetting.iOption, numFilesVaries);
+
+ loggerList.AppendL(logger);
+
+ TBuf<20> threadName;
+ threadName.AppendFormat(_L("NotificationThread%02d"), count);
+
+ RThread notifyOp;
+ notifyOp.Create(threadName, NotificationOperationThread, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, ¶m);
+
+ notiThreads.AppendL(notifyOp);
+
+ notifyOp.Resume();
+
+ smphF.Wait(); // Wait for the parameters being properly passed
+
+ CleanupStack::Pop(logger);
+ count++;
+ }
+
+ gNotiThreads = notiThreads;
+
+ if (iTestSetting.iNumCli == 0) // no notification
+ {
+ TFileName logName;
+ logName.Append(gLogFilePath);
+ logName.Append(_L("SingleClient"));
+ logName.Append(gLogPostFix);
+
+ CTimerLogger* logger = CTimerLogger::NewL(logName);
+ CleanupStack::PushL(logger);
+
+ logger->LogSettingDescription(iTestSetting.iNumFiles, iTestSetting.iNumCli, iTestSetting.iOption);
+
+ loggerList.AppendL(logger);
+ CleanupStack::Pop(logger);
+ }
+
+ TThreadParam paramFileOp;
+ paramFileOp.iSetting = iTestSetting;
+ paramFileOp.iSmphFT = &smphF;
+ paramFileOp.iSmphNT = &smphN;
+ paramFileOp.iLogger = NULL;
+ paramFileOp.iLoggerArray = &loggerList;
+
+ RThread fileOp;
+ fileOp.Create(_L("FileOperationThread"), FileOperationThread, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, ¶mFileOp);
+ gFileThread = fileOp;
+
+ fileOp.Resume();
+
+ TInt err;
+
+ TRequestStatus status;
+ fileOp.Logon(status);
+ User::WaitForRequest(status);
+ err = fileOp.ExitReason();
+ test(err == KErrNone);
+
+ count = 0;
+ while(count < notiThreads.Count())
+ {
+ notiThreads[count].Logon(status);
+ User::WaitForRequest(status);
+ err = notiThreads[count].ExitReason();
+ test(err == KErrNone);
+ count++;
+ }
+
+ CLOSE_AND_WAIT(fileOp);
+
+ count = 0;
+ while(count < notiThreads.Count())
+ {
+ RThread thread = notiThreads[count];
+ CLOSE_AND_WAIT(thread);
+ count++;
+ }
+
+ for (TInt i = 0; i < loggerList.Count(); i++)
+ {
+ loggerList[i]->LogAndPrint(_L("===================================================="));
+ }
+
+ smphN.Close();
+ smphF.Close();
+ loggerList.ResetAndDestroy();
+ loggerList.Close();
+ notiThreads.Reset();
+ notiThreads.Close();
+ }
+
+//===========================================================
+
+CFileOperator::CFileOperator(const TTestSetting& aSetting, RPointerArray<CTimerLogger>& aLoggerArray, RSemaphore* aSmphFT, RSemaphore* aSmphNT)
+: iFirstFile(0)
+ {
+ iNumFiles = aSetting.iNumFiles;
+ iOption = aSetting.iOption;
+ iCurrentOp = aSetting.iOperationList;
+ iNumCli = aSetting.iNumCli;
+
+ iLoggers = aLoggerArray;
+ iSmphS = aSmphNT;
+ iSmphW = aSmphFT;
+
+ iFs.Connect();
+ }
+
+CFileOperator::~CFileOperator()
+ {
+ iFs.Close();
+ }
+
+// starts measuring for all the notification thread
+// the loggers in iLogger are shared by Notification thread
+void CFileOperator::MesureStartsAll()
+ {
+ TInt i = 0;
+ while (i < iNumCli)
+ {
+ iLoggers[i]->MeasureStart();
+ i++;
+ }
+ }
+
+// Wait for all notification threads to signal
+void CFileOperator::WaitForSignalsAll()
+ {
+ TInt i = 0;
+ while (i < iNumCli)
+ {
+ iSmphW->Wait();
+ i++;
+ }
+ }
+
+// prepare each test step
+void CFileOperator::TestStepPrepare(TUint aOp)
+ {
+ RDebug::Print(_L("Preparing for the next test step..."));
+ switch (aOp)
+ {
+ case EOpReplace:
+ {
+ User::After(1500000); // Wait for 1.5 sec so that the new files have different modified time
+ RFile file;
+ TInt count = iFirstFile + iNumFiles;
+ while (count < (iFirstFile + (iNumFiles * 2)))
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count);
+ file.Create(iFs, nextFile, EFileRead);
+ file.Close();
+ count++;
+ }
+ break;
+ }
+ case EOpManyChanges:
+ {
+ RFile file;
+ TFileName nextFile;
+ FileNameGen(nextFile, 9999);
+ file.Create(iFs, nextFile, EFileRead);
+ file.Close();
+ break;
+ }
+ case EOpManyFiles:
+ {
+ CDir* list;
+ iFs.GetDir(gTestPath, KEntryAttMaskSupported, ESortNone, list);
+ TInt count = list->Count();
+ delete list;
+
+ RFile file;
+
+ for (TInt i = 0; i < iNumFiles - count; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count + i);
+ file.Create(iFs, nextFile, EFileRead);
+ file.Close();
+ }
+
+ break;
+ }
+ // No preparation for other operations
+ default:
+ break;
+ }
+ RDebug::Print(_L("Preparation done..."));
+ }
+
+// Finish each test step, do some clearing or test setting modification
+void CFileOperator::TestStepFinish(TUint aOp)
+ {
+ RDebug::Print(_L("Finishing the test step..."));
+ switch (aOp)
+ {
+ case EOpRenameDir:
+ case EOpRename:
+ {
+ iFirstFile += iNumFiles;
+ break;
+ }
+ case EOpDelete:
+ case EOpDeleteDir:
+ {
+ iFirstFile = 0;
+ break;
+ }
+ case EOpManyChanges:
+ {
+ TFileName fileName;
+ FileNameGen(fileName, 9999);
+ iFs.Delete(fileName);
+ iNumFiles += 1000;
+ break;
+ }
+ case EOpManyFiles:
+ {
+ iNumFiles += 1000;
+ break;
+ }
+ case EOpMixed:
+ {
+ iNumFiles += 50;
+ }
+ // no clearing for other operations
+ default:
+ break;
+ }
+ RDebug::Print(_L("***** Test step finished *****"));
+ RDebug::Print(_L("\n"));
+ }
+
+// perform the file operations
+void CFileOperator::DoChangesL()
+ {
+ while(*iCurrentOp != EOpEnd)
+ {
+ TestStepPrepare(*iCurrentOp);
+
+ if (iOption & ENoNotify)
+ {
+ iLoggers[0]->MeasureStart();
+ }
+ else
+ {
+ iSmphS->Signal(iNumCli); // Signal notification threads that preparation is done
+ WaitForSignalsAll(); // Wait for notification threads to finish requesting notifications
+ MesureStartsAll();
+ }
+
+ RDebug::Print(_L("Start Timing and File operations..."));
+ switch(*iCurrentOp)
+ {
+ case EOpCreate:
+ DoCreateL();
+ break;
+ case EOpReplace:
+ DoReplaceL();
+ break;
+ case EOpChgAttr:
+ DoChangeAttL();
+ break;
+ case EOpRename:
+ DoRenameL();
+ break;
+ case EOpWrite:
+ DoWriteL();
+ break;
+ case EOpResize:
+ DoResizeL();
+ break;
+ case EOpDelete:
+ DoDeleteL();
+ break;
+ case EOpManyChanges:
+ DoManyChangesOnSingleFileL();
+ break;
+ case EOpManyFiles:
+ DoSmallChangesOnManyFilesL();
+ break;
+ case EOpCreateDir:
+ DoCreateDirL();
+ break;
+ case EOpRenameDir:
+ DoRenameDirL();
+ break;
+ case EOpDeleteDir:
+ DoDeleteDirL();
+ break;
+ case EOpMixed:
+ DoMixedOperationsL();
+ break;
+ default:
+ User::Leave(KErrArgument);
+ }
+ RDebug::Print(_L("File Operation Ended..."));
+
+ if (iOption & ENoNotify)
+ {
+ RDebug::Print(_L("Timing ended..."));
+ iLoggers[0]->MeasureEnd();
+ iLoggers[0]->LogTestStepTime(*iCurrentOp, iNumFiles);
+ }
+ else
+ {
+ RFile file;
+ TFileName endFile(gLogFilePath);
+ endFile.Append(_L("test.end"));
+ TInt r = file.Replace(iFs, endFile, EFileWrite);
+ SAFETEST0(r == KErrNone);
+ file.Close();
+
+ WaitForSignalsAll(); // Wait for notification threads to receive all the notifications
+ }
+
+ TestStepFinish(*iCurrentOp);
+
+ iCurrentOp++;
+ }
+ }
+
+void CFileOperator::DoCreateL()
+ {
+ RFile file;
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count);
+
+ TInt r = file.Create(iFs, nextFile, EFileRead);
+ SAFETEST0(r == KErrNone);
+ file.Close();
+ count++;
+ }
+ }
+
+void CFileOperator::DoReplaceL()
+ {
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName newFile;
+ TFileName oldFile;
+ FileNameGen(newFile, count);
+ FileNameGen(oldFile, count + iNumFiles);
+
+ iFs.Replace(oldFile, newFile);
+ count++;
+ }
+ }
+
+void CFileOperator::DoChangeAttL()
+ {
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count);
+ iFs.SetAtt(nextFile, KEntryAttNormal, KEntryAttArchive);
+ count++;
+ }
+ }
+
+void CFileOperator::DoRenameL()
+ {
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName newFile;
+ TFileName oldFile;
+ FileNameGen(oldFile, count);
+ FileNameGen(newFile, count + iNumFiles);
+
+ iFs.Rename(oldFile, newFile);
+ count++;
+ }
+ }
+
+void CFileOperator::DoWriteL()
+ {
+ RFile file;
+ TInt count = iFirstFile;
+ _LIT8(KData, "Some text for writing test of enhanced notification performance test.");
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count);
+ file.Open(iFs, nextFile, EFileWrite);
+ file.Write(KData);
+ // Flush file to ensure notification is received
+ file.Flush();
+ file.Close();
+ count++;
+ }
+ }
+
+void CFileOperator::DoResizeL()
+ {
+ RFile file;
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count);
+ file.Open(iFs, nextFile, EFileWrite);
+ TInt size;
+ file.Size(size);
+ file.SetSize(size+10);
+ file.Close();
+ count++;
+ }
+ }
+
+void CFileOperator::DoDeleteL()
+ {
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count);
+ iFs.Delete(nextFile);
+ count++;
+ }
+ }
+
+void CFileOperator::DoCreateDirL()
+ {
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count, EFalse);
+ iFs.MkDir(nextFile);
+ count++;
+ }
+ }
+
+void CFileOperator::DoRenameDirL()
+ {
+ TInt count = iFirstFile;
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName newFile;
+ TFileName oldFile;
+ FileNameGen(oldFile, count, EFalse);
+ FileNameGen(newFile, count + iNumFiles, EFalse);
+
+ iFs.Rename(oldFile, newFile);
+ count++;
+ }
+ }
+
+void CFileOperator::DoDeleteDirL()
+ {
+ TInt count = iFirstFile;
+
+ while (count < iFirstFile + iNumFiles)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, count, EFalse);
+ iFs.RmDir(nextFile);
+ count++;
+ }
+ }
+
+void CFileOperator::DoManyChangesOnSingleFileL()
+ {
+ TFileName fileName;
+ FileNameGen(fileName, 9999);
+
+ RFile file;
+ _LIT8(KData, "a");
+
+ for(TInt i = 0; i < iNumFiles; i++)
+ {
+ TInt offset = 0;
+ file.Open(iFs, fileName, EFileWrite);
+ file.Seek(ESeekEnd, offset);
+ file.Write(KData);
+ file.Flush();
+ file.Close();
+ }
+ }
+
+void CFileOperator::DoSmallChangesOnManyFilesL()
+ {
+ RFile file;
+ _LIT8(KData, "a");
+
+ for(TInt i = 0; i < iNumFiles; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i);
+ file.Open(iFs, nextFile, EFileWrite);
+ file.Write(KData);
+ file.Flush();
+ file.Close();
+ }
+ }
+
+void CFileOperator::DoMixedOperationsL()
+ {
+ // will perform 18*iNumFiles operations
+ RFile file;
+ TInt firstFile = iFirstFile;
+ TInt lastFile = iFirstFile + (2 * iNumFiles);
+ TInt firstDir = iFirstFile;
+ TInt lastDir = iFirstFile + iNumFiles;
+
+ _LIT8(KData, "Some text.");
+
+ TInt i;
+ // Create Files - 2*iNumFiles Ops
+ // we create 2*iNumFiles files here so that we can ensure that at least iNumfiles ops are performed after the replace step
+ for (i = firstFile; i < lastFile; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i);
+ file.Create(iFs, nextFile, EFileRead);
+ file.Close();
+ }
+
+ // Create Directories - iNumFiles Ops
+ for (i = firstDir; i < lastDir; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i, EFalse);
+ iFs.MkDir(nextFile);
+ }
+
+ // Write - 2*iNumFiles Ops
+ for (i = firstFile; i < lastFile; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i);
+ file.Open(iFs, nextFile, EFileWrite);
+ file.Write(KData);
+ file.Flush();
+ file.Close();
+ }
+
+ // Resize - 2*iNumFiles Ops
+ for (i = firstFile; i < lastFile; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i);
+ file.Open(iFs, nextFile, EFileWrite);
+ TInt size;
+ file.Size(size);
+ file.SetSize(size+10);
+ file.Close();
+ }
+
+ // Replace Files - iNumFiles Ops
+ for (i = firstFile; i < firstFile + iNumFiles; i++)
+ {
+ TFileName newFile;
+ TFileName oldFile;
+ FileNameGen(oldFile, i);
+ FileNameGen(newFile, i + iNumFiles);
+ iFs.Replace(oldFile, newFile);
+ }
+ firstFile += iNumFiles;
+
+ // Rename Files - iNumFiles Ops
+ for (i = firstFile; i < lastFile; i++)
+ {
+ TFileName newFile;
+ TFileName oldFile;
+ FileNameGen(newFile, i - iNumFiles);
+ FileNameGen(oldFile, i);
+ iFs.Rename(oldFile, newFile);
+ }
+ firstFile -= iNumFiles;
+ lastFile -= iNumFiles;
+
+ // Delete Dirs - iNumFiles Ops
+ for (i = firstDir; i < lastDir; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i, EFalse);
+ iFs.RmDir(nextFile);
+ }
+
+ // Delete File - iNumFiles Ops
+ for (i = firstFile; i < lastFile; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i);
+ iFs.Delete(nextFile);
+ }
+
+ // All-in-one - 7*iNumFiles Ops
+ for (i = firstFile; i < lastFile; i++)
+ {
+ TFileName nextFile;
+ FileNameGen(nextFile, i);
+ TFileName nextDir;
+ FileNameGen(nextDir, i, EFalse);
+
+ iFs.MkDir(nextDir);
+
+ file.Create(iFs, nextFile, EFileWrite);
+ file.Write(KData);
+ file.Flush();
+ TInt size;
+ file.Size(size);
+ file.SetSize(size+10);
+ file.Close();
+
+ TFileName newName;
+ FileNameGen(newName, i + iNumFiles);
+ iFs.Rename(nextFile, newName);
+
+ iFs.Delete(newName);
+ iFs.RmDir(nextDir);
+ }
+ }
+
+//==========================================================
+
+CNotifyOperator::CNotifyOperator(const TTestSetting& aSetting, RSemaphore* aSmphFT, RSemaphore* aSmphNT, CTimerLogger* aLogger)
+ {
+ iNumFiles = aSetting.iNumFiles;
+ iOption = aSetting.iOption;
+ iCurrentOp = aSetting.iOperationList;
+ iLogger = aLogger;
+ iSmphS = aSmphFT;
+ iSmphW = aSmphNT;
+ }
+
+CNotifyOperator::~CNotifyOperator()
+ {
+ }
+
+// start operations in notification thread
+// this is the main function called in the thread,
+// it creates notification watcher, requests notification, and check test result
+void CNotifyOperator::StartOperationL()
+ {
+ CNotifyWatcher* notifyWatcher = CNotifyWatcher::NewL(iNumFiles, iOption, *iCurrentOp, iLogger);
+ CleanupStack::PushL(notifyWatcher);
+ CTestStopper* stopper = new(ELeave) CTestStopper();
+ CleanupStack::PushL(stopper);
+
+ CActiveScheduler::Add(notifyWatcher);
+ CActiveScheduler::Add(stopper);
+
+ while (*iCurrentOp != EOpEnd)
+ {
+ iSmphW->Wait(); // wait for file thread finishing preparation for the current file operation.
+
+ notifyWatcher->FullDirectoryScanL(notifyWatcher->iEntries);
+ notifyWatcher->RequestNotification();
+ stopper->StartWaitingForFile();
+
+ iSmphS->Signal(); // Signal file thread that the notifications are requested, ready to receive
+
+ CActiveScheduler::Start();
+ ////////////////////////////////
+ // receiving notifications... //
+ ////////////////////////////////
+
+ notifyWatcher->HandleNotification(ETrue); // handle for the last time
+
+ LogTestResult(notifyWatcher->iCounter, notifyWatcher->iMeanCounter, notifyWatcher->iOverflowCounter);
+
+ if(iOption & EReportChg)
+ {
+ TestChangeReport(notifyWatcher->iRecords.Count());
+ }
+
+ if (!gPerfMeasure)
+ {
+ TInt id = iOption & KNotifyTreadIdMask;
+ if (iOption & EMultiNoti2)
+ {
+ if ( *iCurrentOp == EOpCreate ||
+ (id % 4 == 0 && (*iCurrentOp == EOpRename || *iCurrentOp == EOpReplace)) ||
+ (id % 4 == 1 && *iCurrentOp == EOpChgAttr) ||
+ (id % 4 == 2 && (*iCurrentOp == EOpResize || *iCurrentOp == EOpWrite)) ||
+ (id % 4 == 3 && *iCurrentOp == EOpDelete))
+ {
+ SAFETEST2(notifyWatcher->iCounter, iNumFiles, id);
+ }
+ }
+ else
+ {
+ SAFETEST2(notifyWatcher->iCounter, iNumFiles, id);
+ }
+ }
+
+ iSmphS->Signal(); // Signal file thread that all notifications are received
+
+ iCurrentOp++;
+
+ notifyWatcher->Reset(*iCurrentOp);
+ if ((*iCurrentOp == EOpManyFiles) || (*iCurrentOp == EOpManyChanges))
+ {
+ iNumFiles += 1000;
+ }
+ else if (*iCurrentOp == EOpMixed)
+ {
+ iNumFiles += 50;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2);
+
+ }
+
+// Write log and print the notification numbers using iLogger
+void CNotifyOperator::LogNotificationNumbers(TInt aNumNoti, TInt aNumIter, TInt aNumOverflow)
+ {
+ TBuf<100> buf;
+
+ if (iOption & EEnhanced)
+ {
+ if (aNumOverflow > 0)
+ {
+ buf.AppendFormat(_L("Buffer overflow: %d overflow notifications received."), aNumOverflow, aNumNoti);
+ iLogger->LogAndPrint(buf);
+ buf.Zero();
+ }
+
+ TReal mean = static_cast<TReal>(aNumNoti)/aNumIter;
+ buf.AppendFormat(_L("%.2f mean enhanced notifications per iteration."), mean);
+ iLogger->LogAndPrint(buf);
+ buf.Zero();
+ }
+
+ buf.AppendFormat(_L("%d notifications received overall."), aNumNoti);
+ iLogger->LogAndPrint(buf);
+ }
+
+// Write log and print the test reault
+void CNotifyOperator::LogTestResult(TInt aCounter, TInt aMeanCounter, TInt aOFCounter)
+ {
+ if (iOption & EMultiNoti2)
+ {
+ TInt id = iOption & KNotifyTreadIdMask;
+ if ( *iCurrentOp == EOpCreate ||
+ (id % 4 == 0 && (*iCurrentOp == EOpRename || *iCurrentOp == EOpReplace)) ||
+ (id % 4 == 1 && *iCurrentOp == EOpChgAttr) ||
+ (id % 4 == 2 && (*iCurrentOp == EOpWrite || *iCurrentOp == EOpResize)) ||
+ (id % 4 == 3 && *iCurrentOp == EOpDelete))
+ {
+ iLogger->LogTestStepTime(*iCurrentOp, iNumFiles);
+ LogNotificationNumbers(aCounter, aMeanCounter, aOFCounter);
+ }
+ else
+ iLogger->LogAndPrint(_L("File operation not tested - time: 0 ms"));
+ }
+ else if (iOption & EPlugin)
+ {
+ if (*iCurrentOp == EOpChgAttr || *iCurrentOp == EOpWrite || *iCurrentOp == EOpResize)
+ iLogger->LogAndPrint(_L("File operation not tested - time: 0 ms"));
+ else
+ {
+ iLogger->LogTestStepTime(*iCurrentOp, iNumFiles);
+ LogNotificationNumbers(aCounter, aMeanCounter, aOFCounter);
+ }
+ }
+ else
+ {
+ iLogger->LogTestStepTime(*iCurrentOp, iNumFiles);
+ LogNotificationNumbers(aCounter, aMeanCounter, aOFCounter);
+ }
+ }
+
+// When change report enabled, check the number of changes we detected
+void CNotifyOperator::TestChangeReport(TInt aNumChanges)
+ {
+ TBuf<100> buf;
+ buf.AppendFormat(_L("%d file changes detected.\r\n"), aNumChanges);
+ iLogger->LogAndPrint(buf);
+
+ TInt id = iOption & KNotifyTreadIdMask;
+ if (iOption & EEnhanced)
+ {
+ if (iOption & EMultiNoti2)
+ {
+ if ( *iCurrentOp == EOpCreate ||
+ (id % 4 == 0 && (*iCurrentOp == EOpRename || *iCurrentOp == EOpReplace)) ||
+ (id % 4 == 1 && *iCurrentOp == EOpChgAttr) ||
+ (id % 4 == 2 && (*iCurrentOp == EOpResize || *iCurrentOp == EOpWrite)) ||
+ (id % 4 == 3 && *iCurrentOp == EOpDelete))
+ {
+ SAFETEST2(aNumChanges, iNumFiles, id);
+ }
+ }
+ else if (!(iOption & EBigBuffer))
+ {
+ // not testing this case, because the number of file changes detected
+ // could varies depend on when notifications are received
+ }
+ else if (*iCurrentOp == EOpMixed)
+ {
+ SAFETEST2(aNumChanges, (18*iNumFiles), id); // On cached drives, the number of write notification could vary.
+ }
+ else
+ {
+ SAFETEST2(aNumChanges, iNumFiles, id);
+ }
+ }
+ else if (iOption & EOriginal)
+ {
+ if ((*iCurrentOp == EOpManyChanges) || (*iCurrentOp == EOpMixed))
+ {
+ // not testing this case, because the number of file changes detected
+ // could varies depend on when notifications are received
+ }
+ else if ((*iCurrentOp == EOpReplace) || (*iCurrentOp == EOpRename) || (*iCurrentOp == EOpRenameDir))
+ {
+ SAFETEST2(aNumChanges, (2*iNumFiles), id);
+ }
+ else
+ {
+ SAFETEST2(aNumChanges, iNumFiles, id);
+ }
+ }
+ else if (iOption & EPlugin)
+ {
+ if (*iCurrentOp == EOpCreate || *iCurrentOp == EOpReplace || *iCurrentOp == EOpRename ||
+ *iCurrentOp == EOpDelete || *iCurrentOp == EOpRenameDir)
+ {
+ SAFETEST2(aNumChanges, iNumFiles, id);
+ }
+ else if (*iCurrentOp == EOpMixed)
+ {
+ SAFETEST2(aNumChanges, (8*iNumFiles), id); // only part of operations can be notified
+ }
+ // Other cases are not testable.
+ }
+ }
+
+//===========================================================
+
+CNotifyWatcher::CNotifyWatcher(TInt aNumFiles, TUint16 aOption, TUint aCurrentOp, CTimerLogger* aLogger)
+: CActive(CActive::EPriorityStandard), iCounter(0), iMeanCounter(0), iOverflowCounter(0), iCurrentOp(aCurrentOp),
+iNumFiles(aNumFiles), iOption(aOption), iEntries(aNumFiles), iRecords(aNumFiles), iLogger(aLogger)
+ {
+ }
+
+CNotifyWatcher::~CNotifyWatcher()
+ {
+ Cancel();
+ delete iNotify;
+
+ iFs.DismountPlugin(KPluginName);
+ iFs.RemovePlugin(KPluginName);
+
+ iFs.Close();
+ iEntries.Close();
+ iRecords.Close();
+ }
+
+CNotifyWatcher* CNotifyWatcher::NewL(TInt aNumFiles, TUint16 aOption, TUint aCurrentOp, CTimerLogger* aLogger)
+ {
+ CNotifyWatcher* self = new(ELeave) CNotifyWatcher(aNumFiles, aOption, aCurrentOp, aLogger);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CNotifyWatcher::ConstructL()
+ {
+ iFs.Connect();
+
+ if (iOption & EEnhanced)
+ {
+ TInt bufferSize;
+ if(iOption & EBigBuffer)
+ {
+ bufferSize = KMinNotificationBufferSize * iNumFiles;
+ if (iCurrentOp == EOpMixed)
+ bufferSize = bufferSize * 18;
+ }
+ else
+ bufferSize = KMinNotificationBufferSize;
+
+ iNotify = CFsNotify::NewL(iFs, bufferSize);
+ }
+ else
+ iNotify = NULL;
+
+ if (iOption& EPlugin)
+ {
+ TInt r = iFs.AddPlugin(KPluginName);
+ test(r == KErrNone || r == KErrAlreadyExists);
+ if (r != KErrAlreadyExists)
+ {
+ r = iFs.MountPlugin(KPluginName);
+ test(r == KErrNone);
+ }
+ }
+
+ FullDirectoryScanL(iEntries);
+ iRecords.Reset();
+ }
+
+// reset certain members so that we can do next test step
+void CNotifyWatcher::Reset(TUint aOp)
+ {
+ iCurrentOp = aOp;
+ iRecords.Reset();
+ iCounter = 0;
+ iOverflowCounter = 0;
+ iMeanCounter = 0;
+ if ((aOp == EOpManyFiles) || (aOp == EOpManyChanges))
+ iNumFiles += 1000;
+ }
+
+// perform a full dir scan
+void CNotifyWatcher::FullDirectoryScanL(RArray<TEntry>& aArray)
+ {
+ aArray.Reset();
+
+ CDir* list;
+ iFs.GetDir(gTestPath, KEntryAttMaskSupported, ESortByName, list);
+
+ if (!list)
+ return;
+
+ CleanupStack::PushL(list);
+
+ for (TInt i = 0; i < list->Count(); i++)
+ {
+ TEntry en ((*list)[i]);
+ aArray.AppendL(en);
+ }
+
+ CleanupStack::PopAndDestroy();
+ }
+
+// find out what has changed in test path, and save the changes in iRecord
+void CNotifyWatcher::MakeChangeRecordL(RArray<TEntry>& aArray)
+ {
+ TInt num = aArray.Count();
+ TInt r,i;
+ for (i = 0; i < num; i++)
+ {
+ TInt index = iEntries.Find(aArray[i], CompareEntryName);
+ SAFETEST1((index == KErrNotFound || index >= 0), (iOption & KNotifyTreadIdMask));
+
+ TFileName name(aArray[i].iName);
+
+ if (index == KErrNotFound)
+ {
+ r = iRecords.Append(name);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ }
+ else
+ {
+ if (!CompareEntry(iEntries[index], aArray[i]))
+ {
+ r = iRecords.Append(name);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ }
+ iEntries.Remove(index);
+ }
+ }
+
+ num = iEntries.Count();
+
+ for (i = 0; i < num; i++)
+ {
+ TFileName name(iEntries[i].iName);
+ r = iRecords.Append(name);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ }
+
+ iEntries.Reset();
+ num = aArray.Count();
+ for (i = 0; i < num; i++)
+ {
+ TEntry en (aArray[i]);
+ iEntries.AppendL(en);
+ }
+ }
+
+
+TBool CNotifyWatcher::CompareEntry(const TEntry& aEntry1, const TEntry& aEntry2)
+ {
+ // we don't compare name, because names are compared by CompareEntryName() already
+ if ((aEntry1.iAtt == aEntry2.iAtt) && (aEntry1.iModified == aEntry2.iModified)
+ && (aEntry1.iSize == aEntry2.iSize) && (aEntry1.iType == aEntry2.iType))
+ return ETrue;
+
+ return EFalse;
+ }
+
+// add 100 filters for enhanced notification test case
+void CNotifyWatcher::AddLotsOfFilters()
+ {
+ for (TInt i = 0; i < 100; i++)
+ {
+ TFileName path;
+ path.Copy(gTestPath);
+ path.Append('*');
+ TFileName file;
+ file.AppendFormat(_L("*.%3d"), i);
+ TInt r = iNotify->AddNotification((TUint)TFsNotification::EAllOps, gTestPath, file);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ }
+ }
+
+void CNotifyWatcher::RequestNotification()
+ {
+ switch (iOption & KNotifyOptionMask)
+ {
+ case EEnhanced:
+ RequestNotificationEnhanced();
+ break;
+ case EOriginal:
+ RequestNotificationOriginal();
+ break;
+ case EPlugin:
+ RequestNotificationPlugin();
+ break;
+ case ENoNotify:
+ default:
+ return;
+ }
+ }
+
+// request notification using enhanced notification
+void CNotifyWatcher::RequestNotificationEnhanced()
+ {
+ if (iOption & EBigFilter)
+ {
+ AddLotsOfFilters();
+ }
+
+ TFileName path;
+ path.Copy(gTestPath);
+ path.Append('*');
+ TBuf<3> file = _L("*");
+
+ if (iOption & EMultiNoti1)
+ {
+ TInt r = iNotify->AddNotification(TFsNotification::ECreate, path, file); // Create & replace
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ r = iNotify->AddNotification(TFsNotification::ERename, path, file); // Change Attribute
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ r = iNotify->AddNotification(TFsNotification::EAttribute, path, file); // Rename
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ r = iNotify->AddNotification(TFsNotification::EFileChange, path, file); // Write & Setsize
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ r = iNotify->AddNotification(TFsNotification::EDelete, path, file); // Delete
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ }
+ else if (iOption & EMultiNoti2)
+ {
+ TInt r = iNotify->AddNotification(TFsNotification::ECreate, path, file); // Create & replace
+ TInt id = iOption & KNotifyTreadIdMask;
+
+ switch (id%4)
+ {
+ case 0:
+ r = iNotify->AddNotification(TFsNotification::ERename, path, file); // Change Attribute
+ SAFETEST2(r, KErrNone, id);
+ break;
+ case 1:
+ r = iNotify->AddNotification(TFsNotification::EAttribute, path, file); // Rename
+ SAFETEST2(r, KErrNone, id);
+ break;
+ case 2:
+ r = iNotify->AddNotification(TFsNotification::EFileChange, path, file); // Write & Setsize
+ SAFETEST2(r, KErrNone, id);
+ break;
+ case 3:
+ r = iNotify->AddNotification(TFsNotification::EDelete, path, file); // Delete
+ SAFETEST2(r, KErrNone, id);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ TInt r = iNotify->AddNotification((TUint)TFsNotification::EAllOps, path, file);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ }
+
+ TInt r = iNotify->RequestNotifications(iStatus);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+
+ SetActive();
+ }
+
+// request notification using original notification
+void CNotifyWatcher::RequestNotificationOriginal()
+ {
+ iFs.NotifyChange(ENotifyAll, iStatus, gTestPath);
+ SetActive();
+ }
+
+void CNotifyWatcher::HandleNotification(TBool aLastTime)
+ {
+ switch (iOption & KNotifyOptionMask)
+ {
+ case EEnhanced:
+ HandleNotificationEnhanced(aLastTime);
+ break;
+ case EOriginal:
+ HandleNotificationOriginal(aLastTime);
+ break;
+ case EPlugin:
+ HandleNotificationPlugin(aLastTime);
+ break;
+ case ENoNotify:
+ default:
+ return;
+ }
+
+ if(aLastTime)
+ {
+ iLogger->MeasureEnd();
+ RDebug::Print(_L("Timing ended..."));
+ Cancel();
+ }
+ }
+
+// handle enhanced notification
+void CNotifyWatcher::HandleNotificationEnhanced(TBool aLastTime)
+ {
+ TInt num = iCounter;
+ iMeanCounter++;
+
+ TFsNotification::TFsNotificationType type;
+ const TFsNotification* notification;
+
+ while((notification = iNotify->NextNotification())!= NULL)
+ {
+ iCounter++;
+ type = notification->NotificationType();
+ if (iOption & EBigBuffer)
+ {
+ SAFETEST1((type & OpNotifyMapping(iOption, iCurrentOp)), (iOption & KNotifyTreadIdMask));
+ }
+ else
+ {
+ SAFETEST1((type & (OpNotifyMapping(iOption, iCurrentOp) | TFsNotification::EOverflow)), (iOption & KNotifyTreadIdMask));
+ }
+
+ if(iOption & EReportChg)
+ {
+ if (type & TFsNotification::EOverflow)
+ {
+ iOverflowCounter++;
+ RArray<TEntry> newEntries;
+ FullDirectoryScanL(newEntries);
+ MakeChangeRecordL(newEntries);
+ newEntries.Close();
+ }
+ else
+ {
+ TPtrC ptr;
+ notification->Path(ptr);
+ TFileName name;
+ name.Copy(ptr);
+ TInt r = iRecords.Append(name);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ }
+ }
+ }
+
+ if (aLastTime)
+ {
+ if (num == iCounter) // no new notification so this iteration doesn't count
+ {
+ iMeanCounter--;
+ }
+ return;
+ }
+
+ iNotify->RequestNotifications(iStatus);
+ SetActive();
+ }
+
+// handle original notification
+void CNotifyWatcher::HandleNotificationOriginal(TBool aLastTime)
+ {
+ iCounter++;
+
+ if (iOption & EReportChg)
+ {
+ RArray<TEntry> newEntries;
+ FullDirectoryScanL(newEntries);
+ MakeChangeRecordL(newEntries);
+ newEntries.Close();
+ }
+
+ if (aLastTime)
+ {
+ iCounter--; // the last time this function is called is not a notification.
+ return;
+ }
+
+ RequestNotificationOriginal();
+ }
+
+// reset the iPluginStatusPkg, so that we can request notification again
+void CNotifyWatcher::ResetMdsFSPStatus()
+ {
+ TMdsFSPStatus& status = iPluginStatusPkg();
+
+ status.iDriveNumber = 0;
+ status.iFileEventType = EMdsFileUnknown;
+ status.iFileName.Zero();
+ status.iNewFileName.Zero();
+ status.iProcessId = TUid::Null();
+ }
+
+// request notification using nokia MDS plugin
+void CNotifyWatcher::RequestNotificationPlugin()
+ {
+ TInt r = iPlugin.Open(iFs, KMdsFSPluginPosition);
+ SAFETEST2(r, KErrNone, (iOption & KNotifyTreadIdMask));
+ iPlugin.AddNotificationPath(gTestPath);
+
+ iPlugin.Enable();
+ ResetMdsFSPStatus();
+ iPlugin.RegisterNotification(iPluginStatusPkg, iStatus);
+ SetActive();
+ }
+
+// handle notifications from plugin
+void CNotifyWatcher::HandleNotificationPlugin(TBool aLastTime)
+ {
+ if (aLastTime)
+ return;
+
+ if (iOption & EReportChg)
+ {
+ TMdsFSPStatus& status = iPluginStatusPkg();
+ TFileName name;
+ name.Copy(status.iFileName);
+ iRecords.Append(name);
+ if (iCurrentOp != EOpMixed)
+ {
+ TInt type = status.iFileEventType;
+ SAFETEST1(((TUint)type == OpNotifyMapping(iOption, iCurrentOp)), (iOption & KNotifyTreadIdMask));
+ }
+ }
+
+ iCounter++;
+ ResetMdsFSPStatus();
+ iPlugin.RegisterNotification(iPluginStatusPkg, iStatus);
+ SetActive();
+ }
+
+// cancel request
+void CNotifyWatcher::DoCancel()
+ {
+ switch (iOption & KNotifyOptionMask)
+ {
+ case EEnhanced:
+ iNotify->CancelNotifications(iStatus);
+ iNotify->RemoveNotifications();
+ // not breaking here as the Enhanced may change to Original if Overflow
+ case EOriginal:
+ iFs.NotifyChangeCancel(iStatus);
+ break;
+ case EPlugin:
+ iPlugin.Disable();
+ iPlugin.NotificationCancel();
+ iPlugin.Close();
+ break;
+ case ENoNotify:
+ default:
+ return;
+ }
+ }
+
+void CNotifyWatcher::RunL()
+ {
+ HandleNotification(EFalse);
+ }
+
+//========================================================================
+
+CTestStopper::CTestStopper()
+: CActive(EPriorityLow)
+ {
+ iFs.Connect();
+ iTestEndFile.Append(gLogFilePath);
+ iTestEndFile.Append(_L("test.End"));
+ }
+
+CTestStopper::~CTestStopper()
+ {
+ Cancel();
+ iFs.Close();
+ }
+
+void CTestStopper::DoCancel()
+ {
+ iFs.NotifyChangeCancel(iStatus);
+ }
+
+// stop the scheduler since the test is done
+void CTestStopper::RunL()
+ {
+ CActiveScheduler::Stop();
+ iFs.Delete(iTestEndFile);
+ Cancel();
+ }
+
+// start waiting for "test.end" file
+void CTestStopper::StartWaitingForFile()
+ {
+ iFs.NotifyChange(ENotifyAll,iStatus,iTestEndFile);
+ SetActive();
+ }