kerneltest/f32test/concur/t_cfssoakfn.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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:
// f32test\server\t_csfsoakfn.cpp
// 
//

#include <f32file.h>
#include <e32test.h>
#include <e32math.h>
#include <f32dbg.h>
#include "t_server.h"
#include "t_tdebug.h"
#include "t_cfssoak.h"

/// Time value constants
LOCAL_D const TInt KSecond   = 1000000;
LOCAL_D const TInt KTenthSec = KSecond / 10;

/// Time to wait before session/subsession close, to allow some writes to
/// complete but not all (1 second per write with slow FS)
LOCAL_D const TInt KSessionWaitTime = 25 * KTenthSec;

/// Number of writes we expect to have completed
LOCAL_D const TInt KSessionNumEnded = KSessionWaitTime / KSecond;

GLREF_D TExtension gPrimaryExtensions[];
// -----------------------------------------------------------------

void TSoakStats::Print()
///
/// Print a statistics header.
///
	{
	TTest::Printf(_L("                    Total                Fail\n"));
	}

void TSoakStats::Print(const TDesC& aTitle)
///
/// Print the statistics for this item (title, total executed, number executed
/// this time, total failures, failures this time) then reset the "this time"
/// values.
///
	{
	TTest::Printf(_L("  %-8S %8d %+8d   %8d %+8d\n"),
				  &aTitle, iTotal, iThis, iFail, iThisF);
	iThis = 0;
	iThisF = 0;
	}

void TSoakStats::Inc()
///
/// Increment both the total and "this time" execution numbers.
///
	{
	iTotal++;
	iThis++;
	}

void TSoakStats::Fail()
///
/// Increment both the total and "this time" failure numbers.
///
	{
	iFail++;
	iThisF++;
	}


// -----------------------------------------------------------------

TSoakReadOnly::TSoakReadOnly() : iDrive(-1)
///
/// Initialise the "read only" tests, connect the file session.
///
	{
	TInt r = iFs.Connect();
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("iFs connect"));
	}

TSoakReadOnly::TSoakReadOnly(TInt aDriveCh) : iDrive(aDriveCh)
///
/// Initialise the "read only" tests, connect the file session, setting up
/// a drive to be excluded from the reading.
/// @param aDriveCh Drive letter to be excluded.
///
	{
	TInt r = iFs.Connect();
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("iFs connect"));
	}

TSoakReadOnly::~TSoakReadOnly()
///
/// Destructor -- close the file session.
///
	{
	iFs.Close();
	}

TInt TSoakReadOnly::ReadFile(const TDesC& aName, TInt aSize)
///
/// Read a file, expecting a certain size.  No check is done on the actual
/// data, just that it can be read.
/// @param aName Name of the file.
/// @param aSize Expected file size.
///
	{
	TInt r = KErrNone;
	RFile f;
	iReads.Inc();
	r = f.Open(iFs, aName, EFileStreamText);
	if (r == KErrNotFound || r == KErrPathNotFound)
		return KErrNone;
	TBuf<256> errbuf;
	if (r != KErrNone)
		{
		if (r != KErrInUse)
			{
			iFiles.Fail();
			TTest::Printf(_L("%S -- open failed %S\n"), &aName, &TTest::ErrStr(r, errbuf));
			}
		else
			TTest::Printf(_L("Warning: %S -- open failed %S\n"), &aName, &TTest::ErrStr(r, errbuf));
		return r;
		}
	TBuf8<256> buf;
	TInt len = 0;
	while ((r = f.Read(buf)) == KErrNone && buf.Length() > 0)
		len += buf.Length();
	f.Close();
	if (r != KErrNone && r != KErrEof)
		{
		iReads.Fail();
		TTest::Printf(_L("ERROR %S -- READ FAILED %S\n"), &aName, &TTest::ErrStr(r, errbuf));
		}
	else if (len < aSize)
		{
		iReads.Fail();
		TTest::Printf(_L("ERROR %S -- %d READ, %d EXPECTED\n"), &aName, len, aSize);
		}
	else if (len > aSize)
		TTest::Printf(_L("Warning: %S -- %d read, %d expected\n"), &aName, len, aSize);
	return r;
	}

