1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sql/TEST/t_sqltrans.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,321 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <e32test.h>
1.20 +#include <bautils.h>
1.21 +#include <sqldb.h>
1.22 +
1.23 +///////////////////////////////////////////////////////////////////////////////////////
1.24 +
1.25 +#define UNUSED_VAR(a) (a) = (a)
1.26 +
1.27 +RTest TheTest(_L("t_sqltrans test"));
1.28 +
1.29 +_LIT(KTestDir, "c:\\test\\");
1.30 +_LIT(KTestDbName, "c:\\test\\t_sqltrans.db");
1.31 +
1.32 +///////////////////////////////////////////////////////////////////////////////////////
1.33 +
1.34 +void DeleteTestFiles()
1.35 + {
1.36 + RSqlDatabase::Delete(KTestDbName);
1.37 + }
1.38 +
1.39 +///////////////////////////////////////////////////////////////////////////////////////
1.40 +///////////////////////////////////////////////////////////////////////////////////////
1.41 +//Test macros and functions
1.42 +void Check1(TInt aValue, TInt aLine, TBool aPrintThreadName = EFalse)
1.43 + {
1.44 + if(!aValue)
1.45 + {
1.46 + DeleteTestFiles();
1.47 + if(aPrintThreadName)
1.48 + {
1.49 + RThread th;
1.50 + TName name = th.Name();
1.51 + RDebug::Print(_L("*** Thread %S, Line %d\r\n"), &name, aLine);
1.52 + }
1.53 + else
1.54 + {
1.55 + RDebug::Print(_L("*** Line %d\r\n"), aLine);
1.56 + }
1.57 + TheTest(EFalse, aLine);
1.58 + }
1.59 + }
1.60 +void Check2(TInt aValue, TInt aExpected, TInt aLine, TBool aPrintThreadName = EFalse)
1.61 + {
1.62 + if(aValue != aExpected)
1.63 + {
1.64 + DeleteTestFiles();
1.65 + if(aPrintThreadName)
1.66 + {
1.67 + RThread th;
1.68 + TName name = th.Name();
1.69 + RDebug::Print(_L("*** Thread %S, Line %d Expected error: %d, got: %d\r\n"), &name, aLine, aExpected, aValue);
1.70 + }
1.71 + else
1.72 + {
1.73 + RDebug::Print(_L("*** Line %d, Expected error: %d, got: %d\r\n"), aLine, aExpected, aValue);
1.74 + }
1.75 + TheTest(EFalse, aLine);
1.76 + }
1.77 + }
1.78 +#define TEST(arg) ::Check1((arg), __LINE__)
1.79 +#define TEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__)
1.80 +#define TTEST(arg) ::Check1((arg), __LINE__, ETrue)
1.81 +#define TTEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__, ETrue)
1.82 +
1.83 +///////////////////////////////////////////////////////////////////////////////////////
1.84 +
1.85 +void CreateTestDir()
1.86 + {
1.87 + RFs fs;
1.88 + TInt err = fs.Connect();
1.89 + TEST2(err, KErrNone);
1.90 +
1.91 + err = fs.MkDir(KTestDir);
1.92 + TEST(err == KErrNone || err == KErrAlreadyExists);
1.93 +
1.94 + fs.Close();
1.95 + }
1.96 +
1.97 +///////////////////////////////////////////////////////////////////////////////////////
1.98 +
1.99 +_LIT8(KTestSql1, "INSERT INTO A(Id) VALUES(1); INSERT INTO A(Id) VALUES(2);");
1.100 +
1.101 +const TPtrC8 KSqls[] = {KTestSql1()};
1.102 +
1.103 +static RCriticalSection ThreadCritSect;
1.104 +static RCriticalSection MainCritSect;
1.105 +
1.106 +static TInt TheSqlIdx = 0;
1.107 +
1.108 +_LIT(KPanicCategory, "TransFail");
1.109 +const TInt KPanicCode = 0x1234;
1.110 +
1.111 +//Test thread function
1.112 +TInt ThreadFunc1(void*)
1.113 + {
1.114 + __UHEAP_MARK;
1.115 +
1.116 + CTrapCleanup* tc = CTrapCleanup::New();
1.117 + TTEST(tc != NULL);
1.118 +
1.119 + __ASSERT_ALWAYS(TheSqlIdx >= 0 && TheSqlIdx < (TInt)(sizeof(KSqls) / sizeof(KSqls[0])), User::Invariant());
1.120 + const TPtrC8 sql = KSqls[TheSqlIdx];
1.121 +
1.122 + //Open test database
1.123 + RSqlDatabase db;
1.124 + TInt err = db.Open(KTestDbName);
1.125 + TTEST2(err, KErrNone);
1.126 +
1.127 + RDebug::Print(_L("---:WorkThread: Begin transaction. Exec SQL...\r\n"));
1.128 +
1.129 + //Begin a transaction
1.130 + _LIT8(KBeginTrans, "BEGIN");
1.131 + err = db.Exec(KBeginTrans);
1.132 + TTEST(err >= 0);
1.133 +
1.134 + //Execute the SQL statement(s)
1.135 + err = db.Exec(sql);
1.136 + TTEST(err >= 0);
1.137 +
1.138 + RDebug::Print(_L("---:WorkThread: Notify the main thread about the SQL statement execution\r\n"));
1.139 + MainCritSect.Signal();
1.140 +
1.141 + RDebug::Print(_L("---:WorkThread: Wait for permisson to continue...\r\n"));
1.142 + ThreadCritSect.Wait();
1.143 +
1.144 + User::SetJustInTime(EFalse); // disable debugger panic handling
1.145 +
1.146 + //Panic current thread without commiting the transaction
1.147 + RDebug::Print(_L("---:WorkThread: Panic!\r\n"));
1.148 + User::Panic(KPanicCategory, KPanicCode);
1.149 +
1.150 + delete tc;
1.151 +
1.152 + __UHEAP_MARKEND;
1.153 +
1.154 + return KErrNone;
1.155 + }
1.156 +
1.157 +/**
1.158 +@SYMTestCaseID SYSLIB-SQL-CT-1623
1.159 +@SYMTestCaseDesc Transaction atomicity test.
1.160 + Create a test database with a table.
1.161 + Create a worker thread and make some "insert record" operations in a transaction from
1.162 + that thread. Before commiting the transaction notify the main thread that the
1.163 + insert operation completed and wait for a notification from the main thread.
1.164 + The main thread notifies the worker thread to panic and checks the test table
1.165 + content. No records should be found there.
1.166 +@SYMTestPriority High
1.167 +@SYMTestActions Transaction atomicity test.
1.168 +@SYMTestExpectedResults Test must not fail
1.169 +@SYMREQ REQ5792
1.170 + REQ5793
1.171 +*/
1.172 +void TransactionTest1()
1.173 + {
1.174 + RDebug::Print(_L("+++:MainThread: Create critical sections\r\n"));
1.175 + TEST2(ThreadCritSect.CreateLocal(), KErrNone);
1.176 + ThreadCritSect.Wait();
1.177 + TEST2(MainCritSect.CreateLocal(), KErrNone);
1.178 + MainCritSect.Wait();
1.179 +
1.180 + RDebug::Print(_L("+++:MainThread: Create test database\r\n"));
1.181 + (void)RSqlDatabase::Delete(KTestDbName);
1.182 + RSqlDatabase db;
1.183 + TInt err = db.Create(KTestDbName);
1.184 + TEST2(err, KErrNone);
1.185 +
1.186 + RDebug::Print(_L("+++:MainThread: Create a table in the test database\r\n"));
1.187 + _LIT8(KCreateSql, "CREATE TABLE A(Id INTEGER)");
1.188 + err = db.Exec(KCreateSql);
1.189 + TEST(err >= 0);
1.190 +
1.191 + db.Close();
1.192 +
1.193 + RDebug::Print(_L("+++:MainThread: Create the worker thread\r\n"));
1.194 + _LIT(KThreadName, "WorkThrd");
1.195 + RThread thread;
1.196 + TheSqlIdx = 0;
1.197 + TEST2(thread.Create(KThreadName, &ThreadFunc1, 0x2000, 0x1000, 0x10000, NULL, EOwnerProcess), KErrNone);
1.198 + TRequestStatus status;
1.199 + thread.Logon(status);
1.200 + TEST2(status.Int(), KRequestPending);
1.201 + thread.Resume();
1.202 +
1.203 + RDebug::Print(_L("+++:MainThread: Wait SQL statement(s) to be executed...\r\n"));
1.204 + MainCritSect.Wait();
1.205 +
1.206 + RDebug::Print(_L("+++:MainThread: Notify the worker thread to panic...\r\n"));
1.207 + ThreadCritSect.Signal();
1.208 +
1.209 + User::WaitForRequest(status);
1.210 + User::SetJustInTime(ETrue); // enable debugger panic handling
1.211 +
1.212 + TEST2(thread.ExitType(), EExitPanic);
1.213 + TEST2(thread.ExitReason(), KPanicCode);
1.214 +
1.215 + thread.Close();
1.216 +
1.217 + RDebug::Print(_L("+++:MainThread: Check the database content...\r\n"));
1.218 + err = db.Open(KTestDbName);
1.219 + TEST2(err, KErrNone);
1.220 + _LIT8(KSelectSql, "SELECT COUNT(*) AS CNT FROM A");
1.221 + RSqlStatement stmt;
1.222 + err = stmt.Prepare(db, KSelectSql);
1.223 + TEST2(err, KErrNone);
1.224 + err = stmt.Next();
1.225 + TEST2(err, KSqlAtRow);
1.226 + TInt val = stmt.ColumnInt(0);
1.227 + TEST(val == 0);
1.228 + stmt.Close();
1.229 + db.Close();
1.230 +
1.231 + err = RSqlDatabase::Delete(KTestDbName);
1.232 + TEST2(err, KErrNone);
1.233 + }
1.234 +
1.235 +/**
1.236 +@SYMTestCaseID SYSLIB-SQL-CT-1624
1.237 +@SYMTestCaseDesc Transaction consistency test.
1.238 + Create a test database with a table with a field with a CHECK constraint.
1.239 + Try to insert some records in a transaction violating the CHECK constraint.
1.240 + The transaction should fail.
1.241 + No records should be found in the test table.
1.242 +@SYMTestPriority High
1.243 +@SYMTestActions Transaction atomicity test.
1.244 +@SYMTestExpectedResults Test must not fail
1.245 +@SYMREQ REQ5792
1.246 + REQ5793
1.247 +*/
1.248 +void TransactionTest2()
1.249 + {
1.250 + //Create a test database
1.251 + (void)RSqlDatabase::Delete(KTestDbName);
1.252 + RSqlDatabase db;
1.253 + TInt err = db.Create(KTestDbName);
1.254 + TEST2(err, KErrNone);
1.255 +
1.256 + //Create a test table
1.257 + _LIT8(KCreateSql, "CREATE TABLE A(Id INTEGER, CHECK(Id > 10 AND Id <= 20))");
1.258 + err = db.Exec(KCreateSql);
1.259 + TEST(err >= 0);
1.260 +
1.261 + //Begin a transaction
1.262 + _LIT8(KBeginTrans, "BEGIN");
1.263 + err = db.Exec(KBeginTrans);
1.264 + TEST(err >= 0);
1.265 +
1.266 + //Exec SQL, viloate constraint.
1.267 + _LIT8(KInsertSql, "INSERT INTO A(Id) VALUES(15); INSERT INTO A(Id) VALUES(38);");
1.268 + err = db.Exec(KInsertSql);
1.269 + TEST2(err, KSqlErrConstraint);
1.270 +
1.271 + //Rollback transaction
1.272 + _LIT8(KRollbackTrans, "ROLLBACK");
1.273 + err = db.Exec(KRollbackTrans);
1.274 + TEST(err >= 0);
1.275 +
1.276 + //Check the database content
1.277 + _LIT8(KSelectSql, "SELECT COUNT(*) AS CNT FROM A");
1.278 + RSqlStatement stmt;
1.279 + err = stmt.Prepare(db, KSelectSql);
1.280 + TEST2(err, KErrNone);
1.281 + err = stmt.Next();
1.282 + TEST2(err, KSqlAtRow);
1.283 + TInt val = stmt.ColumnInt(0);
1.284 + TEST2(val, 0);
1.285 + stmt.Close();
1.286 +
1.287 + db.Close();
1.288 +
1.289 + err = RSqlDatabase::Delete(KTestDbName);
1.290 + TEST2(err, KErrNone);
1.291 + }
1.292 +
1.293 +void DoTests()
1.294 + {
1.295 + TheTest.Start(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1623 Transaction test 1 "));
1.296 + TransactionTest1();
1.297 +
1.298 + TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1624 Transaction test 2 "));
1.299 + TransactionTest2();
1.300 + }
1.301 +
1.302 +TInt E32Main()
1.303 + {
1.304 + TheTest.Title();
1.305 +
1.306 + CTrapCleanup* tc = CTrapCleanup::New();
1.307 +
1.308 + __UHEAP_MARK;
1.309 +
1.310 + CreateTestDir();
1.311 + DeleteTestFiles();
1.312 + DoTests();
1.313 + DeleteTestFiles();
1.314 +
1.315 + __UHEAP_MARKEND;
1.316 +
1.317 + TheTest.End();
1.318 + TheTest.Close();
1.319 +
1.320 + delete tc;
1.321 +
1.322 + User::Heap().Check();
1.323 + return KErrNone;
1.324 + }