|
1 // Copyright (c) 1997-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 <e32math.h> |
|
18 #include <f32file.h> |
|
19 #include <s32file.h> |
|
20 #include <cntdb.h> |
|
21 #include <cntitem.h> |
|
22 #include <cntfield.h> |
|
23 #include <cntfldst.h> |
|
24 #include "T_UTILS.H" |
|
25 |
|
26 // Type definitions |
|
27 CCntTest* CntTest=NULL; |
|
28 LOCAL_D RTest test(_L("T_FERROR")); |
|
29 LOCAL_D RFile logFile; |
|
30 LOCAL_D RFile threadLogFile; |
|
31 |
|
32 const TPtrC KDatabaseFileName=_L("C:T_FERROR"); |
|
33 const TPtrC KDatabaseRemoveableFileName=_L("D:T_FERROR2"); |
|
34 |
|
35 const TPtrC KLogFileName=_L("C:\\T_FERROR.LOG"); |
|
36 const TPtrC KThreadLogFileName=_L("C:\\T_FERROR2.LOG"); |
|
37 const TInt KNumTestContacts=5; |
|
38 |
|
39 class CFred2 : public CBase |
|
40 { |
|
41 public: |
|
42 ~CFred2(); |
|
43 void ConstructL(); |
|
44 void WaitForLogon(); |
|
45 void Kill(); |
|
46 void DoDamageL(); |
|
47 protected: |
|
48 RThread iThread; |
|
49 TRequestStatus iLogonStatus; |
|
50 }; |
|
51 |
|
52 class CContactReadWriter : public CIdle, public MContactDbObserver |
|
53 { |
|
54 public: |
|
55 static CContactReadWriter *NewLC(); |
|
56 static TInt CallbackL(TAny *xThis); |
|
57 private: |
|
58 TInt DoWorkL(); |
|
59 CContactReadWriter(); |
|
60 ~CContactReadWriter(); |
|
61 void SetNameL(CContactItem& aItem,TUid aVcardType,const TDesC& aName); |
|
62 TPtrC Name(CContactItem& aItem); |
|
63 TBool AddNewContactsL(); |
|
64 TBool EditContactsL(); |
|
65 TBool DeleteContactsL(); |
|
66 void PrintRecovering() const; |
|
67 void PrintErr(TInt aErr) const; |
|
68 public: // from MContactDbObserver |
|
69 void HandleDatabaseEventL(TContactDbObserverEvent aEvent); |
|
70 private: |
|
71 TBool iSuspendWork; |
|
72 TInt iSubState; |
|
73 TInt iState; |
|
74 CContactDatabase* iDb; |
|
75 CArrayFix<TContactItemId>* iIdList; |
|
76 CContactChangeNotifier *iNotify; |
|
77 }; |
|
78 |
|
79 LOCAL_C void doWriteToLogL(RFile &aFile, const TDesC &aLog, TInt aParam, TInt aParam2) |
|
80 { |
|
81 TBuf<128> buf; |
|
82 TTime time; |
|
83 time.UniversalTime(); |
|
84 time.FormatL(buf,_L("%T:%S.%*C3-")); |
|
85 TFileText textFile; |
|
86 textFile.Set(aFile); |
|
87 User::LeaveIfError(textFile.Write(buf)); |
|
88 buf.Format(aLog,aParam,aParam2); |
|
89 User::LeaveIfError(textFile.Write(buf)); |
|
90 aFile.Flush(); |
|
91 } |
|
92 |
|
93 LOCAL_C void WriteToLogL(const TDesC &aLog, TInt aParam=0, TInt aParam2=0) |
|
94 { |
|
95 doWriteToLogL(logFile,aLog,aParam,aParam2); |
|
96 } |
|
97 |
|
98 LOCAL_C void WriteToThreadLogL(const TDesC &aLog, TInt aParam=0, TInt aParam2=0) |
|
99 { |
|
100 doWriteToLogL(threadLogFile,aLog,aParam,aParam2); |
|
101 } |
|
102 |
|
103 // |
|
104 // CContactReadWriter |
|
105 // |
|
106 |
|
107 void CContactReadWriter::HandleDatabaseEventL(TContactDbObserverEvent aEvent) |
|
108 { |
|
109 if (aEvent.iType==EContactDbObserverEventTablesClosed) |
|
110 iSuspendWork=ETrue; |
|
111 else if (aEvent.iType==EContactDbObserverEventTablesOpened) |
|
112 iSuspendWork=EFalse; |
|
113 else if (aEvent.iType==EContactDbObserverEventRollback) |
|
114 { |
|
115 PrintRecovering(); |
|
116 TRAP_IGNORE(iDb->RecoverL()); |
|
117 } |
|
118 WriteToLogL(_L("Event(%d,%d)"),aEvent.iType,aEvent.iContactId); |
|
119 } |
|
120 |
|
121 void CContactReadWriter::SetNameL(CContactItem& aItem,TUid aVcardType,const TDesC& aName) |
|
122 // |
|
123 // Set the contents of a text field, creating the field if required |
|
124 // |
|
125 { |
|
126 CContactItemFieldSet& fieldSet=aItem.CardFields(); |
|
127 const TInt pos=fieldSet.Find(KUidContactFieldFamilyName); |
|
128 if (pos!=KErrNotFound) |
|
129 fieldSet[pos].TextStorage()->SetTextL(aName); |
|
130 else |
|
131 { |
|
132 CContactItemField* field=CContactItemField::NewLC(KStorageTypeText,KUidContactFieldFamilyName); |
|
133 field->SetMapping(aVcardType); |
|
134 field->TextStorage()->SetTextL(aName); |
|
135 aItem.AddFieldL(*field); |
|
136 CleanupStack::Pop(); // item |
|
137 } |
|
138 } |
|
139 |
|
140 TPtrC CContactReadWriter::Name(CContactItem& aItem) |
|
141 { |
|
142 CContactItemFieldSet& fieldSet=aItem.CardFields(); |
|
143 const TInt pos=fieldSet.Find(KUidContactFieldFamilyName); |
|
144 if (pos==KErrNotFound) |
|
145 return _L(""); |
|
146 return fieldSet[pos].TextStorage()->Text(); |
|
147 } |
|
148 |
|
149 TBool CContactReadWriter::AddNewContactsL() |
|
150 { |
|
151 CContactCard* card=CContactCard::NewL(); |
|
152 CleanupStack::PushL(card); |
|
153 TBuf<16> name; |
|
154 name.Format(_L("NAME #%d"),iSubState); |
|
155 SetNameL(*card,KUidContactFieldVCardMapUnusedN,name); |
|
156 CContactItemField* field=CContactItemField::NewLC(KStorageTypeText); |
|
157 card->AddFieldL(*field); |
|
158 CleanupStack::Pop(); // field |
|
159 iIdList->AppendL(iDb->AddNewContactL(*card)); |
|
160 CleanupStack::PopAndDestroy(); // card |
|
161 iSubState++; |
|
162 return(iSubState==KNumTestContacts); |
|
163 } |
|
164 |
|
165 TBool CContactReadWriter::EditContactsL() |
|
166 // |
|
167 // Check then edit contact names |
|
168 // |
|
169 { |
|
170 if (iSubState<KNumTestContacts) |
|
171 { |
|
172 const TInt index=(*iIdList)[iSubState]; |
|
173 CContactItem* item=iDb->OpenContactLX(index); |
|
174 CleanupStack::PushL(item); |
|
175 TBuf<16> name; |
|
176 name.Format(_L("NAME #%d"),iSubState); |
|
177 test(name==Name(*item)); |
|
178 name.Format(_L("NEW NAME #%d"),index); |
|
179 SetNameL(*item,KUidContactFieldVCardMapUnusedN,name); |
|
180 iDb->CommitContactL(*item); |
|
181 CleanupStack::PopAndDestroy(); // item; |
|
182 CleanupStack::Pop(); // Close from OpenContactLX |
|
183 } |
|
184 else if (iSubState<(2*KNumTestContacts)) |
|
185 { |
|
186 const TInt index=(*iIdList)[iSubState-KNumTestContacts]; |
|
187 CContactItem* item=iDb->ReadContactL(index); |
|
188 TBuf<16> name; |
|
189 name.Format(_L("NEW NAME #%d"),index); |
|
190 test(name==Name(*item)); |
|
191 delete item; |
|
192 } |
|
193 return(++iSubState==2*KNumTestContacts); |
|
194 } |
|
195 |
|
196 TBool CContactReadWriter::DeleteContactsL() |
|
197 // |
|
198 // Delete all contacts |
|
199 // |
|
200 { |
|
201 if (iDb->CountL()==0) |
|
202 return(ETrue); |
|
203 iDb->DeleteContactL((*iDb->SortedItemsL())[0]); |
|
204 return(EFalse); |
|
205 } |
|
206 |
|
207 // |
|
208 |
|
209 CContactReadWriter::CContactReadWriter() : CIdle(CActive::EPriorityIdle) |
|
210 { |
|
211 } |
|
212 |
|
213 CContactReadWriter *CContactReadWriter::NewLC() |
|
214 { |
|
215 CContactReadWriter *rw=new(ELeave) CContactReadWriter(); |
|
216 CleanupStack::PushL(rw); |
|
217 CActiveScheduler::Add(rw); |
|
218 rw->Start(TCallBack(CContactReadWriter::CallbackL,rw)); |
|
219 return(rw); |
|
220 } |
|
221 |
|
222 CContactReadWriter::~CContactReadWriter() |
|
223 { |
|
224 delete iNotify; |
|
225 delete iIdList; |
|
226 delete iDb; |
|
227 } |
|
228 |
|
229 TInt CContactReadWriter::DoWorkL() |
|
230 { |
|
231 if (iSuspendWork) |
|
232 { |
|
233 WriteToLogL(_L("Suspended")); |
|
234 User::After(100000); |
|
235 return(ETrue); |
|
236 } |
|
237 WriteToLogL(_L("DoWork(%d,%d)"),iState,iSubState); |
|
238 TBool moveToNextState=ETrue; |
|
239 switch(iState) |
|
240 { |
|
241 case 0: |
|
242 test(iDb==NULL); |
|
243 User::After(200000); // Increase the chance of a damage hit here |
|
244 iDb=CContactDatabase::OpenL(KDatabaseFileName); |
|
245 while(iDb->IsDamaged()) |
|
246 { |
|
247 WriteToLogL(_L("Recovering")); |
|
248 TRAP_IGNORE(iDb->RecoverL()); |
|
249 } |
|
250 iNotify=CContactChangeNotifier::NewL(*iDb,this); |
|
251 iIdList=new(ELeave) CArrayFixFlat<TContactItemId>(5); |
|
252 break; |
|
253 case 1: |
|
254 moveToNextState=AddNewContactsL(); |
|
255 break; |
|
256 case 2: |
|
257 moveToNextState=EditContactsL(); |
|
258 break; |
|
259 case 3: |
|
260 moveToNextState=DeleteContactsL(); |
|
261 break; |
|
262 case 4: |
|
263 CActiveScheduler::Stop(); |
|
264 return(EFalse); |
|
265 } |
|
266 if (moveToNextState) |
|
267 { |
|
268 iState++; |
|
269 iSubState=0; |
|
270 } |
|
271 return(ETrue); |
|
272 } |
|
273 |
|
274 void CContactReadWriter::PrintRecovering() const |
|
275 { |
|
276 test.Printf(_L("Recovering:")); |
|
277 } |
|
278 |
|
279 void CContactReadWriter::PrintErr(TInt aErr) const |
|
280 { |
|
281 TBuf<64> errText; |
|
282 errText.Format(_L("Err %d:"),aErr); |
|
283 test.Printf(errText); |
|
284 } |
|
285 |
|
286 TInt CContactReadWriter::CallbackL(TAny *aThis) |
|
287 { |
|
288 CContactReadWriter *xthis=(CContactReadWriter *)aThis; |
|
289 TInt ret=ETrue; |
|
290 TRAPD(err,ret=xthis->DoWorkL()); |
|
291 if (err!=KErrNone) |
|
292 { |
|
293 xthis->PrintErr(err); |
|
294 /* if (xthis->iDb) |
|
295 { |
|
296 TRAP_IGNORE(xthis->iDb->RecoverL()); |
|
297 }*/ |
|
298 } |
|
299 return(ret); |
|
300 } |
|
301 |
|
302 // |
|
303 |
|
304 LOCAL_C void CreateDatabaseL() |
|
305 // |
|
306 // Create a database in a store |
|
307 // |
|
308 { |
|
309 CntTest->CreateDatabaseL(); |
|
310 CntTest->DeleteAllTemplateFieldsL(); |
|
311 CntTest->CloseDatabase(); |
|
312 } |
|
313 |
|
314 void TestLoop(TInt aNumLoops) |
|
315 { |
|
316 CFred2 *fred2=new(ELeave) CFred2; |
|
317 CleanupStack::PushL(fred2); |
|
318 fred2->ConstructL(); |
|
319 for(TInt loop=0;loop<aNumLoops;loop++) |
|
320 { |
|
321 CContactReadWriter::NewLC(); |
|
322 CActiveScheduler::Start(); |
|
323 CleanupStack::PopAndDestroy(); // CContactReadWriter |
|
324 test.Printf(_L(".")); |
|
325 } |
|
326 test.Printf(_L("\n")); |
|
327 CleanupStack::PopAndDestroy(); // fred2 |
|
328 } |
|
329 |
|
330 LOCAL_C void DriveErrMsg() |
|
331 { |
|
332 test.Printf(_L("Error: For this test to run properly ")); |
|
333 #if defined(__WINS__) |
|
334 test.Printf(_L("_EPOC_DRIVE_D must be set up as a removable drive for this test\n")); |
|
335 #else |
|
336 test.Printf(_L("a removable/writable D: must exist\n")); |
|
337 #endif |
|
338 test.Getch(); |
|
339 } |
|
340 |
|
341 void RemovePackTestL() |
|
342 { |
|
343 RFs fs; |
|
344 test(fs.Connect()==KErrNone); |
|
345 // |
|
346 TDriveInfo driveInfo; |
|
347 if (fs.Drive(driveInfo,EDriveD)!=KErrNone || driveInfo.iType==EMediaNotPresent || driveInfo.iMediaAtt&KMediaAttWriteProtected) |
|
348 DriveErrMsg(); |
|
349 else |
|
350 { |
|
351 TInt err=fs.MkDirAll(_L("D:\\___t___\\")); |
|
352 if (err!=KErrNone) |
|
353 DriveErrMsg(); |
|
354 else |
|
355 { |
|
356 fs.RmDir(_L("D:\\___t___\\")); |
|
357 CContactDatabase *remDb=CContactDatabase::ReplaceL(KDatabaseRemoveableFileName); |
|
358 CleanupStack::PushL(remDb); |
|
359 test.Printf(_L("Remove pack and press a key\n")); |
|
360 test.Getch(); |
|
361 TInt addErr=KErrNone; |
|
362 do |
|
363 { |
|
364 if (addErr!=KErrNone) |
|
365 { |
|
366 test.Printf(_L("Add error %d,"),addErr); |
|
367 TRAP(addErr,remDb->RecoverL()); |
|
368 test.Printf(_L("Recover error %d"),addErr); |
|
369 TRAP(addErr,remDb->OpenTablesL()); |
|
370 test.Printf(_L("Open tables error %d\n"),addErr); |
|
371 test.Printf(_L("Press a key to try again\n")); |
|
372 test.Getch(); |
|
373 } |
|
374 if (addErr==KErrNone) |
|
375 { |
|
376 TRAP(addErr,AddContactL(remDb,KUidContactFieldFamilyName,KUidContactFieldVCardMapUnusedN,_L("x"))); |
|
377 } |
|
378 } while(addErr!=KErrNone); |
|
379 CleanupStack::PopAndDestroy(); // remDb |
|
380 } |
|
381 } |
|
382 } |
|
383 |
|
384 /** |
|
385 |
|
386 @SYMTestCaseID PIM-T-FERROR-0001 |
|
387 |
|
388 */ |
|
389 |
|
390 void DoTestsL() |
|
391 { |
|
392 test.Start(_L("@SYMTESTCaseID:PIM-T-FERROR-0001 Remove pack test")); |
|
393 |
|
394 RemovePackTestL(); |
|
395 |
|
396 test.Next(_L("File error tests")); |
|
397 |
|
398 User::LeaveIfError(logFile.Replace(CntTest->Fs(),KLogFileName,EFileStreamText|EFileWrite)); |
|
399 CleanupClosePushL(logFile); |
|
400 // |
|
401 test.Next(_L("Create new database")); |
|
402 |
|
403 WriteToLogL(_L("Starting Logging")); |
|
404 TRAPD(ret,CreateDatabaseL()); |
|
405 test(ret==KErrNone); |
|
406 test.Next(_L("Starting fail loop")); |
|
407 |
|
408 TestLoop(50); |
|
409 test.Next(_L("Delete database")); |
|
410 |
|
411 TInt retDel=KErrNone; |
|
412 do |
|
413 { |
|
414 TRAP(retDel,CntTest->DeleteDatabaseL()); |
|
415 if (retDel==KErrInUse) |
|
416 { |
|
417 User::After(200000); |
|
418 } |
|
419 else |
|
420 { |
|
421 test(retDel==KErrNone); |
|
422 } |
|
423 } while(retDel!=KErrNone); |
|
424 WriteToLogL(_L("Close log")); |
|
425 CleanupStack::PopAndDestroy(); // logfile |
|
426 } |
|
427 |
|
428 GLDEF_C TInt E32Main() |
|
429 { |
|
430 CntTest=new(ELeave) CCntTest; |
|
431 CntTest->ConstructL(test,KDatabaseFileName); |
|
432 TRAPD(err,DoTestsL()); |
|
433 CntTest->EndTestLib(err); |
|
434 return KErrNone; |
|
435 } |
|
436 |
|
437 // |
|
438 // CFred2 |
|
439 // |
|
440 |
|
441 LOCAL_C TInt FredIIFunc(TAny *aParam); |
|
442 |
|
443 CFred2::~CFred2() |
|
444 { |
|
445 Kill(); |
|
446 iThread.Close(); |
|
447 } |
|
448 |
|
449 void CFred2::ConstructL() |
|
450 { |
|
451 User::LeaveIfError(iThread.Create(_L("FredII"),FredIIFunc,KDefaultStackSize,0x2000,0x20000,this,EOwnerThread)); |
|
452 iThread.Logon(iLogonStatus); |
|
453 iThread.Resume(); |
|
454 } |
|
455 |
|
456 void CFred2::Kill() |
|
457 { |
|
458 iThread.Kill(0); |
|
459 } |
|
460 |
|
461 void CFred2::WaitForLogon() |
|
462 { |
|
463 User::WaitForRequest(iLogonStatus); |
|
464 test(iLogonStatus.Int()==KErrNone); |
|
465 } |
|
466 |
|
467 // |
|
468 // Fred II from here on |
|
469 // |
|
470 |
|
471 LOCAL_C TInt FredIIFunc(TAny *aParam) |
|
472 { |
|
473 CActiveScheduler::Install(new(ELeave) CActiveScheduler); |
|
474 CTrapCleanup* cleanup=CTrapCleanup::New(); |
|
475 TRAPD(err,((CFred2 *)aParam)->DoDamageL()); |
|
476 test(EFalse); |
|
477 delete cleanup; |
|
478 delete CActiveScheduler::Current(); |
|
479 return(err); |
|
480 } |
|
481 |
|
482 #if defined(__WINS__) |
|
483 const TInt KMaxDamageWait=500000; // up to a half a second |
|
484 #else |
|
485 # if defined(_UNICODE) |
|
486 const TInt KMaxDamageWait=1500000; // up to a one second |
|
487 # else |
|
488 const TInt KMaxDamageWait=1000000; // up to one and a half a second |
|
489 # endif |
|
490 #endif |
|
491 |
|
492 void CFred2::DoDamageL() |
|
493 { |
|
494 RFs fs; |
|
495 test(fs.Connect()==KErrNone); |
|
496 CleanupClosePushL(fs); |
|
497 User::LeaveIfError(threadLogFile.Replace(fs,KThreadLogFileName,EFileStreamText|EFileWrite)); |
|
498 CleanupClosePushL(threadLogFile); |
|
499 WriteToThreadLogL(_L("test1")); |
|
500 // |
|
501 WriteToThreadLogL(_L("test2")); |
|
502 CContactDatabase* db=CContactDatabase::OpenL(KDatabaseFileName); |
|
503 WriteToThreadLogL(_L("test3")); |
|
504 CleanupStack::PushL(db); |
|
505 TBool doRecover=EFalse; |
|
506 TInt64 seed=0; |
|
507 User::After(1000000); |
|
508 TInt damageCount=0; |
|
509 TInt error1=KErrNone; |
|
510 TInt error2=KErrNone; |
|
511 WriteToThreadLogL(_L("test4")); |
|
512 FOREVER |
|
513 { |
|
514 TInt after=(Math::Rand(seed)%KMaxDamageWait); |
|
515 User::After(after); |
|
516 WriteToThreadLogL(_L("Doing damage")); |
|
517 TRAP(error1,db->DamageDatabaseL(0x666)); |
|
518 damageCount++; |
|
519 FOREVER |
|
520 { |
|
521 if (doRecover) |
|
522 { |
|
523 WriteToThreadLogL(_L("Start Recover")); |
|
524 TRAP(error2,db->RecoverL()); |
|
525 WriteToThreadLogL(_L("Finished Recover")); |
|
526 } |
|
527 else |
|
528 { |
|
529 WriteToThreadLogL(_L("Close tables")); |
|
530 db->CloseTables(); |
|
531 TRAP(error2,db->OpenTablesL()); |
|
532 WriteToThreadLogL(_L("Open tables %d"),error2); |
|
533 } |
|
534 if (error2==KErrNone) |
|
535 break; |
|
536 User::After(100000); |
|
537 } |
|
538 doRecover=!doRecover; |
|
539 } |
|
540 //unreachable at the mo' CleanupStack::PopAndDestroy(3); // db, log file, fs |
|
541 } |