TInt TSoakReadOnly::ScanDirs(TInt aDriveCh, TInt aReadInterval)
///
/// Scan directories on a drive, reading a selection of the files found.
/// @param aDriveCh Drive letter to be scanned.
/// @param aReadInterval Approximate number of files to be read (they are
///                      read at random, so the actual number read may be
///                      less than this number).
///
	{
	TInt r = KErrNone;
	CDirScan* scanner=NULL;
	TRAP(r, scanner=CDirScan::NewL(iFs));
	ScanDirFunc(scanner, aDriveCh, aReadInterval);
	delete scanner;
	return r;
	}

TInt TSoakReadOnly::ScanDirFunc(CDirScan* aScanner, TInt aDriveCh, TInt aReadInterval)
///
/// Scan directories on a drive, reading a selection of the files found.
/// @param aDriveCh Drive letter to be scanned.
/// @param aReadInterval Approximate number of files to be read (they are
///                      read at random, so the actual number read may be
///                      less than this number).
///
	{
	TInt r = KErrNone;
	TBuf<8> name;
	name.Format(_L("%c:\\"), aDriveCh);
	// TTest::Printf(_L("Scanning %S\n"), &name);
	TParse dirName;
	r=iFs.Parse(name, dirName);
	if (r != KErrNone)
		{
		iDrives.Fail();
		return r;
		}
	CDir* entryList = NULL;
	TInt nfiles = 0;
	TRAP(r, aScanner->SetScanDataL(dirName.FullName(),KEntryAttDir,ESortByName));
	if (r != KErrNone)
		{
		TTest::Fail(HERE, r, _L("SetScanData %S"), &dirName.FullName());
		}
	TRAP(r, aScanner->NextL(entryList));
	if (r == KErrPathNotFound)
		return KErrNone;
	if (r != KErrNone)
		{
		TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName());
		}
	while (entryList)
		{
		for (TInt i = 0; i < entryList->Count(); i++)
			{
			TEntry e = (*entryList)[i];
			if (!e.IsDir())
				++nfiles;
			}
		delete entryList;
		TRAP(r, aScanner->NextL(entryList));
		if (r == KErrPathNotFound)
			break;
		if (r != KErrNone)
			{
			TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName());
			}
		}
	TInt prob = (nfiles / aReadInterval) + 1;
	TRAP(r, aScanner->SetScanDataL(dirName.FullName(),KEntryAttDir,ESortByName));
	if (r == KErrPathNotFound)
		return KErrNone;
	if (r != KErrNone)
		{
		TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName());
		}
	for (;;)
		{
		TRAP(r, aScanner->NextL(entryList));
		if (r == KErrPathNotFound)
			return KErrNone;
		if (r != KErrNone)
			{
			TTest::Fail(HERE, r, _L("Scan Next %S"), &dirName.FullName());
			}
		if (entryList==NULL)
			break;
		TInt count=entryList->Count();
		while (count--)
			{
			TEntry e = (*entryList)[count];
			TFileName path=aScanner->FullPath();
			path.Append(e.iName);
			TBuf<16> attr;
			for (TInt j = 0; j < 16; j++)
				{
				if ((1 << j) & e.iAtt)
					attr.Append(TText("RHSVDA X        "[j]));
				}
			if (e.IsDir())
				{
				iDirs.Inc();
				// TTest::Printf(_L("%c:%-50S    <DIR>  %S\n"), aDriveCh, &path, &attr);
				}
			else
				{
				iFiles.Inc();
				TBool read = (aReadInterval && Math::Rand(iSeed) % prob == 0);
				if (read)
					{
					// TTest::Printf(_L("%-50S %8d  %-8S  test\n"), &path, e.iSize, &attr);
					r = ReadFile(path, e.iSize);
					}
				else
					{
					// TTest::Printf(_L("%c:%-50S %8d  %S\n"), aDriveCh, &path, e.iSize, &attr);
					}
				}
			}
		delete entryList;
		entryList=NULL;
		}
	return r;
	}

