diff -r 000000000000 -r a41df078684a kerneltest/f32test/server/t_notifier.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/f32test/server/t_notifier.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,4523 @@ +// Copyright (c) 2008-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\server\t_notifier.cpp +// +// + +#include +#include +#include +#include +#include "t_server.h" +#include "t_chlffs.h" +#include "t_notify_plugin.h" + +const TInt KNotificationHeaderSize = (sizeof(TUint16)*2)+(sizeof(TUint)); +const TInt KMinNotificationBufferSize = 2*KNotificationHeaderSize + 2*KMaxFileName; + + +RTest test(_L("T_NOTIFIER")); +const TInt KMaxHeapSize = 0x800000; +TInt globalDriveNum; + +void DismountPlugin() + { + TheFs.DismountPlugin(KNotifyPluginName); + TheFs.RemovePlugin(KNotifyPluginFileName); + } + +inline void safe_test(RTest& aTest, TInt aError, TInt aLine, TText* aName) + { + if(aError!=KErrNone) + { + test.Printf(_L(": ERROR : %d received on line %d\n"),aError,aLine); + DismountPlugin(); + aTest.operator()(aError==KErrNone,aLine,(TText*)aName); + } + } + +// Used by TestMultipleNotificationsL() to show which line the function is called from +inline void safe_test(RTest& aTest, TInt aError, TInt aLine, TInt aLineCall) + { + if(aError != KErrNone) + { + aTest.Printf(_L(": ERROR : %d received on line %d\n"), aError, aLine); + aTest.Printf(_L(": ERROR : Function called from line number: %d\n"), aLineCall); + aTest.operator()(aError == KErrNone, aLine); + } + } + +// Prints out the filename +#define ExpandMe(X) L ## X +#define Expand(X) ExpandMe(X) + +namespace t_notification + { + enum EOperation + { + //TFsNotification::ECreate + EFileReplace, + EFileCreate, + EFileCreate_subs, //Create files in subdir, watch subdirs + EFileCreate_subs_nowatch, //Create files in subdir, do not monitor subdirs + EFileCreate_txt_nowatch, //Create .txt files in subdir, do not monitor subdirs + EFileCreate_txt, //Create .txt files + EFsMkDir, //Create directory + //TFsNotification::EAttribute + EFileSetAtt, + EFileSetAtt_subs, //Set attributes in subdir + EFileSet, + EFsSetEntry, + //TFsNotification::ERename + EFsReplace, //Replace file + EFsRename, //Rename file + EFsRename_dir, //Rename directory + EFileRename, + EFileRename_wild, //Rename file using wildcard name + //TFsNotification::EDelete + EFsDelete, //Delete file + EFsRmDir, //Remove directory + EFsRmDir_nonEmpty, //Remove non-empty directory, which will return KErrInUse + EFsRmDir_wild, //Remove subdirectory using wildcard name + //TFsNotification::EFileChange + EFileWrite, + EFileWrite_samesize, //Write to file without changing its size + EFileWrite_async, //Asynchronous write + EFileSetSize, + //TFsNotification::EVolumeName + ESetVolumeLabel, + //TFsNotification::EDriveName + ESetDriveName, + //TFsNotification::EMediaChange + EMount, + EDismount, + EMountScan, + EMountDismount, + EFormat, + EMediaCardRemoval, + EMediaCardInsertion, + ERawDiskWrite, + //Multiple Filters + EAllOps1, //Create/Replace and Delete + EAllOps2, //Create/Replace, FileChange(Write) and Delete + EAllOps3, //Create/Replace, FileChange(SetSize) and Delete + EAllOps4, //Create/Replace, Attribute(SetAtt) and Delete + EAllOps5, //Create/Replace and Rename + EAllOps6, //VolumeName and DriveName + ECFileManMove //Create filex in monitored directory, write 4, move to unmonitored, setsize 8, move back, delete + }; + } + +// Package filename and semaphore for thread +struct SThreadPackage + { + TFileName iFileName; + RSemaphore iBarrier; + }; + +struct SThreadPackageDualSemaphore + { + TFileName iFileName; + RSemaphore iBarrier; + RSemaphore iBarrier2; + }; + +struct SThreadPackage2 + { + TInt iTestCase; + RSemaphore iBarrier; + }; + +// Used by TestMultipleNotificationsL +struct SThreadPackageMultiple + { + TFileName iString; //Commonly stores the filename + TFileName iFileName; //Commonly stores the path (not inc filename) + RSemaphore iBarrier; + t_notification::EOperation iOperation; + TFsNotification::TFsNotificationType iNotifyType; + TInt iIterations; //# of times to 'do' something + TInt iMaxNotifications; //# of notifications expected + TInt iBufferSize; + TInt iLineCall; //Line where the function is called from + }; + +void PrintLine() + { + test.Printf(_L("======================================================================\n")); + } + + +// We should receive an EMediaChange notification even though we did not register for it +void TestMediaCardNotificationWhenNotRegisteredForIt() + { + RFs fs; + TInt r = fs.Connect(); + test(r==KErrNone); + + CFsNotify* notify = NULL; + TRAP(r,notify= CFsNotify::NewL(fs,KMinNotificationBufferSize)); + + TBuf<40> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + + TBuf<20> filename; + filename.Append(_L("media.change1")); + + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,filename); + test(r==KErrNone); + + TRequestStatus status; + r = notify->RequestNotifications(status); + test(r==KErrNone); + + test.Printf(_L("*****************************************************************\n")); + test.Printf(_L("Waiting 10 seconds.\n")); + test.Printf(_L("This is a MANUAL test, it requires the removal of the media card.\n")); + test.Printf(_L("PLEASE REMOVE THE MEDIA CARD. (DriveNumber %d)\n"),globalDriveNum); + test.Printf(_L("Or press Ctrl + F5 on the emulator.\n")); + test.Printf(_L("*****************************************************************\n")); + RTimer timer1; + r = timer1.CreateLocal(); + test(r == KErrNone); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 10000000; + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() != KRequestPending); + timer1.Cancel(); + timer1.Close(); + + const TFsNotification* notification = notify->NextNotification(); + test(notification != NULL); + TFsNotification::TFsNotificationType type = notification->NotificationType(); + test(type == TFsNotification::EMediaChange); + TBuf<2> drive; + drive.Append((TChar)gDriveToTest); + drive.Append(_L(":")); + TPtrC drivePtr; + r = notification->Path(drivePtr); + test(r==KErrNone); + r = drivePtr.Compare(drive); + test(r==0); + + test.Printf(_L("*****************************************************************\n")); + test.Printf(_L("Waiting 10 seconds.\n")); + test.Printf(_L("This is a MANUAL test, it requires the insertion of the media card.\n")); + test.Printf(_L("PLEASE INSERT THE MEDIA CARD. (DriveNumber %d)\n"),globalDriveNum); + test.Printf(_L("Or press Ctrl + F5 on the emulator.\n")); + test.Printf(_L("*****************************************************************\n")); + + notification = notify->NextNotification(); + if(notification == NULL) + { + notify->RequestNotifications(status); + RTimer timer2; + r = timer2.CreateLocal(); + test(r == KErrNone); + TRequestStatus timeout2; + timer2.After(timeout2,time); + User::WaitForRequest(timeout2,status); + test(status.Int() != KRequestPending); + notification = notify->NextNotification(); + timer2.Cancel(); + timer2.Close(); + } + test(notification != NULL); + type = notification->NotificationType(); + test(type == TFsNotification::EMediaChange); + + delete notify; + fs.Close(); + } + +// Creates two sessions, removes the first one +// and then checks if the second one still works +TInt TestClientRemovalL() + { + RFs fs; + TInt r = fs.Connect(); + test(r==KErrNone); + + CFsNotify* notify1 = NULL; + CFsNotify* notify2 = NULL; + TRAP(r,notify1= CFsNotify::NewL(fs,KMinNotificationBufferSize); + notify2= CFsNotify::NewL(fs,KMinNotificationBufferSize); + ); + if(r!=KErrNone) + { + delete notify1; + delete notify2; + test(r==KErrNone); + } + + TBuf<40> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + + TBuf<15> filename; + filename.Append(_L("create.file")); + + TBuf<40> fullname; + fullname.Append(path); + fullname.Append(filename); + + r = notify1->AddNotification((TUint)TFsNotification::ECreate,path,filename); + test(r==KErrNone); + r = notify2->AddNotification((TUint)TFsNotification::ECreate,path,filename); + test(r==KErrNone); + + delete notify1; //Delete notify1 and ensure we still get notification on notify2 + + TRequestStatus status; + r = notify2->RequestNotifications(status); + test(r==KErrNone); + + RFile file; + file.Replace(fs,fullname,EFileWrite); //Replace produces Create notification + file.Close(); + + RTimer tim; + r = tim.CreateLocal(); + test(r==KErrNone); + + TRequestStatus timStatus; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + tim.After(timStatus,time); + + User::WaitForRequest(status,timStatus); + test(status!=KRequestPending); + + r = fs.Delete(fullname); + test(r==KErrNone); + + delete notify2; + tim.Close(); + fs.Close(); + return KErrNone; + } + +/* + * This tests that u can set and receive notifications in the root + * of a drive. + * + * (something which was apparently not possible on RFs::NotifyChange) + */ +TInt TestRootDriveNotifications() + { + test.Next(_L("TestRootDriveNotifications")); + RFs fs; + fs.Connect(); + + CFsNotify* notify = NULL; + + TRAPD(r,notify = CFsNotify::NewL(fs,KMinNotificationBufferSize);); + test(r==KErrNone); + test(notify!=NULL); + + TBuf<40> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\")); + + TBuf<15> filename; + filename.Append(_L("*")); + + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,filename); + test(r==KErrNone); + + TRequestStatus status; + r = notify->RequestNotifications(status); + test(r==KErrNone); + + RFile file; + TBuf<40> filePath; + filePath.Append((TChar)gDriveToTest); + filePath.Append(_L(":\\file.root")); + r = file.Replace(fs,filePath,EFileRead); + test(r==KErrNone); + file.Close(); + + TRequestStatus s2; + RTimer tim; + test(tim.CreateLocal()==KErrNone); + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + tim.After(s2,time); + User::WaitForRequest(status,s2); + test(status!=KRequestPending); + + delete notify; + notify = NULL; + tim.Close(); + fs.Close(); + return KErrNone; + } + +/* + * Creates and deletes loads of CFsNotify objects and makes sure they're all + * cleaned up afterwards. + */ +TInt TestNewDeleteCFsNotify(TInt aIterations) + { + RPointerArray array; + TInt inArray = 0; + TInt r = KErrNone; + for(TInt i = 0; i < aIterations; i++) + { + CFsNotify* notify = NULL; + TRAP(r,notify = CFsNotify::NewL(TheFs,500)); + if(r==KErrNone) + { + test(notify!=NULL); + r = array.Append(notify); + if(r==KErrNone) + { + inArray++; + } + else + { + delete notify; + break; + } + } + else + { + break; + } + } + + for(TInt j = inArray-1; j >= 0; j--) + { + CFsNotify* notify = (CFsNotify*)array[j]; + array.Remove(j); + delete notify; + } + + array.Reset(); + array.Close(); + return KErrNone; + } + + +/* + * Creates a file + * Used in SimpleTest1L(), TestTwoDoersL() TestTwoWatchersL(), TestCancelNotificationL() + */ +TInt SimpleSingleNotificationTFDoer(TAny* aAny) + { + SThreadPackageDualSemaphore pkgDoer = *(SThreadPackageDualSemaphore*)aAny; + RTest simpleTestDoer(_L("SimpleSingleNotificationTFDoer")); + simpleTestDoer.Start(_L("SimpleSingleNotificationTFDoer")); + TBuf<40> path; + path.Append(gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + path.Append(pkgDoer.iFileName); + + //Delete file so we definitely get a create notification + RFs fs; + TInt r = fs.Connect(); + safe_test(simpleTestDoer,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + r = fs.Delete(path); + if(r==KErrNone || r==KErrPathNotFound || r==KErrNotFound) + r = KErrNone; + safe_test(simpleTestDoer,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + r = fs.MkDirAll(path); + if(r==KErrNone || r==KErrAlreadyExists) + r = KErrNone; + safe_test(simpleTestDoer,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + + simpleTestDoer.Printf(_L("SimpleSingleNotificationTFDoer - Create File %S\n"),&path); + //Create file + RFile file; + r = file.Create(fs,path,EFileWrite); + safe_test(simpleTestDoer,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + file.Close(); + + fs.Close(); + simpleTestDoer.End(); + simpleTestDoer.Close(); + return KErrNone; + } + +/* + * Watches 1 file creation + * Used in SimpleTest1L() + */ +TInt SimpleSingleNotificationTFWatcher(TAny* aAny) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + RThread thread; + TUint64 threadId = thread.Id().Id(); + + SThreadPackage pkgDoer = *(SThreadPackage*)aAny; + RSemaphore& simpleBarrierTest = pkgDoer.iBarrier; + + RTest simpleTestWatcher(_L("SimpleSingleNotificationTFWatcher")); + simpleTestWatcher.Start(_L("SimpleSingleNotificationTFWatcher")); + + RFs fs; + fs.Connect(); + + simpleTestWatcher.Printf(_L("SimpleSingleNotificationTFWatcher(%d) - Create CFsNotify\n"),threadId); + CFsNotify* notify = NULL; + TRAPD(r,notify = CFsNotify::NewL(fs,100); ); + safe_test(simpleTestWatcher,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TBuf<40> path; + path.Append(gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); //len=22 + + TBuf<20> filename; + filename.Append(pkgDoer.iFileName); + + TBuf<40> fullname; + fullname.Append(path); + fullname.Append(filename); + + simpleTestWatcher.Printf(_L("SimpleSingleNotificationTFWatcher - Add Notification for %S\n"),&path); + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,filename); + safe_test(simpleTestWatcher,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus status; + simpleTestWatcher.Printf(_L("SimpleSingleNotificationTFWatcher(%d) - Request Notifications\n"),threadId); + r = notify->RequestNotifications(status); + safe_test(simpleTestWatcher,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + + simpleBarrierTest.Signal(); + + simpleTestWatcher.Printf(_L("SimpleSingleNotificationTFWatcher(%d) - Wait for status to return\n"),threadId); + User::WaitForRequest(status); + + simpleTestWatcher.Printf(_L("(%d) NextNotification\n"),threadId); + const TFsNotification* notification = notify->NextNotification(); + //Test notification is not null. + //We should be getting 1 notification. + if(notification == NULL) + safe_test(simpleTestWatcher,KErrNotFound,__LINE__,(TText*)Expand("t_notifier.cpp")); + + simpleTestWatcher.Printf(_L("(%d) - Notification Type\n"),threadId); + TFsNotification::TFsNotificationType notificationType = ((TFsNotification*)notification)->NotificationType(); + if(notificationType != TFsNotification::ECreate) + safe_test(simpleTestWatcher,KErrGeneral,__LINE__,(TText*)Expand("t_notifier.cpp")); + simpleTestWatcher.Printf(_L("(%d) - Notification Path\n"),threadId); + TPtrC _pathC; + ((TFsNotification*)notification)->Path(_pathC); + simpleTestWatcher.Printf(_L("Notification Path = %S\n"),&_pathC); + TBuf<40> _path; + _path.Copy(_pathC); + if(_path.Match(fullname)!=KErrNone) + safe_test(simpleTestWatcher,KErrBadName,__LINE__,(TText*)Expand("t_notifier.cpp")); + + /* + TInt driveNumber = 0; + TInt gDriveNum = -1; + notification->DriveNumber(driveNumber); + RFs::CharToDrive(_pathC[0],gDriveNum); + if(driveNumber != gDriveNum) + safe_test(simpleTestWatcher,KErrBadHandle,__LINE__,(TText*)Expand("t_notifier.cpp")); + + TUid uid; + TUint32 realUID = 0x76543210; + r = notification->UID(uid); + safe_test(simpleTestWatcher,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + safe_test(simpleTestWatcher,(realUID == uid.iUid)==1,__LINE__,(TText*)Expand("t_notifier.cpp")); + */ + delete notify; + fs.Close(); + simpleTestWatcher.End(); + simpleTestWatcher.Close(); + delete cleanup; + return KErrNone; + } + +/* + * SimpleTest1L - Runs a simple Create test, gets 1 notification, calls type, path etc and exits + * Two threads: 1 watcher, 1 doer + */ +TInt SimpleCreateTestL() + { + test.Next(_L("SimpleTest")); + RFs fs; + fs.Connect(); + _LIT(KFileName,"simple.create"); + SThreadPackage pkgDoer; + pkgDoer.iFileName = KFileName; + + SThreadPackage watcherPkg; + watcherPkg.iFileName = KFileName; + User::LeaveIfError(pkgDoer.iBarrier.CreateLocal(0)); + User::LeaveIfError(watcherPkg.iBarrier.CreateLocal(0)); + RThread watcher; + RThread doer; + watcher.Create(_L("Simple1WatcherThread"),SimpleSingleNotificationTFWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&watcherPkg); + doer.Create(_L("Simple1DoerThread"),SimpleSingleNotificationTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&pkgDoer); + watcher.Resume(); + watcherPkg.iBarrier.Wait(); //Wait till Watcher has requested notification + doer.Resume(); + + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test.Printf(_L("SimpleCreateTest - Doer Exit Reason = %d\n"),doer.ExitReason()); + safe_test(test,doer.ExitReason(),__LINE__,(TText*)Expand("t_notifier.cpp")); + + RDebug::Print(_L("Line %d"),__LINE__); + + + watcher.Logon(status); + RTimer timer1; + TInt r = timer1.CreateLocal(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() != KRequestPending); + timer1.Cancel(); + timer1.Close(); + + +// User::WaitForRequest(status); + test.Printf(_L("SimpleCreateTest - Watcher Exit Reason = %d\n"),watcher.ExitReason()); + safe_test(test,watcher.ExitReason(),__LINE__,(TText*)Expand("t_notifier.cpp")); + + CLOSE_AND_WAIT(doer); + CLOSE_AND_WAIT(watcher); + + pkgDoer.iBarrier.Close(); + watcherPkg.iBarrier.Close(); + fs.Close(); + return KErrNone; + } + +// Doer thread for TestMultipleNotificationsL +TInt MultipleNotificationTFDoer(TAny* aAny) + { + RDebug::Print(_L("MultipleNotificationTFDoer - Start, Line %d"), __LINE__); + SThreadPackageMultiple pkgDoer = *(SThreadPackageMultiple*)aAny; + RTest multipleTestDoer(_L("MultipleNotificationTFDoer")); + multipleTestDoer.Start(_L("Multi-Doer")); + multipleTestDoer.Printf(_L("MultipleNotificationTFDoer - Line %d"),__LINE__); + TBuf<40> basepath; + basepath.Append(gDriveToTest); + basepath.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + + RThread thread; + RDebug::Print(_L("MultipleNotificationTFDoer - Line %d"), __LINE__); + TUint64 threadID = thread.Id().Id(); + RDebug::Print(_L("MultipleNotificationTFDoer - Line %d"), __LINE__); + + //Delete file so we definitely get a create notification + RFs fs; + TInt r = fs.Connect(); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + TEntry entry; + TBool wildcard = EFalse; + TBuf<40> _path; + _path.Append(basepath); + _path.Append(pkgDoer.iFileName); + _path.Append(pkgDoer.iString); + r = fs.Entry(_path, entry); + if (pkgDoer.iNotifyType != TFsNotification::EMediaChange && + pkgDoer.iNotifyType != TFsNotification::EDriveName && + pkgDoer.iNotifyType != TFsNotification::EVolumeName && + pkgDoer.iOperation != t_notification::EAllOps6) + { + if (r == KErrBadName) + { + wildcard = ETrue; + } + if(r != KErrNone && r != KErrPathNotFound && r != KErrNotFound && r != KErrBadName) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + if (r == KErrNone && !entry.IsDir() && pkgDoer.iOperation != t_notification::EFsDelete && !wildcard && + pkgDoer.iOperation != t_notification::EFsRmDir && pkgDoer.iOperation != t_notification::EFsRmDir_nonEmpty) + { + r = fs.Delete(_path); + if(r != KErrNone && r != KErrPathNotFound && r != KErrNotFound) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + r = fs.MkDirAll(basepath); + if(r != KErrNone && r != KErrAlreadyExists) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + + multipleTestDoer.Printf(_L("MultipleNotificationTFDoer (%d) - Line %d"),threadID,__LINE__); + + switch(pkgDoer.iOperation) + { + case t_notification::EFileReplace: + { + RFile file; + //Generate Notification + multipleTestDoer.Printf(_L("File Replace - (%d)\n"),threadID); + r = file.Replace(fs,_path,EFileWrite); //RFile::Replace -> TFsNotification::ECreate + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + + r = fs.Delete(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFileCreate: + case t_notification::EFileCreate_txt_nowatch: + case t_notification::EFileCreate_txt: + case t_notification::EAllOps1: + { + multipleTestDoer.Printf(_L("MultipleNotificationTFDoer (%d) - Line %d"),threadID,__LINE__); + if(wildcard) + { + for (TInt i = 0; i < pkgDoer.iIterations; i++) + { + multipleTestDoer.Printf(_L("MultipleNotificationTFDoer (%d) - Line %d"),threadID,__LINE__); + RFile file; + TBuf<40> path; + path.Append(basepath); + path.AppendNum(i); + if(pkgDoer.iOperation == t_notification::EFileCreate_txt) + { + //Create file with different extension (no notification) + path.Append(_L(".wrg")); + fs.Delete(path); + multipleTestDoer.Printf(_L("File Create (wrong extension) - %S (%d)\n"),&path,threadID); + r = file.Create(fs, path, EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + //Change path to contain file with correct extension (notification occurs) + path.Replace(path.Length()-3,3,_L("txt")); + } + else if(pkgDoer.iOperation == t_notification::EFileCreate_txt_nowatch) + { + path.Append(_L(".txt")); + } + fs.Delete(path); + + multipleTestDoer.Printf(_L("File Create - %S (%d)\n"),&path,threadID); + r = file.Create(fs, path, EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + } + else + { + multipleTestDoer.Printf(_L("MultipleNotificationTFDoer (%d) - Line %d"),threadID,__LINE__); + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + multipleTestDoer.Printf(_L("MultipleNotificationTFDoer (%d) - Line %d"),threadID,__LINE__); + RFile file; + multipleTestDoer.Printf(_L("File Create - %S (%d)\n"),&_path,threadID); + r = file.Create(fs,_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + r = fs.Delete(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + } + break; + } + case t_notification::EFileCreate_subs: + case t_notification::EFileCreate_subs_nowatch: + { + if (wildcard) + { + for (TInt i = 0; i < pkgDoer.iIterations; i++) + { + RFile file; + TBuf<40> path; + path.Append(basepath); + path.Append(_L("SubDir\\")); + r = fs.MkDirAll(path); + if(r != KErrNone && r != KErrAlreadyExists) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + path.AppendNum(i); + fs.Delete(path); + multipleTestDoer.Printf(_L("File Create - %S (%d)\n"),&path,threadID); + r = file.Create(fs, path, EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + } + break; + } + case t_notification::EFileWrite: + case t_notification::EAllOps2: + { + //Works on single file + RFile file; + TBuf<40> path; + path.Append(basepath); + path.Append(pkgDoer.iFileName); + path.Append(pkgDoer.iString); + r = file.Replace(fs,path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + multipleTestDoer.Printf(_L("File Write - %S (%d)\n"),&path,threadID); + r = file.Write(4*i,_L8("abcd")); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + //If cache is enabled, a notification is received only when the cache is flushed + //We flush the file to make this a general test + multipleTestDoer.Printf(_L("File Flush - (%d)\n"),threadID); + r = file.Flush(); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + file.Close(); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFileWrite_samesize: + { + RFile file; + TBuf<40> path; + path.Append(basepath); + path.Append(pkgDoer.iFileName); + path.Append(pkgDoer.iString); + r = file.Replace(fs,path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + multipleTestDoer.Printf(_L("File Write - %S (%d)\n"),&path,threadID); + r = file.Write(0,_L8("abcd")); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //If cache is enabled, a notification is received only when the cache is flushed + //We flush the file to make this a general test + multipleTestDoer.Printf(_L("File Flush - (%d)\n"),threadID); + r = file.Flush(); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + TBuf<2> toWrite; + toWrite.AppendNum(i); + multipleTestDoer.Printf(_L("File Write - %S (%d)\n"),&path,threadID); + r = file.Write(0,(TDesC8&)toWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + multipleTestDoer.Printf(_L("File Flush - (%d)\n"),threadID); + r = file.Flush(); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + file.Close(); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFileWrite_async: + { + RFile file; + TBuf<40> path; + path.Append(basepath); + path.Append(pkgDoer.iFileName); + path.Append(pkgDoer.iString); + r = file.Replace(fs,path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + TRequestStatus status; + file.Write(52*i, _L8("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), status); + User::WaitForRequest(status); + multipleTestDoer.Printf(_L("File Write Async - %S (%d)\n"),&path,threadID); + TInt fileSize; + file.Size(fileSize); + multipleTestDoer.Printf(_L("File Write Async - FileSize: %d\n"),fileSize); + multipleTestDoer.Printf(_L("File Flush - (%d)\n"),threadID); + r = file.Flush(); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + file.Close(); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFileSetSize: + case t_notification::EAllOps3: + { + //Works on single file + RFile file; + TBuf<40> path; + path.Append(basepath); + path.Append(pkgDoer.iFileName); + path.Append(pkgDoer.iString); + r = file.Replace(fs,path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //Increase file size + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + r = file.SetSize(4*(i+1)); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + multipleTestDoer.Printf(_L("File Set Size - %d (%d)\n"),4*(i+1),threadID); + } + + //Decrease file size + for(TInt j = pkgDoer.iIterations - 2; j >= 0; j--) + { + r = file.SetSize(4*(j+1)); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + multipleTestDoer.Printf(_L("File Set Size - %d (%d)\n"),4*(j+1),threadID); + } + + file.Close(); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFsReplace: + { + TBuf<45> path; + path.Append(basepath); + path.Append(pkgDoer.iFileName); + path.Append(pkgDoer.iString); + path.AppendNum(0); + + RFile tempFile; + multipleTestDoer.Printf(_L("RFs Replace (Create temp file) - (%d)\n"),threadID); + r = tempFile.Replace(fs,_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + tempFile.Close(); + + multipleTestDoer.Printf(_L("RFs Replace - (%d)\n"),threadID); + r = fs.Replace(_path,path); //RFs::Replace -> TFsNotification::ERename + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFsRename: + { + TBuf<45> path; + path.Append(basepath); + path.Append(pkgDoer.iFileName); + path.Append(pkgDoer.iString); + path.AppendNum(0); + + RFile file; + r = file.Replace(fs,_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + + multipleTestDoer.Printf(_L("RFs Rename - (%d)\n"),threadID); + r = fs.Rename(_path,path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFileRename: + case t_notification::EFileRename_wild: + case t_notification::EAllOps5: + { + TBuf<45> path; + path.Append(basepath); + if (!wildcard) + { + path.Append(pkgDoer.iFileName); + path.Append(pkgDoer.iString); + } + path.AppendNum(0); + + //Delete new path to ensure it does not exist + r = fs.Delete(path); + if(r != KErrNone && r != KErrNotFound && r != KErrPathNotFound) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + if (wildcard) + { + _path.Delete(_path.Length()-1,1); + _path.AppendNum(9); + } + + RFile file; + r = file.Replace(fs, _path, EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + if (wildcard) + { + for(TInt i = 1; i <= pkgDoer.iIterations; i++) + { + path.Delete(path.Length()-1,1); + path.AppendNum(i); + multipleTestDoer.Printf(_L("File Rename - %S (%d)\n"),&path,threadID); + r = file.Rename(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + } + else + { + multipleTestDoer.Printf(_L("File Rename - (%d)\n"),threadID); + r = file.Rename(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + + file.Close(); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFsRename_dir: + { + r = fs.MkDirAll(_path); + if(r != KErrNone && r != KErrAlreadyExists) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + TBuf<45> newPath; + newPath.Copy(_path); + newPath.Delete(newPath.Length()-1,1); + newPath.AppendNum(0); + newPath.Append(KPathDelimiter); + + //Delete new path to ensure it does not exist + r = fs.RmDir(newPath); + if(r != KErrNone && r != KErrNotFound && r != KErrPathNotFound) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("RFs Rename Dir - (%d)\n"),threadID); + r = fs.Rename(_path,newPath); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFsDelete: + { + if (wildcard) + { + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + //Create/replace file + RFile file; + TBuf<40> path; + path.Append(basepath); + r = fs.MkDirAll(path); + if(r != KErrNone && r != KErrAlreadyExists) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + path.AppendNum(i); + path.Append(_L(".txt")); + r = file.Replace(fs,path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + + //Delete file + multipleTestDoer.Printf(_L("RFs Delete - %S (%d)\n"),&path,threadID); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //Create file with a different extension which should not produce notifications + path.AppendNum(i); + r = file.Replace(fs,path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + + //Delete that file + multipleTestDoer.Printf(_L("RFs Delete - %S (%d)\n"),&path,threadID); + r = fs.Delete(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + } + else + { + RFile file; + r = file.Replace(fs,_path,EFileWrite); //Make sure file exists + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + + multipleTestDoer.Printf(_L("RFs Delete - (%d)\n"),threadID); + r = fs.Delete(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + break; + } + case t_notification::EFileSet: + { + RFile file; + r = file.Replace(fs,_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("File Set - (%d)\n"),threadID); + r = file.Set(TTime(0),KEntryAttHidden,KEntryAttReadOnly); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + file.Close(); + break; + } + case t_notification::EFileSetAtt: + case t_notification::EAllOps4: + { + RFile file; + r = file.Replace(fs,_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("File SetAtt - (%d)\n"),threadID); + r = file.SetAtt(KEntryAttHidden,KEntryAttReadOnly); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + file.Close(); + r = fs.Delete(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFileSetAtt_subs: + { + if (wildcard) + { + TBuf<40> path; + path.Append(basepath); + path.Append(_L("SubDir\\")); + r = fs.MkDirAll(path); + if(r != KErrNone && r != KErrAlreadyExists) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //Create/replace files and set their attributes + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + RFile file; + TBuf<40> dirPath; + dirPath.Append(path); + dirPath.AppendNum(i); + dirPath.Append(_L(".ext")); + r = file.Replace(fs, dirPath, EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("File SetAtt Subs - %d.ext - (%d)\n"),i,threadID); + r = file.SetAtt(KEntryAttHidden,KEntryAttReadOnly); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + file.Close(); + r = fs.Delete(dirPath); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + } + break; + } + case t_notification::EFsSetEntry: + { + RFile file; + r = file.Replace(fs,_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + + multipleTestDoer.Printf(_L("RFs SetEntry - (%d)\n"),threadID); + r = fs.SetEntry(_path,TTime(0),KEntryAttHidden,KEntryAttReadOnly); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EDismount: + { + multipleTestDoer.Printf(_L("DismountFileSystem - (%d)\n"),threadID); + r = fs.DismountFileSystem(pkgDoer.iFileName,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EMount: + { + multipleTestDoer.Printf(_L("MountFileSystem - (%d)\n"),threadID); + r = fs.MountFileSystem(pkgDoer.iFileName,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EMountScan: + { + multipleTestDoer.Printf(_L("DismountFileSystem - (%d)\n"),threadID); + r = fs.DismountFileSystem(pkgDoer.iFileName,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + TBool isMount; + multipleTestDoer.Printf(_L("MountFileSystemAndScan - (%d)\n"),threadID); + r = fs.MountFileSystemAndScan(pkgDoer.iFileName,globalDriveNum,isMount); + if(!isMount) + safe_test(multipleTestDoer,KErrGeneral,__LINE__,pkgDoer.iLineCall); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EMountDismount: + { + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + multipleTestDoer.Printf(_L("DismountFileSystem - (%d)\n"),threadID); + r = fs.DismountFileSystem(pkgDoer.iFileName,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("MountFileSystem - (%d)\n"),threadID); + r = fs.MountFileSystem(pkgDoer.iFileName,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + break; + } + case t_notification::EFormat: + { + RFormat format; + TInt count = -1; + TBuf<2> driveDes; + driveDes.Append(pkgDoer.iFileName); + driveDes.Append((TChar)':'); + format.Open(fs,driveDes,EQuickFormat,count); + multipleTestDoer.Printf(_L("Format - (%d)\n"),threadID); + while(count != 0) + { + format.Next(count); + } + format.Close(); + + break; + } + case t_notification::EMediaCardRemoval: + case t_notification::EMediaCardInsertion: + { + //These are MANUAL tests, they require the removal/insertion of the media card + //Instructions are given out in the watcher thread + break; + } + case t_notification::ESetDriveName: + { + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + multipleTestDoer.Printf(_L("SetDriveName - MyDrive\n")); + _LIT(KDriveName,"MyDrive"); + r = fs.SetDriveName(globalDriveNum,KDriveName); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("SetDriveName - MyDrive2\n")); + _LIT(KDriveName2,"MyDrive2"); + r = fs.SetDriveName(globalDriveNum,KDriveName2); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + break; + } + case t_notification::ERawDiskWrite: + { + RRawDisk rawdisk; + TInt drive = 0; + TBuf<1> driveDes; + driveDes.Append(pkgDoer.iFileName); + RFs::CharToDrive(pkgDoer.iFileName[0],drive); + r = rawdisk.Open(fs,drive); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //Read some data + TBuf8<10> readData; + r = rawdisk.Read(0,readData); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //Write it back + TPtrC8 dataPtr(readData); + r = rawdisk.Write((TInt64)0,dataPtr); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + rawdisk.Close(); + break; + } + case t_notification::ESetVolumeLabel: + { + for(TInt i = 0; i < pkgDoer.iIterations; i++) + { + multipleTestDoer.Printf(_L("SetVolumeLabel - MyVolume\n")); + _LIT(KVolumeLabel,"MyVolume"); + r = fs.SetVolumeLabel(KVolumeLabel,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("SetVolumeLabel - MyVolume2\n")); + _LIT(KVolumeLabel2,"MyVolume2"); + r = fs.SetVolumeLabel(KVolumeLabel2,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + } + break; + } + case t_notification::EFsRmDir: + { + r = fs.MkDirAll(_path); //Make sure directory exists + if(r != KErrNone && r != KErrAlreadyExists) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + multipleTestDoer.Printf(_L("RFs RmDir - Remove directory\n")); + r = fs.RmDir(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::EFsRmDir_wild: + { + if (wildcard) + { + TBuf<40> path; + path.Append(basepath); + path.Append(_L("SubDir\\")); + r = fs.MkDirAll(path); + if(r != KErrNone && r != KErrAlreadyExists) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("RFs RmDir - Remove directory\n")); + r = fs.RmDir(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + } + case t_notification::EFsRmDir_nonEmpty: + case t_notification::EFsMkDir: + { + TBuf<50> path; + path.Append(_path); + path.Append(pkgDoer.iFileName); //Append another sub-directory + multipleTestDoer.Printf(_L("RFs RmDir \n")); + r=fs.RmDir(path); + if(r != KErrNone && r != KErrPathNotFound && r != KErrNotFound) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + r=fs.RmDir(_path); + if(r != KErrNone && r != KErrPathNotFound && r != KErrNotFound) + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("RFs MkDir \n")); + r=fs.MkDir(path); + multipleTestDoer (r==KErrPathNotFound); + r=fs.MkDir(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + r=fs.MkDir(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("RFs RmDir nonEmpty - Full path: %S"),&_path); + r = fs.RmDir(_path); + if(r != KErrInUse) + safe_test(multipleTestDoer,KErrGeneral,__LINE__,pkgDoer.iLineCall); + + r = fs.RmDir(path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + multipleTestDoer.Printf(_L("RFs EFsRmDir_nonEmpty - Full path: %S"),&_path); + r = fs.RmDir(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + break; + } + case t_notification::EAllOps6: + { + //Set drive name to TestDrive + multipleTestDoer.Printf(_L("SetDriveName - TestDrive\n")); + _LIT(KDriveName,"TestDrive"); + r = fs.SetDriveName(globalDriveNum,KDriveName); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + //Set volume label to TestVolume + multipleTestDoer.Printf(_L("SetVolumeLabel - TestVolume\n")); + _LIT(KVolumeLabel,"TestVolume"); + r = fs.SetVolumeLabel(KVolumeLabel,globalDriveNum); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + break; + } + case t_notification::ECFileManMove: + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + multipleTestDoer.Printf(_L("Doer - ECFileManMove_part1\n")); + + //Stage 1 - Create File & write some data + RFile file; + r = file.Replace(fs,_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + r = file.SetSize(4); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file.Close(); + + CFileMan* cfman = NULL; + TRAP(r, cfman = CFileMan::NewL(fs);) + test(r == KErrNone); + test(cfman != NULL); + TBuf<40> unmonitored_path; + unmonitored_path.Append(gDriveToTest); + unmonitored_path.Append(_L(":\\F32-TST\\")); + unmonitored_path.Append(pkgDoer.iString); + + //Stage 2 - Move to unmonitored Dir + //Rename 1 + r = cfman->Move(_path,unmonitored_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //SetSize (size := 8) + RFile file2; + r = file2.Open(fs,unmonitored_path,EFileWrite); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + r = file2.SetSize(8); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + file2.Flush(); + file2.Close(); + + //Stage 3 - Move back to monitored Dir + //Rename 2 + r = cfman->Move(unmonitored_path,_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + //Stage 4 - Delete + //Delete + r = cfman->Delete(_path); + safe_test(multipleTestDoer,r,__LINE__,pkgDoer.iLineCall); + + delete cleanup; + delete cfman; + break; + } + default: + { + break; + } + } + + fs.Close(); + multipleTestDoer.End(); + multipleTestDoer.Close(); + return KErrNone; + } + +/* + * Test process Capabilites tries to set up filters on the + * the private folder for uid 01234567. + * This function returns the results to trying to add filters on the specified path. + * + * There are three MMP files: + * t_notifier_nocaps.mmp, t_notifier_allfiles.mmp, t_notifier_belongs.mmp + * + * t_notifier_nocaps.mmp - + * This process does not have any capabilites, so should not be allowed to set the filter. + * t_notifier_allfiles.mmp - + * This process has ALLFILES capability, so should + * t_notifier_belongs.mmp - + * This process is process with UID 01234567 so this should work too. + * + * See: f32test\server\t_notifier_caps.cpp + */ +TInt TestProcessCapabilities(const TDesC& aProcessName) + { + RProcess process; + TUidType uid; + TPtrC command((TText*)&gDriveToTest,1); + TInt r = process.Create(aProcessName,command,uid); + test(r==KErrNone); + process.Resume(); + TRequestStatus s1; + TRequestStatus s2; + RTimer tim; + r = tim.CreateLocal(); + test(r==KErrNone); + TTimeIntervalMicroSeconds32 delay = 5000000; //5 seconds + tim.After(s1,delay); + process.Logon(s2); + User::WaitForRequest(s1,s2); + test(s2.Int()!=KRequestPending); + r = process.ExitReason(); + process.Close(); + return r; + } + +/* + * Creates a file and writes to it twice. + * Used in TestTwoNotificationsL(). + */ +TInt TwoNotificationsTFDoer(TAny* aAny) + { + RTest testDoer(_L("TestTwoNotificationsThreadFunctionDoer")); + testDoer.Start(_L("TestTwoNotificationsThreadFunctionDoer")); + + SThreadPackageMultiple package = *(SThreadPackageMultiple*)aAny; + TBuf<40> path; + path.Append(gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); //len=22 + path.Append(package.iFileName); + + //Delete file so we definitely get a create notification + RFs fs; + TInt r = fs.Connect(); + testDoer(r==KErrNone); + r = fs.Delete(path); + testDoer(r==KErrNone || r==KErrPathNotFound || r==KErrNotFound); + r = fs.MkDirAll(path); + testDoer(r==KErrNone || r==KErrAlreadyExists); + + testDoer.Printf(_L("TestTwoNotificationsThreadFunctionDoer - Create File %S\n"),&path); + //Create file + RFile file; + r = file.Create(fs,path,EFileWrite); + testDoer(r == KErrNone); + + testDoer.Printf(_L("TestTwoNotificationsThreadFunctionDoer - Size File 1 %S\n"),&path); + TInt fileSize = 0; + r = file.Size(fileSize); + testDoer(r == KErrNone); + testDoer(fileSize==0); + + testDoer.Printf(_L("TestTwoNotificationsThreadFunctionDoer - Write File 1 %S\n"),&path); + r = file.Write(_L8("1234")); + testDoer(r == KErrNone); + testDoer.Printf(_L("TestTwoNotificationsThreadFunctionDoer - Size File 2 %S\n"),&path); + r = file.Size(fileSize); + testDoer(r == KErrNone); + test(fileSize==4); + + testDoer.Printf(_L("TestTwoNotificationsThreadFunctionDoer - Write File 2 %S\n"),&path); + r = file.Write(_L8("5678")); + testDoer(r == KErrNone); + testDoer.Printf(_L("TestTwoNotificationsThreadFunctionDoer - Size File 3 %S\n"),&path); + r = file.Size(fileSize); + testDoer(r == KErrNone); + test(fileSize==8); + + file.Close(); + + fs.Close(); + testDoer.End(); + testDoer.Close(); + return KErrNone; + } + + /* + * The following enum are for the CFileMan test + */ + enum TCFsManEnum + { + ECFManCreate1 = 0x01, + ECFManWrite1 = 0x02, + ECFManDelete1 = 0x04, + ECFManCreate2 = 0x08, + ECFManSetSize1 = 0x10, + ECFManWrite2 = 0x20, + ECFManAtt1 = 0x40, + ECFManDelete2 = 0x80, + //Either a create, copy, delete (above - not supported in test) + //or rename operation (below) + ECFManRename1 = 0x100, + ECFManRename2 = 0x200 + }; + +/* + * Used by MultipleNotificationsTFWatcher() to test the notifications. + */ +void HandleMultipleNotifications(RTest& aTest, SThreadPackageMultiple& aPackage, CFsNotify* notify, TDesC& aFullname) + { + RThread thread; + TUint64 threadID = thread.Id().Id(); + TInt numNotifications = 0; + TInt64 fileSize = 0; + TBool overflow = EFalse; + + TInt scratch = 0; + + for(TInt i = 0; i < aPackage.iMaxNotifications; ) //Outer-loop to control when we should exit + { + aTest.Printf(_L("(%d) - NextNotification\n"),threadID); + const TFsNotification* notification = notify->NextNotification(); + while(notification != NULL) + { + numNotifications++; + aTest.Printf(_L("NumNotifications = %d\n"),numNotifications); + //Test notification is not null. + //We should be getting 1 notification. + aTest(notification != NULL); + + aTest.Printf(_L("(%d) - Notification Type\n"),threadID); + TFsNotification::TFsNotificationType notificationType = notification->NotificationType(); + aTest(notificationType & aPackage.iNotifyType || + notificationType & TFsNotification::EOverflow); + + aTest.Printf(_L("Notification Type = %u - (%d)\n"),notificationType,threadID); + + if(notificationType != TFsNotification::EOverflow) + { + aTest.Printf(_L("(%d) - Notification Path\n"),threadID); + TPtrC _pathC; + ((TFsNotification*) notification)->Path(_pathC); + aTest.Printf(_L("%S - (%d)\n"),&_pathC,threadID); + + if(aPackage.iOperation == t_notification::ECFileManMove + && (scratch == (ECFManWrite1 | ECFManCreate1))) + { + TChar drive = gDriveToTest; + TBuf<40> unmodified_path; + unmodified_path.Append(drive); + unmodified_path.Append(_L(":\\F32-TST\\")); + unmodified_path.Append(_L("cf1le.man")); + ((TFsNotification*) notification)->NewName(_pathC); + TInt matches = _pathC.Match(unmodified_path); + safe_test(aTest,matches,__LINE__,aPackage.iLineCall); + } + else if((scratch == (ECFManWrite1 | ECFManCreate1 | ECFManRename1))) + { + ((TFsNotification*) notification)->NewName(_pathC); + safe_test(aTest,_pathC.Match(aFullname),__LINE__,aPackage.iLineCall); + } + else + { + safe_test(aTest,_pathC.Match(aFullname),__LINE__,aPackage.iLineCall); + } + + } + else + { + aTest.Printf(_L("(%d) - OVERFLOW\n"),threadID); + //Overflow + overflow = ETrue; + return; + } + + //notificationType will only be of 1 type + if(notificationType == TFsNotification::EFileChange) + { + if(!(((aPackage.iNotifyType & TFsNotification::EFileChange) == TFsNotification::EFileChange) && + (aPackage.iOperation == t_notification::EFileWrite || + aPackage.iOperation == t_notification::EFileWrite_async || + aPackage.iOperation == t_notification::EFileWrite_samesize || + aPackage.iOperation == t_notification::EFileSetSize || + aPackage.iOperation == t_notification::ECFileManMove || + aPackage.iOperation == t_notification::EAllOps2 || + aPackage.iOperation == t_notification::EAllOps3))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + + if (aPackage.iOperation == t_notification::ECFileManMove) + { + ((TFsNotification*) notification)->FileSize(fileSize); + //File just been created and written to. + if(fileSize == 4) + { + scratch |= ECFManWrite1; + } + else if(fileSize == 8) + { + scratch |= ECFManWrite2; + } + } + else if (aPackage.iNotifyType == TFsNotification::EFileChange) + { + ((TFsNotification*) notification)->FileSize(fileSize); + aTest.Printf(_L("Filesize - %d (%d)\n"),fileSize,threadID); + //A notification is received every time the size is changed + //due to the flushing + if (aPackage.iOperation == t_notification::EFileWrite_async) + { + //We write 52 letters + if(fileSize != 52*(i+1)) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + else if (aPackage.iOperation == t_notification::EFileWrite_samesize) + { + //Only 4 letters in file + if(fileSize != 4) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + else if (i < aPackage.iIterations) + { + //We write/increase size by 4 letters/bytes + if(fileSize != 4*(i+1)) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + else + { + //We decrease size by 4 bytes + if(fileSize != 4*(aPackage.iMaxNotifications-i)) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + } + } + else if(notificationType == TFsNotification::ECreate) + { + if(!(((aPackage.iNotifyType & TFsNotification::ECreate) == TFsNotification::ECreate) && + (aPackage.iOperation == t_notification::EFileCreate || + aPackage.iOperation == t_notification::EFileReplace || + aPackage.iOperation == t_notification::EFileCreate_subs || + aPackage.iOperation == t_notification::EFileCreate_subs_nowatch || + aPackage.iOperation == t_notification::EFileCreate_txt_nowatch || + aPackage.iOperation == t_notification::EFileCreate_txt || + aPackage.iOperation == t_notification::EFsMkDir || + aPackage.iOperation == t_notification::ECFileManMove || + aPackage.iOperation == t_notification::EAllOps1 || + aPackage.iOperation == t_notification::EAllOps2 || + aPackage.iOperation == t_notification::EAllOps3 || + aPackage.iOperation == t_notification::EAllOps4 || + aPackage.iOperation == t_notification::EAllOps5))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + if (aPackage.iOperation == t_notification::EFileCreate_txt) + { + //Check filename is of correct extension + TPtrC _path; + ((TFsNotification*) notification)->Path(_path); + TBuf<5> _ext; + _ext.Append(_L(".txt")); + TBuf<5> ext; + ext.Append(_path.Right(4)); + safe_test(aTest,ext.Match(_ext),__LINE__,aPackage.iLineCall); + } + else if (aPackage.iOperation == t_notification::ECFileManMove) + { + if(scratch & ECFManCreate1) + { + scratch |= ECFManCreate2; //File created second time + } + else + { + scratch |= ECFManCreate1; //File created first time + } + } + } + else if(notificationType == TFsNotification::EDelete) + { + if(!(((aPackage.iNotifyType & TFsNotification::EDelete) == TFsNotification::EDelete) && + (aPackage.iOperation == t_notification::EFsDelete || + aPackage.iOperation == t_notification::EFsRmDir || + aPackage.iOperation == t_notification::EFsRmDir_nonEmpty || + aPackage.iOperation == t_notification::EFsRmDir_wild || + aPackage.iOperation == t_notification::ECFileManMove || + aPackage.iOperation == t_notification::EAllOps1 || + aPackage.iOperation == t_notification::EAllOps2 || + aPackage.iOperation == t_notification::EAllOps3 || + aPackage.iOperation == t_notification::EAllOps4))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + + if(aPackage.iOperation == t_notification::ECFileManMove) + { + if(scratch & ECFManDelete1) + { + scratch |= ECFManDelete2; + } + else + { + scratch |= ECFManDelete1; + } + } + } + else if(notificationType == TFsNotification::ERename) + { + if(!(((aPackage.iNotifyType & TFsNotification::ERename) == TFsNotification::ERename) && + (aPackage.iOperation == t_notification::EFileRename || + aPackage.iOperation == t_notification::EFileRename_wild || + aPackage.iOperation == t_notification::EFsReplace || + aPackage.iOperation == t_notification::ECFileManMove || + aPackage.iOperation == t_notification::EFsRename || + aPackage.iOperation == t_notification::EFsRename_dir || + aPackage.iOperation == t_notification::EAllOps5))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + TPtrC newnameC; + ((TFsNotification*)notification)->NewName(newnameC); + aTest.Printf(_L("%S - (%d)\n"),&newnameC,threadID); + + TPtrC _pathC; + ((TFsNotification*) notification)->Path(_pathC); + + TBuf<40> _path; + _path.Copy(_pathC); + + if (aPackage.iOperation == t_notification::EFsRename_dir) + { + _path.Delete(_path.Length()-1,1); + _path.AppendNum(0); + _path.Append(KPathDelimiter); + } + else if (aPackage.iOperation == t_notification::EFileRename_wild) + { + _path.Delete(_path.Length()-1,1); + _path.AppendNum(numNotifications); + } + else + { + _path.AppendNum(0); + } + + if(aPackage.iOperation != t_notification::ECFileManMove) + { + safe_test(aTest,newnameC.Match(_path),__LINE__,aPackage.iLineCall); + } + else if(scratch & ECFManRename1) + { + scratch |= ECFManRename2; + } + else + { + scratch |= ECFManRename1; + } + + } + else if(notificationType == TFsNotification::EAttribute) + { + if(!(((aPackage.iNotifyType & TFsNotification::EAttribute) == TFsNotification::EAttribute) && + (aPackage.iOperation == t_notification::EFsSetEntry || + aPackage.iOperation == t_notification::EFileSet || + aPackage.iOperation == t_notification::EFileSetAtt || + aPackage.iOperation == t_notification::EFileSetAtt_subs || + aPackage.iOperation == t_notification::ECFileManMove || + aPackage.iOperation == t_notification::EAllOps4))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + TUint setAtt = 0; + TUint clearAtt = 0; + ((TFsNotification*) notification)->Attributes(setAtt, clearAtt); + + if(aPackage.iOperation == t_notification::ECFileManMove) + { + scratch |= ECFManAtt1; + } + else + { + if(setAtt != KEntryAttHidden) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + if(clearAtt != KEntryAttReadOnly) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + } + else if(notificationType == TFsNotification::EMediaChange) + { + if(!(((aPackage.iNotifyType & TFsNotification::EMediaChange) == TFsNotification::EMediaChange) && + (aPackage.iOperation == t_notification::EMount || + aPackage.iOperation == t_notification::EMountScan || + aPackage.iOperation == t_notification::EDismount || + aPackage.iOperation == t_notification::EMountDismount || + aPackage.iOperation == t_notification::EMediaCardInsertion || + aPackage.iOperation == t_notification::EMediaCardRemoval || + aPackage.iOperation == t_notification::EFormat || + aPackage.iOperation == t_notification::ECFileManMove || + aPackage.iOperation == t_notification::ERawDiskWrite))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + else if(notificationType == TFsNotification::EDriveName) + { + if(!(((aPackage.iNotifyType & TFsNotification::EDriveName) == TFsNotification::EDriveName) && + (aPackage.iOperation == t_notification::ESetDriveName || + aPackage.iOperation == t_notification::EAllOps6))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + else if(notificationType == TFsNotification::EVolumeName) + { + if(!(((aPackage.iNotifyType & TFsNotification::EVolumeName) == TFsNotification::EVolumeName) && + (aPackage.iOperation == t_notification::ESetVolumeLabel || + aPackage.iOperation == t_notification::EAllOps6))) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + + TPtrC newnameC; + ((TFsNotification*)notification)->NewName(newnameC); + aTest.Printf(_L("New volume name: %S - (%d)\n"),&newnameC,threadID); + } + + i++; + notification = notify->NextNotification(); + if (notification == NULL) + aTest.Printf(_L("Notification is NULL - (%d)\n"),threadID); + } + + if(i==1) //First iteration will only ever get 1 notification + { + if(numNotifications != 1) + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + + if(numNotifications < aPackage.iMaxNotifications && !overflow) //Ensure we get all of the notifications we expected + { + TRequestStatus status; + notify->RequestNotifications(status); + User::WaitForRequest(status); + } + } + + //0x307 = create1 | write1 | delete1 | rename1 | rename2 + if(aPackage.iOperation == t_notification::ECFileManMove && (scratch != 0x307)) + { + aTest.Printf(_L("CFileManMove test failure - scratch = 0x%x"),scratch); + safe_test(aTest,KErrGeneral,__LINE__,aPackage.iLineCall); + } + + } + +/* + * Watches for changes in files/directories. + * Used in TestMultipleNotificationsL(). + */ +TInt MultipleNotificationsTFWatcher(TAny* aAny) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + RThread thread; + TUint64 threadID = thread.Id().Id(); + + SThreadPackageMultiple package = *(SThreadPackageMultiple*) aAny; + RTest multipleWatcherTest(_L("MultipleNotificationsTFWatcher")); + multipleWatcherTest.Start(_L("MultipleNotificationsTFWatcher")); + + RFs fs; + fs.Connect(); + + multipleWatcherTest.Printf(_L("MultipleNotificationsTFWatcher (%d) - Create CFsNotify\n"),threadID); + CFsNotify* notify = NULL; + TRAPD(r,notify = CFsNotify::NewL(fs,package.iBufferSize)); + safe_test(multipleWatcherTest,r,__LINE__,package.iLineCall); + TBuf<40> path; + TBuf<20> filename; + if(package.iNotifyType != TFsNotification::EMediaChange && + package.iNotifyType != TFsNotification::EDriveName && + package.iNotifyType != TFsNotification::EVolumeName && + package.iOperation != t_notification::EAllOps6) + { + path.Append(gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); //len=22 + path.Append(package.iFileName); + filename.Append(package.iString); + } + else + { + path.Append((TChar)globalDriveNum+(TChar)'A'); + path.Append(_L(":")); + } + TBuf<40> fullname; + fullname.Append(path); + fullname.Append(filename); + + if (package.iNotifyType == TFsNotification::EVolumeName || + package.iOperation == t_notification::EAllOps6) + { + //Ensure volume has no label + multipleWatcherTest.Printf(_L("Set volume label to nothing\n")); + r = fs.SetVolumeLabel(_L(""),globalDriveNum); + safe_test(multipleWatcherTest,r,__LINE__,package.iLineCall); + } + + if (package.iNotifyType == TFsNotification::EDriveName || + package.iOperation == t_notification::EAllOps6) + { + //Ensure drive has no name + multipleWatcherTest.Printf(_L("Set drive name to nothing\n")); + r = fs.SetDriveName(globalDriveNum,_L("")); + safe_test(multipleWatcherTest,r,__LINE__,package.iLineCall); + } + + multipleWatcherTest.Printf(_L("MultipleNotificationsTFWatcher - Add Notification for path %S\n"),&path); + multipleWatcherTest.Printf(_L("Add Notification for type %u - (%d)\n"),(TUint)package.iNotifyType,threadID); + r = notify->AddNotification((TUint)package.iNotifyType,path,filename); + safe_test(multipleWatcherTest,r,__LINE__,package.iLineCall); + + TRequestStatus status; + multipleWatcherTest.Printf(_L("(%d) - Request Notifications\n"),threadID); + r = notify->RequestNotifications(status); + safe_test(multipleWatcherTest,r,__LINE__,package.iLineCall); + + if (package.iOperation == t_notification::EMediaCardRemoval) + { + multipleWatcherTest.Printf(_L("*****************************************************************\n")); + multipleWatcherTest.Printf(_L("Waiting 10 seconds.\n")); + multipleWatcherTest.Printf(_L("This is a MANUAL test, it requires the removal of the media card.\n")); + multipleWatcherTest.Printf(_L("PLEASE REMOVE THE MEDIA CARD. (DriveNumber %d)\n"),globalDriveNum); + multipleWatcherTest.Printf(_L("Or press Ctrl + F5 on the emulator.\n")); + multipleWatcherTest.Printf(_L("*****************************************************************\n")); + } + if (package.iOperation == t_notification::EMediaCardInsertion) + { + multipleWatcherTest.Printf(_L("*******************************************************************\n")); + multipleWatcherTest.Printf(_L("Waiting 10 seconds.\n")); + multipleWatcherTest.Printf(_L("This is a MANUAL test, it requires the insertion of the media card.\n")); + multipleWatcherTest.Printf(_L("PLEASE INSERT THE MEDIA CARD. (DriveNumber %d)\n"),globalDriveNum); + multipleWatcherTest.Printf(_L("*******************************************************************\n")); + } + + multipleWatcherTest.Printf(_L("(%d) - Signal Test thread to start Doer thread\n"),threadID); + package.iBarrier.Signal(); + User::WaitForRequest(status); + + multipleWatcherTest.Printf(_L("(%d) - MultipleNotificationsTFWatcher Line %d\n"),threadID,__LINE__); + + //Handles the notifications + HandleMultipleNotifications(multipleWatcherTest, package, notify, (TDesC&)fullname); + + multipleWatcherTest.Printf(_L("(%d) - MultipleNotificationsTFWatcher Line %d\n"),threadID,__LINE__); + + delete notify; + fs.Close(); + multipleWatcherTest.End(); + multipleWatcherTest.Close(); + delete cleanup; + return KErrNone; + } + +/* + * TestTwoNotificationsL - Tests File Write, 1 Doer writes to a file twice. + * 1 Watcher watches for file write changes. Just so happens that the second one overflows. + */ +TInt TestTwoNotificationsL() + { + test.Next(_L("TestTwoNotifications")); + + RFs fs; + fs.Connect(); + RSemaphore twoNotificationsDoerBar; + SThreadPackageMultiple package; + _LIT(KFileName,"file0.write"); + package.iIterations = 10; + package.iOperation = t_notification::EFileWrite; + package.iNotifyType = TFsNotification::EFileChange; + package.iFileName = KFileName; + package.iBufferSize = 100; //Should get changed to KMin... in CFsNotify::NewL + + User::LeaveIfError(twoNotificationsDoerBar.CreateLocal(0)); + User::LeaveIfError(package.iBarrier.CreateLocal(0)); + RThread watcher; + RThread doer; + + TInt r = watcher.Create(_L("TestTwoNotificationsWatcherThread"),MultipleNotificationsTFWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package); + test(r==KErrNone); + r = doer.Create(_L("TestTwoNotificationsDoerThread"),TwoNotificationsTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package); + test(r==KErrNone); + test.Next(_L("TestTwoNotifications - Resume Watcher")); + watcher.Resume(); + test.Next(_L("TestTwoNotifications - Wait for Watcher to be ready")); + package.iBarrier.Wait(); //Wait till Watcher has requested notification + test.Next(_L("TestTwoNotifications - Resume Doer")); + doer.Resume(); + + test.Next(_L("TestTwoNotifications - Wait for doer thread death")); + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test(doer.ExitReason()==KErrNone); + + test.Next(_L("TestTwoNotifications - Wait for watcher thread death")); + watcher.Logon(status); + User::WaitForRequest(status); + test(watcher.ExitReason()==KErrNone); + + CLOSE_AND_WAIT(doer); + CLOSE_AND_WAIT(watcher); + + twoNotificationsDoerBar.Close(); + package.iBarrier.Close(); + fs.Close(); + + return KErrNone; + } + + +/* + * Watch two threads to receive two notifications. + * Used in TestTwoDoersL(). + */ +TInt TestTwoDoersWatcher(TAny* aAny) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + RSemaphore& twoThreadsBarrier = *(RSemaphore*)aAny; + RTest twoThreadsWatcherTest(_L("TwoThreadsWatcher")); + twoThreadsWatcherTest.Start(_L("TwoThreadsWatcher")); + + RFs fs; + fs.Connect(); + + twoThreadsWatcherTest.Next(_L("Create CFsNotify")); + CFsNotify* notify = NULL; + TRAPD(r,notify = CFsNotify::NewL(fs,200)); + twoThreadsWatcherTest(r == KErrNone); + + TBuf<40> path1; + TBuf<20> filename1; + TBuf<40> path2; + TBuf<20> filename2; + path1.Append(gDriveToTest); + path2.Append(gDriveToTest); + path1.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + filename1.Append(_L("file1.create")); + path2.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + filename2.Append(_L("file2.create")); + TBuf<40> fullname1; + fullname1.Append(path1); + fullname1.Append(filename1); + TBuf<40> fullname2; + fullname2.Append(path2); + fullname2.Append(filename2); + + twoThreadsWatcherTest.Printf(_L("TwoThreadsWatcher - Add Notification for %S\n"),&path1); + r = notify->AddNotification((TUint)TFsNotification::ECreate,path1,filename1); + twoThreadsWatcherTest(r == KErrNone); + + twoThreadsWatcherTest.Printf(_L("TwoThreadsWatcher - Add Notification for %S\n"),&path2); + r = notify->AddNotification((TUint)TFsNotification::ECreate,path2,filename2); + twoThreadsWatcherTest(r == KErrNone); + + TRequestStatus status; + twoThreadsWatcherTest.Next(_L("TwoThreadsWatcher - Request Notifications")); + r = notify->RequestNotifications(status); + twoThreadsWatcherTest(r == KErrNone); + + twoThreadsBarrier.Signal(); //Signal Doer threads to start + User::WaitForRequest(status); + + // We should be getting 2 notifications + // Test notifications are not null and check notification types and paths + // 1st notification: + twoThreadsWatcherTest.Next(_L("TwoThreadsWatcher - First Notification")); + const TFsNotification* notification = notify->NextNotification(); + twoThreadsWatcherTest(notification != NULL); + twoThreadsWatcherTest.Next(_L("TwoThreadsWatcher - First Notification Type")); + TFsNotification::TFsNotificationType notificationType = ((TFsNotification*)notification)->NotificationType(); + twoThreadsWatcherTest(notificationType == TFsNotification::ECreate); + twoThreadsWatcherTest.Next(_L("TwoThreadsWatcher - First Notification Path")); + TPtrC _pathC; + ((TFsNotification*)notification)->Path(_pathC); + twoThreadsWatcherTest.Printf(_L("TwoThreadsWatcher - First Notification Path returned %S\n"),&_pathC); + TBuf<40> _path; + _path.Copy(_pathC); + //We can't guarantee which thread ran first so check that it was either path1 or path2 + twoThreadsWatcherTest(_path.Match(fullname1) == KErrNone || _path.Match(fullname2) == KErrNone); + + // 2nd notification: + twoThreadsWatcherTest.Next(_L("TwoThreadsWatcher - Second Notification")); + notification = notify->NextNotification(); + // Check if next notification exists + if (!notification) + { + notify->RequestNotifications(status); + User::WaitForRequest(status); + notification = notify->NextNotification(); + } + twoThreadsWatcherTest(notification != NULL); + twoThreadsWatcherTest.Next(_L("TwoThreadsWatcher - Second Notification Type")); + notificationType = ((TFsNotification*)notification)->NotificationType(); + twoThreadsWatcherTest(notificationType == TFsNotification::ECreate); + twoThreadsWatcherTest.Next(_L("TwoThreadsWatcher - Second Notification Path")); + ((TFsNotification*)notification)->Path(_pathC); + twoThreadsWatcherTest.Printf(_L("TwoThreadsWatcher - Second Notification Path returned %S\n"),&_pathC); + _path.Copy(_pathC); + twoThreadsWatcherTest(_path.Match(fullname1) == KErrNone || _path.Match(fullname2) == KErrNone); + + delete notify; + fs.Close(); + twoThreadsWatcherTest.End(); + twoThreadsWatcherTest.Close(); + delete cleanup; + return KErrNone; + } + +/* + * TestTwoDoersL - Two Doer threads create a file each and there's one Watcher + * which expects two notifications (one from each Doer). + */ +TInt TestTwoDoersL() + { + test.Next(_L("TestTwoDoers")); + + RFs fs; + fs.Connect(); + + _LIT(KFileName1,"file1.create"); + _LIT(KFileName2,"file2.create"); + RSemaphore simpleBarrierTest; + SThreadPackage pkgDoer1; + SThreadPackage pkgDoer2; + pkgDoer1.iFileName = KFileName1; + pkgDoer2.iFileName = KFileName2; + + User::LeaveIfError(pkgDoer1.iBarrier.CreateLocal(0)); + User::LeaveIfError(pkgDoer2.iBarrier.CreateLocal(0)); + User::LeaveIfError(simpleBarrierTest.CreateLocal(0)); + RThread watcher; + RThread doer1; + RThread doer2; + + watcher.Create(_L("TestTwoDoers-WatcherThread"),TestTwoDoersWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&simpleBarrierTest); + doer1.Create(_L("TestTwoDoers-DoerThread1"),SimpleSingleNotificationTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&pkgDoer1); + doer2.Create(_L("TestTwoDoers-DoerThread2"),SimpleSingleNotificationTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&pkgDoer2); + watcher.Resume(); + simpleBarrierTest.Wait(); //Wait until Watcher has created CFsNotify + + doer1.Resume(); + doer2.Resume(); + + test.Next(_L("TestTwoDoers - Wait for doer1 thread death")); + TRequestStatus status; + doer1.Logon(status); + User::WaitForRequest(status); + test(doer1.ExitReason()==KErrNone); + + test.Next(_L("TestTwoDoers - Wait for doer2 thread death")); + doer2.Logon(status); + User::WaitForRequest(status); + test(doer2.ExitReason()==KErrNone); + + test.Next(_L("TestTwoDoers - Wait for watcher thread death")); + watcher.Logon(status); + RTimer timer1; + TInt r = timer1.CreateLocal(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() != KRequestPending); + timer1.Cancel(); + timer1.Close(); + //User::WaitForRequest(status); + test(watcher.ExitReason()==KErrNone); + + CLOSE_AND_WAIT(doer1); + CLOSE_AND_WAIT(doer2); + CLOSE_AND_WAIT(watcher); + + pkgDoer1.iBarrier.Close(); + pkgDoer2.iBarrier.Close(); + simpleBarrierTest.Close(); + fs.Close(); + return KErrNone; + } + +/* + * TestTwoWatchersL - Uses two watcher threads and one doer thread to test that running + * two distinct sub sessions at the same time (both watch the same file). + */ +TInt TestTwoWatchersL() + { + test.Next(_L("TestTwoWatchers")); + RFs fs; + fs.Connect(); + _LIT(KFileName,"file.creat3"); + SThreadPackage pkgDoer; + pkgDoer.iFileName = KFileName; + + SThreadPackage watcherPkg; + watcherPkg.iFileName = KFileName; + + User::LeaveIfError(pkgDoer.iBarrier.CreateLocal(0)); + User::LeaveIfError(watcherPkg.iBarrier.CreateLocal(0)); + RThread watcher; + RThread watcher2; + RThread doer; + watcher.Create(_L("TestTwoWatchersWatcherThread"),SimpleSingleNotificationTFWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&watcherPkg); + watcher2.Create(_L("TestTwoWatchersWatcher2Thread"),SimpleSingleNotificationTFWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&watcherPkg); + doer.Create(_L("TestTwoWatchersDoerThread"),SimpleSingleNotificationTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&pkgDoer); + watcher.Resume(); + watcher2.Resume(); + watcherPkg.iBarrier.Wait(); //Wait till both watchers have requested notification + watcherPkg.iBarrier.Wait(); + doer.Resume(); + + test.Printf(_L("Wait for DOER to terminate , Line %d"),__LINE__); + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test(doer.ExitReason()==KErrNone); + + test.Printf(_L("Wait for WATCHER to terminate , Line %d"),__LINE__); + watcher.Logon(status); + RTimer timer1; + TInt r = timer1.CreateLocal(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() != KRequestPending); + timer1.Cancel(); + timer1.Close(); +// User::WaitForRequest(status); + test(watcher.ExitReason()==KErrNone); + + test.Printf(_L("Wait for WATCHER2 to terminate , Line %d"),__LINE__); + watcher2.Logon(status); + RTimer timer2; + r = timer2.CreateLocal(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus timeout2; + timer2.After(timeout2,time); + User::WaitForRequest(timeout2,status); + test(status.Int() != KRequestPending); + timer2.Cancel(); + timer2.Close(); + //User::WaitForRequest(status); + test(watcher2.ExitReason()==KErrNone); + + CLOSE_AND_WAIT(doer); + CLOSE_AND_WAIT(watcher); + CLOSE_AND_WAIT(watcher2); + + pkgDoer.iBarrier.Close(); + watcherPkg.iBarrier.Close(); + fs.Close(); + return KErrNone; + } + + +/* + * TestTwoWatchersTwoDoersL - Two watcher threads watches two different doer threads. + */ +TInt TestTwoWatchersTwoDoersL() + { + test.Next(_L("TestTwoWatchersTwoDoers")); + RFs fs; + fs.Connect(); + _LIT(KFileName1,"f1le.create"); + _LIT(KFileName2,"f2le.create"); + SThreadPackage package1; + package1.iFileName = KFileName1; + + SThreadPackage package2; + package2.iFileName = KFileName2; + + User::LeaveIfError(package1.iBarrier.CreateLocal(0)); + User::LeaveIfError(package2.iBarrier.CreateLocal(0)); + RThread watcher; + RThread watcher2; + RThread doer; + RThread doer2; + watcher.Create(_L("TestTwoWatchersTwoDoersWatcherThread"),SimpleSingleNotificationTFWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package1); + doer.Create(_L("TestTwoWatchersTwoDoersDoerThread"),SimpleSingleNotificationTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package1); + + watcher2.Create(_L("TestTwoWatchersTwoDoersWatcher2Thread"),SimpleSingleNotificationTFWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package2); + doer2.Create(_L("TestTwoWatchersTwoDoersDoer2Thread"),SimpleSingleNotificationTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package2); + watcher.Resume(); + watcher2.Resume(); + package1.iBarrier.Wait(); //Wait till both watchers have requested notification + package2.iBarrier.Wait(); + doer.Resume(); + doer2.Resume(); + + test.Printf(_L("Wait for DOER to terminate , Line %d"),__LINE__); + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test(doer.ExitReason()==KErrNone); + + test.Printf(_L("Wait for DOER2 to terminate , Line %d"),__LINE__); + doer2.Logon(status); + User::WaitForRequest(status); + test(doer2.ExitReason()==KErrNone); + + test.Printf(_L("Wait for WATCHER to terminate , Line %d"),__LINE__); + watcher.Logon(status); + RTimer timer1; + TInt r = timer1.CreateLocal(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() != KRequestPending); + timer1.Cancel(); + timer1.Close(); + test(watcher.ExitReason()==KErrNone); + + test.Printf(_L("Wait for WATCHER2 to terminate , Line %d"),__LINE__); + watcher2.Logon(status); + RTimer timer2; + r = timer2.CreateLocal(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus timeout2; + timer2.After(timeout2,time); + User::WaitForRequest(timeout2,status); + test(status.Int() != KRequestPending); + timer2.Cancel(); + timer2.Close(); + test(watcher2.ExitReason()==KErrNone); + + CLOSE_AND_WAIT(doer); + CLOSE_AND_WAIT(doer2); + CLOSE_AND_WAIT(watcher); + CLOSE_AND_WAIT(watcher2); + + package1.iBarrier.Close(); + package2.iBarrier.Close(); + fs.Close(); + return KErrNone; + } + + +/* + * Multi-purpose test + * + * If aFailureExpected is ETrue, it is expected that the watcher thread is not terminated normally, + * due to the notification(s) not being sent. + * Since this function is called many times, aLineCall is used to show the line where it is called from. + * See SThreadPackageMultiple. + */ +TInt TestMultipleNotificationsL(const TDesC& aFilename, const TDesC& aString, TInt aIterations, + TInt aMaxNotifications, t_notification::EOperation aOperation, + TUint aNotifyType, TInt aBufferSize, TBool aFailureExpected, TInt aLineCall) + { + test.Next(_L("TestMultipleNotifications")); + + RFs fs; + fs.Connect(); + SThreadPackageMultiple package; + package.iIterations = aIterations; + package.iMaxNotifications = aMaxNotifications; + package.iOperation = aOperation; + package.iNotifyType = (TFsNotification::TFsNotificationType)aNotifyType; + package.iString = aString; + package.iFileName = aFilename; + package.iBufferSize = aBufferSize; + package.iLineCall = aLineCall; + + User::LeaveIfError(package.iBarrier.CreateLocal(0)); + RThread watcher; + RThread doer; + RTimer tim; + User::LeaveIfError(tim.CreateLocal()); + + TInt r = watcher.Create(_L("TestMultipleNotificationsWatcherThread"),MultipleNotificationsTFWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package); + safe_test(test,r,__LINE__,package.iLineCall); + r = doer.Create(_L("TestMultipleNotificationsDoerThread"),MultipleNotificationTFDoer,KDefaultStackSize*2,KMinHeapSize,KMaxHeapSize,&package); + safe_test(test,r,__LINE__,package.iLineCall); + test.Next(_L("TestMultipleNotifications - Resume Watcher")); + watcher.Resume(); + test.Next(_L("TestMultipleNotifications - Wait for Watcher to be ready")); + package.iBarrier.Wait(); //Wait till Watcher has requested notification + test.Next(_L("TestMultipleNotifications - Resume Doer")); + doer.Resume(); + + test.Next(_L("TestMultipleNotifications - Wait for doer thread death")); + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test.Printf(_L("TestMultipleNotifications - Doer Exit Reason %d\n"),doer.ExitReason()); + safe_test(test,doer.ExitReason(),__LINE__,package.iLineCall); + + TRequestStatus timStatus; + TTimeIntervalMicroSeconds32 timeout; + if (aFailureExpected && !(package.iOperation == t_notification::EMediaCardInsertion || + package.iOperation == t_notification::EMediaCardRemoval)) + { + timeout = 1500000; //1.5 seconds, we don't want to wait too long if we expect it to fail + } + else + { + timeout = 10000000; //10 seconds + } + tim.After(timStatus,timeout); + + test.Next(_L("TestMultipleNotifications - Wait for watcher thread death or timeout")); + watcher.Logon(status); + User::WaitForRequest(status,timStatus); + if(!(status != KRequestPending || aFailureExpected)) + safe_test(test,KErrGeneral,__LINE__,package.iLineCall); + + test.Printf(_L("TestMultipleNotifications - Watcher Exit Reason %d\n"),watcher.ExitReason()); + safe_test(test,watcher.ExitReason(),__LINE__,package.iLineCall); + + CLOSE_AND_WAIT(doer); + + if(status == KRequestPending) + { + watcher.Kill(KErrTimedOut); + test.Printf(_L("TestMultipleNotifications - Watcher timed out\n")); + } + CLOSE_AND_WAIT(watcher); + + package.iBarrier.Close(); + fs.Close(); + tim.Close(); + test.Printf(_L("----------------------------------------------------------------------\n")); + return KErrNone; + } + +TInt TestMultipleNotificationsL(const TDesC& aFilename, const TDesC& aString, TInt aIterations, + TInt aMaxNotifications, t_notification::EOperation aOperation, + TFsNotification::TFsNotificationType aNotifyType, TInt aBufferSize, + TBool aFailureExpected, TInt aLineCall) + { + return TestMultipleNotificationsL(aFilename, aString, aIterations, aMaxNotifications, aOperation, + (TUint)aNotifyType, aBufferSize, aFailureExpected, aLineCall); + } + +TInt TestMultipleNotificationsL(const TDesC& aFilename, TInt aIterations, TInt aMaxNotifications, + t_notification::EOperation aOperation, TUint aNotifyType, TInt aBufferSize, + TBool aFailureExpected, TInt aLineCall) + { + return TestMultipleNotificationsL(aFilename,_L(""), aIterations, aMaxNotifications, aOperation, aNotifyType, + aBufferSize, aFailureExpected, aLineCall); + } + + +// Watcher for TestAddRemoveNotificationL() +TInt TestAddRemoveNotificationWatcher(TAny* aAny) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + RThread thread; + TUint64 threadId = thread.Id().Id(); + + SThreadPackage pkgDoer = *(SThreadPackage*)aAny; + RSemaphore& addRemoveBarrier = pkgDoer.iBarrier; + + RTest addRemoveWatcherTest(_L("TestAddRemoveNotificationWatcher")); + addRemoveWatcherTest.Start(_L("TestAddRemoveNotificationWatcher")); + + RFs fs; + fs.Connect(); + + addRemoveWatcherTest.Printf(_L("TestAddRemoveNotificationWatcher(%d) - Create CFsNotify\n"),threadId); + CFsNotify* notify = NULL; + TRAPD(r,notify = CFsNotify::NewL(fs,100); ); + addRemoveWatcherTest( r == KErrNone); + TBuf<40> path; + TBuf<20> filename; + path.Append(gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); //len=22 + filename.Append(pkgDoer.iFileName); + + addRemoveWatcherTest.Printf(_L("TestAddRemoveNotificationWatcher - Add Notification for %S\n"),&path); + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,filename); + addRemoveWatcherTest(r==KErrNone); + addRemoveWatcherTest.Printf(_L("TestAddRemoveNotificationWatcher(%d) - Remove Notifications\n"),threadId); + r = notify->RemoveNotifications(); + addRemoveWatcherTest(r==KErrNone); + addRemoveWatcherTest.Printf(_L("TestAddRemoveNotificationWatcher(%d) - Request Notifications\n"),threadId); + TRequestStatus status; + r = notify->RequestNotifications(status); + addRemoveWatcherTest(r==KErrNone); + addRemoveWatcherTest.Printf(_L("TestAddRemoveNotificationWatcher status = %d"),status.Int()); + addRemoveBarrier.Signal(); + + addRemoveWatcherTest.Printf(_L("TestAddRemoveNotificationWatcher(%d) - NextNotification\n"),threadId); + //We should not be getting any notifications as the notification request has been removed + const TFsNotification* notification = notify->NextNotification(); + addRemoveWatcherTest(notification == NULL); + + delete notify; + fs.Close(); + addRemoveWatcherTest.End(); + addRemoveWatcherTest.Close(); + delete cleanup; + return KErrNone; + } + + +/* + * TestAddRemoveNotificationL - Watcher adds and removes notification request. + * Any changes by doer thread should not be detected. + */ +TInt TestAddRemoveNotificationL() + { + test.Next(_L("TestAddRemoveNotification")); + RFs fs; + fs.Connect(); + + SThreadPackage package; + _LIT(KFileName,"noFile.create"); + package.iFileName = KFileName; + + User::LeaveIfError(package.iBarrier.CreateLocal(0)); + RThread watcher; + RThread doer; + + watcher.Create(_L("TestAddRemoveNotification-WatcherThread"),TestAddRemoveNotificationWatcher,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package); + doer.Create(_L("TestAddRemoveNotification-DoerThread"),SimpleSingleNotificationTFDoer,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package); + watcher.Resume(); + + test.Printf(_L("TestAddRemoveNotification - Wait until Watcher has created CFsNotify\n")); + package.iBarrier.Wait(); //Wait until Watcher has created CFsNotify + doer.Resume(); + + test.Next(_L("TestAddRemoveNotification - Wait for doer thread death")); + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test(doer.ExitReason()==KErrNone); + + test.Next(_L("TestAddRemoveNotification - Wait for watcher thread death")); + watcher.Logon(status); + RTimer timer1; + TInt r = timer1.CreateLocal(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() != KRequestPending); + timer1.Cancel(); + timer1.Close(); + test.Printf(_L("Test - Watcher Exit Reason %d\n"),watcher.ExitReason()); + test(watcher.ExitReason()==KErrNone); + + CLOSE_AND_WAIT(doer); + CLOSE_AND_WAIT(watcher); + + package.iBarrier.Close(); + fs.Close(); + return KErrNone; + } + + +/* + * Adds and cancels notification request. + * Used in TestCancelNotificationL(). + */ +TInt TestCancelNotificationWatcher(TAny* aAny) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + RTest cancelNotificationsWatcherTest(_L("TestCancelNotificationWatcher")); + cancelNotificationsWatcherTest.Start(_L("TestCancelNotificationWatcher")); + + RThread thread; + TUint64 threadId = thread.Id().Id(); + + SThreadPackageDualSemaphore pkgDoer = *(SThreadPackageDualSemaphore*)aAny; + RSemaphore& addRemoveBarrier = pkgDoer.iBarrier; + RSemaphore& addRemoveBarrier2 = pkgDoer.iBarrier2; + + RFs fs; + fs.Connect(); + + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher(%d) - Create CFsNotify\n"),threadId); + CFsNotify* notify = NULL; + TRAPD(r,notify = CFsNotify::NewL(fs,100); ); + cancelNotificationsWatcherTest(r == KErrNone); + TBuf<40> path; + TBuf<20> filename; + path.Append(gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); //len=22 + filename.Append(pkgDoer.iFileName); + + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher - Add Notification for %S\n"),&path); + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,filename); + cancelNotificationsWatcherTest(r==KErrNone); + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher(%d) - Request Notifications\n"),threadId); + TRequestStatus status; + r = notify->RequestNotifications(status); + cancelNotificationsWatcherTest(r==KErrNone); + + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher(%d) - Cancel Notifications\n"),threadId); + r = notify->CancelNotifications(status); + cancelNotificationsWatcherTest(r==KErrNone); + + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher(%d) - Signal W1 - Start doer\n"),threadId); + addRemoveBarrier.Signal(); //W1 - Start doer + + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher(%d) - Wait S1 - doer complete\n"),threadId); + addRemoveBarrier2.Wait(); //S1 - Wait for doer to have created file + + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher(%d) - NextNotification\n"),threadId); + //We should not be getting any notifications as the notification request has been removed + const TFsNotification* notification = notify->NextNotification(); + cancelNotificationsWatcherTest(notification == NULL); + + delete notify; + fs.Close(); + cancelNotificationsWatcherTest.Printf(_L("TestCancelNotificationWatcher(%d) - Complete\n"),threadId); + cancelNotificationsWatcherTest.End(); + cancelNotificationsWatcherTest.Close(); + delete cleanup; + return KErrNone; + } + + +/* + * TestCancelNotificationL - Watcher adds and cancels notification request. + */ +TInt TestCancelNotificationL() + { + test.Next(_L("TestCancelNotification")); + RFs fs; + fs.Connect(); + + SThreadPackageDualSemaphore package; + _LIT(KFileName,"cancel.create"); + package.iFileName = KFileName; + + User::LeaveIfError(package.iBarrier.CreateLocal(0)); + User::LeaveIfError(package.iBarrier2.CreateLocal(0)); + RThread watcher; + RThread doer; + + TInt r = watcher.Create(_L("TestCancelNotification-WatcherThread"),TestCancelNotificationWatcher,KDefaultStackSize*2,KMinHeapSize,KMaxHeapSize,&package); + test(r == KErrNone); + r = doer.Create(_L("TestCancelNotification-DoerThread"),SimpleSingleNotificationTFDoer,KDefaultStackSize*2,KMinHeapSize,KMaxHeapSize,&package); + test(r == KErrNone); + test.Printf(_L("TestCancelNotificationL - Watcher.Resume()")); + watcher.Resume(); + test.Printf(_L("TestCancelNotificationL - Waiting on package.iBarrier.Wait()")); + package.iBarrier.Wait(); //W1 - Wait until Watcher has created CFsNotify + test.Printf(_L("TestCancelNotificationL -Doer Resume")); + TRequestStatus status; + doer.Logon(status); + doer.Resume(); + + test.Next(_L("TestCancelNotification - Wait for doer thread death")); + User::WaitForRequest(status); + test(doer.ExitReason()==KErrNone); + + package.iBarrier2.Signal(); //S1 + + test.Next(_L("TestCancelNotification - Wait for watcher thread death")); + watcher.Logon(status); + + RTimer tim; + r = tim.CreateLocal(); + test(r==KErrNone); + + TRequestStatus timStatus; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + tim.After(timStatus,time); + + User::WaitForRequest(status,timStatus); + test(status!=KRequestPending); + test(watcher.ExitReason()==KErrNone); + + CLOSE_AND_WAIT(doer); + CLOSE_AND_WAIT(watcher); + + package.iBarrier.Close(); + package.iBarrier2.Close(); + fs.Close(); + tim.Close(); + return KErrNone; + } + +/* + * Test that if we close the session + * before closing the subsession (deleting CFsNotify) + * that everything is A-Ok. + */ +TInt TestSessionCloseTF(TAny* aTestCase) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + TRAPD(r, + RFs fs; + fs.Connect(); + RDebug::Printf("TestSessionClose\n"); + + SThreadPackage2 package = *(SThreadPackage2*)aTestCase; + package.iBarrier.Signal(); + + switch(package.iTestCase) + { + case 1: + { + RDebug::Printf("TestSessionCloseTF - Case 1 - NewL\n"); + CFsNotify* notify = CFsNotify::NewL(fs,KMinNotificationBufferSize); + User::LeaveIfNull(notify); + + RDebug::Printf("TestSessionCloseTF - Case 1 - Fs.Close\n"); + fs.Close(); + + TBuf<45> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + + TBuf<20> filename; + filename.Append(_L("session.close")); + + CleanupStack::PushL(notify); + + RDebug::Printf("TestSessionCloseTF - Case 1 - Add Notification - Panic Expected\n"); + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,filename); + User::LeaveIfError(r); + + RDebug::Printf("TestSessionCloseTF - Case 1 - After Session Close\n"); + fs.Close(); + CleanupStack::Pop(notify); + + RDebug::Printf("TestSessionCloseTF - Case 1 - After Delete Notify\n"); + delete notify; + break; + } + case 2: + { + RDebug::Printf("TestSessionCloseTF - Case 2 - NewL\n"); + CFsNotify* notify = CFsNotify::NewL(fs,KMinNotificationBufferSize); + User::LeaveIfNull(notify); + + TBuf<45> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + TBuf<20> filename; + filename.Append(_L("session.close")); + + RDebug::Printf("TestSessionCloseTF - Case 2 - Add Notification\n"); + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,filename); + test(r==KErrNone); + + RDebug::Printf("TestSessionCloseTF - Case 2 - Fs.Close\n"); + fs.Close(); + + CleanupStack::PushL(notify); + TRequestStatus status; + RDebug::Printf("TestSessionCloseTF - Case 2 - Request Notification - Panic Expected\n"); + r = notify->RequestNotifications(status); + CleanupStack::Pop(notify); + + RDebug::Printf("TestSessionCloseTF - Case 2 - After Delete Notify\n"); + delete notify; + break; + } + default: + { + break; + } + } + ); + delete cleanup; + return r; + } + +/* + * Test that if we close the session + * before closing the subsession (deleting CFsNotify) + * that everything is A-Ok. + */ +void TestSessionClose(TInt aTestCase) + { + RSemaphore sem; + User::LeaveIfError(sem.CreateLocal(0)); + + SThreadPackage2 package; + package.iTestCase = aTestCase; + package.iBarrier = sem; + + RThread thread; + thread.Create(_L("TestSessionClose"),TestSessionCloseTF,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&package); + + thread.Resume(); + sem.Wait(); + + TRequestStatus status; + thread.Logon(status); + User::WaitForRequest(status); + test.Printf(_L("Kern-Exec 0 is EXPECTED\n")); + TInt err = thread.ExitReason(); + test(err == KErrNone); + TExitType et = thread.ExitType(); + test(et == EExitPanic); + CLOSE_AND_WAIT(thread); + sem.Close(); + } + +const TInt KNotificationOverflowIterationLimit = 7; + +/* + * Does stuff for TestOverflowL + * Synchronises such that watchers have seen 1 change. + * Then fills their buffers up to KNotificationOverflowIterationLimit. + * + */ +TInt TestOverflowDoerTF(TAny* aAny) + { + RFs fs; + fs.Connect(); + + SThreadPackage& package = *(SThreadPackage*) aAny; + + TBuf<45> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + path.Append(package.iFileName); + + fs.MkDirAll(path); + + RFile file; + TInt r = file.Replace(fs,path,EFileWrite); + User::LeaveIfError(r); + + //Perform first set size. + r = file.SetSize(1); + User::LeaveIfError(r); + + //Wait until both watchers have received this change. + package.iBarrier.Wait(); + + for(TInt i = 0; i< KNotificationOverflowIterationLimit; i++) + { + file.SetSize(i); + } + + file.Close(); + fs.Close(); + return KErrNone; + } + +/* + * Thread function used as part of TestOverflowL + * Counts the number of notifications and ensures it the correct number before overflow is received# + */ +TInt TestOverflowWatcher1TF(TAny* aAny) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + RTest overflowTest(_L("TestOverflowWatcher1TF")); + overflowTest.Start(_L("TestOverflowWatcher1TF")); + + SThreadPackage& package = *(SThreadPackage*) aAny; + RFs fs; + fs.Connect(); + TBuf<45> path; + TBuf<20> filename; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + filename.Append(package.iFileName); + + TRequestStatus status; + CFsNotify* notify = NULL; + + //This notification's size is 80. + //80*7 = 560. + // -4 means we should get 6 notifications + //Except the first one will still be in the buffer + // (as we've not called RequestNotification yet) so we'll only actually get 5. + TRAPD(r, notify = CFsNotify::NewL(fs,(80*7)-4)); + test(r == KErrNone); + User::LeaveIfNull(notify); + notify->AddNotification(TFsNotification::EFileChange,path,filename); + notify->RequestNotifications(status); + + //Signal that we are ready for doer to start (W1) + package.iBarrier.Signal(); + + //We wait for the 1 notification (doer only does 1 at first) + User::WaitForRequest(status); + + overflowTest.Next(_L("Overflow- Get First Notification (Start framework)")); + const TFsNotification *notification = notify->NextNotification(); + + TFsNotification::TFsNotificationType type = notification->NotificationType(); + overflowTest.Printf(_L("Overflow - First Notification Type = %d\n"),type); + + //Signal the test thread (W2) + package.iBarrier.Signal(); + //Wait for Signal to continue (W3); + package.iBarrier.Wait(); + + notify->RequestNotifications(status); + User::WaitForRequest(status); + + TInt count = 0; + overflowTest.Next(_L("Overflow- Get the rest of the notifications")); + notification = notify->NextNotification(); + while(notification != NULL) + { + + type = notification->NotificationType(); + overflowTest.Printf(_L("Overflow - NotificationType = %d\n"),type); + if(type & TFsNotification::EOverflow) + { + delete notify; + fs.Close(); + overflowTest.Printf(_L("Overflow +- Count = %d\n"),count); + overflowTest.End(); + overflowTest.Close(); + return count; + } + + notification = notify->NextNotification(); + count++; + } + overflowTest.Printf(_L("Overflow -- Count = %d\n"),count); + + overflowTest.End(); + overflowTest.Close(); + delete notify; + delete cleanup; + fs.Close(); + return -1; + } + + +/* + * Overflow test + * As some of the tests above assume sucess if they receive an overflow + * we need to ensure that overflow works properly! + */ +TInt TestOverflowL() + { + /* + * The scheme used is as follows: + * 1 Doer thread which is setting the size of a file, over and over. + * 1 watcher thread. + * + * The doer thread does 1 operation then waits on a signal. + * The watcher thread requests notification and receives 1 notification. + * It then signals the Doer thread. + * + * The doer thread continues doing setsize until the number of notifications + * should have overflowed. + * + * The watcher Waits for a signal from doer (that all of the notifications have been sent). + * The watcher's last notification should be an overflow + */ + test.Next(_L("TestOverflow")); + RFs fs; + TInt r = fs.Connect(); + test(r == KErrNone); + _LIT(KFileName,"over.flow"); + SThreadPackage doerPkg; + doerPkg.iFileName = KFileName; + + SThreadPackage watcher1Pkg; + watcher1Pkg.iFileName = KFileName; + + User::LeaveIfError(doerPkg.iBarrier.CreateLocal(0)); + User::LeaveIfError(watcher1Pkg.iBarrier.CreateLocal(0)); + RThread watcher1; + RThread doer; + watcher1.Create(_L("TestOverflowWatcher1Thread"),TestOverflowWatcher1TF,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&watcher1Pkg); + doer.Create(_L("TestOverflowDoerThread"),TestOverflowDoerTF,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&doerPkg); + watcher1.Resume(); + + //Wait until Request has been requested. (W1) + watcher1Pkg.iBarrier.Wait(); + + doer.Resume(); + + //Wait till watcher has received first notification (W2) + watcher1Pkg.iBarrier.Wait(); + + //Signal the doer that it is free to continue + //doing the rest of the operations + doerPkg.iBarrier.Signal(); + + test.Next(_L("TestOverflow - Wait for doer thread death")); + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test(doer.ExitReason()==KErrNone); + CLOSE_AND_WAIT(doer); + + //Wait until doer has finished doing notifications + //thus the watcher should receive an overflow + // (W3) + watcher1Pkg.iBarrier.Signal(); + + RTimer tim; + r = tim.CreateLocal(); + test(r==KErrNone); + TRequestStatus timStatus; + + test.Next(_L("TestOverflow - Wait for watcher1 thread death")); + TTimeIntervalMicroSeconds32 interval = 10000000; //10 seconds + tim.After(timStatus,interval); + watcher1.Logon(status); + User::WaitForRequest(status,timStatus); + test(status != KRequestPending); + /* + * The number of notifications returned here should be 5. + * This is because : + * + * The first notification means that the buffer has lost 80 (the size of this + * particular notification). Even though the client has read it becase they've not called + * RequestNotification the server doesn't know that yet so that's why it's 5 not 6. + * + * That leaves 556 - 80. Which means only 5 notifications will fit. + */ + TInt count = watcher1.ExitReason(); + test(count==5); + + CLOSE_AND_WAIT(watcher1); + watcher1Pkg.iBarrier.Close(); + doerPkg.iBarrier.Close(); + fs.Close(); + tim.Close(); + return KErrNone; + } + +/* + * Does stuff for TestPostOverflowL + * Synchronises such that watchers have seen 1 change. + * Then fills their buffers up to KNotificationOverflowIterationLimit. + * Then continues to request changes and akes sure that it gets 3 non-overflow notifications + * For DEF140387. + */ +TInt TestPostOverflowDoerTF(TAny* aAny) + { + RFs fs; + fs.Connect(); + + SThreadPackage& package = *(SThreadPackage*) aAny; + + TBuf<45> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + path.Append(package.iFileName); + + fs.MkDirAll(path); + + RFile file; + TInt r = file.Replace(fs,path,EFileWrite); + User::LeaveIfError(r); + + //Perform first set size. + r = file.SetSize(1); + User::LeaveIfError(r); + + //Wait until both watchers have received this change. + //D-W-1 + package.iBarrier.Wait(); + + for(TInt i = 0; i< KNotificationOverflowIterationLimit; i++) + { + file.SetSize(i); + } + + file.Close(); + fs.Close(); + return KErrNone; + } + +TInt HandlePostOverflow(SThreadPackage& aPackage, CFsNotify* aNotify) + { + TRequestStatus status; + TInt r = aNotify->RequestNotifications(status); + test(r == KErrNone); + //Signal that overflow has been found (W4) + aPackage.iBarrier.Signal(); + + User::WaitForRequest(status); + + const TFsNotification* notification = NULL; + TInt count = 1; + + notification = aNotify->NextNotification(); + test(notification != NULL); + + //3 set sizes will be done (Sx) + aPackage.iBarrier.Wait(); + + while(count < 3) + { + TUint type = notification->NotificationType(); + if(type & TFsNotification::EOverflow) + { + return KErrOverflow; + } + notification = aNotify->NextNotification(); + if(notification == NULL) + { + r = aNotify->RequestNotifications(status); + test(r == KErrNone); + User::WaitForRequest(status); + notification = aNotify->NextNotification(); + } + test(notification != NULL); + count++; + } + return count; + } + + +/* + * Thread function used as part of TestOverflowL + * Counts the number of notifications and ensures it the correct number before overflow is received# + */ +TInt TestPostOverflowWatcher1TF(TAny* aAny) + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + RTest overflowTest(_L("TestOverflowWatcher1TF")); + overflowTest.Start(_L("TestOverflowWatcher1TF")); + + SThreadPackage& package = *(SThreadPackage*) aAny; + RFs fs; + fs.Connect(); + TBuf<45> path; + TBuf<20> filename; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + filename.Append(package.iFileName); + + TRequestStatus status; + CFsNotify* notify = NULL; + + //This notification's size is 80. + //80*7 = 560. + // -4 means we should get 6 notifications + //Except the first one will still be in the buffer + // (as we've not called RequestNotification yet) so we'll only actually get 5. + TRAPD(r, notify = CFsNotify::NewL(fs,(80*7)-4)); + test(r == KErrNone); + User::LeaveIfNull(notify); + notify->AddNotification(TFsNotification::EFileChange,path,filename); + notify->RequestNotifications(status); + + //Signal that we are ready for doer to start (W1) + package.iBarrier.Signal(); + + //We wait for the 1 notification (doer only does 1 at first) + User::WaitForRequest(status); + + overflowTest.Next(_L("Overflow- Get First Notification (Start framework)")); + const TFsNotification *notification = notify->NextNotification(); + + TFsNotification::TFsNotificationType type = notification->NotificationType(); + overflowTest.Printf(_L("Overflow - First Notification Type = %d\n"),type); + + //Signal the test thread (W2) + package.iBarrier.Signal(); + //Wait for Signal to continue (W3); + package.iBarrier.Wait(); + + notify->RequestNotifications(status); + User::WaitForRequest(status); + + TInt handlePostOverflow = 0; + TInt count = 0; + overflowTest.Next(_L("Overflow- Get the rest of the notifications")); + notification = notify->NextNotification(); + while(notification != NULL) + { + + type = notification->NotificationType(); + overflowTest.Printf(_L("Overflow - NotificationType = %d\n"),type); + if(type & TFsNotification::EOverflow) + { + overflowTest.Printf(_L("Overflow +- Count = %d\n"),count); + if(handlePostOverflow) + { + count = HandlePostOverflow(package,notify); + } + delete notify; + fs.Close(); + overflowTest.End(); + overflowTest.Close(); + return count; + } + notification = notify->NextNotification(); + count++; + + if(count==5) + handlePostOverflow = 1; + } + overflowTest.Printf(_L("Overflow -- Count = %d\n"),count); + + overflowTest.End(); + overflowTest.Close(); + delete notify; + delete cleanup; + fs.Close(); + return -1; + } + + +TInt TestPostOverflowNotifications() + { + test.Next(_L("TestPostOverflowNotifications")); + RFs fs; + TInt r = fs.Connect(); + test(r == KErrNone); + _LIT(KFileName,"post.over"); + SThreadPackage doerPkg; + doerPkg.iFileName = KFileName; + + SThreadPackage watcher1Pkg; + watcher1Pkg.iFileName = KFileName; + + User::LeaveIfError(doerPkg.iBarrier.CreateLocal(0)); + User::LeaveIfError(watcher1Pkg.iBarrier.CreateLocal(0)); + RThread watcher1; + RThread doer; + watcher1.Create(_L("TestPostOverflowWatcher1Thread"),TestPostOverflowWatcher1TF,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&watcher1Pkg); + doer.Create(_L("TestPostOverflowDoerThread"),TestPostOverflowDoerTF,KDefaultStackSize,KMinHeapSize,KMaxHeapSize,&doerPkg); + watcher1.Resume(); + + //Wait until Request has been requested. (W1) + watcher1Pkg.iBarrier.Wait(); + + doer.Resume(); + + //Wait till watcher has received first notification (W2) + watcher1Pkg.iBarrier.Wait(); + + //Signal the doer that it is free to continue + //doing the rest of the operations (D-W-1) + doerPkg.iBarrier.Signal(); + + test.Next(_L("TestOverflow - Wait for doer thread death")); + TRequestStatus status; + doer.Logon(status); + User::WaitForRequest(status); + test(doer.ExitReason()==KErrNone); + CLOSE_AND_WAIT(doer); + + //Wait until doer has finished doing notifications + //thus the watcher should receive an overflow + // (W3) + watcher1Pkg.iBarrier.Signal(); + + + //wait for the watcher to have processed the first overflow + //and to have requested notification. + //Then we will perform some actions here + // The watcher will wait on the semaphore until we are doing + // doing all the operations we want to do + // then it should process next notification + watcher1Pkg.iBarrier.Wait(); //W4 + + TBuf<45> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + path.Append(watcher1Pkg.iFileName); + RFile file; + r = file.Open(fs,path,EFileWrite); + test(r==KErrNone); + + r = file.SetSize(1); + test(r==KErrNone); + r = file.SetSize(2); + test(r==KErrNone); + r = file.SetSize(3); + test(r==KErrNone); + file.Close(); + + watcher1Pkg.iBarrier.Signal(); // Signal post operations complete (Sx) + + RTimer tim; + r = tim.CreateLocal(); + test(r==KErrNone); + TRequestStatus timStatus; + + test.Next(_L("TestOverflow - Wait for watcher1 thread death")); + TTimeIntervalMicroSeconds32 interval = 10000000; //10 seconds + tim.After(timStatus,interval); + watcher1.Logon(status); + User::WaitForRequest(status,timStatus); + test(status != KRequestPending); + /* + * The number of notifications returned here should be 3. + * This is because : + * + * The first notification means that the buffer has lost 80 (the size of this + * particular notification). Even though the client has read it becase they've not called + * RequestNotification the server doesn't know that yet so that's why it's 5 not 6. + * + * That leaves 556 - 80. Which means only 5 notifications will fit. + * + * Then overflow occurs. + * + * Then count is reset and 3 more operations are performed. + */ + TInt count = watcher1.ExitReason(); + test(count==3); + + CLOSE_AND_WAIT(watcher1); + watcher1Pkg.iBarrier.Close(); + doerPkg.iBarrier.Close(); + fs.Close(); + tim.Close(); + return KErrNone; + } + +/* + * Call AddNotification with a file without a path nor drive + */ +void TestNonDriveFilters() + { + test.Next(_L("TestNonDriveFilters")); + RFs fs; + TInt r = fs.Connect(); + test(r==KErrNone); + + TDriveList drives; + r = fs.DriveList(drives); + test(r==KErrNone); + + CFsNotify* notify = NULL; + TRAP(r,notify= CFsNotify::NewL(fs,KMinNotificationBufferSize)); + + TBuf<20> testfile; + testfile.Append(_L("test.file")); + + r = notify->AddNotification((TUint)TFsNotification::ECreate,_L(""),testfile); + test(r==KErrNone); + + TRequestStatus status; + r = notify->RequestNotifications(status); + test(r==KErrNone); + + TBuf<40> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + + TBuf<40> fullname; + fullname.Append(path); + fullname.Append(testfile); + + RFile file; + r = fs.MkDirAll(path); + test(r==KErrNone || r==KErrAlreadyExists); + r = file.Replace(fs,fullname,EFileWrite); + test(r==KErrNone); + file.Close(); + + fs.Delete(fullname); + + TChar testDrive = (TChar)gDriveToTest; + testDrive.UpperCase(); + + //Also create the file on another drive; + for(TInt i = 0; i < KMaxDrives; i++) + { + TChar drive = drives[i]; + if(drive == testDrive) + continue; + + if(drive) + { + TText16 drive16 = (TText16)(i+(TChar)'A'); + fullname.operator [](0) = drive16; + break; + } + } + + r = fs.MkDirAll(fullname); + test(r==KErrNone || r==KErrAlreadyExists); + r = file.Replace(fs,fullname,EFileWrite); + test(r==KErrNone); + file.Close(); + + RTimer timer1; + r = timer1.CreateLocal(); + test(r == KErrNone); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 10000000; //10 seconds + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() != KRequestPending); + timer1.Cancel(); + timer1.Close(); + + const TFsNotification* notification = notify->NextNotification(); + test(notification != NULL); + TPtrC _path; + r = notification->Path(_path); + test(r==KErrNone); + TChar driveletter = _path[0]; + driveletter.UpperCase(); + test(driveletter == (TChar)gDriveToTest); + + if(notification = notify->NextNotification(), notification==NULL) + { + TRequestStatus status2; + r = notify->RequestNotifications(status2); + test(r==KErrNone); + + RTimer timer2; + r = timer2.CreateLocal(); + test(r == KErrNone); + TRequestStatus timeout2; + TTimeIntervalMicroSeconds32 time2 = 10000000; //10 seconds + timer2.After(timeout2,time2); + User::WaitForRequest(timeout2,status2); + test(status2.Int() != KRequestPending); + timer2.Cancel(); + timer2.Close(); + + notification = notify->NextNotification(); + } + test(notification != NULL); + r = notification->Path(_path); + test(r==KErrNone); + driveletter = _path[0]; + driveletter.UpperCase(); + test(driveletter == (TChar)'C'); + + delete notify; + fs.Close(); + } + +// Negative testing for directory without * +// We receive no notifications for files changed under the directory +void NegativeTestDirStar() + { + RFs fs; + TInt r = fs.Connect(); + test(r==KErrNone); + + CFsNotify* notify = NULL; + TRAP(r,notify= CFsNotify::NewL(fs,KMinNotificationBufferSize)); + + TBuf<40> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + r = fs.MkDirAll(path); + test(r == KErrNone || r == KErrAlreadyExists); + + r = notify->AddNotification((TUint)TFsNotification::ECreate,path,_L("")); + test(r==KErrNone); + + TRequestStatus status; + r = notify->RequestNotifications(status); + test(r==KErrNone); + + TBuf<40> filename; + filename.Append((TChar)gDriveToTest); + filename.Append(_L(":\\F32-TST\\T_NOTIFIER\\dir.star")); + + RFile file; + r = file.Replace(fs,filename,EFileWrite); + test(r==KErrNone); + file.Close(); + + RTimer timer1; + r = timer1.CreateLocal(); + test(r == KErrNone); + TRequestStatus timeout; + TTimeIntervalMicroSeconds32 time = 2000000; //2 seconds + timer1.After(timeout,time); + User::WaitForRequest(timeout,status); + test(status.Int() == KRequestPending); + timer1.Cancel(); + timer1.Close(); + + const TFsNotification* notification = notify->NextNotification(); + test(notification == NULL); + + delete notify; + fs.Close(); + } + +/* + * Negative Testing + */ +void NegativeTests() + { + test.Next(_L("Negative Tests")); + //1 + test.Printf(_L("NegativeTests() A\n")); + RFs fs; + CFsNotify* notify = NULL; + TInt r = fs.Connect(); + test(r == KErrNone); + TRAP(r,notify = CFsNotify::NewL(fs,0)); + test(notify != NULL); + delete notify; + notify = NULL; + + //2 + test.Printf(_L("NegativeTests() B\n")); + TRAP(r,notify = CFsNotify::NewL(fs,-1)); + test(notify != NULL); + delete notify; + notify = NULL; + + test.Printf(_L("NegativeTests() C\n")); + TRAP(r,notify = CFsNotify::NewL(fs,KMaxTInt)); + test(r==KErrArgument); + test(notify==NULL); + + //3 + test.Printf(_L("NegativeTests() D\n")); + TBuf<40> path; + path.Append((TChar)gDriveToTest); + path.Append(_L(":\\F32-TST\\T_NOTIFIER\\")); + TBuf<20> filename; + filename.Append(_L("file.txt")); + TRAP(r,notify = CFsNotify::NewL(fs,KMinNotificationBufferSize)); + test(r==KErrNone); + test(notify!=NULL); + r = notify->AddNotification(0,path,filename); + test(r == KErrArgument); + + test.Printf(_L("NegativeTests() E\n")); + r = notify->AddNotification((TUint)0x8000,path,filename); //invalid value + test(r == KErrArgument); + + test.Printf(_L("NegativeTests() F\n")); + TBuf<40> invalidPath; + invalidPath.Append(_L("1:\\*")); + r = notify->AddNotification((TUint)TFsNotification::ECreate,invalidPath,filename); + test(r == KErrNotFound || r == KErrPathNotFound); + + //4 + test.Printf(_L("NegativeTests() G\n")); + TRequestStatus wrongStatus; + wrongStatus = KRequestPending; + r = notify->RequestNotifications(wrongStatus); + test(r == KErrInUse); + + test.Printf(_L("NegativeTests() H\n")); + TRequestStatus status; + r = notify->RequestNotifications(status); + test(r==KErrNone); + r = notify->CancelNotifications(wrongStatus); + test(r == KErrInUse); + + delete notify; + notify = NULL; + fs.Close(); + } + + +/* + * RPlugin devired. + * Doesn't actually do anything special. + * Can probably be deleted. + */ +class MyRPlugin : public RPlugin + { +public: + void DoRequest(TInt aReqNo,TRequestStatus& aStatus) const; + void DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1) const; + void DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1,TDes8& a2) const; + TInt DoControl(TInt aFunction) const; + TInt DoControl(TInt aFunction,TDes8& a1) const; + TInt DoControl(TInt aFunction,TDes8& a1,TDes8& a2) const; + void DoCancel(TUint aReqMask) const; + }; + +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus) const + { + RPlugin::DoRequest(aReqNo,aStatus); + } +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1) const + { + RPlugin::DoRequest(aReqNo,aStatus,a1); + } +void MyRPlugin::DoRequest(TInt aReqNo,TRequestStatus& aStatus,TDes8& a1,TDes8& a2) const + { + RPlugin::DoRequest(aReqNo,aStatus,a1,a2); + } +TInt MyRPlugin::DoControl(TInt aFunction) const + { + return RPlugin::DoControl(aFunction); + } +TInt MyRPlugin::DoControl(TInt aFunction,TDes8& a1) const + { + return RPlugin::DoControl(aFunction,a1); + } +TInt MyRPlugin::DoControl(TInt aFunction,TDes8& a1,TDes8& a2) const + { + return RPlugin::DoControl(aFunction,a1,a2); + } +void MyRPlugin::DoCancel(TUint aReqMask) const + { + RPlugin::DoCancel(aReqMask); + } + +/* + * This tests that when file server plugins perform operations that + * the framework doesn't notify about them + */ +TInt TestNotificationsWithFServPlugins() + { + TInt r = TheFs.AddPlugin(KNotifyPluginFileName); + test(r==KErrNone || r==KErrAlreadyExists); + r = TheFs.MountPlugin(KNotifyPluginName,(TUint)gDriveToTest.GetUpperCase() - 65); + if (r == KErrNotSupported) + { + test.Printf(_L("Plugins are not supported on pagable drives.\nSkipping test.\n")); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + } + + MyRPlugin rplugin; + TPckgBuf drivePckg(gDriveToTest); + + test.Next(_L("Open RPlugin connection for NotifyPlugin")); + r = rplugin.Open(TheFs,KNotifyPos); + safe_test(test,r,__LINE__,(TText*)Expand("t_notify_plugin.cpp")); + + test.Next(_L("Send drive letter to test down to plugin")); + r = rplugin.DoControl(KPluginSetDrive,drivePckg); + safe_test(test,r,__LINE__,(TText*)Expand("t_notify_plugin.cpp")); + rplugin.Close(); + + r = SimpleCreateTestL(); + safe_test(test,r,__LINE__,(TText*)Expand("t_notifier.cpp")); + + DismountPlugin(); + return KErrNone; + } + +/* + * This test is testing the use cases + * and for negative testing of SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION + * + * Performance tests can be found in test t_notify_perf + */ +void CallTestsL() + { + CTrapCleanup* cleanup; + cleanup = CTrapCleanup::New(); + + globalDriveNum = gDriveToTest - (TChar)'A'; + + PrintLine(); + test.Start(_L("T_NOTIFIER Test Start")); + TInt r = KErrNone; + + //========================================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2443 + //! @SYMTestType CIT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Simple Tests/User Heap Tests + //! @SYMTestStatus Implemented + //========================================================================================= + // + // 1. Create and delete many CFsNotify objects + // + PrintLine(); + test.Next(_L("CFsNotify Creation and Delete Tests")); + //Creates and Deletes 1 CFsNotify + __UHEAP_MARK; + r = TestNewDeleteCFsNotify(1); + __UHEAP_MARKEND; + test(r==KErrNone); + //Creates and Deletes 50 CFsNotifys + __UHEAP_MARK; + r = TestNewDeleteCFsNotify(50); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of User Heap Tests ---------------------------------------\n")); + // + // 2. Add notification for creating a file + // Create that file + // + PrintLine(); + __UHEAP_MARK; + r = SimpleCreateTestL(); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of CFsNotify Creation and Delete Tests -------------------\n")); + // + // 3. Add notification at the root of a drive + // Create a file in that drive + // + PrintLine(); + TestRootDriveNotifications(); + test.Printf(_L("------- End of RootDriveNotifications Test ---------------------------\n")); + // + // 4. Add notification for a filename without a drive + // Create that file in the current drive + // Create that file in another drive + // + PrintLine(); + TestNonDriveFilters(); + test.Printf(_L("------- End of TestNonDriveFilters Test ------------------------------\n")); + // + // 5. Add notifications for 2 file creations + // Create 2 clients + // The clients create a file each + // + PrintLine(); + __UHEAP_MARK; + r = TestTwoDoersL(); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of TwoDoers Test -----------------------------------------\n")); + // + // 6. Create 2 file server sessions + // Add a notification on each session for the same specific file creation + // Create that file + // + PrintLine(); + __UHEAP_MARK; + r = TestTwoWatchersL(); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of TwoWatchers Test --------------------------------------\n")); + // + // 7. Create 2 file server sessions and 2 clients + // Add a notification on each session for different file creations + // Clients create a file each + // + PrintLine(); + __UHEAP_MARK; + r = TestTwoWatchersTwoDoersL(); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of TwoWatchersTwoDoers Test ------------------------------\n")); + // + // 8. Add notification for a specific file creation + // Cancel the notification request + // Create that file + // + PrintLine(); + __UHEAP_MARK; + r = TestCancelNotificationL(); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of CancelNotification Test -------------------------------\n")); + // + // 9. Create 2 file server sessions + // Add a notification on each session for the same specific file creation + // Delete the first notification + // Create that file + // + PrintLine(); + test.Next(_L("TestClientRemoval")); + __UHEAP_MARK; + r = TestClientRemovalL(); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of TestClientRemoval Test --------------------------------\n")); + // + // 10. Create a CFsNotify object + // Close the session before closing the subsession + // Add notification and request notifications + // + PrintLine(); + __UHEAP_MARK; + // Close session after creating the object + TestSessionClose(1); + __UHEAP_MARKEND; + __UHEAP_MARK; + // Close session after adding the notification + TestSessionClose(2); + __UHEAP_MARKEND; + test.Printf(_L("------- End of TestSessionClose Test ---------------------------------\n")); + + + //========================================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2444 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc File/Directory Create and Replace – Single File Server Session + //! @SYMTestStatus Implemented + //! + //! TFsNotificationType ECreate + //========================================================================================= + // + // RFile::Create + // 1. Add notification for a specific file creation + // Create that file + // + PrintLine(); + test.Next(_L("EFileCreate Tests")); + _LIT(KFilename3,"file.create"); + r = TestMultipleNotificationsL(_L(""),KFilename3,5,5,t_notification::EFileCreate,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of EFileCreate Tests -------------------------------------\n")); + // + // RFs::MkDir + // 2. Add notification for a specific directory creation + // Create that directory + // + PrintLine(); + test.Next(_L("EFsMkDir Test")); + _LIT(KDirName1,"dirCreate\\"); + r = TestMultipleNotificationsL(KDirName1,_L(""),1,1,t_notification::EFsMkDir,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of EFsMkDir Test -----------------------------------------\n")); + // + // RFile::Replace + // 3. Add notification for a specific file creation + // Replace that file + // + PrintLine(); + test.Next(_L("EFileReplace Test")); + r = TestMultipleNotificationsL(_L(""),KFilename3,1,1,t_notification::EFileReplace,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of EFileReplace Test -------------------------------------\n")); + // + // 4. Add notification for a specific file creation + // Remove that notification + // Create that file + // + PrintLine(); + __UHEAP_MARK; + r = TestAddRemoveNotificationL(); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of Add and Remove Notification Test ----------------------\n")); + // + // Wildcard Create Tests + // 5. Add notification for file creation using wildcard name + // Add notification for file/directory wildcard including subdirectories + // Create number of files and directories that match each notification + // + PrintLine(); + test.Next(_L("Wildcard Create Tests")); + // + // Wildcard Name + _LIT(KWildcardName1,"*"); + r = TestMultipleNotificationsL(_L(""),KWildcardName1,1,1,t_notification::EFileCreate,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(KWildcardName1,KWildcardName1,1,1,t_notification::EFileCreate_subs,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(KWildcardName1,KWildcardName1,1,1,t_notification::EFileCreate_subs_nowatch,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)ETrue,__LINE__); + test(r==KErrNone); + // + // Wildcard including Subdirectories + _LIT(KWildcardName2,"*\\"); + r = TestMultipleNotificationsL(KWildcardName2,KWildcardName1,1,1,t_notification::EFileCreate,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)ETrue,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(KWildcardName2,KWildcardName1,1,1,t_notification::EFileCreate_subs_nowatch,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + _LIT(KDirName2,"SubDir\\"); + _LIT(KWildcardName3,"?"); + r = TestMultipleNotificationsL(KDirName2,KWildcardName3,1,1,t_notification::EFileCreate_subs_nowatch,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // Wildcard Type + _LIT(KWildcardName4,"*.*"); + r = TestMultipleNotificationsL(_L(""),KWildcardName4,1,1,t_notification::EFileCreate_txt_nowatch,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(_L(""),KWildcardName4,1,1,t_notification::EFileCreate_subs_nowatch,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)ETrue,__LINE__); + test(r==KErrNone); + // + // 6. Add notification for file creation for a specific type + // Create file with that type + // Create file with different type + // + _LIT(KWildcardName5,"*.txt"); + r = TestMultipleNotificationsL(_L(""),KWildcardName5,1,1,t_notification::EFileCreate_txt,TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of Wildcard Create Tests ---------------------------------\n")); + + + //============================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2445 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc File Attribute Change – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EAttribute + //============================================================================= + // + // RFile::SetAtt, RFile::Set and RFs::SetEntry + // 1. Add notification for a specific file attribute change + // Change the attribute for that file + // + PrintLine(); + test.Next(_L("Attribute Tests")); + _LIT(KFilename4,"file.setatts"); + r = TestMultipleNotificationsL(_L(""),KFilename4,1,1,t_notification::EFileSetAtt,TFsNotification::EAttribute,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(_L(""),KFilename4,1,1,t_notification::EFileSet,TFsNotification::EAttribute,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(_L(""),KFilename4,1,1,t_notification::EFsSetEntry,TFsNotification::EAttribute,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // Wildcard Attribute Test including subdirectories + // 2. Add notification for file attribute change using wildcard name + // Create number of files that match the notification + // Change attributes of some files + // + r = TestMultipleNotificationsL(KWildcardName2,_L("*"),3,3,t_notification::EFileSetAtt_subs,TFsNotification::EAttribute,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of Attribute Tests ---------------------------------------\n")); + + + //============================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2446 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc File/Directory Rename – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType ERename + //============================================================================= + // + // RFs::Replace, RFs::Rename and RFile::Rename + // 1. Add notification for a specific file rename change + // Rename that file + // + PrintLine(); + test.Next(_L("Rename Tests")); + _LIT(KFilename5,"file.rename"); + r = TestMultipleNotificationsL(_L(""),KFilename5,1,1,t_notification::EFsReplace,TFsNotification::ERename,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(_L(""),KFilename5,1,1,t_notification::EFsRename,TFsNotification::ERename,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + r = TestMultipleNotificationsL(_L(""),KFilename5,1,1,t_notification::EFileRename,TFsNotification::ERename,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 2. Add notification for a specific directory rename + // Rename that directory + // + _LIT(KDirName3,"dirRename\\"); + r = TestMultipleNotificationsL(KDirName3,_L(""),1,1,t_notification::EFsRename_dir,TFsNotification::ERename,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 3. Add notification for file rename using wildcard name + // Create file that match the notification + // Repeatedly rename the file + // + r = TestMultipleNotificationsL(_L(""),KWildcardName1,3,3,t_notification::EFileRename_wild,TFsNotification::ERename,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of Rename Tests ------------------------------------------\n")); + + + //============================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2447 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc File/Directory Delete – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EDelete + //============================================================================= + // + // RFs::Delete + // 1. Add notification for a specific file delete + // Delete that file + // + PrintLine(); + test.Next(_L("EFsDelete Test")); + _LIT(KFilename6,"file.delete"); + r = TestMultipleNotificationsL(_L(""),KFilename6,1,1,t_notification::EFsDelete,TFsNotification::EDelete,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // RFs::RmDir + // 2. Add notification for a specific directory delete + // Delete that directory + // + PrintLine(); + test.Next(_L("EFsRmDir Tests")); + _LIT(KDirName4,"dirRemove\\"); + r = TestMultipleNotificationsL(KDirName4,_L(""),1,1,t_notification::EFsRmDir,TFsNotification::EDelete,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // This test should not receive any notifications because a non-empty directory cannot be removed + // 3. Add notification for specific directory delete + // Create files inside that directory + // Delete the directory + // + _LIT(KDirName5,"dirRmNonEmp\\"); + r = TestMultipleNotificationsL(KDirName5,_L(""),1,1,t_notification::EFsRmDir_nonEmpty,TFsNotification::EDelete,KMinNotificationBufferSize,(TBool)ETrue,__LINE__); + test(r==KErrNone); + // + // Wildcard Name ("*") + // 4. Add notification for directory delete using wildcard name + // Create directory that match the notification + // Delete that directory + // + r = TestMultipleNotificationsL(KWildcardName1,_L(""),1,1,t_notification::EFsRmDir_wild,TFsNotification::EDelete,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // Wildcard Type ("*.txt") + // Creates files with different types and should only receive notifications from "*.txt" file deletions + // 5. Add notification for file deletes using wildcard type + // Create number of files that match the notification + // Delete those files + // + r = TestMultipleNotificationsL(_L(""),KWildcardName4,3,3,t_notification::EFsDelete,TFsNotification::EDelete,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of Delete Tests ------------------------------------------\n")); + + + //====================================================================== + //! @SYMTestCaseID PBASE-T_NOTIFY-2448 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc File Change – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EFileChange + //====================================================================== + // + // File Write + // If caching is enabled, notifications are received only when the file cache is flushed + // We flush everytime we do a write to ensure the tests work regardless of cache + // + // 1. Add notification for a specific file change + // Create the file + // Write to that file + // + PrintLine(); + test.Next(_L("EFileWrite Tests")); + _LIT(KFilename7,"file.write"); + __UHEAP_MARK; + r = TestMultipleNotificationsL(_L(""),KFilename7,7,7,t_notification::EFileWrite,TFsNotification::EFileChange,3*KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + __UHEAP_MARKEND; + test(r==KErrNone); + // + // 2. Add notification for a specific file change + // Write to the specified file a number of times without changing its size + // + // Four letters are written to a file, then the first letter in the file is replaced aIterations times + // aMaxNotifications = 1 + aIterations + // + r = TestMultipleNotificationsL(_L(""),KFilename7,3,4,t_notification::EFileWrite_samesize,TFsNotification::EFileChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of EFileWrite Tests --------------------------------------\n")); + // + // 3. Add notification for a specific file change + // Write to that file asynchronously + // + PrintLine(); + test.Next(_L("EFileWrite_async Tests")); + _LIT(KFilename8,"async.write"); + __UHEAP_MARK; + r = TestMultipleNotificationsL(_L(""),KFilename8,4,4,t_notification::EFileWrite_async,TFsNotification::EFileChange,2*KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + __UHEAP_MARKEND; + test(r==KErrNone); + test.Printf(_L("------- End of EFileWrite_async Tests --------------------------------\n")); + // + // File Set Size + // 4. Add notification for a specific file change + // Both increase and decrease the file sizes a number of times + // + // The file size is increased aIterations times, and decreased (aIterations - 1) times + // aMaxNotifications = 2*aIterations - 1 + // + PrintLine(); + test.Next(_L("EFileSetSize Tests")); + _LIT(KFilename9,"file.setsize"); + r = TestMultipleNotificationsL(_L(""),KFilename9,5,9,t_notification::EFileSetSize,TFsNotification::EFileChange,3*KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of EFileSetSize Tests ------------------------------------\n")); + + + // + PrintLine(); + test.Next(_L("CFileMan Tests")); + _LIT(KFilenameCFMan,"cf1le.man"); + TUint notificationTypes = (TUint)TFsNotification::ECreate|TFsNotification::EFileChange|TFsNotification::EAttribute|TFsNotification::EDelete|TFsNotification::ERename; + r = TestMultipleNotificationsL(_L(""),KFilenameCFMan,1,5,t_notification::ECFileManMove,notificationTypes,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of CFileMan Tests -------------------------------------\n")); + + + //======================================================================================== + //! @SYMTestCaseID PBASE-T_NOTIFY-2449 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc File System Mounted/Dismounted, Media Card Removal/Insertion, + // RawDisk Write – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EMediaChange + //======================================================================================== + // + // RFs::DismountFileSystem + // 1. Add notification for media change + // Dismount the file system + // + PrintLine(); + test.Next(_L("Mount Tests")); + TFullName filesystemName; + r = TheFs.FileSystemName(filesystemName,globalDriveNum); + test(r==KErrNone); + r = TestMultipleNotificationsL(filesystemName,1,1,t_notification::EDismount,TFsNotification::EMediaChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // RFs::MountFileSystem + // 2. Add notification for media change + // Mount the file system + // + r = TestMultipleNotificationsL(filesystemName,1,1,t_notification::EMount,TFsNotification::EMediaChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // Repeatedly mount and dismount the file system + // 3. Add notification for media change + // Repeatedly dismount and mount the file system + // + // The file system is dismounted and mounted aIterations times + // aMaxNotifications = 2*aIterations + // + r = TestMultipleNotificationsL(filesystemName,5,10,t_notification::EMountDismount,TFsNotification::EMediaChange,3*KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // RFs::MountFileSystemAndScan + // 4. Add notification for media change + // Mount and scan the file system + // + // The file system is dismounted and mounted aIterations times + // aMaxNotifications = 2*aIterations + // +//#ifndef __WINS__ +// r = TestMultipleNotificationsL(filesystemName,1,2,t_notification::EMountScan,TFsNotification::EMediaChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); +// test(r==KErrNone); +//#endif + test.Printf(_L("------- End of Mount Tests -------------------------------------------\n")); + TDriveInfo drvInfo; + TInt driveNum; + TheFs.CharToDrive(gDriveToTest,driveNum); + r = TheFs.Drive(drvInfo,driveNum); + test (r == KErrNone); + TPtrC driveDes((TText*)&gDriveToTest,1); + // + // Manual Tests - Will only run on removable drives + // +/* if(drvInfo.iDriveAtt & KDriveAttRemovable) + { + // + // 5. Add notification for media change + // Remove media card manually + // + PrintLine(); + test.Next(_L("Media Card Removal/Insertion Tests")); + r = TestMultipleNotificationsL(driveDes,1,1,t_notification::EMediaCardRemoval,TFsNotification::EMediaChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 6. Add notification for media change + // Insert media card manually + // + r = TestMultipleNotificationsL(driveDes,1,1,t_notification::EMediaCardInsertion,TFsNotification::EMediaChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of Media Card Removal/Insertion Tests --------------------\n")); + // + // We should receive an EMediaChange notification even though we did not register for it + // 7. Do not add notification for media change + // Remove and insert media card manually + // + PrintLine(); + TestMediaCardNotificationWhenNotRegisteredForIt(); + test.Printf(_L("------- End of TestMediaCardNotificationWhenNotRegisteredForIt -------\n")); + } +*/ // + // RRawDisk::Write + // 8. Add notification for media change + // Write directly to the media + // +#ifdef __WINS__ + if(gDriveToTest-(TChar)'A' != 2) +#endif + { + PrintLine(); + test.Next(_L("RRawDisk::Write Tests")); + r = TestMultipleNotificationsL(driveDes,1,1,t_notification::ERawDiskWrite,TFsNotification::EMediaChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of RRawDisk::Write Test ------------------------------ \n")); + } + + + //=============================================================================== + //! @SYMTestCaseID PBASE-T_NOTIFY-2450 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Drive Name Modification – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EDriveName + //=============================================================================== + // + // RFs::SetDriveName + // The drive name is renamed 2*aIterations times + // aMaxNotifications = 2*aIterations + // + // 1. Add notification for a specific drive name change + // Change the drive name + // + PrintLine(); + test.Next(_L("DriveName Test")); + r = TestMultipleNotificationsL(driveDes,1,2,t_notification::ESetDriveName,TFsNotification::EDriveName,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 2. Add notification for a specific drive name change + // Repeatedly rename the drive + // + r = TestMultipleNotificationsL(driveDes,3,6,t_notification::ESetDriveName,TFsNotification::EDriveName,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of DriveName Test ----------------------------------------\n")); + + + //================================================================================ + //! @SYMTestCaseID PBASE-T_NOTIFY-2451 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Volume Name Modification – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EVolumeName + //================================================================================ + // + // RFs::SetVolumeLabel - Does not run on WINS + // The volume name is renamed 2*aIterations times + // aMaxNotifications = 2*aIterations + // +#ifndef __WINS__ + PrintLine(); + test.Next(_L("VolumeName Test")); + // + // 1. Add notification for a specific volume name change + // Change the volume name + // + r = TestMultipleNotificationsL(driveDes,1,2,t_notification::ESetVolumeLabel,TFsNotification::EVolumeName,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 2. Add notification for a specific volume name change + // Repeatedly rename the volume + // + r = TestMultipleNotificationsL(driveDes,3,6,t_notification::ESetVolumeLabel,TFsNotification::EVolumeName,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of VolumeName Test ---------------------------------------\n")); +#endif + + + //============================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2452 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc All Operations Filter – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EAllOps + //============================================================================= + PrintLine(); + test.Next(_L("AllOps Tests")); + // + // 1. Add notification for all operations + // Create a file + // Delete the file + // + // EAllOps1: A file is created and deleted aIterations times + // aMaxNotification = 2*aIterations + // + _LIT(KFilename10,"file.allops"); + r = TestMultipleNotificationsL(_L(""),KFilename10,4,8,t_notification::EAllOps1,(TUint)TFsNotification::EAllOps,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 2. Add notification for all operations + // Create a file + // Write to the file + // Delete the file + // + // EAllOps2: A file is created, written to aIterations times and then deleted + // aMaxNotification = 2 + aIterations (See File Write Tests) + // + r = TestMultipleNotificationsL(_L(""),KFilename10,4,6,t_notification::EAllOps2,(TUint)TFsNotification::EAllOps,2*KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 3. Add notification for all operations + // Create a file + // Change the file size + // Delete the file + // + // EAllOps3: A file is created, its size is increased size aIterations times, decreased (aIterations - 1) times + // and then deleted + // aMaxNotifications = 1 + 2*aIterations + // + r = TestMultipleNotificationsL(_L(""),KFilename10,4,6,t_notification::EAllOps3,(TUint)TFsNotification::EAllOps,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 4. Add notification for all operations + // Create a file + // Change the file attribute + // Delete the file + // + // EAllOps4: A file is created, its attribute is changed and the file is deleted + // aMaxNotification = 3 + // + r = TestMultipleNotificationsL(_L(""),KFilename10,1,3,t_notification::EAllOps4,(TUint)TFsNotification::EAllOps,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 5. Add notification for all operations + // Create a file + // Rename the file + // + // EAllOps5: A file is created and renamed + // aMaxNotification = 2 + // + r = TestMultipleNotificationsL(_L(""),KFilename10,1,2,t_notification::EAllOps5,(TUint)TFsNotification::EAllOps,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // 6. Add notification for all operations + // Change drive name + // Change volume name + // + // SetVolumeLabel does not run on WINS + // EAllOps6: The drive and volume names are changed + // aMaxNotification = 2 + // +#ifndef __WINS__ + r = TestMultipleNotificationsL(driveDes,1,2,t_notification::EAllOps6,(TUint)TFsNotification::EAllOps,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); +#endif + test.Printf(_L("------- End of AllOps Tests ------------------------------------------\n")); + + + //============================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2453 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Multiple Filters – Single File Server Session + //! @SYMTestStatus Implemented + //============================================================================= + PrintLine(); + test.Next(_L("Multiple-Filter Tests")); + // + // TFsNotification::ECreate | TFsNotification::EDelete + // 1. Add notification for create and delete for a specific file + // Create that file + // Delete the file + // + // A file is created and deleted aIterations times + // aMaxNotification = 2*aIterations + // + _LIT(KFilename11,"file.mulfil"); + r = TestMultipleNotificationsL(_L(""),KFilename11,3,6,t_notification::EAllOps1,TFsNotification::ECreate | TFsNotification::EDelete,2*KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // TFsNotification::EDelete | TFsNotification::ECreate | TFsNotification::EFileChange + // 2. Add notification for create, file change and delete for a specific file + // Create a file + // Change the file size + // Delete the file + // + // A file is created, its size is increased size aIterations times, decreased (aIterations - 1) times + // and then deleted + // aMaxNotifications = 1 + 2*aIterations + // + r = TestMultipleNotificationsL(_L(""),KFilename11,4,6,t_notification::EAllOps3,TFsNotification::EDelete | TFsNotification::ECreate | TFsNotification::EFileChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // TFsNotification::EAttribute | TFsNotification::EDelete | TFsNotification::ECreate + // 3. Add notification for create, attribute change and delete for a specific file + // Create a file + // Change the file attribute + // Delete the file + // + // A file is created, its attribute is changed and the file is deleted + // aMaxNotification = 3 + // + r = TestMultipleNotificationsL(_L(""),KFilename11,1,3,t_notification::EAllOps4,TFsNotification::EAttribute | TFsNotification::EDelete | TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // TFsNotification::ERename | TFsNotification::ECreate + // 4. Add notification for create and rename for a specific file + // Create a file + // Rename the file + // + // A file is created and renamed + // aMaxNotification = 2 + // + r = TestMultipleNotificationsL(_L(""),KFilename11,1,2,t_notification::EAllOps5,TFsNotification::ERename | TFsNotification::ECreate,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + // + // TFsNotification::EVolumeName | TFsNotification::EDriveName + // 5. Add notification for drive and volume name change for a specific drive + // Change drive name + // Change volume name + // + // SetVolumeLabel does not run on WINS + // The drive and volume names are changed + // aMaxNotification = 2 + // +#ifndef __WINS__ + r = TestMultipleNotificationsL(driveDes,1,2,t_notification::EAllOps6,TFsNotification::EVolumeName | TFsNotification::EDriveName,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); +#endif + test.Printf(_L("------- End of Multiple-Filter Tests ---------------------------------\n")); + + + //============================================================================== + //! @SYMTestCaseID PBASE-T_NOTIFY-2454 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Overflow Notification – Single File Server Session + //! @SYMTestStatus Implemented + //============================================================================== + // + // 1. Add notification with a small buffer size, for a specific file change + // Change the file size once + // 2. Make continuous file size changes to the file + // 3. When overflow notification occurs, delete the notification + // + PrintLine(); + r = TestOverflowL(); + test(r==KErrNone); + + //For DEF140387 + PrintLine(); + r= TestPostOverflowNotifications(); + test(r==KErrNone); + test.Printf(_L("------- End of Overflow Test -----------------------------------------\n")); + + + //============================================================================ + //! @SYMTestCaseID PBASE-T_NOTIFY-2455 + //! @SYMTestType CIT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc API Negative Testing – Single File Server Session + //! @SYMTestStatus Implemented + //============================================================================ + // 1. + // a-CFsNotify class creation with zero buffer size + // + // 2. + // b-CFsNotify class creation with negative buffer size + // c-CFsNotify class creation with buffer size that is too large + // + // 3. + // d-Call AddNotification with aNotiififcationType zero + // e-Call AddNotification with aNotiififcationType invalid + // f-Call AddNotification with many different invalid paths + // + // 4. + // g-Call RequestNotifications with status that is already in use + // h-Call CancelNotifications with wrong status + // + PrintLine(); + __UHEAP_MARK; + NegativeTests(); + __UHEAP_MARKEND; + // + // 5. + // i-Negative testing for directory without * + // + test.Printf(_L("NegativeTests() I\n")); + NegativeTestDirStar(); + test.Printf(_L("------- End of Negative Tests ----------------------------------------\n")); + + + //============================================================================= + //! @SYMTestCaseID PBASE-T_NOTIFY-2461 + //! @SYMTestType CIT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Plugin Tests + //! @SYMTestStatus + //============================================================================= + PrintLine(); + r = TestNotificationsWithFServPlugins(); + test(r==KErrNone); + test.Printf(_L("------- End of Plugin Tests ------------------------------------------\n")); + + + //====================================================================== + //! @SYMTestCaseID PBASE-T_NOTIFY-2459 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Drive Formatting – Single File Server Session + //! @SYMTestStatus Implemented + // + // TFsNotificationType EMediaChange + //====================================================================== + // + // RFormat + // We do these last so that we can be sure to have deleted anything we've inadvertently not deleted + // + // 1. Add notification for media change of a specific drive + // Format the drive + // +#ifdef __WINS__ + if(gDriveToTest-(TChar)'A' != 2) +#endif + { + PrintLine(); + test.Next(_L("Format Tests")); + r = TestMultipleNotificationsL(driveDes,1,1,t_notification::EFormat,TFsNotification::EMediaChange,KMinNotificationBufferSize,(TBool)EFalse,__LINE__); + test(r==KErrNone); + test.Printf(_L("------- End of Format Tests ------------------------------------------\n")); + } + + + //====================================================================== + //! @SYMTestCaseID PBASE-T_NOTIFY-2460 + //! @SYMTestType UT + //! @SYMREQ PREQ1847 + //! @SYMTestCaseDesc Notifications for Data Caged Areas + //! @SYMTestStatus Implemented + //====================================================================== + // + // Create a private folder for a specified uid + // Add notification filter using the following processes: + // 1. A process with no capability + // 2. A process with all capabilities + // 3. A process with the specified uid + // + PrintLine(); + test.Next(_L("Test T_NOTIFIER_NOCAPS.EXE")); + r = TestProcessCapabilities(_L("T_NOTIFIER_NOCAPS.EXE")); + test(r == KErrPermissionDenied); //Failure on emulator -> Did you forget to do a wintest? + + test.Next(_L("Test T_NOTIFIER_ALLFILES.EXE")); + r = TestProcessCapabilities(_L("T_NOTIFIER_ALLFILES.EXE")); + test(r == KErrNone); + + test.Next(_L("Test T_NOTIFIER_BELONGS.EXE")); + r = TestProcessCapabilities(_L("T_NOTIFIER_BELONGS.EXE")); + test(r == KErrNone); + test.Printf(_L("------- End of Data-Caging Tests -------------------------------------\n")); + + + test.End(); + test.Close(); + delete cleanup; + } //End of CallTestsL +