1 krisbash 1.1 #include <ut/ut.h>
2 #include <base/Strand.h>
3 #include <pal/sleep.h>
4
5 #if defined(CONFIG_OS_WINDOWS)
6 #include <windows.h>
7 #endif
8
9 using namespace std;
10
11 struct TimerFakeStrand
12 {
13 Strand strand;
14
15 MI_Uint32 callbackCounter;
16 PAL_Uint64 timeoutTime;
17 TimerReason reason;
18 };
19
20 NITS_EXTERN_C void TimerTest_Post_NO_OP( _In_ Strand* self_, _In_ Message* msg)
21 {
22 krisbash 1.1 MI_UNUSED( msg );
23 MI_UNUSED(self_);
24 }
25
26 NITS_EXTERN_C void TimerTest_PostControl_NO_OP( _In_ Strand* self, _In_ Message* msg)
27 {
28 MI_UNUSED( self );
29 MI_UNUSED( msg );
30 }
31
32 NITS_EXTERN_C void TimerTest_Ack_NO_OP( _In_ Strand* self )
33 {
34 MI_UNUSED( self );
35 }
36
37 NITS_EXTERN_C void TimerTest_Close_NO_OP( _In_ Strand* self_ )
38 {
39 MI_UNUSED( self_ );
40 }
41
42 NITS_EXTERN_C void TimerTest_Finish_NO_OP( _In_ Strand* self_ )
43 krisbash 1.1 {
44 MI_UNUSED( self_ );
45 }
46
47 NITS_EXTERN_C void TimerTest_UserCallback(
48 _In_ Strand* self,
49 TimerReason reason)
50 {
51 TimerFakeStrand* fakeStrand = (TimerFakeStrand*)self;
52
53 fakeStrand->callbackCounter++;
54 fakeStrand->reason = reason;
55
56 NitsAssert( MI_TRUE == PAL_Time(&fakeStrand->timeoutTime), PAL_T("Unable to get end time") );
57 }
58
59 /*
60 * StrandFT functions and table for a faked "Left" side of an interaction.
61 */
62 static StrandFT TimerTest_Left_InteractionFT =
63 {
64 krisbash 1.1 TimerTest_Post_NO_OP,
65 TimerTest_PostControl_NO_OP,
66 TimerTest_Ack_NO_OP,
67 NULL,
68 TimerTest_Close_NO_OP,
69 TimerTest_Finish_NO_OP,
70 TimerTest_UserCallback,
71 NULL,
72 NULL,
73 NULL,
74 NULL,
75 NULL
76 };
77
78 Selector testSelector; // For POSIX implementations
79 TimerFakeStrand timerTestStrand; // Implemented as a "left" strand
80
81 static const MI_Uint64 FIFTY_MILLISECONDS_AS_USEC = 50 * 1000;
82 static const MI_Uint64 SIXTY_SECONDS_AS_USEC = 60 * 1000 * 1000;
83
84
85 krisbash 1.1 //
86 // Basic checks on uninitialized structures.
87 //
88 NitsTest0(TimerTest_CloseOrFire_on_Uninitialized_Does_Nothing)
89 {
90 Timer timer;
91
92 memset( &timer, 0, sizeof(Timer) );
93
94 Timer_Close( &timer );
95 NitsAssert( TimerReason_Expired == timer.reason, PAL_T("Value should not be changed") );
96
97 Timer_Fire( &timer, &timerTestStrand.strand, TimerReason_ManuallyFired );
98 NitsAssert( TimerReason_Expired == timer.reason, PAL_T("Value should not be changed") );
99 }
100 NitsEndTest
101
102 STRAND_DEBUGNAME(TestTimer);
103
104 //
105 // Initializes a Selector and Strand for timer tests.
106 krisbash 1.1 //
107 NitsSetup0(TimerTest_SetupSelectorAndStrand, NitsEmptyStruct)
108 {
109 // Note: This is not required for Windows, but it is included for test uniformity
110 memset( &testSelector, 0, sizeof(Selector) );
111
112 NitsAssert( MI_RESULT_OK == Selector_Init( &testSelector ), PAL_T("Unable to initialize Selector") );
113
114 Timer_SetSelector(&testSelector);
115
116 // Strand initialization is needed for all test flavors
117 memset( &timerTestStrand, 0, sizeof(TimerFakeStrand) );
118 Strand_Init( STRAND_DEBUG(TestTimer) &timerTestStrand.strand, &TimerTest_Left_InteractionFT, STRAND_FLAG_ENTERSTRAND, NULL );
119 }
120 NitsEndSetup
121
122 NitsCleanup(TimerTest_SetupSelectorAndStrand)
123 {
124 // Posix-specific test cleanup
125 Selector_Destroy( &testSelector );
126 Timer_SetSelector( NULL );
127 krisbash 1.1 }
128 NitsEndCleanup
129
130 //
131 // Verifies that a timeout occurs within a reasonable amount of time after the
132 // specified time.
133 //
134 NitsTest1(TimerTest_BasicTimeout_Success, TimerTest_SetupSelectorAndStrand, NitsEmptyValue)
135 {
136 NitsFaultSimMarkForRerun;
137 Timer timer;
138 PAL_Uint64 startTimeUsec = 0;
139
140 memset( &timer, 0, sizeof(Timer) );
141
142 timerTestStrand.callbackCounter = 0;
143 NitsAssert( MI_TRUE == PAL_Time(&startTimeUsec), PAL_T("Unable to get start time") );
144
145 Strand_StartTimer( &timerTestStrand.strand, &timer, FIFTY_MILLISECONDS_AS_USEC );
146 Strand_Leave( &timerTestStrand.strand );
147
148 krisbash 1.1 while (0 == timerTestStrand.callbackCounter)
149 {
150 // This is specific to non-Windows, but it acts as a wait loop for Windows
151 // as well depending on the length of the timeout value.
152 Selector_Run( &testSelector, SELECT_BASE_TIMEOUT_MSEC * 1000, MI_FALSE );
153 }
154
155 // "Natural" because it was not manually triggered
156 NitsAssert( TimerReason_Expired == timerTestStrand.reason, PAL_T("Triggered flag not set correctly") );
157 NitsAssert( 1 == timerTestStrand.callbackCounter, PAL_T("Only one callback call expected") );
158
159 /* Verify that the timeout occurred after waiting at least 50 milliseconds */
160 NitsAssert( timerTestStrand.timeoutTime-startTimeUsec >= FIFTY_MILLISECONDS_AS_USEC, PAL_T("Timeout took shorter than expected") );
161 }
162 NitsEndTest
163
164 //
165 // Verifies that Strand_FireTimer works in a normal scenario.
166 //
167 NitsTest1(TimerTest_BasicFireTimer, TimerTest_SetupSelectorAndStrand, NitsEmptyValue)
168 {
169 krisbash 1.1 NitsFaultSimMarkForRerun;
170 Timer timer;
171 PAL_Uint64 startTimeUsec = 0;
172
173 memset( &timer, 0, sizeof(Timer) );
174
175 timerTestStrand.callbackCounter = 0;
176 NitsAssert( MI_TRUE == PAL_Time(&startTimeUsec), PAL_T("Unable to get start time") );
177
178 Strand_StartTimer( &timerTestStrand.strand, &timer, SIXTY_SECONDS_AS_USEC ); // Large value to ensure that the timer gets manually triggered. The system will not actually wait this long unless the test case fails.
179 Strand_Leave( &timerTestStrand.strand );
180
181 // Manually trigger the timer early
182 Timer_Fire( &timer, &timerTestStrand.strand, TimerReason_ManuallyFired );
183
184 while (0 == timerTestStrand.callbackCounter)
185 {
186 // This is specific to non-Windows, but it acts as a wait loop for Windows
187 // as well depending on the length of the timeout value.
188 Selector_Run( &testSelector, SELECT_BASE_TIMEOUT_MSEC * 1000, MI_FALSE );
189 }
190 krisbash 1.1
191 // Manually triggered, so it is not "natural."
192 NitsAssert( TimerReason_ManuallyFired == timerTestStrand.reason, PAL_T("Triggered flag not set correctly") );
193 NitsAssert( 1 == timerTestStrand.callbackCounter, PAL_T("Only one callback call expected") );
194 }
195 NitsEndTest
196
197 //
198 // Verifies that the timer is fired/closed uppon strand finish.
199 //
200 NitsTest1(TimerTest_StrandFinish, TimerTest_SetupSelectorAndStrand, NitsEmptyValue)
201 {
202 NitsFaultSimMarkForRerun;
203 Timer timer;
204 PAL_Uint64 startTimeUsec = 0;
205
206 memset( &timer, 0, sizeof(Timer) );
207
208 timerTestStrand.callbackCounter = 0;
209 NitsAssert( MI_TRUE == PAL_Time(&startTimeUsec), PAL_T("Unable to get start time") );
210
211 krisbash 1.1 Strand_StartTimer( &timerTestStrand.strand, &timer, SIXTY_SECONDS_AS_USEC ); // Large value to ensure that the timer gets canceled. The system will not actually wait this long unless the test case fails.
212
213 // Simutlate closed interaction
214 timerTestStrand.strand.info.thisAckPending = timerTestStrand.strand.info.otherAckPending = MI_FALSE;
215 timerTestStrand.strand.info.thisClosedOther = timerTestStrand.strand.info.otherClosedThis = MI_TRUE;
216
217 Strand_Leave( &timerTestStrand.strand );
218
219 while (0 == timerTestStrand.callbackCounter)
220 {
221 // This is specific to non-Windows, but it acts as a wait loop for Windows
222 // as well depending on the length of the timeout value.
223 Selector_Run( &testSelector, SELECT_BASE_TIMEOUT_MSEC * 1000, MI_FALSE );
224 }
225
226 // It should be Canceled
227 NitsAssert( TimerReason_Canceled == timerTestStrand.reason, PAL_T("Triggered flag not set correctly") );
228 NitsAssert( 1 == timerTestStrand.callbackCounter, PAL_T("Only one callback call expected") );
229 }
230 NitsEndTest
231
232 krisbash 1.1
233 //
234 // Verifies that it is OK to have Strand_FireTimer called twice prior to the
235 // Strand's timer method getting called. This simulates a race between two
236 // threads to trigger a timer.
237 //
238 NitsTest1(TimerTest_DoubleFireTimer, TimerTest_SetupSelectorAndStrand, NitsEmptyValue)
239 {
240 NitsFaultSimMarkForRerun;
241 Timer timer;
242 PAL_Uint64 startTimeUsec = 0;
243
244 memset( &timer, 0, sizeof(Timer) );
245
246 timerTestStrand.callbackCounter = 0;
247 NitsAssert( MI_TRUE == PAL_Time(&startTimeUsec), PAL_T("Unable to get start time") );
248
249 Strand_StartTimer( &timerTestStrand.strand, &timer, SIXTY_SECONDS_AS_USEC ); // Large value to ensure that the timer gets manually triggered. The system will not actually wait this long unless the test case fails.
250 Strand_Leave( &timerTestStrand.strand );
251
252 // Manually trigger the timer early twice
253 krisbash 1.1 Timer_Fire( &timer, &timerTestStrand.strand, TimerReason_ManuallyFired );
254 Timer_Fire( &timer, &timerTestStrand.strand, TimerReason_ManuallyFired );
255
256 while (0 == timerTestStrand.callbackCounter)
257 {
258 // This is specific to non-Windows, but it acts as a wait loop for Windows
259 // as well depending on the length of the timeout value.
260 Selector_Run( &testSelector, SELECT_BASE_TIMEOUT_MSEC * 1000, MI_FALSE );
261 }
262
263 // Manually triggered, so it is not a "natural" timeout
264 NitsAssert( TimerReason_ManuallyFired == timerTestStrand.reason, PAL_T("Triggered flag not set correctly") );
265 NitsAssert( 1 == timerTestStrand.callbackCounter, PAL_T("Only one callback call expected") );
266 }
267 NitsEndTest
268
269 //
270 // Verifies that calling Timer_Start twice has no effect on the timer's timeout.
271 //
272 NitsTest1(TimerTest_DoubleStart, TimerTest_SetupSelectorAndStrand, NitsEmptyValue)
273 {
274 krisbash 1.1 NitsFaultSimMarkForRerun;
275 Timer timer;
276 PAL_Uint64 startTimeUsec = 0;
277
278 memset( &timer, 0, sizeof(Timer) );
279
280 timerTestStrand.callbackCounter = 0;
281 NitsAssert( MI_TRUE == PAL_Time(&startTimeUsec), PAL_T("Unable to get start time") );
282
283 Strand_StartTimer( &timerTestStrand.strand, &timer, FIFTY_MILLISECONDS_AS_USEC );
284 Strand_Leave( &timerTestStrand.strand );
285
286 // Manually call Timer_Start a second time. It should fail and not interfere
287 // with the timer already started.
288 NitsAssert( TimerResult_InvalidArgument == Timer_Start( &timer, &timerTestStrand.strand ), PAL_T("Start while already running not supported") );
289
290 while (0 == timerTestStrand.callbackCounter)
291 {
292 // This is specific to non-Windows, but it acts as a wait loop for Windows
293 // as well depending on the length of the timeout value.
294 Selector_Run( &testSelector, SELECT_BASE_TIMEOUT_MSEC * 1000, MI_FALSE );
295 krisbash 1.1 }
296
297 // "Natural" because it was not manually triggered
298 NitsAssert( TimerReason_Expired == timerTestStrand.reason, PAL_T("Triggered flag not set correctly") );
299 NitsAssert( 1 == timerTestStrand.callbackCounter, PAL_T("Only one callback call expected") );
300
301 /* Verify that the timeout occurred after waiting at least 50 milliseconds */
302 NitsAssert( timerTestStrand.timeoutTime-startTimeUsec >= FIFTY_MILLISECONDS_AS_USEC, PAL_T("Timeout took shorter than expected") );
303 }
304 NitsEndTest
305
306
307 #if defined(CONFIG_POSIX)
308
309 NitsTest0(TimerTest_Start_Without_Selector_Fails_Posix)
310 {
311 Timer timer;
312
313 memset( &timer, 0, sizeof(Timer) );
314
315 TimerResult result = Timer_Start( &timer, &timerTestStrand.strand );
316 krisbash 1.1
317 NitsAssert( TimerResult_InvalidArgument == result, PAL_T("Selector required for operation") );
318 }
319 NitsEndTest
320
321 #endif // #if defined(CONFIG_POSIX)
|