blob: 845a0e18c5d42760ad780ddff5e62cada3acf75d [file] [log] [blame]
Matt Spinler59c29c72017-04-27 11:17:28 -05001/**
2 * Copyright © 2017 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <iostream>
17#include <chrono>
18#include <gtest/gtest.h>
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070019#include <sdeventplus/event.hpp>
Matt Spinler59c29c72017-04-27 11:17:28 -050020#include "timer.hpp"
21
22/**
23 * Testcases for the Timer class
24 */
25
26using namespace phosphor::fan::util;
27using namespace std::chrono;
28
Matt Spinler59c29c72017-04-27 11:17:28 -050029
30/**
31 * Class to ensure sd_events are correctly
32 * setup and destroyed.
33 */
34class TimerTest : public ::testing::Test
35{
36 public:
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070037 // event loop
38 sdeventplus::Event event;
Matt Spinler59c29c72017-04-27 11:17:28 -050039
40 // Gets called as part of each TEST_F construction
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070041 TimerTest() : event(sdeventplus::Event::get_default())
42 { }
Matt Spinler59c29c72017-04-27 11:17:28 -050043};
44
45/**
46 * Helper class to hande tracking timer expirations
47 * via callback functions.
48 */
49class CallbackTester
50{
51 public:
52
53 CallbackTester() {}
54
55 size_t getCount()
56 {
57 return _count;
58 }
59
60 void callbackFunction()
61 {
62 _count++;
63 _gotCallback = true;
64 }
65
66 bool gotCallback()
67 {
68 return _gotCallback;
69 }
70
71 private:
72 bool _gotCallback = false;
73 size_t _count = 0;
74};
75
76
77/**
78 * Helper class that more closely mimics real usage,
79 * which is another class containing a timer and using
80 * one of its member functions as the callback.
81 */
82class CallbackTesterWithTimer : public CallbackTester
83{
84 public:
William A. Kennington III1cfc2f12018-10-19 17:29:46 -070085 CallbackTesterWithTimer(const sdeventplus::Event& event) :
86 _timer(event,
Matt Spinler59c29c72017-04-27 11:17:28 -050087 std::bind(&CallbackTesterWithTimer::callbackFunction,
88 this))
89 {
90 }
91
92 void callbackFunction()
93 {
94 //restart the timer once from the callback
95 if (!_restarted)
96 {
97 _restarted = true;
98 auto time = duration_cast<microseconds>(seconds(1));
99 _timer.start(time, Timer::TimerType::oneshot);
100 }
101
102 CallbackTester::callbackFunction();
103 }
104
105 Timer& getTimer()
106 {
107 return _timer;
108 }
109
110 inline bool restarted() const
111 {
112 return _restarted;
113 }
114
115 private:
116
117 Timer _timer;
118 bool _restarted = false;
119};
120
121
122/**
123 * Test that a callback will occur after 2 seconds.
124 */
125TEST_F(TimerTest, timerExpiresAfter2seconds)
126{
127 CallbackTester tester;
128
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700129 Timer timer(event,
Matt Spinler59c29c72017-04-27 11:17:28 -0500130 std::bind(&CallbackTester::callbackFunction, &tester));
131
132
133 auto time = duration_cast<microseconds>(seconds(2));
134
135 EXPECT_EQ(false, timer.running());
136
137 timer.start(time, Timer::TimerType::oneshot);
138 EXPECT_EQ(false, tester.gotCallback());
139 EXPECT_EQ(true, timer.running());
140
141 int count = 0;
Matt Spinler59c29c72017-04-27 11:17:28 -0500142
143 //Wait for 2 1s timeouts
144 while (count < 2)
145 {
146 // Returns 0 on timeout and positive number on dispatch
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700147 if (event.run(seconds(1)) == 0)
Matt Spinler59c29c72017-04-27 11:17:28 -0500148 {
149 count++;
150 }
151 }
152
153 EXPECT_EQ(true, tester.gotCallback());
154 EXPECT_EQ(1, tester.getCount());
155 EXPECT_EQ(false, timer.running());
156}
157
158/**
159 * Test that a timer can be restarted.
160 */
161TEST_F(TimerTest, timerRestart)
162{
163 CallbackTester tester;
164
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700165 Timer timer(event,
Matt Spinler59c29c72017-04-27 11:17:28 -0500166 std::bind(&CallbackTester::callbackFunction, &tester));
167
168
169 auto time = duration_cast<microseconds>(seconds(2));
170 timer.start(time, Timer::TimerType::oneshot);
171
172 //wait for a second
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700173 auto rc = event.run(seconds(1));
Matt Spinler59c29c72017-04-27 11:17:28 -0500174
175 //expect the timeout, not the dispatch
176 //and the timer should still be running
177 EXPECT_EQ(0, rc);
178 EXPECT_EQ(true, timer.running());
179
180 //Restart it
181 timer.start(time, Timer::TimerType::oneshot);
182
183 //Wait just 1s, make sure not done
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700184 rc = event.run(seconds(1));
Matt Spinler59c29c72017-04-27 11:17:28 -0500185 EXPECT_EQ(0, rc);
186 EXPECT_EQ(true, timer.running());
187 EXPECT_EQ(false, tester.gotCallback());
188
189 //Wait 1 more second, this time expecting a dispatch
190 int count = 0;
191 while (count < 1)
192 {
193 // Returns 0 on timeout and positive number on dispatch
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700194 if (event.run(seconds(1)) == 0)
Matt Spinler59c29c72017-04-27 11:17:28 -0500195 {
196 count++;
197 }
198 }
199
200 EXPECT_EQ(true, tester.gotCallback());
201 EXPECT_EQ(1, tester.getCount());
202 EXPECT_EQ(false, timer.running());
203}
204
205
206/**
207 * Test that a timer can be stopped.
208 */
209TEST_F(TimerTest, timerStop)
210{
211 CallbackTester tester;
212
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700213 Timer timer(event,
Matt Spinler59c29c72017-04-27 11:17:28 -0500214 std::bind(&CallbackTester::callbackFunction, &tester));
215
216
217 auto time = duration_cast<microseconds>(seconds(2));
218 timer.start(time, Timer::TimerType::oneshot);
219
Matt Spinler59c29c72017-04-27 11:17:28 -0500220 //wait 1s
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700221 auto rc = event.run(seconds(1));
Matt Spinler59c29c72017-04-27 11:17:28 -0500222
223 //expect the timeout, not the dispatch
224 EXPECT_EQ(rc, 0);
225 EXPECT_EQ(true, timer.running());
226
227 timer.stop();
228
229 EXPECT_EQ(false, timer.running());
230 EXPECT_EQ(false, tester.gotCallback());
231
232 //Wait another 2s, make sure no callbacks happened
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700233 rc = event.run(seconds(2));
Matt Spinler59c29c72017-04-27 11:17:28 -0500234
235 EXPECT_EQ(rc, 0);
236 EXPECT_EQ(false, timer.running());
237 EXPECT_EQ(false, tester.gotCallback());
238}
239
240
241/**
242 * Test that the timer can be restarted from within
243 * a callback function.
244 */
245TEST_F(TimerTest, timerRestartFromCallback)
246{
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700247 CallbackTesterWithTimer tester(event);
Matt Spinler59c29c72017-04-27 11:17:28 -0500248
249 auto& timer = tester.getTimer();
250
251 auto time = duration_cast<microseconds>(seconds(2));
252 timer.start(time, Timer::TimerType::oneshot);
253
254 //after running for 2 seconds, the timer will get restarted
255 //for another 1s
256
257 int count = 0;
Matt Spinler59c29c72017-04-27 11:17:28 -0500258 while (count < 3)
259 {
260 // Returns 0 on timeout and positive number on dispatch
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700261 if (event.run(seconds(1)) == 0)
Matt Spinler59c29c72017-04-27 11:17:28 -0500262 {
263 count++;
264 }
265 }
266
267 EXPECT_EQ(false, timer.running());
268 EXPECT_EQ(true, tester.gotCallback());
269 EXPECT_EQ(2, tester.getCount()); //2 callbacks
270 EXPECT_EQ(true, tester.restarted());
271}
272
273/**
274 * This shows what happens when the timer expires but
275 * sd_event_run never got called.
276 */
277TEST_F(TimerTest, timerNoEventRun)
278{
279 CallbackTester tester;
280
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700281 Timer timer(event,
Matt Spinler59c29c72017-04-27 11:17:28 -0500282 std::bind(&CallbackTester::callbackFunction, &tester));
283
284
285 auto time = duration_cast<microseconds>(milliseconds(500));
286
287 timer.start(time, Timer::TimerType::oneshot);
288
289 sleep(1);
290
291 //The timer should have expired, but with no event processing
292 //it will still think it's running.
293
294 EXPECT_EQ(true, timer.running());
295 EXPECT_EQ(false, tester.gotCallback());
296
297 //Now process an event
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700298 auto rc = event.run(milliseconds(5));
Matt Spinler59c29c72017-04-27 11:17:28 -0500299
300 EXPECT_GT(rc, 0);
301 EXPECT_EQ(false, timer.running());
302 EXPECT_EQ(true, tester.gotCallback());
303}
304
305
306/**
307 * Tests that a timer in repeating mode will keep calling
308 * the callback.
309 */
310TEST_F(TimerTest, RepeatingTimer)
311{
312 CallbackTester tester;
313
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700314 Timer timer(event,
Matt Spinler59c29c72017-04-27 11:17:28 -0500315 std::bind(&CallbackTester::callbackFunction, &tester));
316
317 auto time = duration_cast<microseconds>(seconds(1));
318 timer.start(time, Timer::TimerType::repeating);
319
320 int count = 0;
Matt Spinler59c29c72017-04-27 11:17:28 -0500321
322 while (count < 5)
323 {
William A. Kennington III1cfc2f12018-10-19 17:29:46 -0700324 if (event.run(milliseconds(500)) == 0)
Matt Spinler59c29c72017-04-27 11:17:28 -0500325 {
326 count++;
327 }
328 }
329
330 EXPECT_EQ(true, timer.running());
331 EXPECT_EQ(true, tester.gotCallback());
332 EXPECT_EQ(4, tester.getCount());
333
334 timer.stop();
335
336 EXPECT_EQ(false, timer.running());
337}