diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/TEST/t_sqlload.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/sql/TEST/t_sqlload.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,563 @@ +// 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 +#include +#include +#include +#include "SqlResourceTester.h" + +/////////////////////////////////////////////////////////////////////////////////////// + +#define UNUSED_VAR(a) (a) = (a) + +RTest TheTest(_L("t_sqlload test")); + +_LIT(KTestDir, "c:\\test\\"); +_LIT(KTestDbName1, "c:\\test\\t_sqlload_1.db"); +_LIT(KTestDbName2, "c:\\test\\t_sqlload_2.db"); +_LIT(KTestDbName3, "c:\\test\\t_sqlload_3.db"); + +//Test thread count +const TInt KTestThreadCnt = 4; + +//Test database names +const TPtrC KTestDbNames[] = + { + KTestDbName1(), + KTestDbName2(), + KTestDbName3() + }; + +//Test database count +const TInt KTestDbCnt = sizeof(KTestDbNames) / sizeof(KTestDbNames[0]); + +//Test duration +const TInt KTestDuration = 120;//seconds + +//Test record count +const TInt KRecordCnt = 100; +//Record count which will be used in the test SQL queries +const TInt KQueriedRecordCnt = 40; +//Every SQL query will be processed (stepped) in KTestStepCnt steps. +const TInt KTestStepCnt = 4; +//RSqlStatement object count which will be used in the tests +const TInt KStatementCnt = 10; +//Max allowed alive RSqlStatement objects per thread +const TInt KMaxStatementPerThread = 30; +//Binary data length +const TInt KBinDataLen = 2003; + +/////////////////////////////////////////////////////////////////////////////////////// + +void DeleteTestFiles() + { + RSqlDatabase::Delete(KTestDbName3); + RSqlDatabase::Delete(KTestDbName2); + RSqlDatabase::Delete(KTestDbName1); + } + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Test macros and functions +void Check1(TInt aValue, TInt aLine, TBool aPrintThreadName = EFalse) + { + if(!aValue) + { + DeleteTestFiles(); + if(aPrintThreadName) + { + RThread th; + TName name = th.Name(); + RDebug::Print(_L("*** Thread %S, Line %d\r\n"), &name, aLine); + } + else + { + RDebug::Print(_L("*** Line %d\r\n"), aLine); + } + TheTest(EFalse, aLine); + } + } +void Check2(TInt aValue, TInt aExpected, TInt aLine, TBool aPrintThreadName = EFalse) + { + if(aValue != aExpected) + { + DeleteTestFiles(); + if(aPrintThreadName) + { + RThread th; + TName name = th.Name(); + RDebug::Print(_L("*** Thread %S, Line %d Expected error: %d, got: %d\r\n"), &name, aLine, aExpected, aValue); + } + else + { + RDebug::Print(_L("*** Line %d, Expected error: %d, got: %d\r\n"), aLine, aExpected, aValue); + } + TheTest(EFalse, aLine); + } + } +#define TEST(arg) ::Check1((arg), __LINE__) +#define TEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__) +#define TTEST(arg) ::Check1((arg), __LINE__, ETrue) +#define TTEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__, ETrue) + +/////////////////////////////////////////////////////////////////////////////////////// + +void CreateTestDir() + { + RFs fs; + TInt err = fs.Connect(); + TEST2(err, KErrNone); + + err = fs.MkDir(KTestDir); + TEST(err == KErrNone || err == KErrAlreadyExists); + + fs.Close(); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +void CreateTestDatabases() + { + HBufC8* recData = HBufC8::New(KBinDataLen * 2 + 50);//"* 2" - hex values for the INSERT SQL statement + TEST(recData != NULL); + TPtr8 sql = recData->Des(); + + for(TInt dbIdx=0;dbIdx= 0); + + //Insert records in the test table + for(TInt recIdx=1;recIdx<=KRecordCnt;++recIdx) + { + _LIT8(KInsertSql, "INSERT INTO A(F1, F2) VALUES("); + sql.Copy(KInsertSql); + sql.AppendNum((TInt64)recIdx); + sql.Append(_L(", X'")); + for(TInt k=0;k RSqlStatementArray; + +//Inits the random numbers generator. +//Opens one of the test databases. +void PreTest(RSqlDatabase& aDb, TInt64& aSeed, TName& aThreadName) + { + RThread currThread; + + //Init the random numbers generator + TTime now; + now.UniversalTime(); + aSeed = now.Int64() + currThread.Id(); + + //Open one of the test databases + const TInt KDbIndex = Math::Rand(aSeed) % KTestDbCnt; + + aThreadName = currThread.Name(); + RDebug::Print(_L("=== Thread %S, database %S\r\n"), &aThreadName, &KTestDbNames[KDbIndex]); + + TInt err = aDb.Open(KTestDbNames[KDbIndex]); + TTEST2(err, KErrNone); + } + +//Creates N statements, where 0 < N < KStatementCnt +TInt CreateStatements(RSqlDatabase& aDb, TInt64& aSeed, RSqlStatementArray& aStmtArray) + { + TInt stmtCount = Math::Rand(aSeed) % KStatementCnt; + if(stmtCount == 0) + { + stmtCount = 1; + } + for(TInt i=0;i (KRecordCnt - KQueriedRecordCnt)) + { + stmt.iCurIndex = KRecordCnt - KQueriedRecordCnt; + } + stmt.iEndIndex = stmt.iCurIndex + KQueriedRecordCnt; + TBuf8<100> sql; + sql.Copy(_L8("SELECT * FROM A WHERE F1 >= ")); + sql.AppendNum(stmt.iCurIndex); + sql.Append(_L8(" AND F1 < ")); + sql.AppendNum(stmt.iEndIndex); + TInt err = stmt.iObj.Prepare(aDb, sql); + TTEST2(err, KErrNone); + stmt.iAlive = ETrue; + err = aStmtArray.Append(stmt); + TTEST2(err, KErrNone); + } + return stmtCount; + } + +//For each alive statement object - do (TSqlStatement::iCount / KTestStepCnt) +//RSqlStatement::Next() calls. If the Next() call reaches the end - close the statement object. +TInt ProcessStatements(RSqlStatementArray& aStmtArray) + { + const TInt KTotalStmtCount = aStmtArray.Count(); + TInt alive = 0; + TInt completed = 0; + for(TInt k=0;k= stmt.iEndIndex) + { + stmt.iObj.Close(); + stmt.iAlive = EFalse; + ++completed; + } + } + } + return completed; + } + +//Close up to N statements, where 0 < N < KStatementCnt +TInt CloseStatements(RSqlStatementArray& aStmtArray, TInt64& aSeed) + { + TInt stmtCount = Math::Rand(aSeed) % KStatementCnt; + if(stmtCount == 0) + { + stmtCount = 1; + } + const TInt KTotalStmtCount = aStmtArray.Count(); + TInt closed = 0; + for(TInt j=0;j=0;--i) + { + if(!aStmtArray[i].iAlive) + { + aStmtArray.Remove(i); + } + } + aStmtArray.Compress(); + } + +//Close statement objects, statements array and the database object +TInt PostTest(RSqlDatabase& aDb, RSqlStatementArray& aStmtArray) + { + TInt statementsAlive = AliveStatementsCount(aStmtArray); + CloseAllStatements(aStmtArray); + aStmtArray.Close(); + aDb.Close(); + return statementsAlive; + } + +//Test thread function +//The thread function works with a set of TSqlStatement objects +//The test consists of 4 steps: +//Step 1: the test thread creates m TSqlStatement objects, 0 < m < KStatementCnt. +// With each of the created TSqlStatement objects the test thread prepares SELECT SQL query +// "SELECT * FROM A WHERE F1 >= K1 AND F1 < K2", where K1 is random generated number, such that: +// 0 < K1 < (KRecordCnt - KQueriedRecordCnt) +// K2 = K1 + KQueriedRecordCnt +// All just created TSqlStatement objects are marked as alive. +//Step 2: For each alive TSqlStatement object the test thread calls iObj.Next() method KTestStepCnt times, +// KTestStepCnt < KQueriedRecordCnt. +// The column values are retrieved and checked. +//Step 3: the test thread closes n TSqlStatement objects, 0 < n < KStatementCnt. +//Step 4: the test thread counts how many alive TSqlStatement objects are there. +// If this count > KMaxStatementPerThread then the test thread closes all alive TSqlStatement objects +// to avoid OOM errors during the test. +// +// Each test thread does steps 1..4 for a period of KTestDuration seconds. +// At the end all TSqlStatement objects are closed. +// +// The idea of the test is to load the SQL server creating several amount of statement and stream objects +// and see that it is working stable and without problems. +TInt ThreadFunc(void*) + { + __UHEAP_MARK; + + CTrapCleanup* tc = CTrapCleanup::New(); + TTEST(tc != NULL); + + TInt64 seed = 0; + RSqlDatabase db; + TName threadName; + RSqlStatementArray statements; + + //Init the random numbers generator, opens the database + PreTest(db, seed, threadName); + + //Main test loop + TInt iteration = 0; + TTime currTime; + currTime.UniversalTime(); + TTime endTime = currTime + TTimeIntervalSeconds(KTestDuration); + while(currTime < endTime) + { + ++iteration; + /////////////////////////////////////////////////////////////////////// + TInt statementsAliveBegin = statements.Count(); + //Step 1: Create N statements, where 0 < N < KStatementCnt + TInt statementsCreated = CreateStatements(db, seed, statements); + /////////////////////////////////////////////////////////////////////// + //Step 2: For each alive statement object - do (TSqlStatement::iCount / KTestStepCnt) + // RSqlStatement::Next() calls. If the Next() call reaches the end - close the statement object. + TInt statementsCompleted = ProcessStatements(statements); + /////////////////////////////////////////////////////////////////////// + //Step 3: Close up to N statements, where 0 < N < KStatementCnt + TInt statementsClosed = CloseStatements(statements, seed); + /////////////////////////////////////////////////////////////////////// + //Step 4: If the alive statement count is more than KMaxStatementPerThread, then close them all + TInt statementsAliveEnd = AliveStatementsCount(statements); + if(statementsAliveEnd > KMaxStatementPerThread) + { + RDebug::Print(_L("!!! Thread %S, iteration %d, alive %d, close all\r\n"), &threadName, iteration, statementsAliveEnd); + CloseAllStatements(statements); + statementsAliveEnd = 0; + } + /////////////////////////////////////////////////////////////////////// + RemoveDeadStatements(statements); + RDebug::Print(_L("=== Thread %S, iteration % 4d, begin: % 3d, created % 2d, closed % 2d, completed % 2d, end % 3d, \r\n"), + &threadName, iteration, statementsAliveBegin, + statementsCreated, statementsClosed, statementsCompleted, + statementsAliveEnd); + currTime.UniversalTime(); + } + + //Close statement objects and the database object + TInt statementsAlive = PostTest(db, statements); + + delete tc; + + __UHEAP_MARKEND; + + RDebug::Print(_L("=== Thread %S exit, still alive %d\r\n"), &threadName, statementsAlive); + + return KErrNone; + } + +void CreateTestThreads(RThread aThreads[], TRequestStatus aStatuses[], TInt aMaxCount) + { + _LIT(KThreadName, "TstThr"); + for(TInt i=0;i threadName(KThreadName); + threadName.AppendNum((TInt64)(i + 1)); + TEST2(aThreads[i].Create(threadName, &ThreadFunc, 0x2000, 0x1000, 0x10000, NULL, EOwnerProcess), KErrNone); + aThreads[i].Logon(aStatuses[i]); + TEST2(aStatuses[i].Int(), KRequestPending); + } + } + +void ResumeTestThreads(RThread aThreads[], TInt aMaxCount) + { + for(TInt i=0;i= K1 AND F1 < K2", where K1 is random generated number, such that: + 0 < K1 < (KRecordCnt - KQueriedRecordCnt) + K2 = K1 + KQueriedRecordCnt + All just created TSqlStatement objects are marked as alive. + Step 2: For each alive TSqlStatement object the test thread calls iObj.Next() method KTestStepCnt times, + KTestStepCnt < KQueriedRecordCnt. + The column values are retrieved and checked. + Step 3: the test thread closes n TSqlStatement objects, 0 < n < KStatementCnt. + Step 4: the test thread counts how many alive TSqlStatement objects are there. + If this count > KMaxStatementPerThread then the test thread closes all alive TSqlStatement objects + to avoid OOM errors during the test. + + Each test thread does steps 1..4 for a period of KTestDuration seconds. + At the end all TSqlStatement objects are closed. + + The idea of the test is to load the SQL server creating several amount of statement and stream objects + and see that it is working stable and without problems. +@SYMTestPriority High +@SYMTestActions SQL server load test +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ5792 + REQ5793 +*/ +void SqlLoadTest() + { + CreateTestDatabases(); + + RThread threads[KTestThreadCnt]; + TRequestStatus statuses[KTestThreadCnt]; + + CreateTestThreads(threads, statuses, KTestThreadCnt); + + ResumeTestThreads(threads, KTestThreadCnt); + + User::After(2000000); + + CloseTestThreads(threads, statuses, KTestThreadCnt); + } + +void DoTests() + { + TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1627-0001 SQL server load test ")); + SqlLoadTest(); + } + +TInt E32Main() + { + TheTest.Title(); + + CTrapCleanup* tc = CTrapCleanup::New(); + + __UHEAP_MARK; + + CreateTestDir(); + DeleteTestFiles(); + DoTests(); + DeleteTestFiles(); + + __UHEAP_MARKEND; + + TheTest.End(); + TheTest.Close(); + + delete tc; + + User::Heap().Check(); + return KErrNone; + }