persistentstorage/sql/TEST/t_sqlbur.cpp
changeset 0 08ec8eefde2f
child 12 6b6fd149daa2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/TEST/t_sqlbur.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,864 @@
+// Copyright (c) 2006-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 <e32test.h>
+#include <bautils.h>
+#include <sqldb.h>
+#include <e32math.h>
+
+#include "SqlBur.h"
+#include "t_sqlbur.h"
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+RTest TheTest(_L("SQL Backup and Restore Test"));
+
+_LIT(KPrivateDir, "C:\\private\\10281e17\\");
+
+const TUid KClientUid = {0x21212122}; // the data owner's UID
+
+_LIT(KBackupDir, "C:\\TEST\\");
+_LIT(KBackupFile, "C:\\TEST\\Backup.bak");
+_LIT(KBackupFile2Z, "Z:\\TEST\\t_sqlbur_backup_ver0.bak");
+_LIT(KBackupFile2, "C:\\TEST\\t_sqlbur_backup_ver0.bak");
+
+const TUint KBufferSize = 2048; // used for reading backup files for validation
+
+static CActiveScheduler* TheScheduler = NULL;
+static CSqlBurTestHarness* TheTestHarness = NULL;
+
+/////////////////////////////////////
+
+const TInt KMaxDbFileSize = 10 * 1024;//The max test db file size
+const TInt KTestDbFileCnt = 2;
+
+//Test db files
+_LIT(KTestFileName1,"[21212122]AADB2.db");//Created outside this test app
+_LIT(KTestFileName2,"[21212122]BBDB2.db");//Created outside this test app
+_LIT(KTestDbFileName1,"C:[21212122]AADB2.db");
+_LIT(KTestDbFileName2,"C:[21212122]BBDB2.db");
+
+const TPtrC KTestFileNames[KTestDbFileCnt] = {KTestFileName1(), KTestFileName2()};
+
+static TInt TheDbFileSizes[KTestDbFileCnt];//An array where the real db file size will be stored
+static TUint8 TheDbFileData[KTestDbFileCnt][KMaxDbFileSize];//An array where the original db file content will be stored
+static TUint8 TheBuf[KMaxDbFileSize];
+
+/////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+void TestEnvDestroy()
+	{
+	delete TheTestHarness;
+	TheTestHarness = NULL;		
+	
+	delete TheScheduler;
+	TheScheduler = NULL;
+	}
+
+////////////////////////////
+// Test macros and functions
+////////////////////////////
+
+void Check(TInt aValue, TInt aLine)
+	{
+	if(!aValue)
+		{
+		TestEnvDestroy();
+		TheTest(EFalse, aLine);
+		}
+	}
+
+void Check(TInt aValue, TInt aExpected, TInt aLine)
+	{
+	if(aValue != aExpected)
+		{
+		TestEnvDestroy();
+		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__)
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+//CSqlBurTestHarness - test implementation of the MSqlSrvBurInterface, implemented in the production code by the SQL server.
+CSqlBurTestHarness *CSqlBurTestHarness::New()
+	{
+	CSqlBurTestHarness* self = new CSqlBurTestHarness;
+	TEST(self != NULL);
+	self->Construct();
+	return self;
+	}
+
+CSqlBurTestHarness::CSqlBurTestHarness()
+	{
+	}
+
+void CSqlBurTestHarness::Construct()
+	{
+	TInt err = iFs.Connect();
+	TEST2(err, KErrNone);
+	err = iFs.MkDir(KBackupDir);
+	TEST(err == KErrNone || err == KErrAlreadyExists);
+	err = iFs.CreatePrivatePath(EDriveC);
+	TEST2(err, KErrNone);
+	}
+
+CSqlBurTestHarness::~CSqlBurTestHarness()
+	{
+	(void)iFs.Delete(KBackupFile);
+	iFs.Close();
+	}
+
+//Called by the backup client ot get a list of database files to backup
+//The array is owned by the caller
+//The SQL server would have the job to get a list of databases owned by
+//the given SID and to determine whether the backup flag is set
+//All databases that satisfy this requirement will be added to the array
+void CSqlBurTestHarness::GetBackUpListL(TSecureId /*aUid*/, RArray<TParse>& aFileList)
+	{
+	//TheTest.Printf(_L("Getting backup file list for SID=%x\r\n"),aUid);
+	for(TInt i=0;i<KTestDbFileCnt;++i)
+		{
+		TParse parse;
+		parse.Set(KTestFileNames[i], &KPrivateDir, NULL);
+		aFileList.AppendL(parse);
+		}
+	}
+
+//Notification that a backup is starting
+TBool CSqlBurTestHarness::StartBackupL(const RArray<TParse>& /*aFileList*/) 
+	{
+	//TheTest.Printf(_L("Start \"backup\". %d files in the list.\r\n"), aFileList.Count());
+	return ETrue;
+	}
+
+//Notification that a backup has ended
+void CSqlBurTestHarness::EndBackup(const RArray<TParse>& /*aFileList*/)
+	{
+	//TheTest.Printf(_L("End \"backup\". %d files in the list.\r\n"), aFileList.Count());
+	}
+
+//Notification that a restore is starting
+TBool CSqlBurTestHarness::StartRestoreL(TSecureId /*aUid*/) 
+	{
+	//TheTest.Printf(_L("Start \"restore\" for UID=%X\r\n"), aUid);
+	return ETrue;
+	}
+
+//Notification that a restore has ended
+void CSqlBurTestHarness::EndRestore(TSecureId /*aUid*/) 
+	{
+	//TheTest.Printf(_L("End \"restore\" for UID=%X\r\n"), aUid);
+	}
+	
+//Returns the file system resource handle to the caller.
+RFs& CSqlBurTestHarness::Fs()
+	{
+	return iFs;
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
+
+TBool FileExists(RFs& aFs, const TDesC& aFileName)
+	{
+	TEntry entry;
+	return aFs.Entry(aFileName, entry) == KErrNone;
+	}
+
+void TestEnvCreate()
+	{
+	TheScheduler = new CActiveScheduler;
+	TEST(TheScheduler != NULL);
+	
+	CActiveScheduler::Install(TheScheduler);
+
+	TheTestHarness = CSqlBurTestHarness::New();
+	TEST(TheTestHarness != NULL);
+	}
+
+//Reads the content of the db files and stores the content to a global memory buffer.
+//That buffer content will be sued later for  a verification of the restore process.
+void StoreDbContentToBuf(RFs& aFs)
+	{
+	for(TInt i=0;i<KTestDbFileCnt;++i)
+		{
+		RFile dbFile;
+		TInt err = dbFile.Open(aFs, KTestFileNames[i], EFileRead);
+		TEST2(err, KErrNone);
+		
+		TInt fileSize = 0;
+		err = dbFile.Size(fileSize);
+		TEST2(err, KErrNone);
+		TEST(fileSize > 0);
+
+		TPtr8 bufptr(TheDbFileData[i], 0, KMaxDbFileSize);
+		err = dbFile.Read(bufptr, fileSize);
+		TEST2(err, KErrNone);
+		TEST(fileSize == bufptr.Length());
+
+		TheDbFileSizes[i] = fileSize;
+		
+		dbFile.Close();
+		}
+	}
+
+//At the moment when this function is called, the db files content is already restored.
+//The function will open the restored db files and compare their content against the content
+//of the original db files (kept in a global memory buffer).
+void CompareDbContentWithBuf(RFs& aFs)
+	{
+	for(TInt i=0;i<KTestDbFileCnt;++i)
+		{
+		TEST(TheDbFileSizes[i] > 0);
+		
+		RFile dbFile;
+		TInt err = dbFile.Open(aFs, KTestFileNames[i], EFileRead);
+		TEST2(err, KErrNone);
+		
+		TInt fileSize = 0;
+		err = dbFile.Size(fileSize);
+		TEST2(err, KErrNone);
+		TEST(fileSize > 0);
+		TEST(TheDbFileSizes[i] == fileSize);
+
+		TPtr8 bufptr(TheBuf, 0, KMaxDbFileSize);
+		err = dbFile.Read(bufptr, fileSize);
+		TEST2(err, KErrNone);
+		TEST(fileSize == bufptr.Length());
+
+		err = Mem::Compare(TheBuf, fileSize, TheDbFileData[i], TheDbFileSizes[i]);
+		TEST2(err, 0);
+
+		dbFile.Close();
+		}
+	}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+//The backup client will return a series of data chunks representing
+//one of more databases for the uid of the data owner.
+//This data is stored in a file on the C drive for the purposes of the test
+TInt TestBackupL(CSqlBackupClient &aBackupClient, RFs& aFs, TInt aDataChunkSize = KBufferSize)
+	{
+	RFile file;
+	CleanupClosePushL(file);
+	TInt err = file.Replace(aFs, KBackupFile, EFileWrite | EFileStream | EFileShareExclusive);
+	User::LeaveIfError(err);
+	aBackupClient.InitialiseGetProxyBackupDataL(KClientUid, EDriveC);
+	
+	TBuf8<KBufferSize> buf;
+	TPtr8 ptr((TUint8*)buf.Ptr(), aDataChunkSize);
+	TBool finishedFlag = EFalse;
+	TInt count = 0;
+	
+	do
+		{
+		aBackupClient.GetBackupDataSectionL(ptr, finishedFlag);
+		count += ptr.Length();
+		err = file.Write(ptr);
+		User::LeaveIfError(err);
+		ptr.SetLength(0);
+		}
+	while(!finishedFlag);
+
+	CleanupStack::PopAndDestroy(&file);
+	
+	if(count == 0)
+		{
+		User::Leave(KErrEof);
+		}
+	if(!FileExists(aFs, KBackupFile))
+		{
+		User::Leave(KErrNotFound);
+		}
+	TheTest.Printf(_L("Backup complete. %d bytes processed.\r\n"), count);
+	return count;
+	}
+
+//This sends the data in chunks form back to the BUR client
+//for nupacking and restoration of the original databases files
+TInt TestRestoreL(CSqlBackupClient &aRestoreClient, RFs& aFs, TInt aDataChunkSize = KBufferSize)
+	{
+	RFile file;
+	CleanupClosePushL(file);
+	TInt err = file.Open(aFs, KBackupFile, EFileRead | EFileShareExclusive);
+	User::LeaveIfError(err);
+	aRestoreClient.InitialiseRestoreProxyBaseDataL(KClientUid, EDriveC);
+	
+	TBuf8<KBufferSize> buf;
+	TPtr8 ptr((TUint8*)buf.Ptr(), aDataChunkSize);
+	TBool finishedFlag = EFalse;
+	
+	TInt fileSize = 0;
+	err = file.Size(fileSize);
+	User::LeaveIfError(err);
+	TInt count = fileSize;
+	
+	do
+		{
+		err = file.Read(ptr, aDataChunkSize);
+		User::LeaveIfError(err);
+		fileSize -= ptr.Length();
+		finishedFlag = fileSize == 0;
+		aRestoreClient.RestoreBaseDataSectionL(ptr, finishedFlag);
+		ptr.SetLength(0);
+		} 
+	while(fileSize > 0);
+	
+	CleanupStack::PopAndDestroy(&file);
+	
+	aRestoreClient.RestoreComplete(EDriveC);
+	
+	if(!finishedFlag)
+		{
+		User::Leave(KErrEof);
+		}
+	for(TInt i=0;i<KTestDbFileCnt;++i)
+		{
+		if(!FileExists(aFs, KTestFileNames[i]))
+			{
+			User::Leave(KErrNotFound);
+			}
+		}
+		
+	TheTest.Printf(_L("Restore complete. %d bytes processed.\r\n"), count);
+	return count;
+	}
+
+//Verifies the integrity of the backup file.
+void TestArchiveIntegrityL(CSqlBackupClient &aBackupClient, RFs& aFs)
+	{
+	RFile bkpFile;
+	CleanupClosePushL(bkpFile);
+	
+	TInt err = bkpFile.Open(aFs, KBackupFile, EFileRead | EFileShareExclusive);
+	User::LeaveIfError(err);
+	
+	TBuf8<KBufferSize> buf;
+	TPtr8 ptr((TUint8*)buf.Ptr(), buf.MaxLength());
+	
+	TInt bkpFileSize = 0;
+	err = bkpFile.Size(bkpFileSize);
+	User::LeaveIfError(err);
+	
+	while(bkpFileSize > 0)
+		{
+		// get the checksum
+		err = bkpFile.Read(ptr, 16); // 8 UTF-16 characters
+		User::LeaveIfError(err);
+		if(ptr.Length() != 16)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		TPtr ptr16((TUint16*) ptr.Ptr(), 8, 8);
+		TLex lex(ptr16);
+		TUint32 checksum;
+		lex.SkipSpace();
+		err = lex.Val(checksum, EHex);
+		User::LeaveIfError(err);
+		bkpFileSize -= 16;
+
+		// get the old file size
+		err = bkpFile.Read(ptr, 16); // 8 UTF-16 characters
+		User::LeaveIfError(err);
+		if(ptr.Length() != 16)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		ptr16.Set((TUint16*) ptr.Ptr(), 8, 8);
+		lex.Assign(ptr16);
+		TUint32 oldFileSize;
+		lex.SkipSpace();
+		err = lex.Val(oldFileSize, EHex);
+		User::LeaveIfError(err);
+		bkpFileSize -= 16;
+
+		// get the backup file header version
+		err = bkpFile.Read(ptr, 8); // 4 UTF-16 characters
+		User::LeaveIfError(err);
+		ptr16.Set((TUint16*)ptr.Ptr(), 4, 4);
+		lex.Assign(ptr16);
+		TUint32 hdrVer;
+		lex.SkipSpace();
+		err = lex.Val(hdrVer, EHex);
+		User::LeaveIfError(err);
+		bkpFileSize -= 8;
+
+		// get the file size
+		err = bkpFile.Read(ptr, 32); // 16 UTF-16 characters
+		User::LeaveIfError(err);
+		if(ptr.Length() != 32)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		ptr16.Set((TUint16*) ptr.Ptr(), 16, 16);
+		lex.Assign(ptr16);
+		TInt64 fileSize;
+		lex.SkipSpace();
+		err = lex.Val(fileSize, EHex);
+		User::LeaveIfError(err);
+		bkpFileSize -= 32;
+
+		// get the filename size
+		err = bkpFile.Read(ptr, 16); // 8 UTF-16 characters
+		User::LeaveIfError(err);
+		ptr16.Set((TUint16*)ptr.Ptr(), 8, 8);
+		lex.Assign(ptr16);
+		TUint32 fileNameSize;
+		lex.SkipSpace();
+		err = lex.Val(fileNameSize, EHex);
+		User::LeaveIfError(err);
+		bkpFileSize -= 16;
+
+		// get the filename
+		err = bkpFile.Read(ptr, fileNameSize * 2); // fileName UTF-16 characters
+		User::LeaveIfError(err);
+		if(ptr.Length() != (fileNameSize * 2))
+			{
+			User::Leave(KErrCorrupt);
+			}
+		ptr16.Set((TUint16*) ptr.Ptr(), fileNameSize, fileNameSize);
+		lex.Assign(ptr16);
+		TParse tp;
+		tp.Set(ptr16, NULL, NULL);
+		TPtrC dbFileName = tp.Name();
+		bkpFileSize -= fileNameSize * 2;
+	
+		// open a local file - replaces any previous one
+		RFile64 dbFile;
+		CleanupClosePushL(dbFile);
+		err = dbFile.Replace(aFs, dbFileName, EFileWrite | EFileShareExclusive);
+		User::LeaveIfError(err);
+	
+		// copy all the data (file size bytes)
+		TInt bytesLeftToRead = fileSize;
+
+		while(bytesLeftToRead > 0)
+			{
+			TInt readSize = bytesLeftToRead > KBufferSize ? KBufferSize : bytesLeftToRead;
+			err = bkpFile.Read(ptr, readSize);
+			User::LeaveIfError(err);
+			if(ptr.Length() != readSize)
+				{
+				User::Leave(KErrCorrupt);	
+				}
+			bytesLeftToRead -= readSize;
+			err = dbFile.Write(ptr, readSize);
+			User::LeaveIfError(err);
+			}
+
+		bkpFileSize -= fileSize;
+		
+		// checksum the file
+		TUint32 dbChecksum = aBackupClient.CheckSumL(dbFile) & 0xFFFFFFFF;
+		
+		if(checksum != dbChecksum)
+			{
+			User::Leave(KErrCorrupt);
+			}
+			
+		// all done with this file
+		CleanupStack::PopAndDestroy(&dbFile);
+		err = aFs.Delete(dbFileName);
+		User::LeaveIfError(err);
+		}
+	
+	CleanupStack::PopAndDestroy(&bkpFile);
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4002
+@SYMTestCaseDesc		Test for DEF113598 - "SQL, t_sqlbur unit test needs refactoring"
+						The test backups 2 test db files, then verifies the backup file integrity,
+						then restores the test db files content from the backup file.
+						At the end, the test checks that the restored test db files content is the
+						same as the content of the original test db file.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF113598 - "SQL, t_sqlbur unit test needs refactoring"
+@SYMTestExpectedResults Test must not fail
+@SYMDEF					DEF113598
+*/	
+void FunctionalTest()
+	{
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4002 Backup: functional test "));
+	
+	CSqlBackupClient* backupClient = NULL;
+	TRAPD(err, backupClient = CSqlBackupClient::NewL(TheTestHarness));
+	TEST(backupClient != NULL);
+
+	////////////////////////////////////////
+
+	const TDriveNumber KDrive = EDriveC;
+	
+	//Virtual functions - with default implementation
+	
+	(void)backupClient->GetExpectedDataSize(KDrive);
+
+	(void)backupClient->GetDataChecksum(KDrive);
+	
+	TBool finished = EFalse;
+	TPtr8 ptr(0, 0, 0);
+	TRAP(err, backupClient->GetSnapshotDataL(KDrive, ptr, finished));
+	TEST2(err, KErrNotSupported);
+
+	TRAP(err, backupClient->InitialiseGetBackupDataL(KDrive));
+	TEST2(err, KErrNotSupported);
+
+	TRAP(err, backupClient->InitialiseRestoreBaseDataL(KDrive));
+	TEST2(err, KErrNotSupported);
+
+	TRAP(err, backupClient->InitialiseRestoreIncrementDataL(KDrive));
+	TEST2(err, KErrNotSupported);
+
+	TPtrC8 ptr2(KNullDesC8);
+	TRAP(err, backupClient->RestoreIncrementDataSectionL(ptr2, finished));
+	TEST2(err, KErrNotSupported);
+
+	TRAP(err, backupClient->AllSnapshotsSuppliedL());
+	TEST2(err, KErrNone);
+
+	TRAP(err, backupClient->ReceiveSnapshotDataL(KDrive, ptr2, finished));
+	TEST2(err, KErrNotSupported);
+
+	backupClient->TerminateMultiStageOperation();
+
+	////////////////////////////////////////
+
+	TInt bytesStored = 0;
+	TRAP(err, bytesStored = TestBackupL(*backupClient, TheTestHarness->Fs()));
+	TEST2(err, KErrNone);
+
+	TheTest.Next(_L("Archive integrity test"));
+	
+	TRAP(err, TestArchiveIntegrityL(*backupClient, TheTestHarness->Fs()));
+	TEST2(err, KErrNone);
+
+	delete backupClient;
+
+	TheTest.Next(_L("Restore: functional test"));
+
+	CSqlBackupClient* restoreClient = NULL;
+	TRAP(err, restoreClient = CSqlBackupClient::NewL(TheTestHarness));
+	TEST(restoreClient != NULL);
+
+	TInt bytesRestored = 0;
+	TRAP(err, bytesRestored = TestRestoreL(*restoreClient, TheTestHarness->Fs()));
+	TEST2(err, KErrNone);
+	
+	TEST(bytesRestored == bytesStored);
+
+	delete restoreClient;
+
+	CompareDbContentWithBuf(TheTestHarness->Fs());
+	}
+	
+TInt DoBackupL()
+	{
+	CSqlBackupClient* backupClient = CSqlBackupClient::NewLC(TheTestHarness);
+	TInt bytesStored = TestBackupL(*backupClient, TheTestHarness->Fs());
+	CleanupStack::PopAndDestroy(backupClient);
+	return bytesStored;
+	}
+
+TInt DoRestoreL()
+	{
+	CSqlBackupClient* restoreClient = CSqlBackupClient::NewLC(TheTestHarness);
+	TInt bytesRestored = TestRestoreL(*restoreClient, TheTestHarness->Fs());
+	CleanupStack::PopAndDestroy(restoreClient);
+	return bytesRestored;
+	}
+
+/**
+@SYMTestCaseID			SYSLIB-SQL-UT-4003
+@SYMTestCaseDesc		Test for DEF113598 - "SQL, t_sqlbur unit test needs refactoring"
+						Under simulated OOM condition, the test backups 2 test db files, 
+						then restores the test db files content from the backup file.
+						At the end, the test checks that the restored test db files content is the
+						same as the content of the original test db file.
+@SYMTestPriority		High
+@SYMTestActions			Test for DEF113598 - "SQL, t_sqlbur unit test needs refactoring"
+@SYMTestExpectedResults Test must not fail
+@SYMDEF					DEF113598
+*/	
+void OomTest()
+	{
+	///////////////////////////////////////////////////////////////////////////////
+	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4003 Backup: OOM test "));
+	TInt err = KErrNoMemory;
+	TInt bytesStored = 0;
+	TInt count = 0;
+	
+	for(count=1;err==KErrNoMemory;++count)
+		{
+		TInt startProcessHandleCount;
+		TInt startThreadHandleCount;
+		RThread().HandleCount(startProcessHandleCount, startThreadHandleCount);
+		
+		User::__DbgMarkStart(RHeap::EUser);
+		User::__DbgSetAllocFail(RHeap::EUser,RHeap::EFailNext, count);
+		TRAP(err, bytesStored = DoBackupL());
+		User::__DbgMarkEnd(RHeap::EUser, 0);
+		
+		TInt endProcessHandleCount;
+		TInt endThreadHandleCount;
+		RThread().HandleCount(endProcessHandleCount, endThreadHandleCount);
+		
+		TEST(startProcessHandleCount == endProcessHandleCount);
+		TEST(startThreadHandleCount == endThreadHandleCount);
+		}
+	TEST2(err, KErrNone);
+	TheTest.Printf(_L("OOM backup test succeeded at heap failure rate of %d\r\n"), count);
+
+	///////////////////////////////////////////////////////////////////////////////
+	TheTest.Next(_L("Restore: OOM test"));
+	err = KErrNoMemory;
+	TInt bytesRestored = 0;
+	
+	for(count=1;err==KErrNoMemory;++count)
+		{
+		TInt startProcessHandleCount;
+		TInt startThreadHandleCount;
+		RThread().HandleCount(startProcessHandleCount, startThreadHandleCount);
+		
+		User::__DbgMarkStart(RHeap::EUser);
+		User::__DbgSetAllocFail(RHeap::EUser,RHeap::EFailNext, count);
+		TRAP(err, bytesRestored = DoRestoreL());
+		User::__DbgMarkEnd(RHeap::EUser, 0);
+		
+		TInt endProcessHandleCount;
+		TInt endThreadHandleCount;
+		RThread().HandleCount(endProcessHandleCount, endThreadHandleCount);
+		
+		TEST(startProcessHandleCount == endProcessHandleCount);
+		TEST(startThreadHandleCount == endThreadHandleCount);
+		}
+	TEST2(err, KErrNone);
+	User::__DbgSetAllocFail(RHeap::EUser, RAllocator::ENone, 0);
+	TheTest.Printf(_L("OOM restore test succeeded at heap failure rate of %d\r\n"), count);
+	
+	TEST(bytesStored == bytesRestored);
+
+	CompareDbContentWithBuf(TheTestHarness->Fs());
+	}
+
+/**
+@SYMTestCaseID			PDS-SQL-UT-4143
+@SYMTestCaseDesc		SQL Backup&Restore - data chunk size test.
+						The test uses an integer array of 10 elements with randomly generated data chunk sizes.
+						Then the test runs 10 backup iterations using each time different data chunk size.
+						After each backup iteration the test performs a restore operation and checks that the 
+						data has been backup&restored without errors.
+@SYMTestActions			SQL Backup&Restore - data chunk size test.
+@SYMTestExpectedResults Test must not fail
+@SYMTestPriority		Medium
+@SYMREQ					REQ12104
+*/
+void FunctionalTest2()
+	{
+	TheTest.Next(_L(" @SYMTestCaseID:PDS-SQL-UT-4143 Backup&Restore: functional test 2"));
+	
+	TTime now;
+	now.UniversalTime();
+	TInt64 seed = now.Int64();
+
+	const TInt KArraySize = 10;
+	TInt  dataChunks[10] = {2, 6, 0, 0, 0, 0, 0, 0, 0, 0};
+	const TInt KMaxDataChunkSize = 50;
+	
+	for(TInt i=2;i<KArraySize;)
+		{
+		TInt dataChunkSize = Math::Rand(seed) % KMaxDataChunkSize;
+		if((dataChunkSize % 2) == 0 && dataChunkSize != 0)	//The code works only with data chunks with even sizes!!!
+			{
+			dataChunks[i++] = dataChunkSize;
+			}
+		}
+	
+	for(TInt i=0;i<KArraySize;++i)
+		{
+		TheTest.Printf(_L(" === Iteration %d, chunk size %d\r\n"), i + 1, dataChunks[i]);
+		CSqlBackupClient* backupClient = NULL;
+		TRAPD(err, backupClient = CSqlBackupClient::NewL(TheTestHarness));
+		TEST(backupClient != NULL);
+
+		TInt bytesStored = 0;
+		TRAP(err, bytesStored = TestBackupL(*backupClient, TheTestHarness->Fs(), dataChunks[i]));
+		TEST2(err, KErrNone);
+
+		TRAP(err, TestArchiveIntegrityL(*backupClient, TheTestHarness->Fs()));
+		TEST2(err, KErrNone);
+
+		delete backupClient;
+
+		CSqlBackupClient* restoreClient = NULL;
+		TRAP(err, restoreClient = CSqlBackupClient::NewL(TheTestHarness));
+		TEST(restoreClient != NULL);
+
+		TInt bytesRestored = 0;
+		TRAP(err, bytesRestored = TestRestoreL(*restoreClient, TheTestHarness->Fs(), dataChunks[i]));
+		TEST2(err, KErrNone);
+		
+		TEST(bytesRestored == bytesStored);
+
+		delete restoreClient;
+
+		CompareDbContentWithBuf(TheTestHarness->Fs());
+		}
+	}
+
+/**
+@SYMTestCaseID			PDS-SQL-UT-4144
+@SYMTestCaseDesc		SQL Backup&Restore - legacy backup file format header test.
+						The 64-bit file system related changes made in the SQL server required some 
+						changes to be made in the format of the backup file header.
+						The test checks that a backup file created with the previous format of the file header
+						can be restored without errors by the updated Backup&Restore implementation.
+@SYMTestActions			SQL Backup&Restore - legacy backup file format header test.
+@SYMTestExpectedResults Test must not fail
+@SYMTestPriority		Medium
+@SYMREQ					REQ12104
+*/
+void LegacyFileFormatTest()
+	{
+	TheTest.Next(_L(" @SYMTestCaseID:PDS-SQL-UT-4144 Backup&Restore: legacy file format test"));
+
+	//KBackupFile2 is a database backup file with header version 0.
+	(void)TheTestHarness->Fs().Delete(KBackupFile2);
+	TInt rc = BaflUtils::CopyFile(TheTestHarness->Fs(), KBackupFile2Z, KBackupFile2);
+	TEST2(rc, KErrNone);
+	(void)TheTestHarness->Fs().SetAtt(KBackupFile2, 0, KEntryAttReadOnly);
+
+	//Restore the databases from KBackupFile2.
+	CSqlBackupClient* restoreClient = NULL;
+	TRAP(rc, restoreClient = CSqlBackupClient::NewL(TheTestHarness));
+	TEST(restoreClient != NULL);
+
+	RFile file;
+	rc = file.Open(TheTestHarness->Fs(), KBackupFile2, EFileRead | EFileShareExclusive);
+	TEST2(rc, KErrNone);
+	
+	TRAP(rc, restoreClient->InitialiseRestoreProxyBaseDataL(KClientUid, EDriveC));
+	TEST2(rc, KErrNone);
+	
+	TBuf8<KBufferSize> buf;
+	TPtr8 ptr((TUint8*)buf.Ptr(), buf.MaxSize());
+	TBool finishedFlag = EFalse;
+	
+	TInt fileSize = 0;
+	rc = file.Size(fileSize);
+	TEST2(rc, KErrNone);
+	
+	do
+		{
+		rc = file.Read(ptr);
+		TEST2(rc, KErrNone);
+		fileSize -= ptr.Size();
+		finishedFlag = fileSize == 0;
+		TRAP(rc, restoreClient->RestoreBaseDataSectionL(ptr, finishedFlag));
+		ptr.SetLength(0);
+		} 
+	while(fileSize > 0);
+	
+	file.Close();	
+	
+	restoreClient->RestoreComplete(EDriveC);
+	
+	TEST(finishedFlag);
+		
+	delete restoreClient;
+
+	//At this point we have two restored databases: KTestDbFileName1 and KTestDbFileName2.
+	//The content of the restored file cannot be compared directly, because t_sqlattach uses the same test databases
+	//and modifies them. The original database content was stored without executing t_sqlattach.
+	//Hence a simple test is made: open the restored database, check if the database content can be accessed.
+	
+	RSqlDatabase db;
+	rc = db.Open(KTestDbFileName1);
+	TEST2(rc, KErrNone);
+	//The database contains this table: "TABLE C(A1 INTEGER, B2 BLOB)". 
+	rc = db.Exec(_L("INSERT INTO C VALUES(100, 200)"));
+	TEST2(rc, 1);
+	RSqlStatement stmt;
+	rc = stmt.Prepare(db, _L("SELECT * FROM C"));
+	TEST2(rc, KErrNone);
+	while((rc = stmt.Next()) == KSqlAtRow)
+		{
+		}
+	stmt.Close();
+	TEST2(rc, KSqlAtEnd);
+	db.Close();
+
+	rc = db.Open(KTestDbFileName2);
+	TEST2(rc, KErrNone);
+	//The database contains this table: "TABLE A1(F1 INTEGER , F2 INTEGER, B1 BLOB)"
+	rc = db.Exec(_L("INSERT INTO A1 VALUES(100, 200, NULL)"));
+	TEST2(rc, 1);
+	rc = stmt.Prepare(db, _L("SELECT * FROM A1"));
+	TEST2(rc, KErrNone);
+	while((rc = stmt.Next()) == KSqlAtRow)
+		{
+		}
+	stmt.Close();
+	TEST2(rc, KSqlAtEnd);
+	db.Close();
+
+	(void)TheTestHarness->Fs().Delete(KBackupFile2);
+	}
+			
+void DoMain()
+	{
+	TestEnvCreate();
+
+	TheTest.Start(_L("Store db content to memory buffer"));
+	StoreDbContentToBuf(TheTestHarness->Fs());
+		
+	FunctionalTest();
+
+	OomTest();
+
+	FunctionalTest2();
+
+	LegacyFileFormatTest();
+
+	TestEnvDestroy();
+	}
+
+TInt E32Main()
+	{
+	TheTest.Title();
+	
+	CTrapCleanup* tc = CTrapCleanup::New();
+	TEST(tc != NULL);
+	
+	__UHEAP_MARK;
+	
+	DoMain();
+	
+	__UHEAP_MARKEND;
+	
+	TheTest.End();
+	TheTest.Close();
+	
+	delete tc;
+	
+	User::Heap().Check();
+	return KErrNone;
+	}