--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/concur/t_cfstest.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,697 @@
+// Copyright (c) 2002-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:
+//
+
+//! @file f32test\concur\t_csfsoak.cpp
+
+#include <f32file.h>
+#include <e32test.h>
+#include <e32math.h>
+#include <f32dbg.h>
+
+#include "t_server.h"
+#include "t_chlffs.h"
+#include "t_tdebug.h"
+#include "t_cfssoak.h"
+#include "f32_test_utils.h"
+
+using namespace F32_Test_Utils;
+
+
+
+
+GLDEF_D RTest test(_L("T_CFSTEST"));
+
+LOCAL_D TFullName gFsName;
+LOCAL_D TFullName gFsName1;
+LOCAL_D TFullName gFsName2;
+LOCAL_D TFullName gOldFsName;
+LOCAL_D TFullName gNewFsName;
+LOCAL_D TBool gNoMedia = ETrue;
+
+_LIT(KFsFile, "CFAFSDLY");
+_LIT(KFsName, "DelayFS");
+
+LOCAL_D const TInt32 KSecond = 1000000;
+LOCAL_D const TInt32 KTenthS = KSecond/10;
+LOCAL_D const TInt KNumBuf = 10;
+LOCAL_D const TInt KBufLen = 50000;
+
+LOCAL_D TInt KSessionWaitSlow = 50 * KTenthS;
+
+LOCAL_D TBuf8<KBufLen> gBuff[KNumBuf];
+LOCAL_D TRequestStatus gStat[KNumBuf];
+
+LOCAL_D TChar gRemFsChr = 0;
+LOCAL_D TInt gRemFsDrv = 0;
+
+LOCAL_D TChar gDrvCh0 = 0;
+LOCAL_D TChar gDrvCh1 = 0;
+LOCAL_D TChar gDrvCh2 = 0;
+
+LOCAL_D TInt gWaitTime = KSessionWaitSlow;
+
+GLDEF_D TExtension gPrimaryExtensions[KMaxDrives];
+
+inline void TraceError(const char* aFile, TInt aLine, const TDesC& aStr, TInt aRsp)
+//
+// 'Helper' routine to output the file and line of an error as well as a string
+// and a response value.
+//
+ {
+ TBuf<256> fbuf;
+ TPtrC8 fptr((const TUint8*)aFile);
+ fbuf.Copy(fptr);
+ RDebug::Print(_L("%S:%d %S: r = %d"), &fbuf, aLine, &aStr, aRsp);
+ }
+
+#define TESTSTR(r,s,cond) if (!(cond)) { TraceError(__FILE__, __LINE__, (s), (r)); test(0); }
+#define TESTLIT(r,s,cond) { _LIT(KStr,s); TESTSTR(r,KStr,cond); }
+#define TESTRES(r,cond) TESTLIT(r,"ERROR",cond)
+
+LOCAL_C TChar MountTestFileSystem(TInt aDrive)
+///
+/// Mount a new CTestFileSystem on the drive under test.
+/// @param aDrive Drive number (EDriveC etc.) to be used.
+///
+ {
+ TInt r;
+ // Check attributes
+ TBuf<64> b;
+ TChar c;
+ r=TheFs.DriveToChar(aDrive,c);
+ TESTLIT(r, "DriveToChar", r==KErrNone);
+
+ b.Format(_L("Mount test file system on %c:"),(TUint)c);
+ test.Next(b);
+
+ r=TheFs.AddFileSystem(KFsFile);
+ TESTLIT(r, "AddFileSystem", r==KErrNone || r==KErrAlreadyExists);
+
+ r=TheFs.FileSystemName(gOldFsName,aDrive);
+ TESTLIT(r, "FileSystemName", r==KErrNone || r==KErrNotFound);
+
+ TDriveInfo drv;
+ r = TheFs.Drive(drv, gRemFsDrv);
+ TESTLIT(r, "Drive()", r == KErrNone);
+
+ gNoMedia = (drv.iType == EMediaUnknown || drv.iType == EMediaNotPresent);
+
+ if (gOldFsName.Length() > 0)
+ {
+ r = TheFs.ExtensionName(gPrimaryExtensions[aDrive].iName, aDrive, 0);
+ if (r == KErrNone)
+ gPrimaryExtensions[aDrive].iExists = ETrue;
+
+ TTest::Printf(_L("Dismount %C: %S"), (TUint)c, &gOldFsName);
+ r=TheFs.DismountFileSystem(gOldFsName,aDrive);
+ TESTLIT(r, "DismountFileSystem", r==KErrNone);
+ }
+
+ if (gPrimaryExtensions[aDrive].iExists == EFalse)
+ r=TheFs.MountFileSystem(KFsName,aDrive);
+ else
+ r=TheFs.MountFileSystem(KFsName,gPrimaryExtensions[aDrive].iName,aDrive);
+
+ TESTLIT(r, "MountFileSystem", r==KErrNone);
+
+ r=TheFs.FileSystemName(gNewFsName,aDrive);
+ TESTLIT(r, "FileSystemName", r==KErrNone);
+
+ r = gNewFsName.CompareF(KFsName);
+ TESTLIT(r, "gNewFsName.Compare", r==0);
+
+ return c;
+ }
+
+LOCAL_C void UnmountFileSystem(TInt aDrive)
+///
+/// Dismount the filesystem and remount the original one.
+/// @param aDrive Drive number (EDriveC etc.) to be unmounted.
+///
+ {
+ TChar c;
+ TInt r=TheFs.DriveToChar(aDrive,c);
+ TESTLIT(r, "DriveToChar", r==KErrNone);
+
+ if (gNewFsName.Length() > 0)
+ {
+ TTest::Printf(_L("Dismount %C: %S"), (TUint)c, &gNewFsName);
+ r=TheFs.DismountFileSystem(gNewFsName,aDrive);
+ TESTLIT(r, "DismountFileSystem", r==KErrNone);
+
+ // if there's no media present, don't try to mount it
+ if (gNoMedia)
+ {
+ TTest::Printf(_L("No media on %C: so don't remount it"), (TUint)c);
+ }
+ else if (gOldFsName.Length() > 0)
+ {
+ TTest::Printf(_L("Mount %C: %S"), (TUint)c, &gOldFsName);
+ if (gPrimaryExtensions[aDrive].iExists == EFalse)
+ r=TheFs.MountFileSystem(gOldFsName,aDrive);
+ else
+ r=TheFs.MountFileSystem(gOldFsName,gPrimaryExtensions[aDrive].iName,aDrive);
+ TESTLIT(r, "MountFileSystem", r==KErrNone);
+ }
+ }
+ }
+
+LOCAL_C TInt TestCalibrate(TChar aDrvCh)
+///
+/// Calibrate the timing for writing the data buffers. This also sets up
+/// the buffers to the appropriate length (fast file systems such as LFFS
+/// and FAT need big buffers, the slow test filesystem needs small ones).
+///
+ {
+ TFileName name;
+ RFile file;
+ RFs fs;
+ TBool fast = (aDrvCh != gRemFsChr);
+ TInt drive;
+ TInt r;
+
+ fs.Connect();
+
+ name.Format(_L("%C:\\cfstest.txt"), (TUint)aDrvCh);
+
+ r=fs.CharToDrive(aDrvCh, drive);
+ TESTLIT(r, "CharToDrive", r==KErrNone);
+
+ TVolumeInfo info;
+ r = fs.Volume(info, drive);
+ if (r != KErrNone)
+ TTest::Fail(HERE, r, _L("Getting volume info"));
+ TTest::Printf(_L("Total space on drive %C = %ld (0x%lX)"), (TUint) aDrvCh, info.iSize, info.iSize);
+ TTest::Printf(_L("Free space on drive %C = %ld (0x%lX)"), (TUint) aDrvCh, info.iFree, info.iFree);
+
+ TInt buffsize;
+ if (fast)
+ {
+ TInt64 bufSize64 = info.iFree / KNumBuf;
+ buffsize = bufSize64 > KBufLen ? KBufLen : I64LOW(bufSize64);
+ }
+ else
+ {
+ buffsize = 100;
+ }
+
+ TTest::Printf(_L("Writing %d buffers of size %d"), KNumBuf, buffsize);
+
+
+ TInt i;
+ for (i = 0; i < KNumBuf; i++)
+ gBuff[i].Fill('*', fast ? buffsize : 100);
+
+ r = file.Replace(fs, name, EFileStreamText | EFileWrite);
+ if (r != KErrNone)
+ TTest::Fail(HERE, r, _L("opening %S for writing"), name.Ptr());
+
+ TTime startTime;
+ TTime endTime;
+ TTimeIntervalMicroSeconds timeTaken;
+ startTime.HomeTime();
+
+
+ for (i = 0; i < KNumBuf; i++)
+ {
+ r = file.Write(gBuff[i]);
+ if (r != KErrNone)
+ {
+ TTest::Printf(_L("Error writing file, r %d buffsize %d"), r, buffsize);
+ file.Close();
+ fs.Close();
+ return r;
+ }
+ }
+
+ file.Close();
+ fs.Close();
+
+ endTime.HomeTime();
+ timeTaken=endTime.MicroSecondsFrom(startTime);
+
+ TInt64 dtime = timeTaken.Int64();
+ gWaitTime = I64LOW(dtime);
+
+ if (gWaitTime < KTenthS)
+ {
+ TTest::Printf(_L("Time to complete writes (%d uS) too short"), gWaitTime);
+ return KErrGeneral;
+ }
+
+ while (gWaitTime > 50*KSecond && buffsize > 100)
+ {
+ gWaitTime /= 10;
+ buffsize /= 10;
+ }
+
+ for (i = 0; i < KNumBuf; i++)
+ gBuff[i].Fill('*', buffsize);
+
+ TTest::Printf(_L("Time to complete writes %d mS"), gWaitTime / 1000);
+
+ return KErrNone;
+ }
+
+void PrintBufStatus()
+ {
+ for (TInt i = 0; i < KNumBuf; i++)
+ {
+ TTest::Printf(_L("Req %d r %08X\n"), i, gStat[i].Int());
+ }
+ }
+
+LOCAL_C TInt TestClose(TChar aDrvCh, TBool aCloseFs)
+///
+/// Test what happens when a file is closed in the middle of writing it. Note
+/// that this assumes that the filesystem under test has been calibrated and
+/// the buffers set up already.
+///
+/// @return KErrGeneral if an error was detected, KErrNone otherwise
+///
+ {
+ TFileName fsname;
+ TFileName name;
+ RFile file;
+ RFs fs;
+ TInt drive;
+ TInt r;
+
+ fs.Connect();
+
+ r=TheFs.CharToDrive(aDrvCh, drive);
+ TESTLIT(r, "CharToDrive", r==KErrNone);
+
+ r=fs.FileSystemName(fsname, drive);
+ TESTLIT(r, "FileSystemName", r==KErrNone);
+
+ name.Format(_L("%C:\\cfstest.txt"), (TUint)aDrvCh);
+ TTest::Printf(_L("Testing %S (%S)"), &name, &fsname);
+
+ r = file.Replace(fs, name, EFileStreamText | EFileWrite);
+ if (r != KErrNone)
+ TTest::Fail(HERE, r, _L("opening %S for writing"), name.Ptr());
+
+ TInt i;
+ for (i = 0; i < KNumBuf; i++)
+ {
+ file.Write(gBuff[i], gStat[i]);
+ }
+
+ // wait for around a half of the writes to complete, then close the file
+ // before the others finish.
+ // If the media is unexpectedly slow and hasn't written a single buffer, wait a little bit longer
+ TInt KMaxWaitTime = Max(gWaitTime * 3, KSessionWaitSlow);
+ TInt totalTimeWaited = 0;
+ for (TInt waitTime = gWaitTime/2;
+ totalTimeWaited < KMaxWaitTime && gStat[0].Int() == KRequestPending;
+ totalTimeWaited+= waitTime, waitTime = gWaitTime / 10)
+ {
+ TTest::Printf(_L("Waiting %d mS"), waitTime / 1000);
+ User::After(waitTime);
+ }
+
+ TTest::Printf(_L("Wait ended"));
+ if (aCloseFs)
+ {
+ TTest::Printf(_L("Closing file server session"));
+ fs.Close();
+ }
+
+ else
+ {
+ TTest::Printf(_L("Closing file"));
+ file.Close();
+ }
+
+ // test what has happened
+ TInt nFinished = 0;
+ TInt nCancelled = 0;
+ TInt nPending = 0;
+ TBool bad = EFalse;
+ TRequestStatus tstat;
+ RTimer timer;
+ timer.CreateLocal();
+ timer.After(tstat, 2 * gWaitTime);
+ TInt requestsCompleted = 0;
+ for (i = 0; i < KNumBuf; i++)
+ {
+ User::WaitForRequest(tstat, gStat[i]);
+ ++requestsCompleted;
+ if (tstat != KRequestPending)
+ {
+ TTest::Printf(_L("Timer expired"));
+ break;
+ }
+ r = gStat[i].Int();
+ switch (r)
+ {
+ case KErrNone:
+ TTest::Printf(_L("write %d finished\n"), i);
+ nFinished++;
+ if (nCancelled > 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nCancelled > 0"));
+ }
+ break;
+ case KErrCancel:
+ TTest::Printf(_L("write %d cancelled\n"), i);
+ nCancelled++;
+#if !defined(__WINS__) // under some loads the calibration is wrong by now and no writes have finished yet
+ if (nFinished == 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nFinished == 0"));
+ }
+#endif
+ break;
+ case KRequestPending:
+ TTest::Printf(_L("write %d pending\n"), i);
+ nPending++;
+ if (nCancelled > 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nCancelled > 0"));
+ }
+#if !defined(__WINS__) // timing issue as above
+ if (nFinished == 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nFinished == 0"));
+ }
+#endif
+ break;
+ default:
+ TTest::Fail(HERE, r, _L("incorrect status for write %d"), i);
+ }
+ }
+
+ while (i < KNumBuf)
+ {
+ r = gStat[i].Int();
+ switch (r)
+ {
+ case KErrNone:
+ TTest::Printf(_L("write %d finished\n"), i);
+ nFinished++;
+ if (nCancelled > 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nCancelled > 0"));
+ }
+ break;
+ case KErrCancel:
+ TTest::Printf(_L("write %d cancelled\n"), i);
+ nCancelled++;
+#if !defined(__WINS__) // under some loads the calibration is wrong by now and no writes have finished yet
+ if (nFinished == 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nFinished == 0"));
+ }
+#endif
+ break;
+ case KRequestPending:
+ TTest::Printf(_L("write %d pending\n"), i);
+ nPending++;
+ if (nCancelled > 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nCancelled > 0"));
+ }
+#if !defined(__WINS__) // timing issue as above
+ if (nFinished == 0)
+ {
+ bad = ETrue;
+ PrintBufStatus();
+ TTest::Fail(HERE, _L("nFinished == 0"));
+ }
+#endif
+ break;
+ default:
+ TTest::Fail(HERE, r, _L("incorrect status for write %d"), i);
+ }
+ i++;
+ }
+
+ if (!aCloseFs)
+ {
+ // If we HAVEN'T closed the file server session, we must wait for all the remaining
+ // requests, including the timer.
+
+ TTest::Printf(_L("Waiting for %d uncompleted requests\n"), KNumBuf + 1 - requestsCompleted);
+ for (i = requestsCompleted ; i < KNumBuf + 1 ; ++i)
+ User::WaitForAnyRequest();
+ }
+ else
+ {
+ // If we have closed the session, then we need to work out if the timer went off (by
+ // checking if there are any writes still pending) and if not then we need to wait for it.
+
+ if (nPending == 0)
+ {
+ TTest::Printf(_L("Waiting for timer to complete\n"));
+ User::WaitForRequest(tstat);
+ }
+ }
+
+ if (aCloseFs)
+ fs.Connect();
+
+ TEntry entry;
+ r = fs.Entry(name, entry);
+ if (r != KErrNone)
+ TTest::Fail(HERE, r, _L("Entry(%S)"), &name);
+
+ TInt nWritten = entry.iSize / gBuff[0].Length();
+ TTest::Printf(_L("Created file %d bytes, %d complete buffers written"),
+ entry.iSize, nWritten);
+
+ fs.Delete(name);
+
+ fs.Close();
+
+ if (nCancelled < 2)
+ {
+ // At present, undefined whether cancelled or left pending
+ // TTest::Fail(HERE, _L("Not enough buffers (%d) cancelled"), nCancelled);
+ }
+
+ if (nPending > 0)
+ {
+ // At present, undefined whether cancelled or left pending
+ // TTest::Fail(HERE, _L("Too many buffers (%d) still pending"), nPending);
+ }
+
+ // Get the TFileCacheFlags for this drive
+ TVolumeInfo volInfo; // volume info for current drive
+ r = TheFs.Volume(volInfo, drive);
+ test(r==KErrNone);
+ test.Printf(_L("DriveCacheFlags = %08X\n"), volInfo.iFileCacheFlags);
+
+ // There's no point testing the numbers of buffers written if write caching enabled, as
+ // in this case, the write requests are completed successfully before the data is written to disk
+ if ((volInfo.iFileCacheFlags & EFileCacheWriteOn) && aCloseFs)
+ {
+ test.Printf(_L("%d write requests completed, %d of %d buffers written to disk\n"), nFinished, nWritten, KNumBuf);
+ test.Printf(_L("Skipping test for buffers written as write caching enabled and FS session destroyed\n"));
+ }
+ else
+ {
+
+#if !defined(__WINS__) // timing issue as above
+ if (nWritten < 2)
+ {
+ TTest::Fail(HERE, _L("Not enough buffers (%d) written"), nFinished);
+ }
+#endif
+ if (nWritten < nFinished)
+ {
+ TTest::Fail(HERE, _L("Only %d buffers written, should be %d"), nWritten, nFinished);
+ }
+ }
+
+ if (bad)
+ TTest::Printf(_L("Test %c: FAILED\n"), name[0]);
+ else
+ TTest::Printf(_L("Test %c: OK\n"), name[0]);
+
+ return (bad ? KErrGeneral : KErrNone);
+ }
+
+LOCAL_C TInt TestCloseOperation()
+///
+/// Task to exercise the remote (special) filesystem.
+///
+ {
+ TSoakRemote rem(gDrvCh1);
+ TInt r = KErrNone;
+ TBool ok = ETrue;
+
+ test.Next(_L("Mount as synchronous"));
+ rem.Remount(ETrue);
+ r = TestCalibrate(gDrvCh1);
+ if (r == KErrNone)
+ {
+ test.Next(_L("Test SubSession synchronous"));
+ r = TestClose(gDrvCh1, EFalse);
+ if (r != KErrNone)
+ ok = EFalse;
+ test.Next(_L("Test Session synchronous"));
+ r = TestClose(gDrvCh1, ETrue);
+ if (r != KErrNone)
+ ok = EFalse;
+ }
+
+ test.Next(_L("Mount as asynchronous"));
+ rem.Remount(EFalse);
+ r = TestCalibrate(gDrvCh1);
+ if (r == KErrNone)
+ {
+ test.Next(_L("Test SubSession asynchronous"));
+ r = TestClose(gDrvCh1, EFalse);
+ if (r != KErrNone)
+ ok = EFalse;
+ test.Next(_L("Test Session asynchronous"));
+ r = TestClose(gDrvCh1, ETrue);
+ if (r != KErrNone)
+ ok = EFalse;
+ }
+
+ return (ok ? KErrNone : KErrGeneral);
+ }
+
+LOCAL_C TInt parseCmd(TInt aArgC, TPtrC aArgV[], TChar& dr0, TChar& dr1, TChar& dr2)
+///
+/// Get drive characters from the command line.
+///
+ {
+ if (aArgC > 1)
+ dr0 = User::UpperCase(aArgV[1][0]);
+ if (aArgC > 2)
+ dr1 = User::UpperCase(aArgV[2][0]);
+ if (aArgC > 3)
+ dr2 = User::UpperCase(aArgV[3][0]);
+
+ if (dr1 < 'A' || dr1 > 'Z')
+ dr1 = dr0;
+
+ return KErrNone;
+ }
+
+GLDEF_C void CallTestsL()
+///
+/// Do all tests.
+///
+ {
+ //-- set up console output
+ F32_Test_Utils::SetConsole(test.Console());
+
+ for (TInt i = 0; i < KMaxDrives; i++)
+ {
+ gPrimaryExtensions[i].iExists = EFalse;
+ }
+
+
+ // first thing, initialise local test class to make sure it gets done.
+ TInt r = TTest::Init();
+ test(r == KErrNone);
+
+ const TInt KMaxArgs = 4;
+ TPtrC argv[KMaxArgs];
+ TInt argc = TTest::ParseCommandArguments(argv, KMaxArgs);
+
+ gDrvCh0 = TTest::DefaultDriveChar();
+
+ r = parseCmd(argc, argv, gDrvCh0, gDrvCh1, gDrvCh2);
+ if (r != KErrNone)
+ {
+ User::Exit(KErrAbort);
+ }
+
+ gRemFsChr = gDrvCh0;
+ r = TheFs.CharToDrive(gRemFsChr, gRemFsDrv);
+
+ test(r == KErrNone);
+
+ PrintDrvInfo(TheFs, gRemFsDrv);
+
+ if (r != KErrNone || gRemFsDrv == EDriveZ)
+ {
+ test.Printf(_L("Test cannnot run on drive %C:\n"), (TUint)gRemFsChr);
+ return;
+ }
+
+ TDriveInfo drv;
+ r = TheFs.Drive(drv, gRemFsDrv);
+ test(r == KErrNone);
+
+ if(Is_Automounter(TheFs, gRemFsDrv))
+ {
+ //-- this test tries to mount the curent drive as a synchronous one,
+ //-- automounter can't work on synchronous drives.
+ test.Printf(_L("This test can't be performed on AutoMounter FS, Skipping.\n"));
+ return;
+ }
+
+ // if it's a RAM drive or no media present, use the slow FS
+ if (drv.iType == EMediaRam)
+ {
+ test.Printf(_L("Test can't run on RAM drive %C:\n"), (TUint)gRemFsChr);
+ return;
+ }
+ if (drv.iType == EMediaUnknown || drv.iType == EMediaNotPresent)
+ {
+ // Mount test filesystem on that drive
+ test.Printf(_L("Using slow filesystem on drive %C:\n"), (TUint)gRemFsChr);
+ MountTestFileSystem(gRemFsDrv);
+ }
+ else if (argc > 2)
+ {
+ // two parameters, mount the test filesystem on the first
+ MountTestFileSystem(gRemFsDrv);
+ }
+ else
+ {
+ // Use the existing filesystem on the drive
+ gRemFsChr = 0;
+ }
+
+ // If we can do it, check whether the drive is LFFS and is OK
+// !!! Disable platform security tests until we get the new APIs
+// if (User::Capability() & KCapabilityRoot)
+// CheckMountLFFS(TheFs, gDrvCh1);
+
+ //!!!!! Warning: MountTestFileSystem() and UnmountFileSystem() code is lousy! it always mounts back the drive as SYNCHRONOUS.
+ //!!!!! anyway, this code seems not to be called, because of "else if (argc > 2)"
+
+ // Do tests
+ r = TestCloseOperation();
+
+ // restore the original mounted drive if anything changed
+ UnmountFileSystem(gRemFsDrv);
+
+ test(r == KErrNone);
+ }
+
+