Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Tests for I/O bindings
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include <stdio.h>
11 : #include <stdlib.h>
12 : #include <string.h>
13 :
14 : #include <kdbhelper.h>
15 : #include <tests.h>
16 :
17 : #include "test.h"
18 : #include <kdbio.h>
19 : #include <kdbiotest.h>
20 :
21 : #define TIMER_TEST_INTERVAL 250
22 : #define TIMER_TEST_TIMES 3
23 : #define TIMER_DIFF_WARNING_THRESHOLD 5
24 : #define TIMER_DIFF_ERROR_THRESHOLD (TIMER_DIFF_WARNING_THRESHOLD * 100)
25 :
26 : // Control interval is 50ms * 5 = 250ms for the probe interval
27 : // To check for the change (enabled or interval) we need control to run 5 + 1 times
28 : #define TIMER_CHANGE_CONTROL_INTERVAL 50
29 : #define TIMER_CHANGE_TIMES 6
30 :
31 : #define TIMER_CHANGE_SECOND_INTERVAL TIMER_TEST_INTERVAL - TIMER_CHANGE_CONTROL_INTERVAL
32 : #define TIMER_CHANGE_PROBE_TIMES 2
33 :
34 : ElektraIoTestSuiteStop testStop;
35 : struct timespec testTimeStarted;
36 :
37 : int testCallbackOnceCalled;
38 : struct timespec testCallbackOnceTimeCalled;
39 :
40 : int testCallbackAtIntervalsCounter;
41 : struct timespec testCallbackAtIntervalsTimeCalled[TIMER_TEST_TIMES];
42 :
43 : int testUpdateEnabledControlCalled;
44 : int testUpdateEnabledProbeCalled;
45 : ElektraIoTimerOperation * testUpdateEnabledTimerProbe;
46 : ElektraIoInterface * testUpdateEnabledBinding;
47 :
48 : int testUpdateIntervalControlCalled;
49 : int testUpdateIntervalProbeCalled;
50 : ElektraIoTimerOperation * testUpdateIntervalTimerProbe;
51 : ElektraIoInterface * testUpdateIntervalBinding;
52 : struct timespec testUpdateIntervalTimeCalled, testUpdateIntervalTimeCalledLast;
53 :
54 : int testRemoveControlCalled;
55 : int testRemoveProbeCalled;
56 : ElektraIoTimerOperation * testRemoveTimerProbe;
57 : ElektraIoInterface * testRemoveBinding;
58 :
59 0 : static void testTimerBasicsCallback (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
60 : {
61 0 : yield_error ("should not be called");
62 0 : }
63 :
64 6 : static void testTimerBasics (ElektraIoTestSuiteCreateBinding createBinding)
65 : {
66 6 : ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 0, testTimerBasicsCallback, NULL);
67 :
68 6 : ElektraIoInterface * binding = createBinding ();
69 6 : succeed_if (elektraIoBindingAddTimer (binding, timerOp), "addTimer did not succeed");
70 6 : succeed_if (elektraIoBindingAddTimer (binding, timerOp) == 0, "addTimer: should not be able to reassign operation to a binding");
71 :
72 6 : elektraIoTimerSetEnabled (timerOp, 1);
73 6 : succeed_if (elektraIoBindingUpdateTimer (timerOp), "updateTimer did not succeed");
74 :
75 6 : succeed_if (elektraIoBindingRemoveTimer (timerOp), "removeTimer did not succeed");
76 :
77 6 : succeed_if (elektraIoBindingAddTimer (binding, timerOp), "addTimer: should be able to assign operation after removal");
78 6 : succeed_if (elektraIoBindingRemoveTimer (timerOp), "removeTimer did not succeed");
79 6 : elektraIoBindingCleanup (binding);
80 6 : elektraFree (timerOp);
81 6 : }
82 :
83 6 : static void testTimerShouldCallbackOnceElapsed (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
84 : {
85 6 : testCallbackOnceCalled = 1;
86 6 : elektraIoTestSuiteUtilGetCurrentTime (&testCallbackOnceTimeCalled);
87 6 : testStop ();
88 6 : }
89 :
90 6 : static void testTimerShouldCallbackOnce (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
91 : ElektraIoTestSuiteStop stop)
92 : {
93 6 : ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldCallbackOnceElapsed, NULL);
94 :
95 6 : ElektraIoInterface * binding = createBinding ();
96 6 : elektraIoBindingAddTimer (binding, timerOp);
97 :
98 6 : testStop = stop;
99 6 : testCallbackOnceCalled = 0;
100 :
101 6 : elektraIoTestSuiteUtilGetCurrentTime (&testTimeStarted);
102 :
103 6 : start ();
104 :
105 6 : succeed_if (testCallbackOnceCalled, "callback was not called");
106 :
107 6 : long diff = elektraIoTestSuiteUtilGetTimeDifference (testTimeStarted, testCallbackOnceTimeCalled);
108 6 : int deviation = labs (TIMER_TEST_INTERVAL - diff);
109 6 : if (deviation > TIMER_DIFF_WARNING_THRESHOLD)
110 : {
111 2 : printf ("testTimerShouldCallbackOnce (warning): measured %ldms, expected %dms - deviation %dms.\n", diff,
112 : TIMER_TEST_INTERVAL, deviation);
113 : }
114 6 : succeed_if (deviation <= TIMER_DIFF_ERROR_THRESHOLD, "timer interval not within error threshold");
115 :
116 6 : elektraIoBindingRemoveTimer (timerOp);
117 6 : elektraIoBindingCleanup (binding);
118 6 : elektraFree (timerOp);
119 6 : }
120 :
121 18 : static void testTimerShouldCallbackAtIntervalsCallback (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
122 : {
123 18 : testCallbackAtIntervalsCounter--;
124 18 : elektraIoTestSuiteUtilGetCurrentTime (&testCallbackAtIntervalsTimeCalled[testCallbackAtIntervalsCounter]);
125 :
126 18 : if (testCallbackAtIntervalsCounter == 0)
127 : {
128 6 : testStop ();
129 : }
130 18 : }
131 :
132 6 : static void testTimerShouldCallbackAtIntervals (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
133 : ElektraIoTestSuiteStop stop)
134 : {
135 6 : ElektraIoTimerOperation * timerOp =
136 : elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldCallbackAtIntervalsCallback, NULL);
137 :
138 6 : ElektraIoInterface * binding = createBinding ();
139 6 : elektraIoBindingAddTimer (binding, timerOp);
140 :
141 6 : testCallbackAtIntervalsCounter = TIMER_TEST_TIMES;
142 6 : testStop = stop;
143 :
144 6 : elektraIoTestSuiteUtilGetCurrentTime (&testTimeStarted);
145 :
146 6 : start ();
147 :
148 6 : succeed_if (testCallbackAtIntervalsCounter == 0, "intervals timer not called the required amount of times");
149 :
150 : // Verify intervals
151 6 : struct timespec lastTime = testTimeStarted;
152 24 : for (int i = TIMER_TEST_TIMES - 1; i >= 0; i--)
153 : {
154 18 : long diff = elektraIoTestSuiteUtilGetTimeDifference (lastTime, testCallbackAtIntervalsTimeCalled[i]);
155 18 : int deviation = labs (TIMER_TEST_INTERVAL - diff);
156 18 : if (deviation > TIMER_DIFF_WARNING_THRESHOLD)
157 : {
158 1 : printf ("testTimerShouldCallbackAtIntervals (warning): measured %ldms, expected %dms - deviation %dms.\n", diff,
159 : TIMER_TEST_INTERVAL, deviation);
160 : }
161 18 : succeed_if (deviation <= TIMER_DIFF_ERROR_THRESHOLD, "timer interval not within error threshold");
162 :
163 18 : lastTime = testCallbackAtIntervalsTimeCalled[i];
164 : }
165 :
166 6 : elektraIoBindingRemoveTimer (timerOp);
167 6 : elektraIoBindingCleanup (binding);
168 6 : elektraFree (timerOp);
169 6 : }
170 :
171 36 : static void testTimerShouldChangeEnabledControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
172 : {
173 36 : testUpdateEnabledControlCalled--;
174 :
175 : // Disable probe timer on first run
176 36 : if (testUpdateEnabledControlCalled == TIMER_CHANGE_TIMES - 1)
177 : {
178 6 : elektraIoTimerSetEnabled (testUpdateEnabledTimerProbe, 0);
179 6 : elektraIoBindingUpdateTimer (testUpdateEnabledTimerProbe);
180 : }
181 :
182 36 : if (testUpdateEnabledControlCalled == 0 || testUpdateEnabledProbeCalled > 1)
183 : {
184 6 : testStop ();
185 : }
186 36 : }
187 :
188 0 : static void testTimerShouldChangeEnabledProbe (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
189 : {
190 0 : testUpdateEnabledProbeCalled++;
191 0 : }
192 :
193 6 : static void testTimerShouldChangeEnabled (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
194 : ElektraIoTestSuiteStop stop)
195 : {
196 6 : ElektraIoTimerOperation * timerControl =
197 : elektraIoNewTimerOperation (TIMER_CHANGE_CONTROL_INTERVAL, 1, testTimerShouldChangeEnabledControl, NULL);
198 :
199 6 : ElektraIoTimerOperation * timerProbe = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldChangeEnabledProbe, NULL);
200 :
201 6 : ElektraIoInterface * binding = createBinding ();
202 6 : elektraIoBindingAddTimer (binding, timerControl);
203 6 : elektraIoBindingAddTimer (binding, timerProbe);
204 :
205 6 : testStop = stop;
206 6 : testUpdateEnabledControlCalled = TIMER_CHANGE_TIMES;
207 6 : testUpdateEnabledProbeCalled = 0;
208 6 : testUpdateEnabledTimerProbe = timerProbe;
209 6 : testUpdateEnabledBinding = binding;
210 :
211 6 : start ();
212 :
213 6 : succeed_if (testUpdateEnabledProbeCalled == 0, "timer callback was not disabled");
214 6 : succeed_if (testUpdateEnabledControlCalled == 0, "timout control callback was not called required amount of times");
215 :
216 6 : elektraIoBindingRemoveTimer (timerControl);
217 6 : elektraIoBindingRemoveTimer (timerProbe);
218 6 : elektraIoBindingCleanup (binding);
219 6 : elektraFree (timerControl);
220 6 : elektraFree (timerProbe);
221 6 : }
222 :
223 74 : static void testTimerShouldChangeIntervalControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
224 : {
225 74 : testUpdateIntervalControlCalled++;
226 :
227 : // Change probe interval on first run, before probe was run
228 74 : if (testUpdateIntervalControlCalled == 1)
229 : {
230 6 : elektraIoTimerSetInterval (testUpdateIntervalTimerProbe, TIMER_CHANGE_SECOND_INTERVAL);
231 6 : elektraIoBindingUpdateTimer (testUpdateIntervalTimerProbe);
232 : }
233 :
234 74 : if (testUpdateIntervalProbeCalled > TIMER_CHANGE_PROBE_TIMES)
235 : {
236 6 : testStop ();
237 : }
238 74 : }
239 :
240 18 : static void testTimerShouldChangeIntervalProbe (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
241 : {
242 18 : testUpdateIntervalTimeCalledLast = testUpdateIntervalTimeCalled;
243 18 : elektraIoTestSuiteUtilGetCurrentTime (&testUpdateIntervalTimeCalled);
244 :
245 18 : testUpdateIntervalProbeCalled++;
246 18 : }
247 :
248 6 : static void testTimerShouldChangeInterval (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
249 : ElektraIoTestSuiteStop stop)
250 : {
251 : // Control timer will change interval
252 6 : ElektraIoTimerOperation * timerControl =
253 : elektraIoNewTimerOperation (TIMER_CHANGE_CONTROL_INTERVAL, 1, testTimerShouldChangeIntervalControl, NULL);
254 :
255 : // Probe will just count and measure time
256 6 : ElektraIoTimerOperation * timerProbe =
257 : elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldChangeIntervalProbe, NULL);
258 :
259 6 : ElektraIoInterface * binding = createBinding ();
260 6 : elektraIoBindingAddTimer (binding, timerControl);
261 6 : elektraIoBindingAddTimer (binding, timerProbe);
262 :
263 6 : testStop = stop;
264 6 : testUpdateIntervalControlCalled = 0;
265 6 : testUpdateIntervalProbeCalled = 0;
266 6 : testUpdateIntervalTimerProbe = timerProbe;
267 6 : testUpdateIntervalBinding = binding;
268 :
269 6 : elektraIoTestSuiteUtilGetCurrentTime (&testTimeStarted);
270 :
271 6 : start ();
272 :
273 6 : succeed_if (testUpdateIntervalProbeCalled == TIMER_TEST_TIMES, "timer was not called the required amount of times");
274 :
275 : // Verify last interval
276 6 : long diff = elektraIoTestSuiteUtilGetTimeDifference (testUpdateIntervalTimeCalledLast, testUpdateIntervalTimeCalled);
277 6 : int deviation = labs (TIMER_CHANGE_SECOND_INTERVAL - diff);
278 6 : if (deviation > TIMER_DIFF_WARNING_THRESHOLD)
279 : {
280 0 : printf ("testTimerShouldCallbackAtIntervals (warning): measured %ldms, expected %dms - deviation %dms.\n", diff,
281 : TIMER_CHANGE_SECOND_INTERVAL, deviation);
282 : }
283 6 : succeed_if (deviation <= TIMER_DIFF_ERROR_THRESHOLD, "timer interval not within threshold");
284 :
285 6 : elektraIoBindingRemoveTimer (timerControl);
286 6 : elektraIoBindingRemoveTimer (timerProbe);
287 6 : elektraIoBindingCleanup (binding);
288 6 : elektraFree (timerControl);
289 6 : elektraFree (timerProbe);
290 6 : }
291 :
292 36 : static void testTimerShouldRemoveControl (ElektraIoTimerOperation * idleInfo ELEKTRA_UNUSED)
293 : {
294 36 : testRemoveControlCalled--;
295 :
296 : // Disable probe timer on first run
297 36 : if (testRemoveControlCalled == TIMER_CHANGE_TIMES - 1)
298 : {
299 6 : elektraIoBindingRemoveTimer (testRemoveTimerProbe);
300 : }
301 :
302 36 : if (testRemoveControlCalled == 0 || testRemoveProbeCalled > 1)
303 : {
304 6 : testStop ();
305 : }
306 36 : }
307 :
308 0 : static void testTimerShouldRemoveProbe (ElektraIoTimerOperation * idleInfo ELEKTRA_UNUSED)
309 : {
310 0 : testRemoveProbeCalled++;
311 0 : }
312 :
313 6 : static void testTimerShouldRemove (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
314 : ElektraIoTestSuiteStop stop)
315 : {
316 6 : ElektraIoTimerOperation * timerControl =
317 : elektraIoNewTimerOperation (TIMER_CHANGE_CONTROL_INTERVAL, 1, testTimerShouldRemoveControl, NULL);
318 :
319 6 : ElektraIoTimerOperation * timerProbe = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldRemoveProbe, NULL);
320 :
321 6 : ElektraIoInterface * binding = createBinding ();
322 6 : elektraIoBindingAddTimer (binding, timerControl);
323 6 : elektraIoBindingAddTimer (binding, timerProbe);
324 :
325 6 : testStop = stop;
326 6 : testRemoveControlCalled = TIMER_CHANGE_TIMES;
327 6 : testRemoveProbeCalled = 0;
328 6 : testRemoveTimerProbe = timerProbe;
329 6 : testRemoveBinding = binding;
330 :
331 6 : start ();
332 :
333 6 : succeed_if (testRemoveProbeCalled == 0, "timer callback was not removed");
334 6 : succeed_if (testRemoveControlCalled == 0, "timout control callback was not called required amount of times");
335 :
336 6 : elektraIoBindingRemoveTimer (timerControl);
337 6 : if (testRemoveProbeCalled != 0)
338 : {
339 0 : elektraIoBindingRemoveTimer (timerProbe);
340 : }
341 6 : elektraIoBindingCleanup (binding);
342 6 : elektraFree (timerControl);
343 6 : elektraFree (timerProbe);
344 6 : }
345 :
346 : /**
347 : * Test timer functions of the I/O binding returned by createBinding.
348 : * Requires the following operations: Timer
349 : *
350 : * @param createBinding binding creation function
351 : * @param start starts I/O operations
352 : * @param stop stops I/O operations
353 : */
354 6 : void elektraIoTestSuiteTimer (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start, ElektraIoTestSuiteStop stop)
355 : {
356 6 : printf ("test timer\n");
357 :
358 6 : testTimerBasics (createBinding);
359 :
360 6 : testTimerShouldCallbackOnce (createBinding, start, stop);
361 :
362 6 : testTimerShouldCallbackAtIntervals (createBinding, start, stop);
363 :
364 6 : testTimerShouldChangeEnabled (createBinding, start, stop);
365 :
366 6 : testTimerShouldChangeInterval (createBinding, start, stop);
367 :
368 6 : testTimerShouldRemove (createBinding, start, stop);
369 6 : }
|