persistentstorage/sql/TEST/t_sqlood.cpp
changeset 0 08ec8eefde2f
child 8 fa9941cf3867
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 static RFs TheFs;
       
    23 RTest TheTest(_L("t_sqlood test"));
       
    24 
       
    25 #if  defined __WINSCW__ || defined __WINS__
       
    26 
       
    27 	//The C: drive may be too big and may be used concurently by other applications. 
       
    28 	//The T: drive is more suitable for the test if running on the emulator
       
    29 	const TInt KTestDrive = EDriveT;
       
    30 	_LIT(KTestDir, "t:\\test\\");
       
    31 	_LIT(KTestDatabase, "t:\\test\\t_sql_ood.db");
       
    32 	
       
    33 #elif defined __X86GCC__
       
    34 
       
    35 	const TInt KTestDrive = EDriveG;
       
    36 	_LIT(KTestDir, "g:\\test\\");
       
    37 	_LIT(KTestDatabase, "g:\\test\\t_sql_ood.db");
       
    38 	
       
    39 #else
       
    40 
       
    41 	const TInt KTestDrive = EDriveE;
       
    42 	_LIT(KTestDir, "e:\\test\\");
       
    43 	_LIT(KTestDatabase, "e:\\test\\t_sql_ood.db");
       
    44 	
       
    45 #endif
       
    46 
       
    47 //One or more files with KLargeFileName name and ".<n>" extension, where n is 
       
    48 //000, 001, 002, 003...
       
    49 //will be created and they will occupy almost all available disk space.
       
    50 //The idea is to perform after that one "delete"
       
    51 //transaction, which must to fail, because there won't be enough available disk space to complete the transaction.
       
    52 #if  defined __WINSCW__ || defined __WINS__
       
    53 
       
    54 	_LIT(KLargeFileName, "t:\\test\\DeleteMe");
       
    55 
       
    56 #elif defined __X86GCC__
       
    57 
       
    58 	_LIT(KLargeFileName, "g:\\test\\DeleteMe");
       
    59 
       
    60 #else
       
    61 
       
    62 	_LIT(KLargeFileName, "e:\\test\\DeleteMe");
       
    63 
       
    64 #endif
       
    65 
       
    66 const TInt KTestRecordsCount = 350;
       
    67 
       
    68 ///////////////////////////////////////////////////////////////////////////////////////
       
    69 
       
    70 //Assemblesd a file name from "aFileName" and "aFileNumber" parameters and places the resulting string in "aResultPath".
       
    71 void AssembleLargeFileName(const TDesC& aFileName, TInt aFileNumber, TDes& aResultPath)
       
    72 	{
       
    73 	_LIT(KFormatStr, "%S.%03d");
       
    74 	aResultPath.Format(KFormatStr, &aFileName, aFileNumber);
       
    75 	}
       
    76 
       
    77 //Deletes all created large data files.
       
    78 void DeleteLargeDataFiles()
       
    79 	{
       
    80 	TInt err = KErrNone;
       
    81 	TInt i = -1;
       
    82 	while(err == KErrNone)
       
    83 		{
       
    84 		TBuf<KMaxFileName> filePath;
       
    85 		::AssembleLargeFileName(KLargeFileName, ++i, filePath);
       
    86 		err = TheFs.Delete(filePath);
       
    87 		}
       
    88 	}
       
    89 
       
    90 //Deletes all created test files.
       
    91 void DeleteTestFiles()
       
    92 	{
       
    93 	DeleteLargeDataFiles();
       
    94 	(void)RSqlDatabase::Delete(KTestDatabase);
       
    95 	}
       
    96 
       
    97 ///////////////////////////////////////////////////////////////////////////////////////
       
    98 ///////////////////////////////////////////////////////////////////////////////////////
       
    99 //Test macros and functions
       
   100 void Check1(TInt aValue, TInt aLine)
       
   101 	{
       
   102 	if(!aValue)
       
   103 		{
       
   104 		DeleteTestFiles();
       
   105 		RDebug::Print(_L("*** Line %d\r\n"), aLine);
       
   106 		TheTest(EFalse, aLine);
       
   107 		}
       
   108 	}
       
   109 void Check2(TInt aValue, TInt aExpected, TInt aLine)
       
   110 	{
       
   111 	if(aValue != aExpected)
       
   112 		{
       
   113 		DeleteTestFiles();
       
   114 		RDebug::Print(_L("*** Line %d, Expected error: %d, got: %d\r\n"), aLine, aExpected, aValue);
       
   115 		TheTest(EFalse, aLine);
       
   116 		}
       
   117 	}
       
   118 #define TEST(arg) ::Check1((arg), __LINE__)
       
   119 #define TEST2(aValue, aExpected) ::Check2(aValue, aExpected, __LINE__)
       
   120 
       
   121 ///////////////////////////////////////////////////////////////////////////////////////
       
   122 
       
   123 //Creates file session instance and the test directory
       
   124 void CreateTestEnv()
       
   125     {
       
   126 	TInt err = TheFs.Connect();
       
   127 	TEST2(err, KErrNone);
       
   128 
       
   129 	err = TheFs.MkDir(KTestDir);
       
   130 	TEST(err == KErrNone || err == KErrAlreadyExists);
       
   131 	}
       
   132 
       
   133 //Creates one or more large files with the total size near to the size of the available disk space.
       
   134 //The idea is to cause an "out of disk space" condition.
       
   135 void FillLargeDataFile(RFile& aFile, TInt aSize)
       
   136 	{
       
   137 	TInt err = KErrDiskFull;
       
   138 	while(err == KErrDiskFull)
       
   139 		{
       
   140 		err = aFile.SetSize(aSize);
       
   141 		aSize -= 100;
       
   142 		if(aSize <= 0)
       
   143 			{
       
   144 			break;
       
   145 			}
       
   146 		}
       
   147 	TEST(err == KErrNone || err == KErrDiskFull);
       
   148 	}
       
   149 
       
   150 //Gets and returns the available disk space of the tested drive.
       
   151 TInt64 FreeDiskSpace()
       
   152 	{
       
   153 	TVolumeInfo volInfoBefore;
       
   154 	TInt err = TheFs.Volume(volInfoBefore, KTestDrive);
       
   155 	TEST2(err, KErrNone);
       
   156 	return volInfoBefore.iFree;
       
   157 	}
       
   158 
       
   159 //Creates a large data file with aSize size (in bytes).
       
   160 void DoCreateLargeFile(const TDesC& aPath, TInt aSize)
       
   161 	{
       
   162 	RFile file;
       
   163 	TInt err = file.Replace(TheFs, aPath, EFileRead | EFileWrite);
       
   164 	TEST2(err, KErrNone);
       
   165 	FillLargeDataFile(file, aSize);
       
   166 	err = file.Flush();
       
   167 	TEST2(err, KErrNone);
       
   168 	file.Close();
       
   169 	}
       
   170 
       
   171 //Creates enough number of large data files to fill the available disk space.
       
   172 void CreateLargeFile()
       
   173 	{
       
   174 	TInt fileNo = 0;
       
   175 	const TInt KLargeFileSize = 1000000000;
       
   176 	TInt64 diskSpace = ::FreeDiskSpace();
       
   177 	RDebug::Print(_L("CreateLargeFile: free space before = %ld\r\n"), diskSpace);
       
   178 	TBuf<KMaxFileName> filePath;
       
   179 	while(diskSpace > KLargeFileSize)
       
   180 		{
       
   181 		AssembleLargeFileName(KLargeFileName, fileNo++, filePath);
       
   182 		DoCreateLargeFile(filePath, KLargeFileSize);
       
   183 		diskSpace = ::FreeDiskSpace();
       
   184 		RDebug::Print(_L("----CreateLargeFile, step %d, free space = %ld\r\n"), fileNo, diskSpace);
       
   185 		}
       
   186 	//Reserve almost all disk space, except a small amount - 200 bytes.
       
   187 	if(diskSpace > 0)
       
   188 		{
       
   189 		::AssembleLargeFileName(KLargeFileName, fileNo++, filePath);
       
   190 		const TInt64 KSpaceLeft = 200;
       
   191 		TInt64 lastFileSize = diskSpace - KSpaceLeft;
       
   192         TInt lastFileSize32 = I64LOW(lastFileSize);
       
   193 		RDebug::Print(_L("----file size32 = %d\r\n"), lastFileSize32);
       
   194 		::DoCreateLargeFile(filePath, lastFileSize32);
       
   195 		RDebug::Print(_L("----CreateLargeFile, last step (%d), file size = %ld\r\n"), fileNo, lastFileSize);
       
   196 		}
       
   197 	diskSpace = ::FreeDiskSpace();
       
   198 	RDebug::Print(_L("CreateLargeFile: free space after = %ld\r\n"), diskSpace);
       
   199 	}
       
   200 
       
   201 //Creates and fills with some records a test database
       
   202 void CreateAndFillTestDatabase(RSqlDatabase& aDb)
       
   203 	{
       
   204 	TInt err = aDb.Create(KTestDatabase);
       
   205 	TEST2(err, KErrNone);
       
   206 	err = aDb.Exec(_L("CREATE TABLE A(Id INTEGER, Data TEXT)"));
       
   207 	TEST(err >= 0);
       
   208 	err = aDb.Exec(_L("BEGIN TRANSACTION"));
       
   209 	TEST(err >= 0);
       
   210 	for(TInt i=0;i<KTestRecordsCount;++i)
       
   211 		{
       
   212 		TBuf<200> sql;
       
   213 		sql.Format(_L("INSERT INTO A(Id, Data) VALUES(%d, 'A0123456789B0123456789C0123456789D0123456789E0123456789F0123456789G0123456789H0123456789')"), i + 1);
       
   214 		err = aDb.Exec(sql);
       
   215 		TEST2(err, 1);
       
   216 		}
       
   217 	err = aDb.Exec(_L("COMMIT TRANSACTION"));
       
   218 	TEST(err >= 0);
       
   219 	}
       
   220 
       
   221 //Tries to delete test database records
       
   222 TInt DeleteTestRecords(RSqlDatabase& aDb)
       
   223 	{
       
   224 	TInt err = aDb.Exec(_L("BEGIN TRANSACTION"));
       
   225 	TEST(err >= 0);
       
   226 	for(TInt i=0;i<KTestRecordsCount;++i)
       
   227 		{
       
   228 		TBuf<100> sql;
       
   229 		sql.Format(_L("DELETE FROM A WHERE Id = %d"), i + 1);
       
   230 		err = aDb.Exec(sql);// May fail with KErrDiskFull
       
   231 		if(err < 0)
       
   232 			{
       
   233 			(void)aDb.Exec(_L("ROLLBACK TRANSACTION"));
       
   234 			return err;
       
   235 			}
       
   236 		}
       
   237 	err = aDb.Exec(_L("COMMIT TRANSACTION"));// May fail with KErrDiskFull
       
   238 	return err;
       
   239 	}
       
   240 
       
   241 ///////////////////////////////////////////////////////////////////////////////////////
       
   242 
       
   243 //The function simply calls RSqlDatabase::ReserveDriveSpace(), RSqlDatabase::GetReserveAccess(),
       
   244 //RSqlDatabase::ReleaseReserveAccess() methods and checks the return values.
       
   245 //It might be usefull for debugging in case if something gets wrong.
       
   246 void SimpleCallsTest()
       
   247 	{
       
   248 	RSqlDatabase db, db2;
       
   249 	TInt err = db.Create(KTestDatabase);
       
   250 	TEST2(err, KErrNone);
       
   251 
       
   252 	err = db2.Open(KTestDatabase);
       
   253 	TEST2(err, KErrNone);
       
   254 	
       
   255 	//An attempt to get an access to the reserved space (which is not reserved yet).
       
   256 	err = db.GetReserveAccess();
       
   257 	TEST2(err, KErrNotFound);
       
   258 
       
   259 	//Reserve disk space
       
   260 	err = db.ReserveDriveSpace(0);
       
   261 	TEST2(err, KErrNone);
       
   262 
       
   263 	//An attempt to re-reserve it
       
   264    	err = db.ReserveDriveSpace(0);
       
   265 	TEST2(err, KErrAlreadyExists);
       
   266 
       
   267 	//Get an access to the reserved disk space
       
   268 	err = db.GetReserveAccess();
       
   269 	TEST2(err, KErrNone);
       
   270 
       
   271 	//Reserve disk space from the second connection
       
   272 	err = db2.ReserveDriveSpace(0);
       
   273 	TEST2(err, KErrNone);
       
   274 
       
   275 	//An attempt to get an access to the reserved space twice.
       
   276 	err = db.GetReserveAccess();
       
   277 	TEST2(err, KErrInUse);
       
   278 
       
   279 	//An attempt to get an access to the reserved space from the second connection.
       
   280 	err = db2.GetReserveAccess();
       
   281 	TEST2(err, KErrNone);
       
   282 
       
   283 	db.ReleaseReserveAccess();
       
   284 
       
   285 	//An attempt to release the reserved space twice.
       
   286 	db.ReleaseReserveAccess();
       
   287 
       
   288 	//Free the reserved disk space
       
   289 	db.FreeReservedSpace();
       
   290 
       
   291 	//Free the reserved disk space twice.
       
   292 	db.FreeReservedSpace();
       
   293 
       
   294 	//Free the reserved disk space from the second connection.
       
   295 	db2.FreeReservedSpace();
       
   296 
       
   297 	db2.Close();
       
   298 	db.Close();
       
   299 	(void)RSqlDatabase::Delete(KTestDatabase);
       
   300 	}
       
   301 
       
   302 /**
       
   303 @SYMTestCaseID			SYSLIB-SQL-CT-1649
       
   304 @SYMTestCaseDesc		SQL database "out of disk space" tests.
       
   305 						The test creates and fills with some records a test database and then reserves a disk space.
       
   306 						The second step: the test fills almost all available disk space creting large data files.
       
   307 						The third step: the test attempts to delete all records from the test database and fails with
       
   308 						KErrDiskFull error.
       
   309 						The fourth step: the test gets an access to the reserved disk space and attempts to delete
       
   310 						records again. This time the test should not fail.
       
   311 @SYMTestPriority		High
       
   312 @SYMTestActions			SQL database "out of disk space" tests.
       
   313 @SYMTestExpectedResults Test must not fail
       
   314 @SYMREQ					REQ5792
       
   315                         REQ5793
       
   316 */
       
   317 void DeleteTransactionTest()
       
   318 	{
       
   319 	TVolumeIOParamInfo volIoPrm;
       
   320 	TInt err = TheFs.VolumeIOParam(KTestDrive, volIoPrm);
       
   321     TEST2(err, KErrNone);
       
   322     RDebug::Print(_L("--Drive %d. BlockSize=%d, ClusterSize=%d, RecReadBufSize=%d, RecWriteBufSize=%d\r\n"), KTestDrive, volIoPrm.iBlockSize, volIoPrm.iClusterSize, volIoPrm.iRecReadBufSize, volIoPrm.iRecWriteBufSize);
       
   323 	/////////////////////////////////////////////////////////
       
   324     RDebug::Print(_L("--Create and fill database \"%S\".\r\n"), &KTestDatabase);
       
   325 	RSqlDatabase db;
       
   326 	CreateAndFillTestDatabase(db);
       
   327 	db.Close();//When the database gets closed, the persisted journal file will be deleted.
       
   328     RDebug::Print(_L("--Close and reopen database \"%S\" (in order to get the persisted journal file deleted).\r\n"), &KTestDatabase);
       
   329     err = db.Open(KTestDatabase);
       
   330     TEST2(err, KErrNone);
       
   331     RDebug::Print(_L("--Reserve disk space for database \"%S\".\r\n"), &KTestDatabase);
       
   332     err = db.ReserveDriveSpace(0);
       
   333 	TEST2(err, KErrNone);
       
   334     RDebug::Print(_L("--Simulate an \"out of disk space\" situation with creating a very large data file, which occupies almost the all the available disk space.\r\n"));
       
   335 	CreateLargeFile();
       
   336 	RDebug::Print(_L("--Attempt to delete test data records. The transaction must fail, because of \"out of disk space\".\r\n"));
       
   337 	err = DeleteTestRecords(db);
       
   338 	TEST2(err, KErrDiskFull);
       
   339     RDebug::Print(_L("--Get an access to the reserved disk space.\r\n"));
       
   340 	err = db.GetReserveAccess();
       
   341 	TEST2(err, KErrNone);
       
   342     TInt64 diskSpace = ::FreeDiskSpace();
       
   343     RDebug::Print(_L("After GetReserveAccess(), free disk space = %ld. Try again \"Delete records\" transaction. The transaction must not fail.\r\n"), diskSpace);
       
   344 	err = DeleteTestRecords(db);
       
   345 	RDebug::Print(_L("--DeleteTestRecords() returned %d error.\r\n"), err);
       
   346 	TEST(err >= 0);
       
   347 	//Releases the access to the reserved disk space
       
   348 	db.ReleaseReserveAccess();
       
   349 	//Frees the reserved disk space
       
   350 	db.FreeReservedSpace();
       
   351     //Free the resources, used in the test
       
   352 	DeleteLargeDataFiles();
       
   353 	//Verify that the records have been deleted
       
   354 	RSqlStatement stmt;
       
   355 	err = stmt.Prepare(db, _L("SELECT COUNT(*) FROM A"));
       
   356 	TEST2(err, KErrNone);
       
   357 	err = stmt.Next();
       
   358 	TEST2(err, KSqlAtRow);
       
   359 	TInt recCount = stmt.ColumnInt(0);
       
   360 	TEST2(recCount, 0);
       
   361 	stmt.Close();
       
   362 	db.Close();
       
   363 	(void)RSqlDatabase::Delete(KTestDatabase);
       
   364 	}
       
   365 
       
   366 //OOD API tests with more than one connection to the same SQL database.
       
   367 //The test calls ReserveDriveSpace/GetReserveAccess/ReleaseReserveAccess in a different
       
   368 //combinations on four RSqlDatabase objects, connected to the same database .
       
   369 //The test should not fail or panic.
       
   370 void MultiDbTest()
       
   371     {
       
   372     RSqlDatabase db1;
       
   373 	CreateAndFillTestDatabase(db1);
       
   374 
       
   375     RSqlDatabase db2;
       
   376     TInt err = db2.Open(KTestDatabase);
       
   377     TEST2(err, KErrNone);
       
   378 
       
   379     //Play with "ReserveDriveSpace" on both sessions
       
   380     err = db1.ReserveDriveSpace(0);
       
   381     TEST2(err, KErrNone);
       
   382     err = db2.ReserveDriveSpace(0);
       
   383     TEST2(err, KErrNone);
       
   384     db2.FreeReservedSpace();
       
   385     err = db2.ReserveDriveSpace(0);
       
   386     TEST2(err, KErrNone);
       
   387 
       
   388     //Get an access to the reserved space through db2
       
   389 	err = db2.GetReserveAccess();
       
   390     TEST2(err, KErrNone);
       
   391     //Free/re-reserve disk space for db1.
       
   392     db1.FreeReservedSpace();
       
   393     err = db1.ReserveDriveSpace(0);
       
   394     TEST2(err, KErrNone);
       
   395 
       
   396     RSqlDatabase db4;
       
   397     err = db4.Open(KTestDatabase);
       
   398     TEST2(err, KErrNone);
       
   399 
       
   400     //Try to reserve space for db4.
       
   401     err = db4.ReserveDriveSpace(0);
       
   402     TEST2(err, KErrNone);
       
   403 
       
   404     RSqlDatabase db3;
       
   405     err = db3.Open(KTestDatabase);
       
   406     TEST2(err, KErrNone);
       
   407 
       
   408     //Try to reserve space for session db3.
       
   409     err = db3.ReserveDriveSpace(0);
       
   410     TEST2(err, KErrNone);
       
   411 
       
   412     //Release and free db2 access to the reserved space.
       
   413     db2.ReleaseReserveAccess();
       
   414     db2.FreeReservedSpace();
       
   415 
       
   416     db3.FreeReservedSpace();
       
   417     db3.Close();
       
   418 
       
   419     db4.FreeReservedSpace();
       
   420     db4.Close();
       
   421 
       
   422     //Get an access to the reserved space through db2.
       
   423     //But it was freed, so the call will fail.
       
   424 	err = db2.GetReserveAccess();
       
   425     TEST2(err, KErrNotFound);
       
   426 
       
   427     //Free/re-reserve disk space for db1.
       
   428     db1.FreeReservedSpace();
       
   429     err = db1.ReserveDriveSpace(0);
       
   430     TEST2(err, KErrNone);
       
   431 
       
   432     //Get/release the access to the reserved space for db1.
       
   433 	err = db1.GetReserveAccess();
       
   434     TEST2(err, KErrNone);
       
   435     db1.ReleaseReserveAccess();
       
   436 
       
   437     //Get an access to the reserved space for db2.
       
   438     //The call will fail because there is no reserved disk space for db2.
       
   439 	err = db2.GetReserveAccess();
       
   440     TEST2(err, KErrNotFound);
       
   441 
       
   442     //Free the reserved space - db1
       
   443     db1.FreeReservedSpace();
       
   444 
       
   445 	db2.Close();
       
   446 	db1.Close();
       
   447 
       
   448 	(void)RSqlDatabase::Delete(KTestDatabase);
       
   449     }
       
   450 
       
   451 void DoTests()
       
   452 	{
       
   453 	TheTest.Start(_L(" \"Simple calls\" OOD test "));
       
   454 	SimpleCallsTest();
       
   455 
       
   456 	TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-CT-1649 \"Delete transaction\" OOD test "));
       
   457 	DeleteTransactionTest();
       
   458 
       
   459 	TheTest.Next(_L(" Multi db OOD test "));
       
   460 	MultiDbTest();
       
   461 	}
       
   462 
       
   463 TInt E32Main()
       
   464 	{
       
   465 	TheTest.Title();
       
   466 
       
   467 	CTrapCleanup* tc = CTrapCleanup::New();
       
   468 
       
   469 	__UHEAP_MARK;
       
   470 
       
   471 	CreateTestEnv();
       
   472 	DeleteTestFiles();
       
   473 	DoTests();
       
   474 	DeleteTestFiles();
       
   475 	TheFs.Close();
       
   476 
       
   477 	__UHEAP_MARKEND;
       
   478 
       
   479 	TheTest.End();
       
   480 	TheTest.Close();
       
   481 
       
   482 	delete tc;
       
   483 
       
   484 	User::Heap().Check();
       
   485 	return KErrNone;
       
   486 	}