diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/TEST/t_sqlcompact4.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/sql/TEST/t_sqlcompact4.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,1093 @@ +// 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 +#include +#include +#include +#include "sqlite3.h" +#include "SqliteSymbian.h" +#include "SqlResourceTester.h" + +/////////////////////////////////////////////////////////////////////////////////////// + +RTest TheTest(_L("t_sqlcompact4 test")); +TParse TheParse; +TDriveName TheDrive; + +RSqlDatabase TheDb; +sqlite3* TheSqliteDb = NULL; +TBuf<256> TheCmd; + +const TInt KTextLen = 1000; +const TInt KRecLen = 2000; + +TBuf TheText; +TBuf8 TheSqlQuery; +TBuf8 TheSqlFmt; +TBuf TheSqlTexLen; + +_LIT(KDefaultDriveName, "c:"); +_LIT(KTestDir, "c:\\test\\"); +_LIT(KTestDbTemplate8, "c:\\test\\t_sqlcompact4_tmpl8.dat"); +_LIT(KTestDbTemplate16, "c:\\test\\t_sqlcompact4_tmpl16.dat"); +_LIT(KDbName, "c:\\test\\t_sqlcompact4_1.db"); +_LIT(KDbName2, "c:\\test\\t_sqlcompact4_2.db"); +_LIT(KRoDbName, "z:\\test\\testdb1.db");//Created outside the test app +TFileName TheTestDbName; + +const TInt KMaxThreadCount = 100; +TInt32 TheTestThreadCount = 8; + +const TInt KTestDbPageSize = 1024; + +TInt TheOriginalDbSize8 = -1; +TInt TheCompactedDbSize8 = -1; + +TInt TheOriginalDbSize16 = -1; +TInt TheCompactedDbSize16 = -1; + +//In order to be able to compile the test, the following variables are defined (used inside the OS porting layer, when _SQLPROFILER macro is defined) +#ifdef _SQLPROFILER +TInt TheSqlSrvProfilerFileRead = 0; +TInt TheSqlSrvProfilerFileWrite = 0; +TInt TheSqlSrvProfilerFileSync = 0; +TInt TheSqlSrvProfilerFileSetSize = 0; +#endif + +/////////////////////////////////////////////////////////////////////////////////////// + +void DestroyTestEnv() + { + if(TheSqliteDb) + { + sqlite3_close(TheSqliteDb); + TheSqliteDb = NULL; + } + TheDb.Close(); + (void)RSqlDatabase::Delete(KDbName2); + (void)RSqlDatabase::Delete(TheTestDbName); + (void)RSqlDatabase::Delete(KTestDbTemplate16); + (void)RSqlDatabase::Delete(KTestDbTemplate8); + sqlite3SymbianLibFinalize(); + CloseSTDLIB(); + } + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Test macros and functions +void Check(TInt aValue, TInt aLine) + { + if(!aValue) + { + DestroyTestEnv(); + RDebug::Print(_L("*** Test failure. Boolean expression evaluates to false.\r\n")); + TheTest(EFalse, aLine); + } + } +void Check(TInt aValue, TInt aExpected, TInt aLine) + { + if(aValue != aExpected) + { + DestroyTestEnv(); + 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 CreateTestEnv() + { + RFs fs; + TInt err = fs.Connect(); + TEST2(err, KErrNone); + + err = fs.MkDir(KTestDir); + TEST(err == KErrNone || err == KErrAlreadyExists); + + TheParse.Set(TheDrive, &KTestDir, 0); + + err = fs.MkDir(TheParse.DriveAndPath()); + TEST(err == KErrNone || err == KErrAlreadyExists); + + fs.Close(); + + sqlite3SymbianLibInit(); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +void CreateTestDatabase8() + { + TheTest.Printf(_L("Create UTF8 test database: %S\r\n"), &KTestDbTemplate8); + (void)RSqlDatabase::Delete(KTestDbTemplate8); + TBuf8 fname; + fname.Copy(KTestDbTemplate8); + TheSqliteDb = NULL; + TInt rc = sqlite3_open((const char*)fname.PtrZ(), &TheSqliteDb); + TEST2(rc, SQLITE_OK); + TBuf8<100> sql; + _LIT8(KSql, "PRAGMA page_size=%d\x0"); + sql.Format(KSql, KTestDbPageSize); + rc = sqlite3_exec(TheSqliteDb, (const char*)sql.Ptr(), 0, 0, 0); + TEST2(rc, SQLITE_OK); + rc = sqlite3_exec(TheSqliteDb, "CREATE TABLE A(Id INTEGER,Data BLOB)", 0, 0, 0); + TEST2(rc, SQLITE_OK); + //Insert records + rc = sqlite3_exec(TheSqliteDb, "BEGIN", 0, 0, 0); + TEST2(rc, SQLITE_OK); + TheSqlQuery.Copy(_L8("INSERT INTO A VALUES(%d,x'")); + for(TInt j=0;j<(KRecLen-50);++j) + { + TheSqlQuery.Append(_L8("A")); + } + TheSqlQuery.Append(_L8("')")); + const TInt KRecCount = 100; + for(TInt i=0;i 10", 0, 0, 0); + TEST2(rc, SQLITE_OK); + sqlite3_close(TheSqliteDb); + TheSqliteDb = NULL; + } + +void CreateTestDatabase16() + { + TheTest.Printf(_L("Create UTF16 test database: %S\r\n"), &KTestDbTemplate16); + (void)RSqlDatabase::Delete(KTestDbTemplate16); + TBuf fname; + fname.Copy(KTestDbTemplate16); + TheSqliteDb = NULL; + TInt rc = sqlite3_open16(fname.PtrZ(), &TheSqliteDb); + TEST2(rc, SQLITE_OK); + TBuf8<100> sql; + _LIT8(KSql, "PRAGMA page_size=%d\x0"); + sql.Format(KSql, KTestDbPageSize); + rc = sqlite3_exec(TheSqliteDb, (const char*)sql.Ptr(), 0, 0, 0); + TEST2(rc, SQLITE_OK); + rc = sqlite3_exec(TheSqliteDb, "CREATE TABLE A(Id INTEGER,Data BLOB)", 0, 0, 0); + TEST2(rc, SQLITE_OK); + //Insert records + rc = sqlite3_exec(TheSqliteDb, "BEGIN", 0, 0, 0); + TEST2(rc, SQLITE_OK); + TheSqlQuery.Copy(_L8("INSERT INTO A VALUES(%d,x'")); + for(TInt j=0;j<(KRecLen-50);++j) + { + TheSqlQuery.Append(_L8("A")); + } + TheSqlQuery.Append(_L8("')")); + const TInt KRecCount = 100; + for(TInt i=0;i 10", 0, 0, 0); + TEST2(rc, SQLITE_OK); + sqlite3_close(TheSqliteDb); + TheSqliteDb = NULL; + } + +void CreateDatabase8(const TDesC& aTargetDbName) + { + RFs fs; + TInt err = fs.Connect(); + TEST2(err, KErrNone); + CFileMan* fm = NULL; + TRAP(err, fm = CFileMan::NewL(fs)); + TEST2(err, KErrNone); + err = fm->Copy(KTestDbTemplate8, aTargetDbName); + delete fm; + fs.Close(); + TEST2(err, KErrNone); + } + +void CreateDatabase16(const TDesC& aTargetDbName) + { + RFs fs; + TInt err = fs.Connect(); + TEST2(err, KErrNone); + CFileMan* fm = NULL; + TRAP(err, fm = CFileMan::NewL(fs)); + TEST2(err, KErrNone); + err = fm->Copy(KTestDbTemplate16, aTargetDbName); + delete fm; + fs.Close(); + TEST2(err, KErrNone); + } + +void CalculateMaxCompaction8() + { + TheTest.Printf(_L("UTF8 test database - calculate max compaction\r\n")); + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase8(TheTestDbName); + TInt err = TheDb.Open(TheTestDbName); + TEST2(err, KErrNone); + RSqlDatabase::TSize size1; + err = TheDb.Size(size1); + TEST2(err, KErrNone); + TheTest.Printf(_L("UTF8.Database before compaction: size %ld, free space %ld\r\n"), size1.iSize, size1.iFree); + err = TheDb.Compact(RSqlDatabase::EMaxCompaction); + TEST2(err, size1.iFree); + RSqlDatabase::TSize size2; + err = TheDb.Size(size2); + TEST2(err, KErrNone); + TheTest.Printf(_L("UTF8.Database after compaction: size %ld, free space %ld\r\n"), size2.iSize, size2.iFree); + TheDb.Close(); + (void)RSqlDatabase::Delete(TheTestDbName); + TheOriginalDbSize8 = size1.iSize; + TheCompactedDbSize8 = size2.iSize; + TEST(TheOriginalDbSize8 > 0); + TEST(TheCompactedDbSize8 > 0 && TheCompactedDbSize8 < TheOriginalDbSize8); + } + +void CalculateMaxCompaction16() + { + TheTest.Printf(_L("UTF16 test database - calculate max compaction\r\n")); + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase16(TheTestDbName); + TInt err = TheDb.Open(TheTestDbName); + TEST2(err, KErrNone); + RSqlDatabase::TSize size1; + err = TheDb.Size(size1); + TEST2(err, KErrNone); + TheTest.Printf(_L("UTF16.Database before compaction: size %ld, free space %ld\r\n"), size1.iSize, size1.iFree); + err = TheDb.Compact(RSqlDatabase::EMaxCompaction); + TEST2(err, size1.iFree); + RSqlDatabase::TSize size2; + err = TheDb.Size(size2); + TEST2(err, KErrNone); + TheTest.Printf(_L("UTF16.Database after compaction: size %ld, free space %ld\r\n"), size2.iSize, size2.iFree); + TheDb.Close(); + (void)RSqlDatabase::Delete(TheTestDbName); + TheOriginalDbSize16 = size1.iSize; + TheCompactedDbSize16 = size2.iSize; + TEST(TheOriginalDbSize16 > 0); + TEST(TheCompactedDbSize16 > 0 && TheCompactedDbSize16 < TheOriginalDbSize16); + } + +/////////////////////////////////////////////////////////////////////////////////////// + + +enum TCompactionType {ESyncCompaction, EAsyncCompaction, EMaxCompactionType}; + +TInt DoCompact(TCompactionType aType, TInt aSize, const TDesC& aAttachDbName = KNullDesC) + { + TInt err = KErrGeneral; + switch(aType) + { + case ESyncCompaction: + err = TheDb.Compact(aSize, aAttachDbName); + break; + case EAsyncCompaction: + { + TRequestStatus stat; + TheDb.Compact(aSize, stat, aAttachDbName); + User::WaitForRequest(stat); + TEST(stat != KRequestPending); + err = stat.Int(); + break; + } + default: + TEST(0); + break; + } + return err; + } + +TInt DoManualCompaction(TCompactionType aType, const TDesC& aMainDb, TInt aSize, TBool aRoFlag = EFalse) + { + if(!aRoFlag) + { + (void)RSqlDatabase::Delete(aMainDb); + CreateDatabase8(aMainDb); + } + + TInt err = TheDb.Open(aMainDb); + TEST2(err, KErrNone); + + err = DoCompact(aType, aSize); + + TheDb.Close(); + if(!aRoFlag) + { + (void)RSqlDatabase::Delete(aMainDb); + } + return err; + } + +TInt DoManualCompaction(TCompactionType aType, TInt aSize, const TDesC& aAttachDbName) + { + return DoCompact(aType, aSize, aAttachDbName); + } + +void DoManualCompaction(TCompactionType aType, TInt aSize, TInt aCompactedSize) + { + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase8(TheTestDbName); + + TInt err = TheDb.Open(TheTestDbName); + TEST2(err, KErrNone); + + err = DoCompact(aType, aSize); + TEST(err >= 0); + + RSqlDatabase::TSize size; + err = TheDb.Size(size); + TEST2(err, KErrNone); + TEST2(size.iSize, aCompactedSize); + + TheDb.Close(); + (void)RSqlDatabase::Delete(TheTestDbName); + } + +void DoManualCompaction(TCompactionType aType, TInt aSize, TInt aCompactedSize, const TDesC& aAttachDbName) + { + TInt err = DoCompact(aType, aSize, aAttachDbName); + TEST(err >= 0); + + RSqlDatabase::TSize size; + err = TheDb.Size(size, aAttachDbName); + TEST2(err, KErrNone); + TEST2(size.iSize, aCompactedSize); + } + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4064 +@SYMTestCaseDesc Manual compaction - negative tests. + The test creates a database with a manual compaction mode. + Then the test executes the following negative tests using both synchronous and + asynchronous Compact() methods: + - RSqlDatabase::Compact() called with aSize parameter value = KMinTInt; + - RSqlDatabase::Compact() called with negative aSize parameter value; + - RSqlDatabase::Compact() called on a read-only database; + - RSqlDatabase::Compact() called on an attached read-only database; + - RSqlDatabase::Compact() called on a nonexisting attached database with very long name; + - RSqlDatabase::Compact() called with aSize = 0; + - RSqlDatabase::Compact() called on a read-only database where the version number of symbian_settings table is 3; +@SYMTestPriority Medium +@SYMTestActions Manual compaction - negative tests. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10273 + REQ10274 + REQ10402 +*/ +void ManualCompactionNegativeTest() + { + for(TInt i=0;i 0); + //Specifying KMinTInt as aSize argument value. + err = DoManualCompaction((TCompactionType)i, TheTestDbName, KMinTInt); + TEST2(err, KErrArgument); + //Specifying another negative value as aSize argument value. + err = DoManualCompaction((TCompactionType)i, TheTestDbName, -357); + TEST2(err, KErrArgument); + //Specifying zero as aSize argument value. + err = DoManualCompaction((TCompactionType)i, TheTestDbName, 0); + TEST2(err, 0); + //Read-only database - old format (version 3 of symbian_settings table) + err = DoManualCompaction((TCompactionType)i, KRoDbName, RSqlDatabase::EMaxCompaction, ETrue); + TEST2(err, KSqlErrReadOnly); + // + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase16(TheTestDbName); + err = TheDb.Open(TheTestDbName); + TEST2(err, KErrNone); + _LIT(KAttachDbName, "Db"); + //Attached read-only database + err = TheDb.Attach(KRoDbName, KAttachDbName); + TEST2(err, KErrNone); + err = DoManualCompaction((TCompactionType)i, RSqlDatabase::EMaxCompaction, KAttachDbName); + TEST2(err, KSqlErrReadOnly); + err = TheDb.Detach(KAttachDbName); + TEST2(err, KErrNone); + //Nonexisting attached database + err = DoManualCompaction((TCompactionType)i, RSqlDatabase::EMaxCompaction, _L("aaa")); + TEST2(err, KSqlErrGeneral); + //Very long name of a nonexisting attached database + TBuf fname; + fname.SetLength(fname.MaxLength()); + fname.Fill(0xDD); + err = DoManualCompaction((TCompactionType)i, RSqlDatabase::EMaxCompaction, fname); + TEST2(err, KErrBadName); + // + TheDb.Close(); + (void)RSqlDatabase::Delete(TheTestDbName); + } + } + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4065 +@SYMTestCaseDesc Manual compaction - functional tests. + The test creates a database with a manual compaction mode. + Then the test executes the following functional tests using both synchronous and + asynchronous Compact() methods: + - RSqlDatabase::Compact() called with aSize parameter value = RSqlDatabase::EMaxCompaction; + - RSqlDatabase::Compact() called with aSize parameter value = 0. No pages should be removed; + - RSqlDatabase::Compact() called with aSize parameter value = 1. 1 page should be removed; + - RSqlDatabase::Compact() called with aSize parameter value = "db page size - 1". 1 page should be removed; + - RSqlDatabase::Compact() called with aSize parameter value = "db page size * ". pages should be removed; + - RSqlDatabase::Compact() called with aSize parameter value > the free db space. All free pages should be removed; + The same functional tests are repeated with an attached database. +@SYMTestPriority Medium +@SYMTestActions Manual compaction - functional tests. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10273 + REQ10274 + REQ10402 +*/ +void ManualCompactionTest() + { + for(TInt i=0;i TheOriginalDbSize8. All free pages expected to be removed + DoManualCompaction((TCompactionType)i, TheOriginalDbSize8 + 2000, TheCompactedDbSize8); + //Attached database + (void)RSqlDatabase::Delete(KDbName2); + TInt err = TheDb.Create(KDbName2); + TEST2(err, KErrNone); + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase16(TheTestDbName); + _LIT(KAttachDbName, "Db"); + err = TheDb.Attach(TheTestDbName, KAttachDbName); + TEST2(err, KErrNone); + TInt newDatabaseSize = TheOriginalDbSize16; + //Calling Compact() with aSize = 0. 0 pages expected to be removed + DoManualCompaction((TCompactionType)i, 0, newDatabaseSize, KAttachDbName); + //Calling Compact() with aSize = 1. 1 page expected to be removed + DoManualCompaction((TCompactionType)i, 1, TheOriginalDbSize16 - KTestDbPageSize, KAttachDbName); + newDatabaseSize -= KTestDbPageSize; + //Calling Compact() with aSize = KTestDbPageSize - 1. 1 page expected to be removed + DoManualCompaction((TCompactionType)i, KTestDbPageSize - 1, newDatabaseSize - KTestDbPageSize, KAttachDbName); + newDatabaseSize -= KTestDbPageSize; + //Calling Compact() with aSize = KTestDbPageSize. 1 page expected to be removed + DoManualCompaction((TCompactionType)i, KTestDbPageSize, newDatabaseSize - KTestDbPageSize, KAttachDbName); + newDatabaseSize -= KTestDbPageSize; + //Calling Compact() with aSize = KTestDbPageSize * KPagesCnt1. KPagesCnt1 pages expected to be removed + DoManualCompaction((TCompactionType)i, KTestDbPageSize * KPagesCnt1, newDatabaseSize - KTestDbPageSize * KPagesCnt1, KAttachDbName); + newDatabaseSize -= KTestDbPageSize * KPagesCnt1; + //Calling Compact() with aSize > newDatabaseSize. All free pages expected to be removed + DoManualCompaction((TCompactionType)i, newDatabaseSize + 2000, TheCompactedDbSize16, KAttachDbName); + // + err = TheDb.Detach(KAttachDbName); + TEST2(err, KErrNone); + TheDb.Close(); + (void)RSqlDatabase::Delete(KDbName2); + } + } + + +enum TSizeTestType {EManualSizeTest, EAutoSizeTest}; + +void DoCompactionDbSizeTest(TSizeTestType aType) + { + (void)RSqlDatabase::Delete(TheTestDbName); + _LIT8(KConfig1, "compaction=manual"); + _LIT8(KConfig2, "compaction=auto"); + TInt err = TheDb.Create(TheTestDbName, aType == EManualSizeTest ? &KConfig1 : &KConfig2); + TEST2(err, KErrNone); + err = TheDb.Exec(_L("CREATE TABLE A(T TEXT)")); + TEST2(err, 1); + // + RSqlDatabase::TSize size; + err = TheDb.Size(size); + TEST2(err, KErrNone); + TEST2(size.iFree, 0); + // + const TInt KRecCnt = 50; + for(TInt i=0;i 0); + } + else + { + TEST2(size.iFree, 0); + } + // + TheDb.Close(); + (void)RSqlDatabase::Delete(TheTestDbName); + } + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4066 +@SYMTestCaseDesc RSqlDatabase::Size(TSize&) called on a database with manual compaction mode. + The test creates a database with a manual compaction mode. + Then the test inserts some records and deletes the records making some free database pages. + The test calls RSqlDatabase::Size(TSize&) before and after the delete operation and verifies + that the database file size stays unchanged. +@SYMTestPriority Medium +@SYMTestActions RSqlDatabase::Size(TSize&) called on a database with manual compaction mode. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10407 +*/ +void ManualCompactionSizeTest() + { + DoCompactionDbSizeTest(EManualSizeTest); + } + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// OOM testing //////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void PrintEndOfOomTest(TInt aFailingAllocationNo) + { + TheTest.Printf(_L("=== OOM Test succeeded at heap failure rate of %d ===\r\n"), aFailingAllocationNo); + } + +void SetDbHeapFailure(TInt aFailingAllocationNo) + { + const TInt KDelayedDbHeapFailureMask = 0x1000; + TSqlResourceTester::SetDbHeapFailure(RHeap::EDeterministic | KDelayedDbHeapFailureMask, aFailingAllocationNo); + } + +void ResetDbHeapFailure() + { + TSqlResourceTester::SetDbHeapFailure(RHeap::ENone, 0); + } + +static TInt TheHandleCount1B; +static TInt TheHandleCount2B; +static TInt TheAllocatedCellsCountB; + +void MarkHandles() + { + RThread().HandleCount(TheHandleCount1B, TheHandleCount2B); + } + +void CheckHandles() + { + TInt endHandleCount1E; + TInt endHandleCount2E; + + RThread().HandleCount(endHandleCount1E, endHandleCount2E); + + TEST(TheHandleCount1B == endHandleCount1E); + TEST(TheHandleCount2B == endHandleCount2E); + } + +void MarkAllocatedCells() + { + TheAllocatedCellsCountB = User::CountAllocCells(); + } + +void CheckAllocatedCells() + { + TInt allocatedCellsCountE = User::CountAllocCells(); + TEST(allocatedCellsCountE == TheAllocatedCellsCountB); + } + +typedef void (*TDbFuncPtrL)(const TDesC& aDbName); + +void DoManualCompactionOomTest(TDbFuncPtrL aTestFunctionPtrL, const TDesC& aDbFileName, const TDesC& aAttachDbFileName, const TDesC& aDbName) + { + const TInt KDoDbOomTestAllocLimitServer = 1000; + TInt failingAllocation = 0; + TInt allocation = 0; + TInt err = KErrNoMemory; + while(allocation < KDoDbOomTestAllocLimitServer) + { + MarkHandles(); + MarkAllocatedCells(); + + __UHEAP_MARK; + + SetDbHeapFailure(++allocation); + + err = TheDb.Open(aDbFileName); + TEST2(err, KErrNone); + if(aAttachDbFileName != KNullDesC) + { + TEST(aDbName != KNullDesC); + err = TheDb.Attach(aAttachDbFileName, aDbName); + TEST(err == KErrNone || err == KErrNoMemory); + } + if(err == KErrNone) + { + TRAP(err, (*aTestFunctionPtrL)(aDbName)); + if(err != KErrNoMemory) + { + TEST2(err, KErrNone); + } + else + { + failingAllocation = allocation; + } + } + + ResetDbHeapFailure(); + + if(aAttachDbFileName != KNullDesC) + { + (void)TheDb.Detach(aDbName); + } + TheDb.Close(); + + __UHEAP_MARKEND; + + CheckAllocatedCells(); + CheckHandles(); + } + TEST2(err, KErrNone); + PrintEndOfOomTest(failingAllocation + 1); + } + +void OomTest1L(const TDesC&) + { + User::LeaveIfError(TheDb.Compact(RSqlDatabase::EMaxCompaction)); + } + +void OomTest2L(const TDesC& aDbName) + { + TEST(aDbName != KNullDesC); + User::LeaveIfError(TheDb.Compact(RSqlDatabase::EMaxCompaction, aDbName)); + } + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4068 +@SYMTestCaseDesc RSqlDatabase::Compact() - OOM test. + The test creates a database with a manual compaction mode. + Then the test calls Compact() in an OOM loop. + The same OOM test is repeated for Compact() called an attached database. +@SYMTestPriority Medium +@SYMTestActions RSqlDatabase::Compact() - OOM test. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10405 +*/ +void ManualCompactionOomTest() + { + TheTest.Printf(_L("Main database - manual compaction - OOM test\r\n")); + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase8(TheTestDbName); + DoManualCompactionOomTest(&OomTest1L, TheTestDbName, KNullDesC, KNullDesC); + TInt err = TheDb.Open(TheTestDbName); + TEST2(err, KErrNone); + RSqlDatabase::TSize size; + err = TheDb.Size(size); + TEST2(err, KErrNone); + TEST2(size.iSize, TheCompactedDbSize8); + TheDb.Close(); + + TheTest.Printf(_L("Attached database - manual compaction - OOM test\r\n")); + (void)RSqlDatabase::Delete(KDbName2); + err = TheDb.Create(KDbName2); + TEST2(err, KErrNone); + TheDb.Close(); + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase16(TheTestDbName); + DoManualCompactionOomTest(&OomTest2L, KDbName2, TheTestDbName, _L("Db")); + err = TheDb.Open(TheTestDbName); + TEST2(err, KErrNone); + err = TheDb.Size(size); + TEST2(err, KErrNone); + TEST2(size.iSize, TheCompactedDbSize16); + TheDb.Close(); + + (void)RSqlDatabase::Delete(KDbName2); + (void)RSqlDatabase::Delete(TheTestDbName); + } + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4067 +@SYMTestCaseDesc RSqlDatabase::Size(TSize&) called on a database with auto compaction mode. + The test creates a database with an auto compaction mode. + Then the test inserts some records and deletes the records. + The test calls RSqlDatabase::Size(TSize&) after the delete operation and verifies + that the database file does not contain any free pages. +@SYMTestPriority Medium +@SYMTestActions RSqlDatabase::Size(TSize&) called on a database with auto compaction mode. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10407 + REQ10400 +*/ +void AutoCompactionSizeTest() + { + DoCompactionDbSizeTest(EAutoSizeTest); + } + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4069 +@SYMTestCaseDesc Background compaction functional test. + The test executes a 10 iterations loop with a "sleep" time 1000000 us at the beginning. + The "sleep" time is divided by 2 on each iteration. + In each iteration the test creates a database with free pages count big enough to kick-off the + background compaction. Then the test executes enough Exec()s in order to kick-off the background compaction. + Then the test "sleeps" the calculated "sleep" time and checks after that the database size and free pages + count and prints them out. After the last iteration the same test is repeated with no "sleep" time. + The test verifies how the client connection activity affects the possibility of the server to run the + background compaction. +@SYMTestPriority Medium +@SYMTestActions Background compaction functional test. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10271 + REQ10407 +*/ +void BackgroundCompactionTest() + { + TInt interval = 1000000;//us + const TInt KIterationCnt = 10; + TheTest.Printf(_L("===Sleep after Exec()\r\n")); + for(TInt i=0;i= 0); + } + User::After(interval); + RSqlDatabase::TSize size2; + err = TheDb.Size(size2); + TEST2(err, KErrNone); + TheTest.Printf(_L("===Database after background compaction: size %ld, free space %ld\r\n"), size2.iSize, size2.iFree); + TEST(size2.iSize <= size1.iSize); + TEST(size2.iFree <= size1.iFree); + interval /= 2; + TheDb.Close(); + } + TheTest.Printf(_L("===No sleep\r\n")); + (void)RSqlDatabase::Delete(TheTestDbName); + CreateDatabase8(TheTestDbName); + TInt err = TheDb.Open(TheTestDbName); + TEST2(err, KErrNone); + RSqlDatabase::TSize size1; + err = TheDb.Size(size1); + TEST2(err, KErrNone); + TheTest.Printf(_L("===Database before background compaction: size %ld, free space %ld\r\n"), size1.iSize, size1.iFree); + //Simulate Exec() activities + for(TInt j=0;j<100;++j) + { + err = TheDb.Exec(_L8("SELECT Id FROM A LIMIT 1")); + TEST(err >= 0); + } + RSqlDatabase::TSize size2; + err = TheDb.Size(size2); + TEST2(err, KErrNone); + TheTest.Printf(_L("===Database after background compaction: size %ld, free space %ld\r\n"), size2.iSize, size2.iFree); + TEST(size2.iSize <= size1.iSize); + TEST(size2.iFree <= size1.iFree); + TheDb.Close(); + (void)RSqlDatabase::Delete(TheTestDbName); + } + +struct TThreadData + { + TThreadData(const TDesC& aFileName, TInt aSleepInterval) : + iDbName(aFileName), + iSleepInterval(aSleepInterval) + { + TInt err = iCritSection.CreateLocal(); + TEST2(err, KErrNone); + iCritSection.Wait(); + Mem::FillZ(&iSize1, sizeof(iSize1)); + Mem::FillZ(&iSize2, sizeof(iSize2)); + } + TFileName iDbName; + RCriticalSection iCritSection; + RSqlDatabase::TSize iSize1; + RSqlDatabase::TSize iSize2; + TInt iSleepInterval; + }; + +TInt ThreadFunc(void* aPrm) + { + TEST(aPrm != NULL); + + __UHEAP_MARK; + CTrapCleanup* tc = CTrapCleanup::New(); + TheTest(tc != NULL); + + //Wait for a signal from the main thread + TThreadData* thrdat = (TThreadData*)aPrm; + thrdat->iCritSection.Wait(); + + RSqlDatabase db; + TInt err = db.Open(thrdat->iDbName); + TEST2(err, KErrNone); + err = db.Size(thrdat->iSize1); + TEST2(err, KErrNone); + //Simulate Exec() activities + for(TInt j=0;j<100;++j) + { + err = db.Exec(_L8("SELECT Id FROM A LIMIT 1")); + TEST(err >= 0); + if((j % 10) == 0 && thrdat->iSleepInterval > 0) + { + User::After(thrdat->iSleepInterval); + } + } + err = db.Size(thrdat->iSize2); + TEST2(err, KErrNone); + db.Close(); + + delete tc; + __UHEAP_MARKEND; + return KErrNone; + } + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4070 +@SYMTestCaseDesc Background compaction load test. + The test runs 8 threads. Each thread connects to a different database. + Each database has space in the free pages above the "free pages" threshold - + the background compaction will be scheduled at the moment when the database is opened. + Every thread executes some operations on the opened database - that will delay the background compaction. + After every 10 operations the thread sleeps for a specified interval of a time. + After all threads complete, the test checks the database size and free pages count and + prints them out. + The test verifies the ability of the SQL server to run the background compaction under a load. +@SYMTestPriority Medium +@SYMTestActions Background compaction load test. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10271 + REQ10407 +*/ +void BackgroundCompactionLoadTest() + { + RThread threads[KMaxThreadCount]; + TThreadData* thrdata[KMaxThreadCount] = {NULL}; + TRequestStatus thrstat[KMaxThreadCount]; + + const TInt KSleepInterval[] = {0, 50000, 100000, 300000, 500000, 800000};//us + const TInt KTestCnt = sizeof(KSleepInterval) / sizeof(KSleepInterval[0]); + + for(TInt k=0;k fname; + fname.Copy(_L("\\test\\a")); + fname.AppendNum(i + 1); + fname.Append(_L(".db")); + TheParse.Set(TheDrive, &fname, 0); + (void)RSqlDatabase::Delete(TheParse.FullName()); + CreateDatabase8(TheParse.FullName()); + //Thread data + thrdata[i] = new TThreadData(TheParse.FullName(), KSleepInterval[k]); + TEST(thrdata[i] != NULL); + //Thread + TBuf<16> thrname; + thrname.Copy(_L("Thread")); + thrname.AppendNum(i + 1); + TInt err = threads[i].Create(thrname, &ThreadFunc, 0x2000, 0x1000, 0x10000, thrdata[i], EOwnerProcess); + TEST2(err, KErrNone); + threads[i].Logon(thrstat[i]); + TEST2(thrstat[i].Int(), KRequestPending); + threads[i].Resume(); + } + //Enable the threads + for(TInt i=0;iiCritSection.Signal(); + } + //Wait for cmpletion + for(TInt i=0;iiDbName)); + TheTest.Printf(_L("===Before background compaction: size %6ld, free space %6ld\r\n"), thrdata[i]->iSize1.iSize, thrdata[i]->iSize1.iFree); + TheTest.Printf(_L("===After background compaction: size %6ld, free space %6ld\r\n"), thrdata[i]->iSize2.iSize, thrdata[i]->iSize2.iFree); + TEST(thrdata[i]->iSize2.iSize <= thrdata[i]->iSize1.iSize); + TEST(thrdata[i]->iSize2.iFree <= thrdata[i]->iSize1.iFree); + } + //Destroy + for(TInt i=0;iiDbName); + thrdata[i]->iCritSection.Close(); + delete thrdata[i]; + thrdata[i] = NULL; + CLOSE_AND_WAIT(threads[i]); + } + } + } + +/** +@SYMTestCaseID SYSLIB-SQL-UT-4071 +@SYMTestCaseDesc Background compaction in a DDL transaction test. + The test creates a database, begins a transaction that modifies the database structure + and executes enough operations in order free enough space to kick-off the background compaction. + The test should not report any failures caused by the fact that the main database connection is + in a DML transaction and at the same time the background connection may try to execute + a "PRAGMA freelist_count" statement. +@SYMTestPriority Medium +@SYMTestActions Background compaction in a DDL transaction test. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ10271 +*/ +void BackgroundCompactionInDDLTransactionTest() + { + const TInt KOperationCount = 100; + (void)RSqlDatabase::Delete(KDbName); + TInt err = TheDb.Create(KDbName); + TEST2(err, KErrNone); + err = TheDb.Exec(_L("BEGIN")); + TEST(err >= 0); + err = TheDb.Exec(_L("CREATE TABLE A(I INTEGER, T TEXT)")); + TEST2(err, 1); + TheText.SetLength(KTextLen); + TheText.Fill(TChar('A')); + for(TInt i=0;i<=KOperationCount;++i) + { + TheSqlTexLen.Format(_L("INSERT INTO A VALUES(%d, '%S')"), i + 1, &TheText); + err = TheDb.Exec(TheSqlTexLen); + TEST2(err, 1); + } + err = TheDb.Exec(_L("COMMIT")); + TEST(err >= 0); + TheDb.Close(); + (void)RSqlDatabase::Delete(KDbName); + } + +void DoTestsL() + { + CreateTestDatabase8(); + CalculateMaxCompaction8(); + CreateTestDatabase16(); + CalculateMaxCompaction16(); + + TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4064 Manual Compact() - negative tests")); + ManualCompactionNegativeTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4065 Manual Compact() tests")); + ManualCompactionTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4066 Manual compaction db size test")); + ManualCompactionSizeTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4068 Manual compaction - OOM test")); + ManualCompactionOomTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4067 Auto compaction db size test")); + AutoCompactionSizeTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4069 Background compaction test")); + BackgroundCompactionTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4070 Background compaction - load test")); + BackgroundCompactionLoadTest(); + + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4071 Background compaction activated inside a DDL transaction - test")); + BackgroundCompactionInDDLTransactionTest(); + } + +TInt E32Main() + { + TheTest.Title(); + + CTrapCleanup* tc = CTrapCleanup::New(); + TheTest(tc != NULL); + + TheTest.Printf(_L("Usage:\r\n t_sqlcompact4 [[drive:] [test thread count]]\r\n")); + TheDrive.Copy(KDefaultDriveName); + User::CommandLine(TheCmd); + TheCmd.TrimAll(); + if(TheCmd.Length() > 0) + { + TInt pos = TheCmd.Locate(TChar(' ')); + TheTest(pos > 0); + TPtrC prm1(TheCmd.Left(pos)); + TPtrC prm2(TheCmd.Mid(pos + 1)); + + TheDrive.Copy(prm1); + + TLex lex(prm2); + lex.Val(TheTestThreadCount); + } + TheParse.Set(TheDrive, &KDbName, 0); + TheTestDbName.Copy(TheParse.FullName()); + TheTest.Printf(_L("Test database: %S\r\n"), &TheTestDbName); + + __UHEAP_MARK; + + CreateTestEnv(); + TRAPD(err, DoTestsL()); + DestroyTestEnv(); + TEST2(err, KErrNone); + + __UHEAP_MARKEND; + + TheTest.End(); + TheTest.Close(); + + delete tc; + + User::Heap().Check(); + return KErrNone; + }