TInt TSoakReadOnly::ScanDrives(TBool aScanDirs, TInt aReadInterval)
///
/// Scan all drives (except the one excluded) for directories and files.
/// @param aScanDirs If true, read subdirectories, if false don't.
/// @param aReadInterval approximate number of files to read.
///
	{
	TInt r = KErrNone;
	TInt i;
	for (i = EDriveA; i <= EDriveZ; i++)
		{
		TChar drv;
		r=iFs.DriveToChar(i, drv);
		if (r != KErrNone)
			return r;
		TDriveInfo info;
		r=iFs.Drive(info, i);
		if (r != KErrNone)
			return r;
		if (i != iDrive
			&& info.iDriveAtt != 0
			&& info.iType != EMediaUnknown
			&& info.iType != EMediaNotPresent)
			{
			iDrives.Inc();
			// TTest::Printf(_L("Drive %c:"), drv);
			if (aScanDirs)
				{
				iDirs.Inc();
				r = ScanDirs(drv, aReadInterval);
				if (r != KErrNone)
					return r;
				}
			}
		}
	return r;
	}

void
TSoakReadOnly::ExcludeDrive(TInt aDriveCh)
///
/// Set a drive to be excluded from scanning.
/// @param aDriveCh Drive letter to be excluded.
///
	{
	iDrive = aDriveCh;
	}


// --------------------------------------------------------------------------

TSoakFill::TSoakFill()
///
/// Initialise the fill/clean cycle.
///
	{
	iSeed = 186483;
	TInt r = iFs.Connect();
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("iFs connect"));
	}

TInt TSoakFill::SetDrive(TInt aDriveCh)
///
/// Set a drive to be stressed.  The test directory is created and then it is
/// cleaned (in case anything was left over from previous tests).  Note that
/// other directories on the drive are untouched.
/// @param aDriveCh Drive letter to be used.
/// @leave The drive scanning can cause the function to leave.
///
	{
	TInt  r = KErrNone;
	iDrive = aDriveCh;
	if (aDriveCh)
		{
		iDrvCh = aDriveCh;
		iFs.CharToDrive(iDrvCh, iDrive);
		r=iFs.Volume(iInfo, iDrive);
		if (r != KErrNone)
			TTest::Fail(HERE, r, _L("volume info for %C:"), aDriveCh);
		iFree = iInfo.iSize;
		iName.Format(_L("%c:\\SOAK\\"), iDrvCh);
		r = iFs.MkDir(iName);
		if (r != KErrNone && r != KErrAlreadyExists)
			TTest::Fail(HERE, r, _L("mkdir %S"), &iName);
		r = KErrNone;
		}
	return r;
	}

TInt TSoakFill::FillDrive()
///
/// Fill the drive with files and directories of random lengths.
/// @param aDriveCh Drive letter to be tested, or zero (absent) to use the one
///        set up with SetDrive().
/// @leave Setting up a new drive can cause this function to leave.
///
	{
	TInt  r = KErrNone;
	r=iFs.Volume(iInfo, iDrive);
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("volume info for %C:"), iDrvCh);
	iFree = iInfo.iFree;
	r = iFs.MkDir(iName);
	if (r != KErrNone && r != KErrAlreadyExists && r != KErrNotSupported)
		TTest::Fail(HERE, r, _L("mkdir %S"), &iName);
	do
		{
		r = Fill(iName);
		if (r == KErrDiskFull)
			{
			// TTest::Printf(_L("Disk full on %c:\n"), iDrvCh);
			break;
			}
		if (r != KErrNone)
			TTest::Fail(HERE, r, _L("Filling drive %c"), iDrvCh);
		r=iFs.Volume(iInfo, iDrive);
		if (r != KErrNone)
			TTest::Fail(HERE, r, _L("volume info for %c:"), iDrvCh);
		} while (iInfo.iFree > 0);
	r=iFs.Volume(iInfo, iDrive);
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("volume info for %c:"), iDrvCh);
	if (iInfo.iFree > 0)
		TTest::Printf(_L("Free space on %c: %S %ld KB (out of %ld KB)\n"),
					  iDrvCh,
					  &iInfo.iName,
					  I64LOW(iInfo.iFree / 1024),
					  I64LOW(iInfo.iSize / 1024));
	return r;
	}

