persistentstorage/sql/TEST/t_sqlcompact2.cpp
changeset 0 08ec8eefde2f
child 12 6b6fd149daa2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/TEST/t_sqlcompact2.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,989 @@
+// 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 "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:
+//
+
+#include <f32file.h>
+#include <e32test.h>
+#include <hal.h>
+#include <stdlib.h>
+#include <sqldb.h>
+#include "sqlite3.h"
+#include "SqliteSymbian.h"
+#include "SqlSrvStatementUtil.h"
+#include "SqlPanic.h"
+#include "SqlCompact.h"
+#include "SqlCompactConn.h"
+#include "SqlCompactEntry.h"
+
+const TInt KOperationCount = 20;
+const TInt KFreePageThresholdKb = 5;
+const TInt KFreePageThreshold = 5;
+
+const TInt KCompactStepInterval = 5;//ms
+
+TSqlCompactSettings TheCompactionSettings;
+
+static RTest 			TheTest(_L ("t_sqlcompact2.exe"));
+static CTrapCleanup*	TheTrapCleanup = NULL;
+static RFs 				TheFs;
+static TBuf<KMaxFileName + 1> TheFileNameZ;
+static TBuf8<KMaxFileName + 1> TheFileNameZ8;
+
+const TInt KBlobMaxSize = 1024 * 32;
+static TBuf8<KBlobMaxSize> TheBlob;
+
+static sqlite3* 		TheDbHandle = NULL;
+
+_LIT8(KFreePageCountPragma, "PRAGMA freelist_count\x0");
+
+TBuf<256>  TheCmd;
+TDriveName TheDriveName;
+TParse     TheParse;
+TFileName  TheDbName;
+
+class CSqlCompactTestActive;
+CSqlCompactTestActive* TheTestActive = NULL;
+
+const TTimeIntervalMicroSeconds32 KInterval(200000);
+
+static TInt TheProcessHandleCount = 0;
+static TInt TheThreadHandleCount = 0;
+static TInt TheAllocatedCellsCount = 0;
+
+#ifdef _DEBUG
+const TInt KBurstRate = 100;
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void DeleteTestFiles()
+	{
+	::CloseDbHandle(TheDbHandle);
+	(void)TheFs.Delete(TheDbName);
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+//Test macros and functions
+void Check(TInt aValue, TInt aLine)
+	{
+	if(!aValue)
+		{
+		DeleteTestFiles();
+		TheTest(EFalse, aLine);
+		}
+	}
+void Check(TInt aValue, TInt aExpected, TInt aLine)
+	{
+	if(aValue != aExpected)
+		{
+		DeleteTestFiles();
+		RDebug::Print(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
+		TheTest(EFalse, aLine);
+		}
+	}
+#define TEST(arg) ::Check((arg), __LINE__)
+#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void TestEnvCreate()
+	{	
+	TInt err = sqlite3SymbianLibInit();
+	__ASSERT_ALWAYS(err == KErrNone, User::Invariant());
+	TheFs = sqlite3SymbianFs();
+	for(TInt i=0;i<('Z'-'A');++i)
+		{
+		TheFs.CreatePrivatePath(i);
+		}
+	err = TheFs.MkDir(TheDbName);
+	TEST(err == KErrNone || err == KErrAlreadyExists);
+	DeleteTestFiles();
+	}
+
+void TestEnvDestroy()
+	{
+	DeleteTestFiles();
+	sqlite3SymbianLibFinalize();
+	CloseSTDLIB();
+	}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void MarkHandles()
+	{
+	RThread().HandleCount(TheProcessHandleCount, TheThreadHandleCount);
+	}
+	
+void MarkAllocatedCells()
+	{
+	TheAllocatedCellsCount = User::CountAllocCells();
+	}
+
+void CheckHandles()
+	{
+	TInt processHandleCount = 0;
+	TInt threadHandleCount = 0;
+
+	RThread().HandleCount(processHandleCount, threadHandleCount);
+
+	TEST(processHandleCount == TheProcessHandleCount);
+	TEST(threadHandleCount == TheThreadHandleCount);
+	}
+	
+void CheckAllocatedCells()
+	{
+	TInt allocatedCellsCount = User::CountAllocCells();
+	TEST(allocatedCellsCount == TheAllocatedCellsCount);
+	}
+		
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+const TDesC& FileNameZ(const TDesC& aFileName)
+	{
+	TheFileNameZ.Copy(aFileName);
+	TheFileNameZ.ZeroTerminate();
+	return TheFileNameZ;
+	}
+
+const TDesC8& FileNameZ8(const TDesC& aFileName)
+	{
+	TheFileNameZ8.Copy(aFileName);
+	TheFileNameZ8.ZeroTerminate();
+	return TheFileNameZ8;
+	}
+
+TInt FreePageCount()
+	{
+	sqlite3_stmt* stmtHandle = NULL;
+	TInt err = ::StmtPrepare8(TheDbHandle, KFreePageCountPragma, stmtHandle);
+	TEST2(err, KErrNone);
+	TEST(stmtHandle != NULL);
+	err = ::StmtNext(stmtHandle);
+	TEST2(err, KSqlAtRow);
+	TInt pageCount = sqlite3_column_int(stmtHandle, 0);
+	TEST(pageCount >= 0);
+	::FinalizeStmtHandle(stmtHandle);
+	return pageCount;
+	}
+
+void PrintInfo(TInt aProcessedPages, const TDesC& aMediaTypeName, TUint32 aStartTicks, TUint32 aEndTicks)
+	{
+	static TInt freq = 0;
+	if(freq == 0)
+		{
+		TEST2(HAL::Get(HAL::EFastCounterFrequency, freq), KErrNone);
+		}
+	TInt64 diffTicks = (TInt64)aEndTicks - (TInt64)aStartTicks;
+	if(diffTicks < 0)
+		{
+		diffTicks = KMaxTUint32 + diffTicks + 1;
+		}
+	const TInt KMicroSecIn1Sec = 1000000;
+	TInt32 us = (diffTicks * KMicroSecIn1Sec) / freq;
+	TheTest.Printf(_L("####Media type: %S. Processed pages: %d. Ticks: %ld. Execution time: %d ms\r\n"), 
+							&aMediaTypeName, aProcessedPages, diffTicks, us / 1000);
+	}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////        CSqlCompactTestActive declaration              /////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+class CSqlCompactTestActive : public CActive
+	{
+private:
+	enum TCommand
+		{
+		ECmdInvalidTest,	
+		ECmdBeginTest1,
+		ECmdEndTest1,
+		ECmdBeginTest2,
+		ECmdEndTest2,
+		ECmdBeginTest3,
+		ECmdEndTest3,
+		ECmdStopTests	
+		};
+	
+public:
+	static void New();
+	virtual ~CSqlCompactTestActive();
+	void OomTest();
+	void FileIoErrTest();
+	void PerformanceTest();
+	
+protected:		
+	virtual void DoCancel();
+	virtual void RunL();
+	virtual TInt RunError(TInt aError);
+	
+private:
+	CSqlCompactTestActive();
+	void Complete(TCommand aNextCommand);
+	void Schedule(TCommand aNextCommand, TTimeIntervalMicroSeconds32 aInterval);
+
+	void CreateTestDatabase();
+	void InsertTestRecords(TInt aOpCount = KOperationCount);
+	void UpdateTestRecords(TInt aOpCount = KOperationCount);
+	void DeleteTestRecords(TInt aOpCount = KOperationCount);
+	void DeleteTestRecords2();
+	void TestEnd();
+	
+	void UpdateTestBegin();
+	void UpdateTestEnd();
+	void DeleteTestBegin();
+	void DeleteTestEnd();
+	void SingleOpCompactTestBegin();
+	void SingleOpCompactTestEnd();
+
+	void DoOomTest1();
+	void DoOomTest2();
+	void DoOomTest3();
+	void DoOomTest4();
+	void DoOomTest5();
+
+private:
+	TInt			iCommand;
+	CSqlCompactor*	iCompactor;
+	RTimer			iTimer;
+
+	};
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////        CSqlCompactTestActive implementation             ///////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void CSqlCompactTestActive::New()
+	{
+	TheTestActive = new CSqlCompactTestActive;
+	TEST(TheTestActive != NULL);
+	}
+
+CSqlCompactTestActive::~CSqlCompactTestActive()
+	{
+	Cancel();
+	iTimer.Close();
+	delete iCompactor;
+	}
+	
+void CSqlCompactTestActive::DoCancel()
+	{
+	iTimer.Cancel();
+	TRequestStatus* stat = &iStatus;
+	User::RequestComplete(stat, KErrNone);
+	}
+	
+void CSqlCompactTestActive::RunL()
+	{
+	switch(iCommand)
+		{
+		case CSqlCompactTestActive::ECmdBeginTest1:
+			TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4053 Update test"));
+			UpdateTestBegin();
+			Schedule(CSqlCompactTestActive::ECmdEndTest1, KInterval);
+			break;
+		case CSqlCompactTestActive::ECmdEndTest1:
+			UpdateTestEnd();
+			Complete(CSqlCompactTestActive::ECmdBeginTest2);
+			break;
+		case CSqlCompactTestActive::ECmdBeginTest2:
+			TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4054 Delete test"));
+			DeleteTestBegin();
+			Schedule(CSqlCompactTestActive::ECmdEndTest2, KInterval);
+			break;
+		case CSqlCompactTestActive::ECmdEndTest2:
+			DeleteTestEnd();
+			Complete(CSqlCompactTestActive::ECmdBeginTest3);
+			break;
+		case CSqlCompactTestActive::ECmdBeginTest3:
+			TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4055 Single operation - compaction test"));
+			SingleOpCompactTestBegin();
+			Schedule(CSqlCompactTestActive::ECmdEndTest3, KInterval);
+			break;
+		case CSqlCompactTestActive::ECmdEndTest3:
+			SingleOpCompactTestEnd();
+			Complete(CSqlCompactTestActive::ECmdStopTests);
+			break;
+		case CSqlCompactTestActive::ECmdStopTests:
+			CActiveScheduler::Stop();
+			break;
+		case CSqlCompactTestActive::ECmdInvalidTest:
+		default:
+			TEST(0);
+			break;
+		}
+	}
+
+TInt CSqlCompactTestActive::RunError(TInt aError)
+	{
+	TEST2(aError, KErrNone);
+	return aError;
+	}
+
+CSqlCompactTestActive::CSqlCompactTestActive() :
+	CActive(CActive::EPriorityStandard),
+	iCommand(CSqlCompactTestActive::ECmdInvalidTest),
+	iCompactor(NULL)
+	{
+	TInt err = sqlite3_enable_shared_cache(1);
+	TEST2(err, SQLITE_OK);
+	TRAP(err, iCompactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KCompactStepInterval));
+	TEST2(err, KErrNone);
+	err = iTimer.CreateLocal();
+	TEST2(err, KErrNone);
+	CActiveScheduler::Add(this);
+	Complete(CSqlCompactTestActive::ECmdBeginTest1);
+	}
+
+void CSqlCompactTestActive::Complete(CSqlCompactTestActive::TCommand aNextCommand)
+	{
+	TEST(!IsActive());
+	iCommand = aNextCommand;
+	TRequestStatus* stat = &iStatus;
+	User::RequestComplete(stat, KErrNone);
+	SetActive();	
+	}
+
+void CSqlCompactTestActive::Schedule(TCommand aNextCommand, TTimeIntervalMicroSeconds32 aInterval)
+	{
+	TEST(!IsActive());
+	iCommand = aNextCommand;
+	iTimer.After(iStatus, aInterval);
+	TEST2(iStatus.Int(), KRequestPending);
+	SetActive();
+	}
+
+void CSqlCompactTestActive::CreateTestDatabase()
+	{
+	TInt err = ::CreateDbHandle8(::FileNameZ8(TheDbName), TheDbHandle);
+	TEST2(err, KErrNone);
+	_LIT8(KCreateTableSql, "CREATE TABLE A(I INTEGRER, B BLOB)\x0");
+	err = ::DbExecStmt8(TheDbHandle, KCreateTableSql);
+	TEST2(err, KErrNone);
+	}
+
+void CSqlCompactTestActive::InsertTestRecords(TInt aOpCount)
+	{
+	TheBlob.SetLength(SQLITE_DEFAULT_PAGE_SIZE);
+	for(TInt i=0;i<aOpCount;++i)
+		{
+		_LIT8(KInsertSql, "INSERT INTO A VALUES(%d, :Prm)\x0");
+		TBuf8<sizeof(KInsertSql) + 10> sqlBuf1;
+		sqlBuf1.Format(KInsertSql, i + 1);
+		sqlite3_stmt* stmtHandle = NULL;
+		TInt err = ::StmtPrepare8(TheDbHandle, sqlBuf1, stmtHandle);
+		TEST2(err, KErrNone);
+		TEST(stmtHandle != NULL);
+		err = sqlite3_bind_blob(stmtHandle, 1, TheBlob.Ptr(), SQLITE_DEFAULT_PAGE_SIZE, SQLITE_STATIC);
+		TEST2(err, SQLITE_OK);
+		err = ::StmtExec(stmtHandle);
+		TEST2(err, KErrNone);
+		::FinalizeStmtHandle(stmtHandle);
+		}
+	}
+
+void CSqlCompactTestActive::UpdateTestRecords(TInt aOpCount)
+	{
+	for(TInt i=0;i<aOpCount;++i)
+		{
+		_LIT8(KUpdateSql, "UPDATE A SET B=x'1122' WHERE I=%d\x0");
+		TBuf8<sizeof(KUpdateSql) + 10> sqlBuf2;
+		sqlBuf2.Format(KUpdateSql, i + 1);
+		TInt err = ::DbExecStmt8(TheDbHandle, sqlBuf2);
+		TEST2(err, KErrNone);
+		}
+	}
+
+void CSqlCompactTestActive::DeleteTestRecords(TInt aOpCount)
+	{
+	for(TInt i=0;i<aOpCount;++i)
+		{
+		_LIT8(KDeleteSql, "DELETE FROM A WHERE I=%d\x0");
+		TBuf8<sizeof(KDeleteSql) + 10> sqlBuf2;
+		sqlBuf2.Format(KDeleteSql, i + 1);
+		TInt err = ::DbExecStmt8(TheDbHandle, sqlBuf2);
+		TEST2(err, KErrNone);
+		}
+	}
+
+void CSqlCompactTestActive::DeleteTestRecords2()
+	{
+	_LIT8(KDeleteSql, "DELETE FROM A\x0");
+	TInt err = ::DbExecStmt8(TheDbHandle, KDeleteSql);
+	TEST2(err, KErrNone);
+	}
+
+void CSqlCompactTestActive::TestEnd()
+	{
+	TInt freePageCount = ::FreePageCount();
+	TEST2(freePageCount, 0);
+	iCompactor->ReleaseEntry(TheDbName);
+	::CloseDbHandle(TheDbHandle);
+	TheDbHandle = NULL;
+	(void)TheFs.Delete(TheDbName);
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4053
+@SYMTestCaseDesc		Background compaction scheduled by a set of UPDATE operations.
+						The test uses the server background compaction classes directly.
+						The test creates a database, inserts records and updates the records.
+						The update operations free enough disk space to kick-off the background compaction.
+						The test active object, that simulates the SQL server, is activated and the
+						background compaction - executed.
+						The test checks at the end that the background compaction really happened - in
+						CSqlCompactTestActive::UpdateTestEnd().
+@SYMTestPriority		Medium
+@SYMTestActions			Background compaction scheduled by a set of UPDATE operations.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10271
+                        REQ10272
+*/
+void CSqlCompactTestActive::UpdateTestBegin()
+	{
+	CreateTestDatabase();
+	TRAPD(err, iCompactor->AddEntryL(TheDbName, TheCompactionSettings));
+	TEST2(err, KErrNone);
+	InsertTestRecords();
+	UpdateTestRecords();
+	TInt freePageCount = ::FreePageCount();
+	TEST(freePageCount > KFreePageThreshold);
+	}
+
+void CSqlCompactTestActive::UpdateTestEnd()
+	{
+	TestEnd();
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4054
+@SYMTestCaseDesc		Background compaction scheduled by a set of DELETE operations.
+						The test uses the server background compaction classes directly.
+						The test creates a database, inserts records and deletes the records.
+						The delete operations free enough disk space to kick-off the background compaction.
+						The test active object, that simulates the SQL server, is activated and the
+						background compaction - executed.
+						The test checks at the end that the background compaction really happened - in
+						CSqlCompactTestActive::DeleteTestEnd().
+@SYMTestPriority		Medium
+@SYMTestActions			Background compaction scheduled by a set of DELETE operations.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10271
+                        REQ10272
+*/
+void CSqlCompactTestActive::DeleteTestBegin()
+	{
+	CreateTestDatabase();
+	TRAPD(err, iCompactor->AddEntryL(TheDbName, TheCompactionSettings));
+	TEST2(err, KErrNone);
+	InsertTestRecords();
+	DeleteTestRecords();
+	TInt freePageCount = ::FreePageCount();
+	TEST(freePageCount >= KFreePageThreshold);
+	}
+	
+void CSqlCompactTestActive::DeleteTestEnd()
+	{
+	TestEnd();
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4055
+@SYMTestCaseDesc		Background compaction, initiated by a single operation.
+						The test uses the server background compaction classes directly.
+						The test creates a database, inserts records and deletes the records using just
+						a single DELETE SQL statement.
+						The test active object, that simulates the SQL server, schedules 
+						CSqlCompactTestActive::SingleOpCompactTestEnd() for execution. The code in
+						SingleOpCompactTestEnd() checks that the background compaction has been activated and closes the
+						database connection. The "database close" operation should start the compaction
+						because the total size of free pages is above the "free pages" threshold (in Kb).
+@SYMTestPriority		Medium
+@SYMTestActions			Background compaction, initiated by a single operation.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10271
+                        REQ10272
+*/
+void CSqlCompactTestActive::SingleOpCompactTestBegin()
+	{
+	CreateTestDatabase();
+	TRAPD(err, iCompactor->AddEntryL(TheDbName, TheCompactionSettings));
+	TEST2(err, KErrNone);
+	InsertTestRecords();
+	DeleteTestRecords2();
+	TInt freePageCount = ::FreePageCount();
+	TEST(freePageCount >= KFreePageThreshold);
+	}
+
+void CSqlCompactTestActive::SingleOpCompactTestEnd()
+	{
+	TestEnd();
+	}
+
+//Background compaction - OOM test.
+//CSqlCompactor::NewL() is the function tested in an OOM simulation loop.
+//The expectation is that if the iteration fails with KErrNoMemory, no memory leak will occur and the compactor object won't be created.
+void CSqlCompactTestActive::DoOomTest1()
+	{
+	TInt err = KErrNoMemory;
+	TInt failingAllocationNo = 0;
+	while(err == KErrNoMemory)
+		{
+		MarkHandles();
+		MarkAllocatedCells();
+				
+		__UHEAP_MARK;
+		
+		__UHEAP_SETBURSTFAIL(RAllocator::EBurstFailNext, ++failingAllocationNo, KBurstRate);
+		
+		CSqlCompactor* compactor = NULL;
+		TRAP(err, compactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KCompactStepInterval));
+		
+		__UHEAP_RESET;
+
+		if(err == KErrNone)	
+			{
+			TEST(compactor != NULL);
+			delete compactor;
+			}
+		else
+			{
+			TEST(!compactor);
+			TEST2(err, KErrNoMemory);	
+			}
+							
+		__UHEAP_MARKEND;
+
+		CheckAllocatedCells();	    	
+		CheckHandles();	    	
+		}
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("=== CSqlCompactor::NewL() OOM test succeeded at heap failure rate of %d ===\r\n"), failingAllocationNo);
+	}
+
+//Background compaction - OOM test.
+//CSqlCompactor::AddEntryL() is the function tested in an OOM simulation loop.
+//The expectation is that no memory leak will occur if OOM iteration fails with KErrNoMemory.
+//The expectation also is that if the iteration fails with KErrNoMemory, no entry will be added to the compactor.
+void CSqlCompactTestActive::DoOomTest2()
+	{
+	CSqlCompactor* compactor = NULL;
+	TRAPD(err, compactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KCompactStepInterval));
+	TEST2(err, KErrNone);
+	TEST(compactor != NULL);
+	
+	err = KErrNoMemory;
+	TInt failingAllocationNo = 0;
+	while(err == KErrNoMemory)
+		{
+		MarkHandles();
+		MarkAllocatedCells();
+				
+		__UHEAP_MARK;
+		
+		__UHEAP_SETBURSTFAIL(RAllocator::EBurstFailNext, ++failingAllocationNo, KBurstRate);
+		
+		TRAP(err, compactor->AddEntryL(TheDbName, TheCompactionSettings));
+		
+		__UHEAP_RESET;
+
+		if(err == KErrNone)	
+			{
+			TEST2(compactor->iEntries.Count(), 1);
+			compactor->ReleaseEntry(TheDbName);
+			compactor->iEntries.Compress();
+			}
+		else
+			{
+			TEST2(compactor->iEntries.Count(), 0);
+			TEST2(err, KErrNoMemory);	
+			}
+							
+		__UHEAP_MARKEND;
+
+		CheckAllocatedCells();	    	
+		CheckHandles();	    	
+		}
+	delete compactor;
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("=== CSqlCompactor::AddEntryL() OOM test succeeded at heap failure rate of %d ===\r\n"), failingAllocationNo);
+	}
+
+//Background compaction - OOM test.
+//CSqlCompactor::NewL() and CSqlCompactor::AddEntryL() are the functions tested in an OOM simulation loop.
+//At the end of the iteration CSqlCompactor::ReleaseEntry() is not called. 
+//The CSqlCompactor's destructor should properly release the entry if the compactor and the entry have been created successfully.
+//The expectation is that no memory leak will occur if OOM iteration fails with KErrNoMemory.
+void CSqlCompactTestActive::DoOomTest3()
+	{
+	TInt err = KErrNoMemory;
+	TInt failingAllocationNo = 0;
+	while(err == KErrNoMemory)
+		{
+		MarkHandles();
+		MarkAllocatedCells();
+				
+		__UHEAP_MARK;
+		
+		__UHEAP_SETBURSTFAIL(RAllocator::EBurstFailNext, ++failingAllocationNo, KBurstRate);
+		
+		CSqlCompactor* compactor = NULL;
+		TRAP(err, compactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KCompactStepInterval));
+		if(err == KErrNone)
+			{
+			TRAP(err, (void)compactor->AddEntryL(TheDbName, TheCompactionSettings));
+			}
+		
+		__UHEAP_RESET;
+
+		if(err == KErrNone)	
+			{
+			TEST(compactor != NULL);
+			}
+		else
+			{
+			TEST2(err, KErrNoMemory);	
+			}
+		delete compactor;
+							
+		__UHEAP_MARKEND;
+
+		CheckAllocatedCells();	    	
+		CheckHandles();	    	
+		}
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("=== CSqlCompactor::NewL()+CSqlCompactor::AddEntryL() OOM test succeeded at heap failure rate of %d ===\r\n"), failingAllocationNo);
+	}
+
+//Background compaction - OOM test.
+//The test database is created inside the OOM loop, at the beginning of each OOM iteration. The database has enough free space.
+//Then the Compact() method is called. The expectation is that if the iteration fails with KErrNoMemory error, no memory leak will occur.
+void CSqlCompactTestActive::DoOomTest4()
+	{
+	TInt err = KErrNoMemory;
+	TInt failingAllocationNo = 0;
+	while(err == KErrNoMemory)
+		{
+		MarkHandles();
+		MarkAllocatedCells();
+						
+		__UHEAP_MARK;
+		
+		(void)TheFs.Delete(TheDbName);
+		CreateTestDatabase();
+		CSqlCompactor* compactor = NULL;
+		TRAP(err, compactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KCompactStepInterval));
+		TEST2(err, KErrNone);
+		TRAP(err, compactor->AddEntryL(TheDbName, TheCompactionSettings));
+		TEST2(err, KErrNone);
+		InsertTestRecords();
+		DeleteTestRecords();
+		TInt freePageCount = ::FreePageCount();
+		TEST(freePageCount >= KFreePageThreshold);
+		
+		__UHEAP_SETBURSTFAIL(RAllocator::EBurstFailNext, ++failingAllocationNo, KBurstRate);
+
+		CSqlCompactEntry* impl = compactor->iEntries[0];
+		err = impl->Compact();
+		
+		__UHEAP_RESET;
+
+		if(err != KErrNone)	
+			{
+			TEST2(err, KErrNoMemory);	
+			}
+		else
+			{
+			TInt freePageCount2 = ::FreePageCount();
+			TEST(freePageCount2 < freePageCount);
+			}
+		delete compactor;
+		::CloseDbHandle(TheDbHandle);
+		TheDbHandle = NULL;
+							
+		__UHEAP_MARKEND;
+
+		CheckAllocatedCells();	    	
+		CheckHandles();	    	
+		}
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("=== CSqlCompactEntry::Compact() OOM test succeeded at heap failure rate of %d ===\r\n"), failingAllocationNo);
+	(void)TheFs.Delete(TheDbName);
+	}
+
+//Background compaction - OOM test.
+//The test database is created outside the OOM loop. The database has enough free space.
+//Then the Compact() method is called under OOM simulation. 
+//The expectation is that if the iteration fails with KErrNoMemory error, no memory leak will occur and the number of 
+//the free pages is the same as it was at the beginning of the OOM iteration.
+void CSqlCompactTestActive::DoOomTest5()
+	{
+	__UHEAP_MARK;
+	
+	CreateTestDatabase();
+	CSqlCompactor* compactor = NULL;
+	TRAPD(err, compactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KCompactStepInterval));
+	TEST2(err, KErrNone);
+	TRAP(err, compactor->AddEntryL(TheDbName, TheCompactionSettings));
+	TEST2(err, KErrNone);
+	InsertTestRecords();
+	DeleteTestRecords();
+	TInt freePageCount = ::FreePageCount();
+	TEST(freePageCount >= KFreePageThreshold);
+	err = KErrNoMemory;
+	TInt failingAllocationNo = 0;
+	while(err == KErrNoMemory)
+		{
+		TInt freePageCount2 = ::FreePageCount();
+		
+		__UHEAP_SETBURSTFAIL(RAllocator::EBurstFailNext, ++failingAllocationNo, KBurstRate);
+
+		CSqlCompactEntry* impl = compactor->iEntries[0];
+		impl->iPageCount = freePageCount2;
+		err = impl->Compact();
+		
+		__UHEAP_RESET;
+
+		if(err != KErrNone)	
+			{
+			TEST2(err, KErrNoMemory);	
+			TInt freePageCount3 = ::FreePageCount();
+			TEST2(freePageCount2, freePageCount3);
+			}
+	}
+	TEST2(err, KErrNone);
+	TInt freePageCount4 = ::FreePageCount();
+	TEST(freePageCount4 < freePageCount);
+
+	compactor->ReleaseEntry(TheDbName);
+	delete compactor;
+	::CloseDbHandle(TheDbHandle);
+	TheDbHandle = NULL;
+	
+	__UHEAP_MARKEND;
+	
+	TheTest.Printf(_L("=== CSqlCompactEntry::Compact()-2 OOM test succeeded at heap failure rate of %d ===\r\n"), failingAllocationNo);
+	(void)TheFs.Delete(TheDbName);
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4050
+@SYMTestCaseDesc		Background compaction - OOM tests.
+						The test uses directly the SQL server background compaction classes and does OOM tests for:
+						creating the database compaction object (CSqlCompactor), adding a new background database connection, 
+						calling directly the background compaction method.
+@SYMTestPriority		Medium
+@SYMTestActions			Background compaction - OOM tests.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10271
+*/
+void CSqlCompactTestActive::OomTest()
+	{
+	CreateTestDatabase();
+	::CloseDbHandle(TheDbHandle);
+	TheDbHandle = NULL;
+	
+	DoOomTest1();
+	DoOomTest2();
+	DoOomTest3();
+
+	(void)TheFs.Delete(TheDbName);
+	
+	DoOomTest4();
+	DoOomTest5();
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4051
+@SYMTestCaseDesc		Background compaction - file I/O error simulation test.
+						The test calls the background compaction method, CSqlCompactEntry::Compact(),
+						in a file I/O error simulation loop.
+@SYMTestPriority		Medium
+@SYMTestActions			Background compaction - file I/O error simulation test.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10271
+*/
+void CSqlCompactTestActive::FileIoErrTest()
+	{
+	CreateTestDatabase();
+	CSqlCompactor* compactor = NULL;
+	TRAPD(err, compactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KCompactStepInterval));
+	TEST2(err, KErrNone);
+	TRAP(err, compactor->AddEntryL(TheDbName, TheCompactionSettings));
+	TEST2(err, KErrNone);
+	InsertTestRecords();
+	DeleteTestRecords();
+	TInt freePageCount = ::FreePageCount();
+	TEST(freePageCount >= KFreePageThreshold);
+	err = KErrGeneral;
+	TInt ioCounter = 0;
+	while(err != KErrNone)
+		{
+		TInt freePageCount2 = ::FreePageCount();
+		if(freePageCount2 == 0)
+			{
+			err = KErrNone;
+			break;	
+			}
+		
+		(void)TheFs.SetErrorCondition(err, ++ioCounter);
+
+		CSqlCompactEntry* impl = compactor->iEntries[0];
+		impl->iPageCount = freePageCount2;
+		err = impl->Compact();
+		
+		(void)TheFs.SetErrorCondition(KErrNone);
+
+		//check the database free pages count - all bets are off in a case of an I/O error. 
+		//The free page count may actually have been reduced.
+		TInt freePageCount3 = ::FreePageCount();
+		TEST(freePageCount3  <= freePageCount2);
+		}
+	TEST2(err, KErrNone);
+	TInt freePageCount4 = ::FreePageCount();
+
+	compactor->ReleaseEntry(TheDbName);
+	delete compactor;
+	::CloseDbHandle(TheDbHandle);
+	TheDbHandle = NULL;
+	
+	TheTest.Printf(_L("=== CSqlCompactEntry::Compact() \"file I/O\" error simulation test succeeded at iteration %d, free pages %d ===\r\n"), ioCounter, freePageCount4);
+	(void)TheFs.Delete(TheDbName);
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4052
+@SYMTestCaseDesc		Compaction - performance test.
+						The test creates a test database (the default drive is C:, but different drive 
+						can be specified as a test argument) and runs a compaction performance test. 
+						The performance result is printed out.
+@SYMTestPriority		Medium
+@SYMTestActions			Compaction - performance test.
+@SYMTestExpectedResults Test must not fail
+@SYMREQ					REQ10271
+                        REQ10272
+*/
+void CSqlCompactTestActive::PerformanceTest()
+	{
+	TInt err = TheParse.Set(TheDbName, NULL, NULL);
+	TEST2(err, KErrNone);
+	TPtrC driveName = TheParse.Drive();
+	TEST(driveName.Length() > 0);
+	TInt driveNumber = -1;
+	err = RFs::CharToDrive(driveName[0], driveNumber);
+	TEST2(err, KErrNone);
+	TDriveNumber driveNo = static_cast <TDriveNumber> (driveNumber);
+	TDriveInfo driveInfo;
+	err = TheFs.Drive(driveInfo, driveNo);
+	TEST2(err, KErrNone);
+	
+	_LIT(KType1, "Not present");
+	_LIT(KType2, "Unknown");
+	_LIT(KType3, "Floppy");
+	_LIT(KType4, "Hard disk");
+	_LIT(KType5, "CD ROM");
+	_LIT(KType6, "RAM disk");
+	_LIT(KType7, "Flash");
+	_LIT(KType8, "ROM drive");
+	_LIT(KType9, "Remote drive");
+	_LIT(KType10,"NAND flash");
+	_LIT(KType11,"Rotating media");
+	TPtrC KMediaTypeNames[] = {KType1(), KType2(), KType3(), KType4(), KType5(), KType6(), KType7(), KType8(), KType9(), KType10(), KType11()};
+	TheTest.Printf(_L("Drive: %C: %S. File: \"%S\"\r\n"), 'A' + driveNo, &KMediaTypeNames[driveInfo.iType], &TheDbName);
+
+	(void)TheFs.Delete(TheDbName);
+	CreateTestDatabase();
+	const TInt KRecCount = 90;
+	InsertTestRecords(KRecCount);
+	DeleteTestRecords2();
+	TInt freePageCount = ::FreePageCount();
+	TInt processedPages = 0;
+	TheTest.Printf(_L("   Free pages count = %d\r\n"), freePageCount);
+	TUint32 start = User::FastCounter();
+	err = ::DbCompact(TheDbHandle, KNullDesC, freePageCount, processedPages);
+	TUint32 end = User::FastCounter();
+	TEST2(err, KErrNone);
+	TEST2(processedPages, freePageCount);
+	::CloseDbHandle(TheDbHandle);
+	TheDbHandle = NULL;
+	(void)TheFs.Delete(TheDbName);
+	PrintInfo(processedPages, KMediaTypeNames[driveInfo.iType], start, end);
+	}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void DoTests()
+	{
+	CActiveScheduler* scheduler = new CActiveScheduler;
+	TEST(scheduler != NULL);
+	CActiveScheduler::Install(scheduler);
+	
+	CSqlCompactTestActive::New();
+	
+	TheCompactionSettings.iFreePageThresholdKb = KFreePageThresholdKb;
+
+	TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4050 \"Out of memory\" test"));
+	TheTestActive->OomTest();
+	
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4051 \"File I/O\" error simulation test"));
+	TheTestActive->FileIoErrTest();
+
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4052 Compaction - performance test"));
+	TheTestActive->PerformanceTest();
+
+	CActiveScheduler::Start();
+	
+	delete TheTestActive;
+	TheTestActive = NULL;
+	delete scheduler;
+	}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+//Usage: "t_sqlcompact2 [<drive letter>:]"
+
+TInt E32Main()
+	{
+	TheTest.Title();
+	
+	TheTrapCleanup = CTrapCleanup::New ();
+	__ASSERT_ALWAYS(TheTrapCleanup != NULL, User::Invariant());
+
+	__UHEAP_MARK;
+
+	User::CommandLine(TheCmd);
+	TheCmd.TrimAll();
+	if(TheCmd.Length() > 0)
+		{
+		TheDriveName.Copy(TheCmd);
+		}
+
+	_LIT(KDbName, "c:\\test\\t_sqlcompact2_1.db");
+	TheParse.Set(TheDriveName, &KDbName, 0);
+	const TDesC& dbFilePath = TheParse.FullName();
+	TheDbName.Copy(dbFilePath);
+	
+	TestEnvCreate();
+	
+	DoTests();
+
+	TestEnvDestroy();
+	
+	__UHEAP_MARKEND;
+
+	TheTest.End();
+	TheTest.Close();
+
+	delete TheTrapCleanup;
+
+	return KErrNone;
+	}