|
1 // Copyright (c) 1996-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 the License "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 // e32test\system\t_chnot.cpp |
|
15 // Tests RChangeNotifier class |
|
16 // Overview: |
|
17 // Tests RChangeNotifier class |
|
18 // API Information: |
|
19 // RChangeNotifier |
|
20 // Details: |
|
21 // - Create a RChangeNotifier object and verify the logon status is |
|
22 // as expected. |
|
23 // - Call the Logon and LogonCancel methods, verify results are as |
|
24 // expected. |
|
25 // - Test for the correct midnight crossover notifier results in a |
|
26 // variety of situations: DST On, DST Off, various time offsets |
|
27 // and various dates. |
|
28 // - Test various locale changes and verify that the notifier response |
|
29 // is as expected. |
|
30 // - Test the notification of the death of a thread and check that |
|
31 // results are as expected. Check for normal exit, kill exit, |
|
32 // terminate exit and panic exit. |
|
33 // Platforms/Drives/Compatibility: |
|
34 // All. |
|
35 // Assumptions/Requirement/Pre-requisites: |
|
36 // Failures and causes: |
|
37 // Base Port information: |
|
38 // |
|
39 // |
|
40 |
|
41 #define __E32TEST_EXTENSION__ |
|
42 #include <e32test.h> |
|
43 #include <e32hal.h> |
|
44 #include <e32svr.h> |
|
45 #include <u32hal.h> |
|
46 #include <e32def.h> |
|
47 #include <e32def_private.h> |
|
48 |
|
49 RTest test(_L("T_CHNOT")); |
|
50 |
|
51 RChangeNotifier notifier; |
|
52 |
|
53 void TestStat(const TRequestStatus& aStat, TInt aValue) |
|
54 { |
|
55 if (aStat.Int()!=aValue) |
|
56 { |
|
57 test.Printf(_L("Got %08x Expected %08x\n"),aStat.Int(),aValue); |
|
58 test(0); |
|
59 } |
|
60 } |
|
61 |
|
62 void TestCreate() |
|
63 { |
|
64 notifier.Create(); |
|
65 TRequestStatus stat; |
|
66 notifier.Logon(stat); |
|
67 |
|
68 // Expect all except EChangesLowMemory |
|
69 TUint expected = |
|
70 EChangesLocale | |
|
71 EChangesMidnightCrossover | |
|
72 EChangesThreadDeath | |
|
73 EChangesPowerStatus | |
|
74 EChangesSystemTime | |
|
75 EChangesFreeMemory | |
|
76 EChangesOutOfMemory | |
|
77 EChangesThrashLevel; |
|
78 |
|
79 test(stat==expected); |
|
80 } |
|
81 |
|
82 void TestLogonLogoff() |
|
83 { |
|
84 TRequestStatus stat; |
|
85 notifier.LogonCancel(); |
|
86 notifier.Logon(stat); |
|
87 TestStat(stat,KRequestPending); |
|
88 notifier.LogonCancel(); |
|
89 TestStat(stat,KErrCancel); |
|
90 notifier.LogonCancel(); |
|
91 TestStat(stat,KErrCancel); |
|
92 } |
|
93 |
|
94 void DoTestMidnight() |
|
95 { |
|
96 TTime time; |
|
97 time.HomeTime(); |
|
98 TDateTime dateTime=time.DateTime(); |
|
99 dateTime.SetHour(23); |
|
100 dateTime.SetMinute(59); |
|
101 dateTime.SetSecond(58); |
|
102 dateTime.SetMicroSecond(700000); |
|
103 time=dateTime; |
|
104 TRequestStatus stat; |
|
105 TInt r=notifier.Logon(stat); |
|
106 test(r==KErrNone); |
|
107 TestStat(stat,KRequestPending); |
|
108 test(User::SetHomeTime(time)==KErrNone); |
|
109 time.HomeTime(); |
|
110 TDateTime dateTime2=time.DateTime(); |
|
111 User::WaitForRequest(stat); |
|
112 TestStat(stat,EChangesSystemTime); |
|
113 r=notifier.Logon(stat); |
|
114 test(r==KErrNone); |
|
115 User::WaitForRequest(stat); |
|
116 time.HomeTime(); |
|
117 TestStat(stat,EChangesMidnightCrossover); |
|
118 dateTime2=time.DateTime(); |
|
119 test(dateTime2.Second()==0); |
|
120 test(dateTime2.Minute()==0); |
|
121 test(dateTime2.Hour()==0); |
|
122 if (dateTime2.Month()==dateTime.Month()) |
|
123 test(dateTime2.Day()==dateTime.Day()+1); |
|
124 else |
|
125 test(dateTime2.Day()==0); |
|
126 time=dateTime; |
|
127 r=notifier.Logon(stat); |
|
128 test(r==KErrNone); |
|
129 TestStat(stat,KRequestPending); |
|
130 test(User::SetHomeTime(time)==KErrNone); |
|
131 User::WaitForRequest(stat); |
|
132 TestStat(stat,(EChangesSystemTime|EChangesMidnightCrossover)); |
|
133 time=dateTime2; |
|
134 r=notifier.Logon(stat); |
|
135 test(r==KErrNone); |
|
136 TestStat(stat,KRequestPending); |
|
137 test(User::SetHomeTime(time)==KErrNone); |
|
138 User::WaitForRequest(stat); |
|
139 TestStat(stat,(EChangesSystemTime|EChangesMidnightCrossover)); |
|
140 |
|
141 // Check that a change of secure time also triggers notification, even though the user time is unchanged |
|
142 r = notifier.Logon(stat); |
|
143 test(r == KErrNone); |
|
144 TestStat(stat, KRequestPending); |
|
145 if ((r = time.HomeTimeSecure()) == KErrNone) |
|
146 r = User::SetHomeTimeSecure(time+TTimeIntervalSeconds(60)); |
|
147 if (r == KErrNone) |
|
148 { |
|
149 test(User::SetHomeTimeSecure(time) == KErrNone); |
|
150 r = EChangesSystemTime; |
|
151 } |
|
152 else |
|
153 { |
|
154 RDebug::Printf("WARNING: Secure clock change test skipped because secure time could not be changed!"); |
|
155 notifier.LogonCancel(); |
|
156 r = KErrCancel; |
|
157 } |
|
158 User::WaitForRequest(stat); |
|
159 TestStat(stat, r); |
|
160 } |
|
161 |
|
162 void SetOffsetForMidnight(TTime time,TTimeIntervalSeconds offset) |
|
163 { |
|
164 test(User::SetHomeTime(time)==KErrNone); |
|
165 User::SetUTCOffset(offset); |
|
166 // No longer need next line, as we now only get one notification |
|
167 // User::After(999999);//So, if time has gone backwards, midnight crossover has been noticed |
|
168 TRequestStatus stat; |
|
169 notifier.Logon(stat); |
|
170 User::WaitForRequest(stat); |
|
171 test(stat.Int()&(EChangesSystemTime|EChangesLocale)); |
|
172 } |
|
173 |
|
174 void TestMidnightCrossover() |
|
175 { |
|
176 TTimeIntervalSeconds offset=User::UTCOffset(); |
|
177 TTime time; |
|
178 time.HomeTime(); |
|
179 test.Start(_L("Normal")); |
|
180 DoTestMidnight(); |
|
181 test.Next(_L("Now offset 0")); |
|
182 SetOffsetForMidnight(time,0); |
|
183 DoTestMidnight(); |
|
184 test.Next(_L("Now offset +30")); |
|
185 SetOffsetForMidnight(time,30); |
|
186 DoTestMidnight(); |
|
187 test.Next(_L("Now offset -30")); |
|
188 SetOffsetForMidnight(time,-30); |
|
189 DoTestMidnight(); |
|
190 test.Next(_L("Now offset +60")); |
|
191 SetOffsetForMidnight(time,60); |
|
192 DoTestMidnight(); |
|
193 test.Next(_L("Now offset -60")); |
|
194 SetOffsetForMidnight(time,-60); |
|
195 DoTestMidnight(); |
|
196 test.Next(_L("Now offset +120")); |
|
197 SetOffsetForMidnight(time,120); |
|
198 DoTestMidnight(); |
|
199 test.Next(_L("Now offset -120")); |
|
200 SetOffsetForMidnight(time,-120); |
|
201 DoTestMidnight(); |
|
202 // |
|
203 TTime time1998=TDateTime(1998,EFebruary,2,3,4,5,6); |
|
204 test.Next(_L("1998 offset 0")); |
|
205 SetOffsetForMidnight(time1998,0); |
|
206 DoTestMidnight(); |
|
207 test.Next(_L("1998 offset +30")); |
|
208 SetOffsetForMidnight(time1998,30); |
|
209 DoTestMidnight(); |
|
210 test.Next(_L("1998 offset -30")); |
|
211 SetOffsetForMidnight(time1998,-30); |
|
212 DoTestMidnight(); |
|
213 test.Next(_L("1998 offset +60")); |
|
214 SetOffsetForMidnight(time1998,60); |
|
215 DoTestMidnight(); |
|
216 test.Next(_L("1998 offset -60")); |
|
217 SetOffsetForMidnight(time1998,-60); |
|
218 DoTestMidnight(); |
|
219 test.Next(_L("1998 offset +120")); |
|
220 SetOffsetForMidnight(time1998,120); |
|
221 DoTestMidnight(); |
|
222 test.Next(_L("1998 offset -120")); |
|
223 SetOffsetForMidnight(time1998,-120); |
|
224 DoTestMidnight(); |
|
225 // |
|
226 TTime time1999=TDateTime(1999,EDecember,30,3,4,5,6); |
|
227 test.Next(_L("1999 offset 0")); |
|
228 SetOffsetForMidnight(time1999,0); |
|
229 DoTestMidnight(); |
|
230 TTime now; |
|
231 now.HomeTime(); |
|
232 test(now.DateTime().Year()==2000); |
|
233 test(now.DateTime().Month()==EJanuary); |
|
234 test.Next(_L("1999 offset +30")); |
|
235 SetOffsetForMidnight(time1999,30); |
|
236 DoTestMidnight(); |
|
237 now.HomeTime(); |
|
238 test(now.DateTime().Year()==2000); |
|
239 test(now.DateTime().Month()==EJanuary); |
|
240 test.Next(_L("1999 offset -30")); |
|
241 SetOffsetForMidnight(time1999,-30); |
|
242 DoTestMidnight(); |
|
243 now.HomeTime(); |
|
244 test(now.DateTime().Year()==2000); |
|
245 test(now.DateTime().Month()==EJanuary); |
|
246 test.Next(_L("1999 offset +60")); |
|
247 SetOffsetForMidnight(time1999,60); |
|
248 DoTestMidnight(); |
|
249 now.HomeTime(); |
|
250 test(now.DateTime().Year()==2000); |
|
251 test(now.DateTime().Month()==EJanuary); |
|
252 test.Next(_L("1999 offset -60")); |
|
253 SetOffsetForMidnight(time1999,-60); |
|
254 DoTestMidnight(); |
|
255 now.HomeTime(); |
|
256 test(now.DateTime().Year()==2000); |
|
257 test(now.DateTime().Month()==EJanuary); |
|
258 test.Next(_L("1999 offset +120")); |
|
259 SetOffsetForMidnight(time1999,120); |
|
260 DoTestMidnight(); |
|
261 now.HomeTime(); |
|
262 test(now.DateTime().Year()==2000); |
|
263 test(now.DateTime().Month()==EJanuary); |
|
264 test.Next(_L("1999 offset -120")); |
|
265 SetOffsetForMidnight(time1999,-120); |
|
266 DoTestMidnight(); |
|
267 now.HomeTime(); |
|
268 test(now.DateTime().Year()==2000); |
|
269 test(now.DateTime().Month()==EJanuary); |
|
270 // |
|
271 TTime time2002=TDateTime(2002,EAugust,30,3,4,5,6); |
|
272 test.Next(_L("2002 offset 0")); |
|
273 SetOffsetForMidnight(time2002,0); |
|
274 DoTestMidnight(); |
|
275 test.Next(_L("2002 offset +30")); |
|
276 SetOffsetForMidnight(time2002,30); |
|
277 DoTestMidnight(); |
|
278 test.Next(_L("2002 offset -30")); |
|
279 SetOffsetForMidnight(time2002,-30); |
|
280 DoTestMidnight(); |
|
281 test.Next(_L("2002 offset +60")); |
|
282 SetOffsetForMidnight(time2002,60); |
|
283 DoTestMidnight(); |
|
284 test.Next(_L("2002 offset -60")); |
|
285 SetOffsetForMidnight(time2002,-60); |
|
286 DoTestMidnight(); |
|
287 test.Next(_L("2002 offset +120")); |
|
288 SetOffsetForMidnight(time2002,120); |
|
289 DoTestMidnight(); |
|
290 test.Next(_L("2002 offset -120")); |
|
291 SetOffsetForMidnight(time2002,-120); |
|
292 DoTestMidnight(); |
|
293 // |
|
294 SetOffsetForMidnight(time,offset); |
|
295 test.End(); |
|
296 } |
|
297 |
|
298 void TestLocaleChanges() |
|
299 { |
|
300 TRequestStatus stat; |
|
301 notifier.Logon(stat); |
|
302 TestStat(stat,KRequestPending); |
|
303 TLocale locale; |
|
304 locale.Set(); |
|
305 User::WaitForRequest(stat); |
|
306 TestStat(stat,EChangesLocale); |
|
307 } |
|
308 |
|
309 void TestOffsetChanges() |
|
310 { |
|
311 TTimeIntervalSeconds oldOffset = User::UTCOffset(); |
|
312 User::SetUTCOffset(0); |
|
313 |
|
314 TRequestStatus stat; |
|
315 TTime time; |
|
316 time.HomeTime(); |
|
317 TDateTime dateTime=time.DateTime(); |
|
318 dateTime.SetHour(23); |
|
319 dateTime.SetMinute(30); |
|
320 dateTime.SetSecond(0); |
|
321 dateTime.SetMicroSecond(0); |
|
322 time=dateTime; |
|
323 test(User::SetHomeTime(time)==KErrNone); |
|
324 notifier.Logon(stat); |
|
325 User::WaitForRequest(stat); |
|
326 TestStat(stat,(EChangesSystemTime)); |
|
327 |
|
328 notifier.Logon(stat); |
|
329 TestStat(stat,KRequestPending); |
|
330 User::SetUTCOffset(3600); |
|
331 User::WaitForRequest(stat); |
|
332 TestStat(stat,(EChangesSystemTime|EChangesLocale|EChangesMidnightCrossover)); |
|
333 User::SetUTCOffset(oldOffset); |
|
334 notifier.Logon(stat); |
|
335 User::WaitForRequest(stat); |
|
336 } |
|
337 |
|
338 const TInt retValue=65432; |
|
339 const TInt killValue=2081953; |
|
340 const TInt terminateValue=512123; |
|
341 const TInt panicValue=1257671; |
|
342 const TInt KHeapSize=0x200; |
|
343 |
|
344 TInt ThreadCode(TAny* aReturnImmetiateFlag) |
|
345 { |
|
346 if(!aReturnImmetiateFlag) |
|
347 User::After(60000000); // wait a minute, (effectively forever as far as the test goes). |
|
348 return retValue; |
|
349 } |
|
350 |
|
351 void TestThreadDeath() |
|
352 { |
|
353 test.Start(_L("Normal Exit")); |
|
354 RThread thread; |
|
355 TInt r=thread.Create(_L("T_CHNOT ThreadCode"),ThreadCode,KDefaultStackSize,KHeapSize,KHeapSize,(TAny*)ETrue); |
|
356 test(r==KErrNone); |
|
357 __KHEAP_MARK; |
|
358 TRequestStatus threadStat; |
|
359 thread.Logon(threadStat); |
|
360 TRequestStatus stat; |
|
361 notifier.Logon(stat); |
|
362 TestStat(stat,KRequestPending); |
|
363 thread.Resume(); |
|
364 User::WaitForRequest(stat); |
|
365 TestStat(stat,EChangesThreadDeath); |
|
366 test(threadStat==retValue); |
|
367 test(thread.ExitReason()==retValue); |
|
368 test(thread.ExitType()==EExitKill); |
|
369 test(thread.ExitCategory()==_L("Kill")); |
|
370 CLOSE_AND_WAIT(thread); |
|
371 __KHEAP_MARKEND; |
|
372 |
|
373 test.Next(_L("Kill")); |
|
374 r=thread.Create(_L("T_CHNOT ThreadCode"),ThreadCode,KDefaultStackSize,KHeapSize,KHeapSize,NULL); |
|
375 test(r==KErrNone); |
|
376 thread.Logon(threadStat); |
|
377 notifier.Logon(stat); |
|
378 TestStat(stat,KRequestPending); |
|
379 thread.Resume(); |
|
380 thread.Kill(killValue); |
|
381 User::WaitForRequest(stat); |
|
382 TestStat(stat,EChangesThreadDeath); |
|
383 test(threadStat==killValue); |
|
384 test(thread.ExitReason()==killValue); |
|
385 test(thread.ExitType()==EExitKill); |
|
386 test(thread.ExitCategory()==_L("Kill")); |
|
387 CLOSE_AND_WAIT(thread); |
|
388 |
|
389 test.Next(_L("Terminate")); |
|
390 r=thread.Create(_L("T_CHNOT ThreadCode"),ThreadCode,KDefaultStackSize,KHeapSize,KHeapSize,NULL); |
|
391 test(r==KErrNone); |
|
392 thread.Logon(threadStat); |
|
393 notifier.Logon(stat); |
|
394 TestStat(stat,KRequestPending); |
|
395 thread.Resume(); |
|
396 thread.Terminate(terminateValue); |
|
397 User::WaitForRequest(stat); |
|
398 TestStat(stat,EChangesThreadDeath); |
|
399 test(threadStat==terminateValue); |
|
400 test(thread.ExitReason()==terminateValue); |
|
401 test(thread.ExitType()==EExitTerminate); |
|
402 test(thread.ExitCategory()==_L("Terminate")); |
|
403 CLOSE_AND_WAIT(thread); |
|
404 |
|
405 test.Next(_L("Panic")); |
|
406 r=thread.Create(_L("T_CHNOT ThreadCode"),ThreadCode,KDefaultStackSize,KHeapSize,KHeapSize,NULL); |
|
407 test(r==KErrNone); |
|
408 thread.Logon(threadStat); |
|
409 notifier.Logon(stat); |
|
410 TestStat(stat,KRequestPending); |
|
411 TBool justInTime=User::JustInTime(); |
|
412 User::SetJustInTime(EFalse); |
|
413 thread.Resume(); |
|
414 thread.Panic(_L("Testing panic"),panicValue); |
|
415 User::WaitForRequest(stat); |
|
416 User::SetJustInTime(justInTime); |
|
417 TestStat(stat,EChangesThreadDeath); |
|
418 test(threadStat==panicValue); |
|
419 test(thread.ExitReason()==panicValue); |
|
420 test(thread.ExitType()==EExitPanic); |
|
421 test(thread.ExitCategory()==_L("Testing panic")); |
|
422 CLOSE_AND_WAIT(thread); |
|
423 test.End(); |
|
424 } |
|
425 |
|
426 void TestCloseWhilstPending() |
|
427 { |
|
428 test_KErrNone(notifier.Create()); |
|
429 TRequestStatus stat; |
|
430 test_KErrNone(notifier.Logon(stat)); |
|
431 User::WaitForRequest(stat); |
|
432 test_KErrNone(notifier.Logon(stat)); |
|
433 notifier.Close(); |
|
434 test_Equal(KErrGeneral,stat.Int()); |
|
435 } |
|
436 |
|
437 void TestCloseAndCompleteRace() |
|
438 { |
|
439 RThread().SetPriority(EPriorityRealTime); |
|
440 |
|
441 // setup notifier2 |
|
442 RChangeNotifier notifier2; |
|
443 test_KErrNone(notifier2.Create()); |
|
444 TRequestStatus stat2; |
|
445 test_KErrNone(notifier2.Logon(stat2)); |
|
446 User::WaitForRequest(stat2); |
|
447 test_KErrNone(notifier2.Logon(stat2)); |
|
448 |
|
449 // setup notifier |
|
450 test_KErrNone(notifier.Create()); |
|
451 TRequestStatus stat; |
|
452 test_KErrNone(notifier.Logon(stat)); |
|
453 User::WaitForRequest(stat); |
|
454 test_KErrNone(notifier.Logon(stat)); |
|
455 |
|
456 // create and kill a thread so notifiers get signaled |
|
457 RThread thread; |
|
458 test_KErrNone(thread.Create(_L("T_CHNOT ThreadCode"),ThreadCode,KDefaultStackSize,KHeapSize,KHeapSize,NULL)); |
|
459 thread.Kill(0); |
|
460 |
|
461 // wait for notifier2 |
|
462 User::WaitForRequest(stat2); |
|
463 |
|
464 // as this thread is realtime priority, then (on unicore systems) it has preempted |
|
465 // kernel supervisor thread after it completed 'notifier2' but before it completed |
|
466 // 'notifier'. if we close both notifiers now we trigger a race conidition which |
|
467 // previousely caused a null pointer dereference in the kernel... |
|
468 notifier.Close(); |
|
469 notifier2.Close(); |
|
470 |
|
471 User::WaitForRequest(stat); |
|
472 TInt result = stat.Int(); |
|
473 |
|
474 // expect KErrGeneral from closing notifier, or on SMP probably EChangesThreadDeath as |
|
475 // the notifier had time to complete |
|
476 const TInt numCpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); |
|
477 if(numCpus==1 || result!=EChangesThreadDeath) |
|
478 test_Equal(KErrGeneral,result); |
|
479 |
|
480 RThread().SetPriority(EPriorityNormal); |
|
481 thread.Close(); |
|
482 } |
|
483 |
|
484 TInt E32Main() |
|
485 { |
|
486 |
|
487 User::After(1000000);//So WINS doesn't give an instant power-status change; |
|
488 test.Start(_L("Create")); |
|
489 TestCreate(); |
|
490 |
|
491 test.Next(_L("Close")); |
|
492 notifier.Close(); |
|
493 |
|
494 test.Next(_L("Create")); |
|
495 TestCreate(); |
|
496 |
|
497 test.Next(_L("Logon/Logoff")); |
|
498 TestLogonLogoff(); |
|
499 |
|
500 test.Next(_L("Midnight crossover")); |
|
501 TestMidnightCrossover(); |
|
502 |
|
503 test.Next(_L("Locale changes")); |
|
504 TestLocaleChanges(); |
|
505 |
|
506 test.Next(_L("Offset changes")); |
|
507 TestOffsetChanges(); |
|
508 |
|
509 test.Next(_L("Thread death")); |
|
510 TestThreadDeath(); |
|
511 |
|
512 test.Next(_L("Close")); |
|
513 notifier.Close(); |
|
514 |
|
515 test.Next(_L("Close whilst pending")); |
|
516 TestCloseWhilstPending(); |
|
517 |
|
518 test.Next(_L("Race between Close and complete")); |
|
519 TestCloseAndCompleteRace(); |
|
520 |
|
521 test.End(); |
|
522 return KErrNone; |
|
523 } |