persistentstorage/sql/TEST/t_sqltrans.cpp
changeset 0 08ec8eefde2f
child 55 44f437012c90
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32test.h>
       
    17 #include <bautils.h>
       
    18 #include <sqldb.h>
       
    19 
       
    20 ///////////////////////////////////////////////////////////////////////////////////////
       
    21 
       
    22 #define UNUSED_VAR(a) (a) = (a)
       
    23 
       
    24 RTest TheTest(_L("t_sqltrans test"));
       
    25 
       
    26 _LIT(KTestDir, "c:\\test\\");
       
    27 _LIT(KTestDbName, "c:\\test\\t_sqltrans.db");
       
    28 
       
    29 ///////////////////////////////////////////////////////////////////////////////////////
       
    30 
       
    31 void DeleteTestFiles()
       
    32 	{
       
    33 	RSqlDatabase::Delete(KTestDbName);
       
    34 	}
       
    35 
       
    36 ///////////////////////////////////////////////////////////////////////////////////////
       
    37 ///////////////////////////////////////////////////////////////////////////////////////
       
    38 //Test macros and functions
       
    39 void Check1(TInt aValue, TInt aLine, TBool aPrintThreadName = EFalse)
       
    40 	{
       
    41 	if(!aValue)
       
    42 		{
       
    43 		DeleteTestFiles();
       
    44 		if(aPrintThreadName)
       
    45 			{
       
    46 			RThread th;
       
    47 			TName name = th.Name();
       
    48 			RDebug::Print(_L("*** Thread %S, Line %d\r\n"), &name, aLine);
       
    49 			}
       
    50 		else
       
    51 			{
       
    52 			RDebug::Print(_L("*** Line %d\r\n"), aLine);
       
    53 			}
       
    54 		TheTest(EFalse, aLine);
       
    55 		}
       
    56 	}
       
    57 void Check2(TInt aValue, TInt aExpected, TInt aLine, TBool aPrintThreadName = EFalse)
       
    58 	{
       
    59 	if(aValue != aExpected)
       
    60 		{
       
    61 		DeleteTestFiles();
       
    62 		if(aPrintThreadName)
       
    63 			{
       
    64 			RThread th;
       
    65 			TName name = th.Name();
       
    66 			RDebug::Print(_L("*** Thread %S, Line %d Expected error: %d, got: %d\r\n"), &name, aLine, aExpected, aValue);
       
    67 			}
       
    68 		else
       
    69 			{
       
    70 			RDebug::Print(_L("*** Line %d, Expected error: %d, got: %d\r\n"), aLine, aExpected, aValue);
       
    71 			}
       
    72 		TheTest(EFalse, aLine);
       
    73 		}
       
    74 	}
       
    75 #define TEST(arg) ::Check1((arg), __LINE__)
       
    76 #define TEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__)
       
    77 #define TTEST(arg) ::Check1((arg), __LINE__, ETrue)
       
    78 #define TTEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__, ETrue)
       
    79 
       
    80 ///////////////////////////////////////////////////////////////////////////////////////
       
    81 
       
    82 void CreateTestDir()
       
    83     {
       
    84     RFs fs;
       
    85 	TInt err = fs.Connect();
       
    86 	TEST2(err, KErrNone);
       
    87 
       
    88 	err = fs.MkDir(KTestDir);
       
    89 	TEST(err == KErrNone || err == KErrAlreadyExists);
       
    90 	
       
    91 	fs.Close();
       
    92 	}
       
    93 
       
    94 ///////////////////////////////////////////////////////////////////////////////////////
       
    95 
       
    96 _LIT8(KTestSql1, "INSERT INTO A(Id) VALUES(1); INSERT INTO A(Id) VALUES(2);");
       
    97 
       
    98 const TPtrC8 KSqls[] = {KTestSql1()};
       
    99 
       
   100 static RCriticalSection ThreadCritSect;
       
   101 static RCriticalSection MainCritSect;
       
   102 
       
   103 static TInt TheSqlIdx = 0;
       
   104 
       
   105 _LIT(KPanicCategory, "TransFail");
       
   106 const TInt KPanicCode = 0x1234;
       
   107 
       
   108 //Test thread function
       
   109 TInt ThreadFunc1(void*)
       
   110 	{
       
   111 	__UHEAP_MARK;
       
   112 	
       
   113 	CTrapCleanup* tc = CTrapCleanup::New();
       
   114 	TTEST(tc != NULL);
       
   115 
       
   116 	__ASSERT_ALWAYS(TheSqlIdx >= 0 && TheSqlIdx < (TInt)(sizeof(KSqls) / sizeof(KSqls[0])), User::Invariant());
       
   117 	const TPtrC8 sql = KSqls[TheSqlIdx];
       
   118 
       
   119 	//Open test database
       
   120 	RSqlDatabase db;
       
   121 	TInt err = db.Open(KTestDbName);
       
   122 	TTEST2(err, KErrNone);
       
   123 
       
   124 	RDebug::Print(_L("---:WorkThread: Begin transaction. Exec SQL...\r\n"));
       
   125 	
       
   126 	//Begin a transaction
       
   127 	_LIT8(KBeginTrans, "BEGIN");
       
   128 	err = db.Exec(KBeginTrans);
       
   129 	TTEST(err >= 0);	
       
   130 
       
   131 	//Execute the SQL statement(s)
       
   132 	err = db.Exec(sql);
       
   133 	TTEST(err >= 0);	
       
   134 
       
   135 	RDebug::Print(_L("---:WorkThread: Notify the main thread about the SQL statement execution\r\n"));
       
   136 	MainCritSect.Signal();
       
   137 
       
   138 	RDebug::Print(_L("---:WorkThread: Wait for permisson to continue...\r\n"));
       
   139 	ThreadCritSect.Wait();
       
   140 
       
   141 	User::SetJustInTime(EFalse);	// disable debugger panic handling
       
   142 
       
   143 	//Panic current thread without commiting the transaction
       
   144 	RDebug::Print(_L("---:WorkThread: Panic!\r\n"));
       
   145 	User::Panic(KPanicCategory, KPanicCode);
       
   146 
       
   147 	delete tc;	
       
   148 	
       
   149 	__UHEAP_MARKEND;
       
   150 	
       
   151 	return KErrNone;		
       
   152 	}
       
   153 
       
   154 /**
       
   155 @SYMTestCaseID			SYSLIB-SQL-CT-1623
       
   156 @SYMTestCaseDesc		Transaction atomicity test.
       
   157 						Create a test database with a table. 
       
   158 						Create a worker thread and make some "insert record" operations in a transaction from 
       
   159 						that thread. Before commiting the transaction notify the main thread that the
       
   160 						insert operation completed and wait for a notification from the main thread.
       
   161 						The main thread notifies the worker thread to panic and checks the test table 
       
   162 						content. No records should be found there.
       
   163 @SYMTestPriority		High
       
   164 @SYMTestActions			Transaction atomicity test.
       
   165 @SYMTestExpectedResults Test must not fail
       
   166 @SYMREQ					REQ5792
       
   167                         REQ5793
       
   168 */	
       
   169 void TransactionTest1()
       
   170 	{
       
   171 	RDebug::Print(_L("+++:MainThread: Create critical sections\r\n"));
       
   172 	TEST2(ThreadCritSect.CreateLocal(), KErrNone);
       
   173 	ThreadCritSect.Wait();
       
   174 	TEST2(MainCritSect.CreateLocal(), KErrNone);
       
   175 	MainCritSect.Wait();
       
   176 	
       
   177 	RDebug::Print(_L("+++:MainThread: Create test database\r\n"));
       
   178 	(void)RSqlDatabase::Delete(KTestDbName);
       
   179 	RSqlDatabase db;
       
   180 	TInt err = db.Create(KTestDbName);
       
   181 	TEST2(err, KErrNone);
       
   182 
       
   183 	RDebug::Print(_L("+++:MainThread: Create a table in the test database\r\n"));
       
   184 	_LIT8(KCreateSql, "CREATE TABLE A(Id INTEGER)");
       
   185 	err = db.Exec(KCreateSql);
       
   186 	TEST(err >= 0);	
       
   187 	
       
   188 	db.Close();
       
   189 
       
   190 	RDebug::Print(_L("+++:MainThread: Create the worker thread\r\n"));
       
   191 	_LIT(KThreadName, "WorkThrd");
       
   192 	RThread thread;
       
   193 	TheSqlIdx = 0;
       
   194 	TEST2(thread.Create(KThreadName, &ThreadFunc1, 0x2000, 0x1000, 0x10000, NULL, EOwnerProcess), KErrNone);
       
   195 	TRequestStatus status;
       
   196 	thread.Logon(status);
       
   197 	TEST2(status.Int(), KRequestPending);
       
   198 	thread.Resume();
       
   199 
       
   200 	RDebug::Print(_L("+++:MainThread: Wait SQL statement(s) to be executed...\r\n"));
       
   201 	MainCritSect.Wait();
       
   202 
       
   203 	RDebug::Print(_L("+++:MainThread: Notify the worker thread to panic...\r\n"));
       
   204 	ThreadCritSect.Signal();
       
   205 	
       
   206 	User::WaitForRequest(status);
       
   207 	User::SetJustInTime(ETrue);	// enable debugger panic handling
       
   208 
       
   209 	TEST2(thread.ExitType(), EExitPanic);
       
   210 	TEST2(thread.ExitReason(), KPanicCode);
       
   211 	
       
   212 	thread.Close();
       
   213 
       
   214 	RDebug::Print(_L("+++:MainThread: Check the database content...\r\n"));
       
   215 	err = db.Open(KTestDbName);
       
   216 	TEST2(err, KErrNone);
       
   217 	_LIT8(KSelectSql, "SELECT COUNT(*) AS CNT FROM A");
       
   218 	RSqlStatement stmt;
       
   219 	err = stmt.Prepare(db, KSelectSql);
       
   220 	TEST2(err, KErrNone);
       
   221 	err = stmt.Next();
       
   222 	TEST2(err, KSqlAtRow);
       
   223 	TInt val = stmt.ColumnInt(0);
       
   224 	TEST(val == 0);
       
   225 	stmt.Close();
       
   226 	db.Close();
       
   227 
       
   228 	err = RSqlDatabase::Delete(KTestDbName);
       
   229 	TEST2(err, KErrNone);
       
   230 	}
       
   231 
       
   232 /**
       
   233 @SYMTestCaseID			SYSLIB-SQL-CT-1624
       
   234 @SYMTestCaseDesc		Transaction consistency test.
       
   235 						Create a test database with a table with a field with a CHECK constraint. 
       
   236 						Try to insert some records in a transaction violating the CHECK constraint.
       
   237 						The transaction should fail.
       
   238 						No records should be found in the test table.
       
   239 @SYMTestPriority		High
       
   240 @SYMTestActions			Transaction atomicity test.
       
   241 @SYMTestExpectedResults Test must not fail
       
   242 @SYMREQ					REQ5792
       
   243                         REQ5793
       
   244 */	
       
   245 void TransactionTest2()
       
   246 	{
       
   247 	//Create a test database
       
   248 	(void)RSqlDatabase::Delete(KTestDbName);
       
   249 	RSqlDatabase db;
       
   250 	TInt err = db.Create(KTestDbName);
       
   251 	TEST2(err, KErrNone);
       
   252 
       
   253 	//Create a test table
       
   254 	_LIT8(KCreateSql, "CREATE TABLE A(Id INTEGER, CHECK(Id > 10 AND Id <= 20))");
       
   255 	err = db.Exec(KCreateSql);
       
   256 	TEST(err >= 0);	
       
   257 
       
   258 	//Begin a transaction
       
   259 	_LIT8(KBeginTrans, "BEGIN");
       
   260 	err = db.Exec(KBeginTrans);
       
   261 	TEST(err >= 0);	
       
   262 	
       
   263 	//Exec SQL, viloate constraint.
       
   264 	_LIT8(KInsertSql, "INSERT INTO A(Id) VALUES(15); INSERT INTO A(Id) VALUES(38);");
       
   265 	err = db.Exec(KInsertSql);
       
   266 	TEST2(err, KSqlErrConstraint);
       
   267 
       
   268 	//Rollback transaction
       
   269 	_LIT8(KRollbackTrans, "ROLLBACK");
       
   270 	err = db.Exec(KRollbackTrans);
       
   271 	TEST(err >= 0);	
       
   272 
       
   273 	//Check the database content
       
   274 	_LIT8(KSelectSql, "SELECT COUNT(*) AS CNT FROM A");
       
   275 	RSqlStatement stmt;
       
   276 	err = stmt.Prepare(db, KSelectSql);
       
   277 	TEST2(err, KErrNone);
       
   278 	err = stmt.Next();
       
   279 	TEST2(err, KSqlAtRow);
       
   280 	TInt val = stmt.ColumnInt(0);
       
   281 	TEST2(val, 0);
       
   282 	stmt.Close();
       
   283 	
       
   284 	db.Close();
       
   285 
       
   286 	err = RSqlDatabase::Delete(KTestDbName);
       
   287 	TEST2(err, KErrNone);
       
   288 	}
       
   289 
       
   290 void DoTests()
       
   291 	{
       
   292 	TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1623 Transaction test 1 "));
       
   293 	TransactionTest1();
       
   294 
       
   295 	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1624 Transaction test 2 "));
       
   296 	TransactionTest2();
       
   297 	}
       
   298 
       
   299 TInt E32Main()
       
   300 	{
       
   301 	TheTest.Title();
       
   302 	
       
   303 	CTrapCleanup* tc = CTrapCleanup::New();
       
   304 	
       
   305 	__UHEAP_MARK;
       
   306 	
       
   307 	CreateTestDir();
       
   308 	DeleteTestFiles();
       
   309 	DoTests();
       
   310 	DeleteTestFiles();
       
   311 
       
   312 	__UHEAP_MARKEND;
       
   313 	
       
   314 	TheTest.End();
       
   315 	TheTest.Close();
       
   316 	
       
   317 	delete tc;
       
   318 
       
   319 	User::Heap().Check();
       
   320 	return KErrNone;
       
   321 	}