1 #include <sdbusplus/timer.hpp>
2
3 #include <chrono>
4 #include <iostream>
5
6 #include <gtest/gtest.h>
7
8 using sdbusplus::Timer;
9
10 class TimerTest : public ::testing::Test
11 {
12 public:
13 // systemd event handler
14 sd_event* events = nullptr;
15
16 // Need this so that events can be initialized.
17 int rc;
18
19 // Source of event
20 sd_event_source* eventSource = nullptr;
21
22 // Add a Timer Object
23 Timer timer;
24
25 // Gets called as part of each TEST_F construction
TimerTest()26 TimerTest() : rc(sd_event_default(&events)), timer(events)
27 {
28 // Check for successful creation of
29 // event handler and timer object.
30 EXPECT_GE(rc, 0);
31 }
32
33 // Gets called as part of each TEST_F destruction
~TimerTest()34 ~TimerTest() override
35 {
36 events = sd_event_unref(events);
37 }
38 };
39
40 class TimerTestCallBack : public ::testing::Test
41 {
42 public:
43 // systemd event handler
44 sd_event* events;
45
46 // Need this so that events can be initialized.
47 int rc;
48
49 // Source of event
50 sd_event_source* eventSource = nullptr;
51
52 // Add a Timer Object
53 std::unique_ptr<Timer> timer = nullptr;
54
55 // Indicates optional call back fun was called
56 bool callBackDone = false;
57
callBack()58 void callBack()
59 {
60 callBackDone = true;
61 }
62
63 // Gets called as part of each TEST_F construction
TimerTestCallBack()64 TimerTestCallBack() : rc(sd_event_default(&events))
65
66 {
67 // Check for successful creation of
68 // event handler and timer object.
69 EXPECT_GE(rc, 0);
70
71 std::function<void()> func(
72 std::bind(&TimerTestCallBack::callBack, this));
73 timer = std::make_unique<Timer>(events, func);
74 }
75
76 // Gets called as part of each TEST_F destruction
~TimerTestCallBack()77 ~TimerTestCallBack() override
78 {
79 events = sd_event_unref(events);
80 }
81 };
82
83 /** @brief Makes sure that timer is expired and the
84 * callback handler gets invoked post 2 seconds
85 */
TEST_F(TimerTest,timerExpiresAfter2seconds)86 TEST_F(TimerTest, timerExpiresAfter2seconds)
87 {
88 using namespace std::chrono;
89
90 auto time = duration_cast<microseconds>(seconds(2));
91 EXPECT_GE(timer.start(time), 0);
92
93 // Waiting 2 seconds is enough here since we have
94 // already spent some usec now
95 int count = 0;
96 while (count < 2 && !timer.isExpired())
97 {
98 // Returns -0- on timeout and positive number on dispatch
99 auto sleepTime = duration_cast<microseconds>(seconds(1));
100 if (!sd_event_run(events, sleepTime.count()))
101 {
102 count++;
103 }
104 }
105 EXPECT_EQ(true, timer.isExpired());
106 EXPECT_EQ(1, count);
107 }
108
109 /** @brief Makes sure that timer is not expired
110 */
TEST_F(TimerTest,timerNotExpiredAfter2Seconds)111 TEST_F(TimerTest, timerNotExpiredAfter2Seconds)
112 {
113 using namespace std::chrono;
114
115 auto time = duration_cast<microseconds>(seconds(2));
116 EXPECT_GE(timer.start(time), 0);
117
118 // Now turn off the timer post a 1 second sleep
119 sleep(1);
120 EXPECT_GE(timer.stop(), 0);
121
122 // Wait 2 seconds and see that timer is not expired
123 int count = 0;
124 while (count < 2)
125 {
126 // Returns -0- on timeout
127 auto sleepTime = duration_cast<microseconds>(seconds(1));
128 if (!sd_event_run(events, sleepTime.count()))
129 {
130 count++;
131 }
132 }
133 EXPECT_EQ(false, timer.isExpired());
134
135 // 2 because of one more count that happens prior to exiting
136 EXPECT_EQ(2, count);
137 }
138
139 /** @brief Makes sure that timer value is changed in between
140 * and that the new timer expires
141 */
TEST_F(TimerTest,updateTimerAndExpectExpire)142 TEST_F(TimerTest, updateTimerAndExpectExpire)
143 {
144 using namespace std::chrono;
145
146 auto time = duration_cast<microseconds>(seconds(2));
147 EXPECT_GE(timer.start(time), 0);
148
149 // Now sleep for a second and then set the new timeout value
150 sleep(1);
151
152 // New timeout is 3 seconds from THIS point.
153 time = duration_cast<microseconds>(seconds(3));
154 EXPECT_GE(timer.start(time), 0);
155
156 // Wait 3 seconds and see that timer is expired
157 int count = 0;
158 while (count < 3 && !timer.isExpired())
159 {
160 // Returns -0- on timeout
161 auto sleepTime = duration_cast<microseconds>(seconds(1));
162 if (!sd_event_run(events, sleepTime.count()))
163 {
164 count++;
165 }
166 }
167 EXPECT_EQ(true, timer.isExpired());
168 EXPECT_EQ(2, count);
169 }
170
171 /** @brief Makes sure that timer value is changed in between
172 * and turn off and make sure that timer does not expire
173 */
TEST_F(TimerTest,updateTimerAndNeverExpire)174 TEST_F(TimerTest, updateTimerAndNeverExpire)
175 {
176 using namespace std::chrono;
177
178 auto time = duration_cast<microseconds>(seconds(2));
179 EXPECT_GE(timer.start(time), 0);
180
181 // Now sleep for a second and then set the new timeout value
182 sleep(1);
183
184 // New timeout is 2 seconds from THIS point.
185 time = duration_cast<microseconds>(seconds(2));
186 EXPECT_GE(timer.start(time), 0);
187
188 // Now turn off the timer post a 1 second sleep
189 sleep(1);
190 EXPECT_GE(timer.stop(), 0);
191
192 // Wait 2 seconds and see that timer is expired
193 int count = 0;
194 while (count < 2)
195 {
196 // Returns -0- on timeout
197 auto sleepTime = duration_cast<microseconds>(seconds(1));
198 if (!sd_event_run(events, sleepTime.count()))
199 {
200 count++;
201 }
202 }
203 EXPECT_EQ(false, timer.isExpired());
204
205 // 2 because of one more count that happens prior to exiting
206 EXPECT_EQ(2, count);
207 }
208
209 /** @brief Makes sure that optional callback is called */
TEST_F(TimerTestCallBack,optionalFuncCallBackDone)210 TEST_F(TimerTestCallBack, optionalFuncCallBackDone)
211 {
212 using namespace std::chrono;
213
214 auto time = duration_cast<microseconds>(seconds(2));
215 EXPECT_GE(timer->start(time), 0);
216
217 // Waiting 2 seconds is enough here since we have
218 // already spent some usec now
219 int count = 0;
220 while (count < 2 && !timer->isExpired())
221 {
222 // Returns -0- on timeout and positive number on dispatch
223 auto sleepTime = duration_cast<microseconds>(seconds(1));
224 if (!sd_event_run(events, sleepTime.count()))
225 {
226 count++;
227 }
228 }
229 EXPECT_EQ(true, timer->isExpired());
230 EXPECT_EQ(true, callBackDone);
231 EXPECT_EQ(1, count);
232 }
233
234 /** @brief Makes sure that timer is not expired
235 */
TEST_F(TimerTestCallBack,timerNotExpiredAfter2SecondsNoOptionalCallBack)236 TEST_F(TimerTestCallBack, timerNotExpiredAfter2SecondsNoOptionalCallBack)
237 {
238 using namespace std::chrono;
239
240 auto time = duration_cast<microseconds>(seconds(2));
241 EXPECT_GE(timer->start(time), 0);
242
243 // Now turn off the timer post a 1 second sleep
244 sleep(1);
245 EXPECT_GE(timer->stop(), 0);
246
247 // Wait 2 seconds and see that timer is not expired
248 int count = 0;
249 while (count < 2)
250 {
251 // Returns -0- on timeout
252 auto sleepTime = duration_cast<microseconds>(seconds(1));
253 if (!sd_event_run(events, sleepTime.count()))
254 {
255 count++;
256 }
257 }
258 EXPECT_EQ(false, timer->isExpired());
259 EXPECT_EQ(false, callBackDone);
260
261 // 2 because of one more count that happens prior to exiting
262 EXPECT_EQ(2, count);
263 }
264