TInt TSoakFill::CleanDrive()
///
/// Clean the test directory on the selected drive, removing all files and
/// subdirectories.  Other directories on the drive are left untouched.
/// @leave Scanning the drive can cause the function to leave.
///
	{
	TInt r = KErrNone;
	CDirScan* scanner=0;
	TRAP(r, scanner=CDirScan::NewL(iFs));
	if (r != KErrNone || !scanner)
		TTest::Fail(HERE, r, _L("creating scanner"));
	TParse dirName;
	r=iFs.Parse(iName, dirName);
	if (r != KErrNone)
		{
		if (r == KErrInUse || r == KErrNotFound || r == KErrPathNotFound)
			{
			// valid conditions, don't report error
			r = KErrNone;
			}
		else
			TTest::Fail(HERE, r, _L("Parse %S"), &iName);
		}
	else
		{
		// TTest::Printf(_L("scan %S\n"), &iName);
		CDir* entryList = NULL;
		TRAP(r, scanner->SetScanDataL(dirName.FullName(),KEntryAttDir,ESortByName,CDirScan::EScanUpTree));
		if (r != KErrNone)
			TTest::Fail(HERE, r, _L("SetScanDataL(%S)"), &dirName.FullName());
		TRAP(r, scanner->NextL(entryList));
		if (r != KErrNone && r != KErrPathNotFound)
			TTest::Fail(HERE, r, _L("Scan NextL()"));
		while (entryList)
			{
			for (TInt i = 0; i < entryList->Count(); i++)
				{
				TEntry e = (*entryList)[i];
				TFileName path = iName;
				if (path.Right(1) == _L("\\"))
					path.SetLength(path.Length()-1);
				path.Append(scanner->AbbreviatedPath());
				path.Append(e.iName);
				// TTest::Printf(_L("remove %S\n"), &path);
				TBuf<256> buf;
				TInt maxInUseCount = 120;
				do
					{
					if (e.IsDir())
						{
						if (path.Right(1) != _L("\\"))
							path.Append(_L("\\"));
						r = iFs.RmDir(path);
						}
					else
						r = iFs.Delete(path);
					if (r == KErrInUse)
						{
						TTest::Printf(_L("Warning: %S deleting %S\n"), &TTest::ErrStr(r, buf), &path);
						User::After(1*KSecond);
						}
					}
					while (r == KErrInUse && maxInUseCount-- > 0);
				if (r != KErrNone)
					{
					TTest::Printf(_L("ERROR %S deleting %S\n"), &TTest::ErrStr(r, buf), &path);
					}
				}
			delete entryList;
			TRAP(r, scanner->NextL(entryList));
			if (r != KErrNone)
				TTest::Fail(HERE, r, _L("Scan NextL()"));
			}
		}
	delete scanner;
	r = iFs.RmDir(iName);
	if (r != KErrNone && r != KErrNotFound && r != KErrPathNotFound)
		{
		TTest::Fail(HERE, r, _L("volume info for %C:"), iName[0]);
		}
	r=iFs.Volume(iInfo, iDrive);
	if (r != KErrNone)
		{
		TTest::Fail(HERE, r, _L("volume info for %C:"), iName[0]);
		}
	if (iInfo.iFree > iFree)
		{
		TTest::Printf(_L("Warning: %C: changed size -- was %ld now %ld\n"),
					  iName[0], iFree, iInfo.iFree);
		return r;
		}
	iFree = iInfo.iFree;
	return r;
	}

