xref: /openbmc/sdbusplus/test/timer.cpp (revision 4690d88c)
1 #include <sdbusplus/timer.hpp>
2 
3 #include <chrono>
4 #include <iostream>
5 
6 #include <gtest/gtest.h>
7 
8 using namespace phosphor;
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
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
34     ~TimerTest()
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 
58     void callBack()
59     {
60         callBackDone = true;
61     }
62 
63     // Gets called as part of each TEST_F construction
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
77     ~TimerTestCallBack()
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  */
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  */
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  */
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  */
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 */
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  */
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