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 : * See test_fd.c for why `pipe()` is used.
9 : */
10 :
11 : #include <stdio.h>
12 : #include <stdlib.h>
13 : #include <string.h>
14 : #include <unistd.h>
15 :
16 : #include <tests.h>
17 :
18 : #include "test.h"
19 : #include <kdbio.h>
20 : #include <kdbiotest.h>
21 :
22 : #define MIX_TIMER_INTERVAL 100
23 : #define MIX_DIFF_WARNING_THRESHOLD 5
24 : #define MIX_DIFF_ERROR_THRESHOLD (MIX_DIFF_WARNING_THRESHOLD * 100)
25 :
26 : #define MIX_BUFFER_TESTDATA "T"
27 : #define MIX_BUFFER_TESTDATA_LENGTH 1
28 :
29 : // Indices for array returned by pipe()
30 : #define MIX_READ_END 0
31 : #define MIX_WRITE_END 1
32 :
33 : ElektraIoTestSuiteStop testStop;
34 :
35 : int testIdleNotStarveTimerTimerCalled;
36 : int testIdleNotStarveTimerIdleCalled;
37 : struct timespec testIdleNotStarveTimerTimeStarted;
38 : struct timespec testIdleNotStarveTimerTimeCalled;
39 :
40 : int testIdleNotStarveFdStep;
41 : int testIdleNotStarveFdFdCalled;
42 : int testIdleNotStarveFdIdleCalled;
43 : int testIdleNotStarveFdWriteFd;
44 : struct timespec testIdleNotStarveFdTimeReadable;
45 : struct timespec testIdleNotStarveFdTimeWrite;
46 :
47 6 : static void testMixIdleShouldNotStarveTimerTimer (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
48 : {
49 6 : elektraIoTestSuiteUtilGetCurrentTime (&testIdleNotStarveTimerTimeCalled);
50 6 : testIdleNotStarveTimerTimerCalled = 1;
51 6 : testStop ();
52 6 : }
53 :
54 191988 : static void testMixIdleShouldNotStarveTimerIdle (ElektraIoIdleOperation * timerOp ELEKTRA_UNUSED)
55 : {
56 191988 : testIdleNotStarveTimerIdleCalled = 1;
57 191988 : }
58 :
59 6 : static void testMixIdleShouldNotStarveTimer (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
60 : ElektraIoTestSuiteStop stop)
61 : {
62 6 : ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (MIX_TIMER_INTERVAL, 1, testMixIdleShouldNotStarveTimerTimer, NULL);
63 :
64 6 : ElektraIoIdleOperation * idleOp = elektraIoNewIdleOperation (1, testMixIdleShouldNotStarveTimerIdle, NULL);
65 :
66 6 : ElektraIoInterface * binding = createBinding ();
67 6 : elektraIoBindingAddTimer (binding, timerOp);
68 6 : elektraIoBindingAddIdle (binding, idleOp);
69 :
70 6 : testStop = stop;
71 6 : testIdleNotStarveTimerTimerCalled = 0;
72 6 : testIdleNotStarveTimerIdleCalled = 0;
73 :
74 6 : elektraIoTestSuiteUtilGetCurrentTime (&testIdleNotStarveTimerTimeStarted);
75 :
76 6 : start ();
77 :
78 6 : succeed_if (testIdleNotStarveTimerTimerCalled, "timer callback was not called");
79 6 : succeed_if (testIdleNotStarveTimerIdleCalled, "idle callback was not called");
80 :
81 6 : long diff = elektraIoTestSuiteUtilGetTimeDifference (testIdleNotStarveTimerTimeStarted, testIdleNotStarveTimerTimeCalled);
82 6 : int deviation = labs (MIX_TIMER_INTERVAL - diff);
83 6 : if (deviation > MIX_DIFF_WARNING_THRESHOLD)
84 : {
85 0 : printf ("testMixIdleShouldNotStarveTimer (warning): measured %ldms, expected %dms - deviation %dms.\n", diff,
86 : MIX_TIMER_INTERVAL, deviation);
87 : }
88 6 : succeed_if (deviation <= MIX_DIFF_ERROR_THRESHOLD, "timer interval not within error threshold");
89 :
90 6 : elektraIoBindingRemoveTimer (timerOp);
91 6 : elektraIoBindingRemoveIdle (idleOp);
92 6 : elektraIoBindingCleanup (binding);
93 6 : elektraFree (timerOp);
94 6 : elektraFree (idleOp);
95 6 : }
96 :
97 :
98 6 : static void testMixIdleShouldNotStarveFdFd (ElektraIoFdOperation * fdOp ELEKTRA_UNUSED, int flags ELEKTRA_UNUSED)
99 : {
100 6 : elektraIoTestSuiteUtilGetCurrentTime (&testIdleNotStarveFdTimeReadable);
101 6 : succeed_if (testIdleNotStarveFdStep != 0, "fd called before data was written");
102 :
103 6 : testIdleNotStarveFdFdCalled = 1;
104 6 : testStop ();
105 6 : }
106 :
107 6 : static void testMixIdleShouldNotStarveFdControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
108 : {
109 6 : switch (testIdleNotStarveFdStep)
110 : {
111 : case 0:
112 6 : testIdleNotStarveFdStep++;
113 6 : succeed_if (write (testIdleNotStarveFdWriteFd, MIX_BUFFER_TESTDATA, MIX_BUFFER_TESTDATA_LENGTH) ==
114 : MIX_BUFFER_TESTDATA_LENGTH,
115 : "write failed");
116 6 : elektraIoTestSuiteUtilGetCurrentTime (&testIdleNotStarveFdTimeWrite);
117 6 : break;
118 : case 1:
119 0 : yield_error ("timeout; test failed");
120 0 : testStop ();
121 0 : break;
122 : }
123 6 : }
124 :
125 191691 : static void testMixIdleShouldNotStarveFdIdle (ElektraIoIdleOperation * idleOp ELEKTRA_UNUSED)
126 : {
127 191691 : testIdleNotStarveFdIdleCalled = 1;
128 191691 : }
129 :
130 6 : static void testMixIdleShouldNotStarveFd (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
131 : ElektraIoTestSuiteStop stop)
132 : {
133 :
134 : int fds[2];
135 6 : if (pipe (fds) == -1)
136 : {
137 0 : yield_error ("pipe() failed");
138 0 : return;
139 : }
140 :
141 6 : ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (MIX_TIMER_INTERVAL, 1, testMixIdleShouldNotStarveFdControl, NULL);
142 :
143 6 : ElektraIoFdOperation * fdOp = elektraIoNewFdOperation (fds[MIX_READ_END],
144 : ELEKTRA_IO_READABLE, // gets changed by control timer
145 : 1, testMixIdleShouldNotStarveFdFd, NULL);
146 :
147 6 : ElektraIoIdleOperation * idleOp = elektraIoNewIdleOperation (1, testMixIdleShouldNotStarveFdIdle, NULL);
148 :
149 6 : ElektraIoInterface * binding = createBinding ();
150 6 : elektraIoBindingAddFd (binding, fdOp);
151 6 : elektraIoBindingAddTimer (binding, timerOp);
152 6 : elektraIoBindingAddIdle (binding, idleOp);
153 :
154 6 : testIdleNotStarveFdWriteFd = fds[1];
155 6 : testIdleNotStarveFdStep = 0;
156 6 : testIdleNotStarveFdFdCalled = 0;
157 6 : testIdleNotStarveFdIdleCalled = 0;
158 6 : testStop = stop;
159 :
160 6 : start ();
161 :
162 6 : succeed_if (testIdleNotStarveFdFdCalled, "fd callback was not called");
163 6 : succeed_if (testIdleNotStarveFdIdleCalled, "idle callback was not called");
164 :
165 6 : elektraIoBindingRemoveFd (fdOp);
166 6 : elektraIoBindingRemoveTimer (timerOp);
167 6 : elektraIoBindingRemoveIdle (idleOp);
168 6 : elektraIoBindingCleanup (binding);
169 6 : elektraFree (fdOp);
170 6 : elektraFree (timerOp);
171 6 : elektraFree (idleOp);
172 6 : close (fds[0]);
173 6 : close (fds[1]);
174 : }
175 :
176 : /**
177 : * Test mixed requirements of the I/O binding returned by createBinding.
178 : * Requires the following operations: Fd, Timer, Idle
179 : *
180 : * @param createBinding binding creation function
181 : * @param start starts I/O operations
182 : * @param stop stops I/O operations
183 : */
184 6 : void elektraIoTestSuiteMix (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start, ElektraIoTestSuiteStop stop)
185 : {
186 6 : printf ("test mix\n");
187 :
188 6 : testMixIdleShouldNotStarveTimer (createBinding, start, stop);
189 :
190 6 : testMixIdleShouldNotStarveFd (createBinding, start, stop);
191 6 : }
|