TInt TSoakFill::Fill(TFileName& aName, TInt aNfiles)
///
/// Recursively create files and subdirectories at random.  If a subdirectory
/// is created, the function recurses to fill it.  This generates a mixture of
/// directories and files of varying lengths.
/// @param aName   Directory in which to create other stuff.
/// @param aNfiles Maximum number of files to create.
/// @return Status of last thing created, KErrDiskFull when out of space.
///
	{
	TInt oldlen = aName.Length();
	if (oldlen + 10 > aName.MaxLength())
		return KErrNone;
	TInt r=iFs.Volume(iInfo, iDrive);
	if (r != KErrNone)
		return r;
	TInt nfiles = I64LOW(iInfo.iFree/10000) + 5;
	if (aNfiles > 0 && nfiles > aNfiles)
		nfiles = aNfiles;
	nfiles = Math::Rand(iSeed) % nfiles + 5;
	TInt filesz = I64LOW(iInfo.iFree/nfiles/256) + 5;
	// TTest::Printf(_L("nfiles = %d\n"), nfiles);
	TInt i;
	for (i = 0; i < nfiles; i++)
		{
		aName.SetLength(oldlen);
		TBool dir = (Math::Rand(iSeed) % 5 == 0);
		if (dir && oldlen < 80)
			{
			aName.Append(_L("d"));
			aName.AppendNum(i);
			aName.Append(_L("\\"));
			r = iFs.MkDir(aName);
			TInt busycount = 120;
			while (busycount-- > 0)
				{
				r = iFs.MkDir(aName);
				if (r == KErrDiskFull)
					TTest::Printf(_L("Disk full creating %S\n"), &aName);
				if (r != KErrInUse)
					break;
				TTest::Printf(_L("Warning: KErrInUse creating %S\n"), &aName);
				User::After(1*KSecond);
				}
			// TTest::Printf(_L("mkdir %S = %d\n"), &aName, r);
			if (r == KErrNone || r == KErrAlreadyExists)
				{
				r = Fill(aName, nfiles - i - 2);
				}
			if (r != KErrNone)
				break;
			}
		else
			{
			aName.Append(_L("F"));
			aName.AppendNum(i);
			RFile f;
			TInt busycount = 120;
			while (busycount-- > 0)
				{
				r = f.Replace(iFs, aName, EFileStreamText | EFileWrite);
				if (r != KErrInUse)
					break;
				TTest::Printf(_L("Warning: KErrInUse creating %S\n"), &aName);
				User::After(1*KSecond);
				}
			if (r == KErrNone)
				{
				// iNames.AppendL(aName);
				TInt num = Math::Rand(iSeed) % filesz + 10;
				TBuf8<256> buf;
				buf.Fill(TText(' '), 256);
				TInt wr = 0;
				while (num-- > 0 && r == KErrNone)
					{
					r = f.Write(buf);
					if (r == KErrNone)
						wr += 256;
					else
						break;
					}
				f.Close();
				/*
				if (r == KErrDiskFull)
					TTest::Printf(_L("Disk full writing %S\n"), &aName);
				*/
				if (r != KErrNone)
					break;
				}
			else
				{
				// TTest::Printf(_L("creat %S = %d\n"), &aName, r);
				if (r == KErrDiskFull)
					TTest::Printf(_L("Disk full creating %S\n"), &aName);
				break;
				}
			}
		}
	aName.SetLength(oldlen);
	return r;
	}


TSoakRemote::TSoakRemote(TInt aDriveCh)
///
/// Initialise testing for 'remote' drive (special filesystem).  Connects to
/// file session, initialises the drive and timer, sets up the buffers and
/// file name.
/// @param aDriveCh Drive letter for the drive to test.
///
	{
	TInt r = iFs.Connect();
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("iFs connect"));
	iDrvCh = aDriveCh;
	iSync  = EFalse;
	iFs.CharToDrive(iDrvCh, iDrive);
	iTimer.CreateLocal();
	Setup();
	}

void TSoakRemote::Setup()
/// Set up the buffers and the filename to be used.
	{
	for (TInt i = 0; i < KSoakNumBuf; i++)
		{
		iBuff[i].Fill('_', KSoakBufLen);
		iStat[i] = KErrNone;
		}
	iName.Format(_L("%c:\\SOAKTEST.FILE"), iDrvCh);
	}

