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