diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/tdbms/t_dbood.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/dbms/tdbms/t_dbood.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,836 @@ +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Testing new RDbs methods, which handle "Out of disk space" situations. +// +// + +#include +#include +#include + +///////////////////////////////////////////////////////////////// +//Globals + +//If you change KTestDrive, don't forget to change KTestDatabase too!!! + +#if defined __WINSCW__ || defined __WINS__ + + //The C: drive may be too big and may be used concurently by other applications. + //The T: drive is more suitable for the test if running on the emulator + const TInt KTestDrive = EDriveT; + _LIT( KTestDatabase, "T:\\DBMS-TST\\T_DbmsOOD.DB"); + +#elif defined __X86GCC__ + + const TInt KTestDrive = EDriveG; + _LIT( KTestDatabase, "G:\\DBMS-TST\\T_DbmsOOD.DB"); + +#else + + const TInt KTestDrive = EDriveE; + _LIT( KTestDatabase, "E:\\DBMS-TST\\T_DbmsOOD.DB"); + +#endif + +const TInt KReservedSpaceSize = 0; //The aSpace parameter of RDbs::ReserveDriveSpace() + //is not used at the moment and shall be set to 0. + +static RTest TheTest(_L("t_dbood - \"Out of Disk space\" test")); +static RFs TheFs; +static RDbNamedDatabase TheDb; +static RDbs TheDbSession; + +//Test table defs +_LIT(KTestTableName, "TABLE1"); + +const TInt KTestRecordsCount = 350; + +struct TColDef + { + const TText* iName; + TDbColType iType; + TInt iAttributes; + }; +static TColDef const KColDefs[]= + { + {_S("ID"), EDbColUint32, TDbCol::EAutoIncrement}, + {_S("DATA"), EDbColBinary, TDbCol::ENotNull}, + {0} + }; + +//One or more files with KLargeFileName name and "." extension, where n is +//000, 001, 002, 003... +//will be created and they will occupy almost all available disk space. +//The idea is to perform after that "delete" +//transaction, which has to fail, because of "out of disk space" condition. +#if defined __WINSCW__ || defined __WINS__ + + _LIT(KLargeFileName, "T:\\DBMS-TST\\DeleteMe"); + +#elif defined __X86GCC__ + + _LIT(KLargeFileName, "G:\\DBMS-TST\\DeleteMe"); + +#else + + _LIT(KLargeFileName, "E:\\DBMS-TST\\DeleteMe"); + +#endif + +static void AssembleLargeFileName(const TDesC& aFileName, TInt aFileNumber, TDes& aResultPath) + { + _LIT(KFormatStr, "%S.%03d"); + aResultPath.Format(KFormatStr, &aFileName, aFileNumber); + } + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Create/Destroy test environment - global functions + +//Deletes "aFullName" file. +static TInt DeleteDataFile(const TDesC& aFullName) + { + RFs fsSession; + TInt err = fsSession.Connect(); + if(err == KErrNone) + { + TEntry entry; + err = fsSession.Entry(aFullName, entry); + if(err == KErrNone) + { + RDebug::Print(_L("Deleting \"%S\" file.\n"), &aFullName); + err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly); + if(err != KErrNone) + { + RDebug::Print(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName); + } + err = fsSession.Delete(aFullName); + if(err != KErrNone) + { + RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName); + } + } + fsSession.Close(); + } + else + { + RDebug::Print(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName); + } + return err; + } + +//Deletes large data files only +static void DeleteLargeDataFiles() + { + for(TInt i=0;i<1000;++i) + { + TBuf filePath; + AssembleLargeFileName(KLargeFileName, i, filePath); + if(DeleteDataFile(filePath) != KErrNone) + { + break; + } + } + } + +//Deletes data files used by the test +static void DeleteDataFiles() + { + if(TheDbSession.Handle()) + { + TheDb.Close(); + } + TheDbSession.Close(); + DeleteDataFile(KTestDatabase); + DeleteLargeDataFiles(); + } + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Tests macros and functions. +//If (!aValue) then the test will be panicked, the test data files will be deleted. +static void Check(TInt aValue, TInt aLine) + { + if(!aValue) + { + DeleteDataFiles(); + TheTest(EFalse, aLine); + } + } +//If (aValue != aExpected) then the test will be panicked, the test data files will be deleted. +static void Check(TInt aValue, TInt aExpected, TInt aLine) + { + if(aValue != aExpected) + { + RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue); + DeleteDataFiles(); + TheTest(EFalse, aLine); + } + } +//Use these to test conditions. +#define TEST(arg) Check((arg), __LINE__) +#define TEST2(aValue, aExpected) Check(aValue, aExpected, __LINE__) + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Global functions + +//Prepares the test directory. +//TheFs.Connect() has to be called already. +static void SetupTestDirectory() + { + TInt err = TheFs.MkDir(KTestDatabase); + TEST(err == KErrNone || err == KErrAlreadyExists); + } + +//Leaves with info message printed out +static void LeaveL(TInt aError, TInt aLine) + { + RDebug::Print(_L("*** Leave. Error: %d, Line: %d\r\n"), aError, aLine); + User::Leave(aError); + } + +//Leaves if aError < 0 with info message printed out +static void LeaveIfErrorL(TInt aError, TInt aLine) + { + if(aError < KErrNone) + { + LeaveL(aError, aLine); + } + } + +//Use LEAVE() macro instead of User::Leave() and LEAVE_IF_ERROR() macro instead of +//User::LeaveIfError(). They will print the line number, where the "leave" was called. +#define LEAVE(aError) LeaveL(aError, __LINE__) +#define LEAVE_IF_ERROR(aError) LeaveIfErrorL(aError, __LINE__) + +//Creates one or more large files with the total size near to the size of the available disk space. +//The idea is to cause an "out of disk space" condition. +static void FillLargeDataFileL(RFile& aFile, TInt aSize) + { + TInt err = KErrDiskFull; + while(err == KErrDiskFull) + { + err = aFile.SetSize(aSize); + aSize -= 100; + if(aSize <= 0) + { + break; + } + } + TEST(err == KErrNone || err == KErrDiskFull); + } + +//Gets the available space of the tested drive. +static TInt64 FreeDiskSpaceL() + { + TVolumeInfo volInfoBefore; + LEAVE_IF_ERROR(TheFs.Volume(volInfoBefore, KTestDrive)); + return volInfoBefore.iFree; + } + +//Creates large data file with aSize size (in bytes). +static void DoCreateLargeFileL(const TDesC& aPath, TInt aSize) + { + RFile file; + CleanupClosePushL(file); + LEAVE_IF_ERROR(file.Replace(TheFs, aPath, EFileRead | EFileWrite)); + FillLargeDataFileL(file, aSize); + LEAVE_IF_ERROR(file.Flush()); + CleanupStack::PopAndDestroy(&file); + } + +//Creates enough number of large data files to fill the available disk space. +//It will change FilesCount global variable's value. +static void CreateLargeFileL() + { + TInt fileNo = 0; + const TInt KLargeFileSize = 1000000000; + TInt64 diskSpace = FreeDiskSpaceL(); + RDebug::Print(_L("CreateLargeFileL: free space before = %ld\n"), diskSpace); + TBuf filePath; + const TInt64 KMinDiskSpace = 200; + //Reserve almost all disk space, except a small amount - 200 bytes. + while(diskSpace > KMinDiskSpace) + { + AssembleLargeFileName(KLargeFileName, fileNo++, filePath); + TInt fileSize = KLargeFileSize; + if(diskSpace < (TInt64)KLargeFileSize) + { + TInt64 lastFileSize = diskSpace - KMinDiskSpace; + fileSize = I64LOW(lastFileSize); + } + DoCreateLargeFileL(filePath, fileSize); + diskSpace = FreeDiskSpaceL(); + RDebug::Print(_L("----CreateLargeFileL, step %d, free space = %ld\n"), fileNo, diskSpace); + } + diskSpace = FreeDiskSpaceL(); + RDebug::Print(_L("CreateLargeFileL: free space after = %ld\n"), diskSpace); + } + +//Reserves disk space for TheDbSession instance. +//TheDbSession instance has to be connected already. +static void ReserveDiskSpace() + { + TInt err = TheDbSession.ReserveDriveSpace(KTestDrive, KReservedSpaceSize); + TEST2(err, KErrNone); + } + +//Frees already reserved disk space for TheDbSession instance. +//TheDbSession instance has to be connected already. +static void FreeReservedSpace() + { + TheDbSession.FreeReservedSpace(KTestDrive); + } + +//Gets an access to the reserved disk space for TheDbSession instance. +//TheDbSession instance has to be connected already. +static void UnlockReservedSpace() + { + TInt err = TheDbSession.GetReserveAccess(KTestDrive); + TEST2(err, KErrNone); + } + +//Releases the access to the reserved disk space. +//TheDbSession instance has to be connected already. +static void LockReservedSpace() + { + (void)TheDbSession.ReleaseReserveAccess(KTestDrive); + } + +//Creates the test DBMS session +static void CreateTestDbSession() + { + TInt err = TheDbSession.Connect(); + TEST2(err, KErrNone); + } + + +//Creates the test database +//TheDbSession instance has to be connected already. +//TheFs.Connect() has to be called already. +static void CreateTestDatabase(RDbs& aDbs, RDbNamedDatabase& aDb) + { + //Create the test database. + TInt err = aDb.Replace(TheFs, KTestDatabase); + TEST2(err, KErrNone); + TheDb.Close(); + //Open it now using DBMS session (so, on DBMS server side), because we want to test + //server side RFs sessions - handling "out of disk space" situations. + err = aDb.Open(aDbs, KTestDatabase); + TEST2(err, KErrNone); + } + +//Creates a test table +static void CreateTestTableL(RDbNamedDatabase& aDb) + { + CDbColSet* colSet = CDbColSet::NewLC(); + for(const TColDef* colDef=KColDefs;colDef->iName;++colDef) + { + TDbCol col(TPtrC(colDef->iName), colDef->iType); + col.iAttributes = colDef->iAttributes; + colSet->AddL(col); + } + TEST2(aDb.CreateTable(KTestTableName, *colSet), KErrNone); + CleanupStack::PopAndDestroy(colSet); + } + +//Adds some data to the test table +static void AddTestDataL(RDbNamedDatabase& aDb) + { + RDbTable tbl; + CleanupClosePushL(tbl); + TEST2(tbl.Open(aDb, KTestTableName, RDbRowSet::EUpdatable), KErrNone); + for(TInt i=0;i