void TSoakRemote::Remount(TBool aSync)
///
/// Remount the test drive as (a)synchronous.
/// @param aSync If true, the drive is set as synchronous access, otherwise
///              as asynchronous.
///
	{
	TFileName fsname;
	iSync = aSync;
	TInt r = iFs.FileSystemName(fsname, iDrive);
	TEST(r == KErrNone || r == KErrNotFound);

	if (fsname.Length() > 0)
		{
		r = iFs.ExtensionName(gPrimaryExtensions[iDrive].iName, iDrive, 0);
		if (r == KErrNone)
			gPrimaryExtensions[iDrive].iExists = ETrue;

		r = iFs.DismountFileSystem(fsname, iDrive);
		if(r != KErrNone)
			{
			TTest::Fail(HERE, r, _L("Dismounting file system %S"), &fsname);
			}
		}

	TBufC<16> type = _L("asynchronous");
	if (iSync)
		type = _L("synchronous");
	TTest::Printf(_L("Remount filesystem %c: %S as %S\n"), iDrvCh, &fsname, &type);

#ifdef __CONCURRENT_FILE_ACCESS__
	if (gPrimaryExtensions[iDrive].iExists == EFalse)
		r=iFs.MountFileSystem(fsname,iDrive,iSync);
	else
		r=iFs.MountFileSystem(fsname,gPrimaryExtensions[iDrive].iName,iDrive,iSync);
#else
	if (gPrimaryExtensions[aDrive].iExists == EFalse)
		r=iFs.MountFileSystem(fsname,iDrive);
	else
		r=iFs.MountFileSystem(fsname,gPrimaryExtensions[iDrive].iName,iDrive);
#endif
	TEST(r==KErrNone);
	}

TInt TSoakRemote::TestSubSession()
///
/// Test what happens when a file is closed in the middle of writing it.  Note
/// that this assumes that the filesystem under test takes a second for each
/// write operation (i.e. is the special test filesystem).
///
	{
	TInt r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite);
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("opening %S for writing"), iName.Ptr());
	TInt i;
	for (i = 0; i < KSoakNumBuf; i++)
		{
		iFile.Write(iBuff[i], iStat[i]);
		}
	// wait for a couple of writes to complete, then close the file before the
	// others finish
	User::After(KSessionWaitTime);
	TTest::Printf(_L("Wait ended"));
	iFile.Close();
	TTest::Printf(_L("Close ended"));
	// test what has happened
	TBool bad = EFalse;
	for (i = 0; i < KSoakNumBuf; i++)
		{
		User::WaitForRequest(iStat[i]);
		r = iStat[i].Int();
		switch (r)
			{
			case KErrNone:
				if (i >= KSessionNumEnded)
					{
					TTest::Printf(_L("Write %d not cancelled"), i);
					bad = ETrue;
					}
				break;
			case KErrCancel:
				if (i <= KSessionNumEnded)
					{
					TTest::Printf(_L("Write %d incorrectly cancelled"), i);
					bad = ETrue;
					}
				TTest::Printf(_L("write %d cancelled\n"), i);
				break;
			default:
				TTest::Fail(HERE, r, _L("incorrect status for write %d"), i);
			}
		}
	iFs.Delete(iName);
	TPtrC sbuf(iSync ? _L("sync") : _L("async"));
	if (bad)
		{
		TTest::Printf(_L("TestSubSession %c: %S FAILED\n"), iName[0], &sbuf);
		// Commented out for the moment as result is undefined
		// TTest::Fail(HERE, _L("TestSubSession %c: %S FAILED\n"), iName[0], &sbuf);
		}
	TTest::Printf(_L("TestSubSession %c: %S OK\n"), iName[0], &sbuf);
	return KErrNone;
	}

