|
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 } |