|
1 // Copyright (c) 2007-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 <e32std.h> |
|
17 #include <e32test.h> |
|
18 #include <e32const.h> |
|
19 #include <collate.h> |
|
20 #include <cntdb.h> |
|
21 #include <cntitem.h> |
|
22 #include <cntfldst.h> |
|
23 #include "t_utils2.h" |
|
24 #include "T_UTILS.H" |
|
25 #include <badesca.h> |
|
26 |
|
27 LOCAL_D TInt ThreadFunction(TAny*); |
|
28 |
|
29 _LIT(KDatabaseFileName, "C:T_OwnCardDelete"); |
|
30 _LIT(KOwnCardMutex, "OwnCardMutex"); |
|
31 _LIT(KOwnCard, "OwnCard"); |
|
32 _LIT(KThreadFunc, "ThreadFunc"); |
|
33 |
|
34 const TInt KTotalContacts = 4; |
|
35 const TInt KTimeout = 2000000; |
|
36 |
|
37 LOCAL_D TInt gEventCounter = 0; |
|
38 LOCAL_D TInt gUnknownEventCounter = 0; |
|
39 // Add*KTotalContacts + 1*OwnCardChanged + 1*UnknownChanges + OwnCardDeleted |
|
40 const TInt KMaxNumOfEvents = KTotalContacts + 3; |
|
41 const TInt KMaxUnknownEvents = 1; |
|
42 |
|
43 |
|
44 class RTestPtr |
|
45 { |
|
46 public: |
|
47 RTestPtr(RTest* aPtr) : iPtr(aPtr) |
|
48 { |
|
49 } |
|
50 ~RTestPtr() |
|
51 { |
|
52 iPtr->Close(); |
|
53 delete iPtr; |
|
54 } |
|
55 RTest* operator->() |
|
56 { |
|
57 return iPtr; |
|
58 } |
|
59 RTest& Ref() |
|
60 { |
|
61 return *iPtr; |
|
62 } |
|
63 private: |
|
64 RTest* iPtr; |
|
65 }; |
|
66 |
|
67 |
|
68 class CMyObserver : public CActive, public MContactDbObserver |
|
69 { |
|
70 public: |
|
71 CMyObserver() : CActive(EPriorityIdle) |
|
72 { |
|
73 iStart.UniversalTime(); |
|
74 } |
|
75 void Activate(); |
|
76 |
|
77 private: // From CActive. |
|
78 void RunL(); |
|
79 void DoCancel(); |
|
80 TInt RunError(TInt aError); |
|
81 |
|
82 private: // From MContactDbObserver |
|
83 void HandleDatabaseEventL(TContactDbObserverEvent aEvent); |
|
84 |
|
85 private: |
|
86 TTime iStart; |
|
87 TTime iEnd; |
|
88 }; |
|
89 |
|
90 void CMyObserver::RunL() |
|
91 { |
|
92 iEnd.UniversalTime(); |
|
93 // Timeout has been excedeed, stop waiting |
|
94 if( iEnd.MicroSecondsFrom(iStart.Int64()) > KTimeout ) |
|
95 { |
|
96 CActiveScheduler::Stop(); |
|
97 } |
|
98 else // Waiting for next event |
|
99 { |
|
100 Activate(); |
|
101 } |
|
102 } |
|
103 |
|
104 void CMyObserver::DoCancel() |
|
105 { |
|
106 } |
|
107 |
|
108 TInt CMyObserver::RunError(TInt aError) |
|
109 { |
|
110 return aError; |
|
111 } |
|
112 |
|
113 void CMyObserver::Activate() |
|
114 { |
|
115 if(!IsActive()) |
|
116 { |
|
117 TRequestStatus* pS = &iStatus; |
|
118 User::RequestComplete(pS, KErrNone); |
|
119 SetActive(); |
|
120 } |
|
121 } |
|
122 |
|
123 |
|
124 void CMyObserver::HandleDatabaseEventL(TContactDbObserverEvent aEvent) |
|
125 { |
|
126 switch( aEvent.iType ) |
|
127 { |
|
128 case EContactDbObserverEventUnknownChanges: |
|
129 { |
|
130 gUnknownEventCounter++; |
|
131 }break; |
|
132 default: |
|
133 { |
|
134 Activate(); |
|
135 break; |
|
136 } |
|
137 } |
|
138 gEventCounter++; |
|
139 } |
|
140 |
|
141 |
|
142 LOCAL_C void WaitForNotificationsL(CContactDatabase* aDb) |
|
143 { |
|
144 CMyObserver* observer = new (ELeave) CMyObserver(); |
|
145 CleanupStack::PushL(observer); |
|
146 CContactChangeNotifier* notifier = CContactChangeNotifier::NewL(*aDb, observer); |
|
147 CleanupStack::PushL(notifier); |
|
148 CActiveScheduler::Add(observer); |
|
149 observer->Activate(); |
|
150 CActiveScheduler::Start(); |
|
151 |
|
152 CleanupStack::PopAndDestroy(notifier); |
|
153 CleanupStack::PopAndDestroy(observer); |
|
154 } |
|
155 |
|
156 |
|
157 LOCAL_C void DeleteMultipleContactsL(CContactDatabase* aDb) |
|
158 { |
|
159 CContactIdArray* idArray = aDb->ContactsChangedSinceL(TTime(0)); |
|
160 CleanupStack::PushL(idArray); |
|
161 aDb->DeleteContactsL(*idArray); |
|
162 CleanupStack::PopAndDestroy(idArray); |
|
163 } |
|
164 |
|
165 LOCAL_C void DeleteOwnContactL(CContactDatabase* aDb) |
|
166 { |
|
167 TContactItemId contactId = aDb->OwnCardId(); |
|
168 aDb->DeleteContactL(contactId); |
|
169 } |
|
170 |
|
171 |
|
172 LOCAL_C void TestSetOwnCardL(CContactDatabase* aDb) |
|
173 { |
|
174 CContactIdArray* idArray = aDb->ContactsChangedSinceL(TTime(0)); |
|
175 CleanupStack::PushL(idArray); |
|
176 TInt count = idArray->Count(); |
|
177 if (count > 0) |
|
178 { |
|
179 TInt someIndex(0); //Make the first contact own contact |
|
180 TContactItemId id = (*idArray)[someIndex]; |
|
181 CContactItem* item = aDb->ReadContactLC(id); // take ownership of item |
|
182 aDb->SetOwnCardL(*item); |
|
183 CleanupStack::PopAndDestroy(item); |
|
184 } |
|
185 CleanupStack::PopAndDestroy(idArray); |
|
186 } |
|
187 |
|
188 |
|
189 LOCAL_C void PopulateDatabaseL(CContactDatabase* aDb, TInt aCntCount) |
|
190 { |
|
191 CRandomContactGenerator* randomCnt = CRandomContactGenerator::NewL(); |
|
192 CleanupStack::PushL(randomCnt); |
|
193 randomCnt->SetDbL(*aDb); |
|
194 for (TInt i = 0; i < aCntCount; ++i) |
|
195 { |
|
196 randomCnt->AddTypicalRandomContactL(); |
|
197 } |
|
198 CleanupStack::PopAndDestroy(randomCnt); |
|
199 } |
|
200 |
|
201 |
|
202 LOCAL_D void SwitchToMainThread(RMutex& aMutex) |
|
203 { |
|
204 RThread::Rendezvous(KErrNone); |
|
205 aMutex.Wait(); |
|
206 aMutex.Signal(); |
|
207 User::After(10); |
|
208 } |
|
209 |
|
210 |
|
211 LOCAL_D void SwitchToWorkerThread(RMutex& aMutex, RThread& aThread, TBool aSignal, TBool aWait) |
|
212 { |
|
213 if (aSignal) |
|
214 { |
|
215 aMutex.Signal(); |
|
216 User::After(10); |
|
217 } |
|
218 |
|
219 if (aWait) |
|
220 { |
|
221 aMutex.Wait(); |
|
222 } |
|
223 |
|
224 TRequestStatus status; |
|
225 aThread.Rendezvous(status); |
|
226 |
|
227 |
|
228 User::WaitForRequest(status); |
|
229 } |
|
230 |
|
231 LOCAL_D void ThreadFirstTestL(RTest& aTest) |
|
232 { |
|
233 aTest.Next(_L("-- Running worker thread --")); |
|
234 |
|
235 |
|
236 RMutex mutex; |
|
237 TInt errMutex = mutex.OpenGlobal(KOwnCardMutex); |
|
238 User::LeaveIfError(errMutex); |
|
239 CleanupClosePushL(mutex); |
|
240 |
|
241 aTest.Printf(_L("Replacing the database \n")); |
|
242 CContactDatabase* db = CContactDatabase::ReplaceL(KDatabaseFileName); |
|
243 CleanupStack::PushL(db); |
|
244 |
|
245 // get a second database object |
|
246 CContactDatabase* dbAnother = CContactDatabase::OpenL(KDatabaseFileName); |
|
247 CleanupStack::PushL(dbAnother); |
|
248 |
|
249 SwitchToMainThread(mutex); // 1) Back to MT-a |
|
250 |
|
251 // |
|
252 // Main thread has now opened the database |
|
253 // |
|
254 |
|
255 aTest.Printf(_L("Populating the database \n")); |
|
256 PopulateDatabaseL(db, KTotalContacts); |
|
257 WaitForNotificationsL(db); |
|
258 |
|
259 aTest.Printf(_L("Set the Own card id \n")); |
|
260 TestSetOwnCardL(db); |
|
261 WaitForNotificationsL(db); |
|
262 |
|
263 aTest.Printf(_L("Checking count value \n")); |
|
264 TInt count = db->CountL(); |
|
265 TInt countAnother = dbAnother->CountL(); |
|
266 aTest.Printf(_L("Count: %d \n"), count ); |
|
267 aTest(count == KTotalContacts && countAnother == KTotalContacts, __LINE__); |
|
268 |
|
269 aTest.Printf(_L("Checking the id \n")); |
|
270 TContactItemId id = db->OwnCardId(); |
|
271 TContactItemId idCopy = dbAnother->OwnCardId(); |
|
272 aTest.Printf(_L("Id: %d \n"), id); |
|
273 aTest(id != KNullContactId && idCopy != KNullContactId, __LINE__); |
|
274 |
|
275 SwitchToMainThread(mutex); // 2) Back to MT-b |
|
276 |
|
277 // |
|
278 // Main thread has now checked the added values |
|
279 // |
|
280 |
|
281 DeleteMultipleContactsL(db); |
|
282 WaitForNotificationsL(db); |
|
283 |
|
284 aTest.Printf(_L("Checking deleted count value \n")); |
|
285 count = db->CountL(); |
|
286 countAnother = dbAnother->CountL(); |
|
287 aTest.Printf(_L("Count: %d \n"), count ); |
|
288 aTest(count == 0 && countAnother == 0, __LINE__); |
|
289 |
|
290 aTest.Printf(_L("Checking the deleted id \n")); |
|
291 id = db->OwnCardId(); |
|
292 idCopy = dbAnother->OwnCardId(); |
|
293 aTest.Printf(_L("Id: %d \n"), id); |
|
294 aTest(id == KNullContactId && idCopy == KNullContactId, __LINE__); |
|
295 |
|
296 SwitchToMainThread(mutex); // 3) Back to MT-c |
|
297 |
|
298 // |
|
299 // Main thread has now checked the deleted values |
|
300 // |
|
301 |
|
302 CleanupStack::PopAndDestroy(dbAnother); |
|
303 CleanupStack::PopAndDestroy(db); |
|
304 CleanupStack::PopAndDestroy(); // close mutex handle |
|
305 |
|
306 RThread::Rendezvous(KErrNone); // Finish) back to MT-d |
|
307 } |
|
308 |
|
309 LOCAL_D void TestSecondL(RTest& aTest) |
|
310 { |
|
311 aTest.Next(_L("-- Second Owncard Test --")); |
|
312 |
|
313 |
|
314 RMutex mtx; |
|
315 TInt errMutex = mtx.CreateGlobal(KOwnCardMutex); |
|
316 User::LeaveIfError(errMutex); |
|
317 CleanupClosePushL(mtx); |
|
318 |
|
319 RThread thd; |
|
320 aTest.Printf(_L("Creating worker thread \n")); |
|
321 TInt errThread = thd.Create(KThreadFunc, ThreadFunction, KDefaultStackSize, KDefaultStackSize*20, KDefaultStackSize*40, NULL); |
|
322 User::LeaveIfError(errThread); |
|
323 CleanupClosePushL(thd); |
|
324 thd.Resume(); |
|
325 |
|
326 SwitchToWorkerThread(mtx, thd, EFalse, ETrue); // a) Run: WT-start to WT-1 |
|
327 |
|
328 // |
|
329 // Worker thread has now replaced the database |
|
330 // |
|
331 |
|
332 aTest.Printf(_L("Open existing database \n")); |
|
333 CContactDatabase* db = CContactDatabase::OpenL(KDatabaseFileName); |
|
334 CleanupStack::PushL(db); |
|
335 |
|
336 SwitchToWorkerThread(mtx, thd, ETrue, ETrue); // b) Run: WT-1 to WT-2 |
|
337 |
|
338 // |
|
339 // Worker thread has now added the contacts |
|
340 // |
|
341 |
|
342 WaitForNotificationsL(db); |
|
343 |
|
344 aTest.Printf(_L("Checking db count \n")); |
|
345 TInt count = db->CountL(); |
|
346 aTest.Printf(_L("Count: %d \n"), count); |
|
347 aTest(count == KTotalContacts, __LINE__); |
|
348 |
|
349 aTest.Printf(_L("Checking owncard id \n")); |
|
350 TContactItemId id = db->OwnCardId(); |
|
351 aTest.Printf(_L("id: %d \n"), id); |
|
352 aTest(id != KNullContactId, __LINE__); |
|
353 |
|
354 SwitchToWorkerThread(mtx, thd, ETrue, ETrue); // c) Run: WT-2 to WT-3 |
|
355 |
|
356 // |
|
357 // Worker thread has now deleted the contacts |
|
358 // |
|
359 |
|
360 aTest.Printf(_L("Checking deleted db count \n")); |
|
361 |
|
362 WaitForNotificationsL(db); |
|
363 |
|
364 count = db->CountL(); |
|
365 aTest.Printf(_L("Count: %d \n"), count); |
|
366 aTest(count == 0, __LINE__); |
|
367 |
|
368 aTest.Printf(_L("Checking deleted owncard id \n")); |
|
369 id = db->OwnCardId(); |
|
370 aTest.Printf(_L("id: %d \n"), id); |
|
371 aTest(id == KNullContactId, __LINE__); |
|
372 |
|
373 CleanupStack::PopAndDestroy(db); |
|
374 |
|
375 SwitchToWorkerThread(mtx, thd, ETrue, EFalse); // d) Run: WT-3 to end |
|
376 |
|
377 CleanupStack::PopAndDestroy(); // close thd handle |
|
378 CleanupStack::PopAndDestroy(); // close mtx handle |
|
379 } |
|
380 |
|
381 |
|
382 LOCAL_D void TestFirstL(RTest& aTest) |
|
383 { |
|
384 aTest.Next(_L("@SYMTestCaseID:PIM-T-OWNCARDDELETE-0001 -- First Owncard Test --")); |
|
385 |
|
386 aTest.Printf(_L("Replacing database \n")); |
|
387 CContactDatabase* db = CContactDatabase::ReplaceL(KDatabaseFileName); |
|
388 CleanupStack::PushL(db); |
|
389 |
|
390 CContactDatabase* dbAnother = CContactDatabase::OpenL(KDatabaseFileName); |
|
391 CleanupStack::PushL(dbAnother); |
|
392 |
|
393 PopulateDatabaseL(db, KTotalContacts); |
|
394 WaitForNotificationsL(db); |
|
395 |
|
396 TestSetOwnCardL(db); |
|
397 WaitForNotificationsL(db); |
|
398 |
|
399 aTest.Printf(_L("Checking the count value \n")); |
|
400 TInt count = dbAnother->CountL(); |
|
401 aTest.Printf(_L("Count: %d \n"), count); |
|
402 aTest(count == KTotalContacts, __LINE__); |
|
403 |
|
404 aTest.Printf(_L("Checking the id \n")); |
|
405 TContactItemId id = dbAnother->OwnCardId(); |
|
406 aTest.Printf(_L("id: %d \n"), id); |
|
407 aTest(id != KNullContactId, __LINE__); |
|
408 |
|
409 TContactIter iter(*db); //Test that the iterator is updated |
|
410 TContactItemId firstContactId; |
|
411 firstContactId = iter.FirstL(); //should be own contactId |
|
412 |
|
413 DeleteOwnContactL(dbAnother); |
|
414 WaitForNotificationsL(dbAnother); |
|
415 |
|
416 TContactItemId secondContactId; |
|
417 TRAPD (err, secondContactId = iter.FirstL()); |
|
418 aTest(err == KErrNone && firstContactId != secondContactId, __LINE__); |
|
419 |
|
420 |
|
421 DeleteMultipleContactsL(db); |
|
422 WaitForNotificationsL(db); |
|
423 |
|
424 aTest.Printf(_L("Checking the deleted count value \n")); |
|
425 count = dbAnother->CountL(); |
|
426 aTest.Printf(_L("Count: %d \n"), count); |
|
427 aTest(count == 0, __LINE__); |
|
428 |
|
429 aTest.Printf(_L("Checking the deleted id \n")); |
|
430 id = dbAnother->OwnCardId(); |
|
431 aTest.Printf(_L("id: %d \n"), id); |
|
432 aTest(id == KNullContactId, __LINE__); |
|
433 |
|
434 aTest(gEventCounter == KMaxNumOfEvents, __LINE__); |
|
435 aTest(gUnknownEventCounter == KMaxUnknownEvents, __LINE__); |
|
436 |
|
437 CleanupStack::PopAndDestroy(2,db); |
|
438 } |
|
439 |
|
440 |
|
441 LOCAL_D void ThreadDoTestsL() |
|
442 { |
|
443 RTestPtr myTest(new(ELeave) RTest(KThreadFunc)); |
|
444 |
|
445 myTest->Start(KThreadFunc); |
|
446 ThreadFirstTestL(myTest.Ref()); |
|
447 myTest->End(); |
|
448 } |
|
449 |
|
450 |
|
451 /** |
|
452 @SYMTestCaseID PIM-T-OWNCARDDELETE-0001 |
|
453 @SYMTestType UT |
|
454 @SYMTestPriority Medium |
|
455 @SYMDEF PDEF107246 |
|
456 @SYMTestCaseDependencies CntModel CoreAppsTest |
|
457 @SYMTestCaseDesc Check that updates to one CContactDatabase-instance will propagate to a second instance |
|
458 @SYMTestActions Add some contacts. Set one as own card. Check that the count is the same for all instances. |
|
459 Check that the own card id is the same for all instances. Delete all contacts and check that |
|
460 the count is zero and own card id is KNullContactId (-1) for all instances. |
|
461 @SYMTestExpectedResults see above. |
|
462 */ |
|
463 LOCAL_D void DoTestsL() |
|
464 { |
|
465 RTestPtr myTest(new(ELeave) RTest(KOwnCard)); |
|
466 |
|
467 myTest->Start(KOwnCard); |
|
468 TestFirstL(myTest.Ref()); |
|
469 TestSecondL(myTest.Ref()); |
|
470 |
|
471 CContactDatabase::DeleteDatabaseL(KDatabaseFileName); |
|
472 myTest->Printf(_L("Completed OK \n")); |
|
473 myTest->End(); |
|
474 } |
|
475 |
|
476 |
|
477 LOCAL_D TInt ThreadFunction(TAny*) |
|
478 { |
|
479 __UHEAP_MARK; |
|
480 CActiveScheduler* scheduler = new CActiveScheduler; |
|
481 if (scheduler) |
|
482 { |
|
483 CActiveScheduler::Install(scheduler); |
|
484 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
485 if (cleanup) |
|
486 { |
|
487 TRAPD(err, ThreadDoTestsL()); |
|
488 __ASSERT_ALWAYS(err == KErrNone, User::Panic(_L("Failure in Worker Thread"),err)); |
|
489 delete cleanup; |
|
490 } |
|
491 delete scheduler; |
|
492 } |
|
493 __UHEAP_MARKEND; |
|
494 return KErrNone; |
|
495 } |
|
496 |
|
497 |
|
498 GLDEF_C TInt E32Main() |
|
499 { |
|
500 __UHEAP_MARK; |
|
501 CActiveScheduler* scheduler = new CActiveScheduler; |
|
502 if (scheduler) |
|
503 { |
|
504 CActiveScheduler::Install(scheduler); |
|
505 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
506 if (cleanup) |
|
507 { |
|
508 TRAPD(err, DoTestsL()); |
|
509 __ASSERT_ALWAYS(err == KErrNone, User::Panic(_L("Failure in Main Thread"),err)); |
|
510 delete cleanup; |
|
511 } |
|
512 delete scheduler; |
|
513 } |
|
514 __UHEAP_MARKEND; |
|
515 return KErrNone; |
|
516 } |