TInt TSoakRemote::TestSession()
///
/// Test what happens when a session is closed in the middle of writing a file.
/// Note that this assumes that the filesystem under test takes a second for
/// each write operation (i.e. is the special test filesystem).
///
	{
	TInt r;
	TInt i;
	TPtrC sbuf(iSync ? _L("sync") : _L("async"));

	r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite);
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("opening %S for writing"), iName.Ptr());
	for (i = 0; i < KSoakNumBuf; i++)
		{
		iFile.Write(iBuff[i], iStat[i]);
		}
	// wait for a couple of them to complete, then close the session
	User::After(KSessionWaitTime);
	TTest::Printf(_L("Close FS %S"), &sbuf);
	// iFs.SetDebugRegister(KFSYS | KFSERV | KTHRD);
	iFs.Close();
	TTest::Printf(_L("FS closed %S"), &sbuf);
	// see what has happened to the writes (wait for at most another 10 seconds).
	TRequestStatus tstat;
	iTimer.After(tstat, 10*KSecond);
	TBool busy = ETrue;
	TInt  file = 0;
	while (tstat == KRequestPending && busy)
		{
		User::WaitForAnyRequest();
		busy = EFalse;
		for (i = file; i < KSoakNumBuf; i++)
			{
			r = iStat[i].Int();
			switch (r)
				{
				case KRequestPending:
					busy = ETrue;
					TTest::Printf(_L("write %d pending\n"), i);
					break;
				case KErrNone:
					file = i + 1;
					TTest::Printf(_L("write %d finished\n"), i);
					break;
				case KErrCancel:
					file = i + 1;
					TTest::Printf(_L("write %d cancelled\n"), i);
					break;
				default:
					file = i + 1;
					TTest::Fail(HERE, r, _L("incorrect status for write %d"), i);
				}
			}
		}
	TBool bad = EFalse;
	if (busy)
		{
		for (i = 0; i < KSoakNumBuf; i++)
			{
			TBuf<64> buf;
			r = iStat[i].Int();
			if (r != KErrNone)
				{
				// We expect that the third and subsequent requests will either
				// have failed with cancel or be still outstanding.  If either
				// of the first two have failed or are outstanding, that's an
				// error.
				if (i < KSessionNumEnded || (r != KErrCancel && r != KRequestPending))
					{
					TTest::Fail(HERE, _L("write %d: %S\n"), i, &TTest::ErrStr(r, buf));
					bad = ETrue;
					}
				}
			}
		}
	iTimer.Cancel();
	// if it's got this far, re-connect the file session
	// User::After(100000);
	// TTest::Printf(_L("FS closed (%S) yet?"), &sbuf);
	r = iFs.Connect();
	iFs.SetDebugRegister(0);
	// TTest::Printf(_L("FS opened"));
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("iFs connect"));
	r = iFs.Delete(iName);
	for (TInt nr = 0; r == KErrInUse && nr < 100; nr++)
		{
		TTest::Printf(_L("Wait for previous session to close"));
		User::After(10*KSecond);
		r = iFs.Delete(iName);
		}
	if (r == KErrNotFound)
		r = KErrNone;
	if (r != KErrNone)
		bad = ETrue;
	TPtrC obuf(bad ? _L("FAIL") : _L("OK"));
	TTest::Printf(_L("TestSession %c: %S %S\n"), iName[0], &sbuf, &obuf);
	if (bad)
		{
		TTest::Printf(_L("Test session close %c: %S FAILED\n"), iName[0], &sbuf);
		// Commented out for the moment as result is undefined
		// TTest::Fail(HERE, _L("Test session close failed"));
		}
	return r;
	}

TInt TSoakRemote::TestMount()
///
/// Test dismounting with a file open (should fail)
///
	{
	TFileName fsname;
	TInt r = iFs.FileSystemName(fsname, iDrive);
	TEST(r == KErrNone || r == KErrNotFound);

	TPtrC sbuf(iSync ? _L("sync") : _L("async"));

	r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite);
	for (TInt nr = 0; r == KErrInUse && nr < 100; nr++)
		{
		TTest::Printf(_L("Warning: KErrInUse opening %S for writing\n"), &iName);
		User::After(10*KSecond);
		r = iFile.Replace(iFs, iName, EFileStreamText | EFileWrite);
		}
	if (r != KErrNone)
		TTest::Fail(HERE, r, _L("opening %S for writing"), &iName);

	if (fsname.Length() > 0)
		{
		r = iFs.DismountFileSystem(fsname, iDrive);
		if (r == KErrNone)
			{
#ifdef __CONCURRENT_FILE_ACCESS__
			r = iFs.MountFileSystem(fsname, iDrive, iSync);
#else
			r = iFs.MountFileSystem(fsname, iDrive);
#endif
			if (r != KErrNone)
				TTest::Fail(HERE, r, _L("MountFileSystem(%S, %C:)"), &fsname, iDrvCh);
			}
		else if (r != KErrInUse)
			{
			TTest::Fail(HERE, r, _L("DismountFileSystem(%S, %C:)"), &fsname, iDrvCh);
			}
		}

	iFile.Close();
	iFs.Delete(iName);

	TTest::Printf(_L("TestMount %c: %S OK\n"), iName[0], &sbuf);

	return KErrNone;
	}