blob: 70fda1b8705bfeb275b5280b475715f4777d6667 [file] [log] [blame]
William A. Kennington III81282e12018-09-19 18:28:37 -07001#include <chrono>
2#include <gmock/gmock.h>
3#include <gtest/gtest.h>
4#include <memory>
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -07005#include <optional>
William A. Kennington III81282e12018-09-19 18:28:37 -07006#include <sdeventplus/clock.hpp>
7#include <sdeventplus/event.hpp>
8#include <sdeventplus/test/sdevent.hpp>
9#include <sdeventplus/utility/timer.hpp>
10#include <stdexcept>
11#include <systemd/sd-event.h>
12
13namespace sdeventplus
14{
15namespace utility
16{
17namespace
18{
19
20constexpr ClockId testClock = ClockId::Monotonic;
21
22using std::chrono::microseconds;
23using std::chrono::milliseconds;
24using testing::DoAll;
25using testing::Return;
William A. Kennington III5320b1f2019-03-29 20:00:37 -070026using testing::ReturnPointee;
William A. Kennington III81282e12018-09-19 18:28:37 -070027using testing::SaveArg;
28using testing::SetArgPointee;
29using TestTimer = Timer<testClock>;
30
31ssize_t event_ref_times = 0;
32
33ACTION(EventRef)
34{
35 event_ref_times++;
36}
37
38ACTION(EventUnref)
39{
40 ASSERT_LT(0, event_ref_times);
41 event_ref_times--;
42}
43
44class TimerTest : public testing::Test
45{
46 protected:
47 testing::StrictMock<test::SdEventMock> mock;
48 sd_event* const expected_event = reinterpret_cast<sd_event*>(1234);
49 sd_event_source* const expected_source =
50 reinterpret_cast<sd_event_source*>(2345);
William A. Kennington IIIa5f85962018-10-29 20:15:45 -070051 sd_event_source* const expected_source2 =
52 reinterpret_cast<sd_event_source*>(3456);
William A. Kennington III81282e12018-09-19 18:28:37 -070053 const milliseconds interval{134};
54 const milliseconds starting_time{10};
William A. Kennington IIIa5f85962018-10-29 20:15:45 -070055 const milliseconds starting_time2{30};
William A. Kennington III81282e12018-09-19 18:28:37 -070056 sd_event_time_handler_t handler = nullptr;
57 void* handler_userdata;
William A. Kennington III5320b1f2019-03-29 20:00:37 -070058 sd_event_destroy_t handler_destroy;
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -070059 std::unique_ptr<Event> event;
William A. Kennington III81282e12018-09-19 18:28:37 -070060 std::unique_ptr<TestTimer> timer;
61 std::function<void()> callback;
62
63 void expectNow(microseconds ret)
64 {
65 EXPECT_CALL(mock,
66 sd_event_now(expected_event,
67 static_cast<clockid_t>(testClock), testing::_))
68 .WillOnce(DoAll(SetArgPointee<2>(ret.count()), Return(0)));
69 }
70
71 void expectSetTime(microseconds time)
72 {
73 EXPECT_CALL(mock,
74 sd_event_source_set_time(expected_source, time.count()))
75 .WillOnce(Return(0));
76 }
77
78 void expectSetEnabled(source::Enabled enabled)
79 {
80 EXPECT_CALL(mock, sd_event_source_set_enabled(
81 expected_source, static_cast<int>(enabled)))
82 .WillOnce(Return(0));
83 }
84
85 void expectGetEnabled(source::Enabled enabled)
86 {
87 EXPECT_CALL(mock,
88 sd_event_source_get_enabled(expected_source, testing::_))
89 .WillOnce(
90 DoAll(SetArgPointee<1>(static_cast<int>(enabled)), Return(0)));
91 }
92
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -070093 void resetTimer()
94 {
95 if (timer)
96 {
97 expectSetEnabled(source::Enabled::Off);
98 timer.reset();
William A. Kennington III5320b1f2019-03-29 20:00:37 -070099 handler_destroy(handler_userdata);
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700100 }
101 }
102
103 void expireTimer()
104 {
105 const milliseconds new_time(90);
106 expectNow(new_time);
107 expectSetTime(new_time + interval);
108 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
109 EXPECT_TRUE(timer->hasExpired());
110 EXPECT_EQ(interval, timer->getInterval());
111 }
112
William A. Kennington III81282e12018-09-19 18:28:37 -0700113 void SetUp()
114 {
115 EXPECT_CALL(mock, sd_event_ref(expected_event))
116 .WillRepeatedly(DoAll(EventRef(), Return(expected_event)));
117 EXPECT_CALL(mock, sd_event_unref(expected_event))
118 .WillRepeatedly(DoAll(EventUnref(), Return(nullptr)));
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700119 event = std::make_unique<Event>(expected_event, &mock);
120 EXPECT_CALL(mock, sd_event_source_unref(expected_source))
121 .WillRepeatedly(Return(nullptr));
William A. Kennington III5320b1f2019-03-29 20:00:37 -0700122 EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
123 testing::_))
124 .WillRepeatedly(DoAll(SaveArg<1>(&handler_destroy), Return(0)));
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700125 EXPECT_CALL(mock,
126 sd_event_source_set_userdata(expected_source, testing::_))
127 .WillRepeatedly(
128 DoAll(SaveArg<1>(&handler_userdata), Return(nullptr)));
William A. Kennington III5320b1f2019-03-29 20:00:37 -0700129 EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
130 .WillRepeatedly(ReturnPointee(&handler_userdata));
William A. Kennington III81282e12018-09-19 18:28:37 -0700131
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700132 // Having a callback proxy allows us to update the test callback
133 // dynamically, without changing it inside the timer
William A. Kennington III47558182018-09-25 15:18:14 -0700134 auto runCallback = [&](TestTimer&) {
William A. Kennington III81282e12018-09-19 18:28:37 -0700135 if (callback)
136 {
137 callback();
138 }
139 };
140 expectNow(starting_time);
141 EXPECT_CALL(mock, sd_event_add_time(
142 expected_event, testing::_,
143 static_cast<clockid_t>(testClock),
144 microseconds(starting_time + interval).count(),
145 1000, testing::_, nullptr))
146 .WillOnce(DoAll(SetArgPointee<1>(expected_source),
147 SaveArg<5>(&handler), Return(0)));
William A. Kennington III81282e12018-09-19 18:28:37 -0700148 expectSetEnabled(source::Enabled::On);
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700149 timer = std::make_unique<TestTimer>(*event, runCallback, interval);
William A. Kennington III27b73012018-10-18 01:12:09 -0700150 EXPECT_EQ(expected_event, timer->get_event().get());
William A. Kennington III81282e12018-09-19 18:28:37 -0700151 }
152
153 void TearDown()
154 {
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700155 resetTimer();
156 event.reset();
William A. Kennington III81282e12018-09-19 18:28:37 -0700157 EXPECT_EQ(0, event_ref_times);
158 }
159};
160
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700161TEST_F(TimerTest, NoCallback)
162{
163 resetTimer();
164 expectNow(starting_time);
165 EXPECT_CALL(
166 mock, sd_event_add_time(expected_event, testing::_,
167 static_cast<clockid_t>(testClock),
168 microseconds(starting_time + interval).count(),
169 1000, testing::_, nullptr))
170 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler),
171 Return(0)));
172 expectSetEnabled(source::Enabled::On);
173 timer = std::make_unique<TestTimer>(*event, nullptr, interval);
174
175 expectNow(starting_time);
176 expectSetTime(starting_time + interval);
177 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
178}
179
180TEST_F(TimerTest, NoInterval)
181{
182 resetTimer();
183 expectNow(starting_time);
184 EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_,
185 static_cast<clockid_t>(testClock),
186 microseconds(starting_time).count(),
187 1000, testing::_, nullptr))
188 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler),
189 Return(0)));
190 expectSetEnabled(source::Enabled::Off);
191 timer = std::make_unique<TestTimer>(*event, nullptr);
192
193 EXPECT_EQ(std::nullopt, timer->getInterval());
194 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
195}
196
William A. Kennington III81282e12018-09-19 18:28:37 -0700197TEST_F(TimerTest, NewTimer)
198{
199 EXPECT_FALSE(timer->hasExpired());
200 EXPECT_EQ(interval, timer->getInterval());
201}
202
203TEST_F(TimerTest, IsEnabled)
204{
205 expectGetEnabled(source::Enabled::On);
206 EXPECT_TRUE(timer->isEnabled());
207 expectGetEnabled(source::Enabled::Off);
208 EXPECT_FALSE(timer->isEnabled());
209}
210
211TEST_F(TimerTest, GetRemainingDisabled)
212{
213 expectGetEnabled(source::Enabled::Off);
214 EXPECT_THROW(timer->getRemaining(), std::runtime_error);
215}
216
217TEST_F(TimerTest, GetRemainingNegative)
218{
219 milliseconds now(675), end(453);
220 expectGetEnabled(source::Enabled::On);
221 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_))
222 .WillOnce(
223 DoAll(SetArgPointee<1>(microseconds(end).count()), Return(0)));
224 expectNow(now);
225 EXPECT_EQ(milliseconds(0), timer->getRemaining());
226}
227
228TEST_F(TimerTest, GetRemainingPositive)
229{
230 milliseconds now(453), end(675);
231 expectGetEnabled(source::Enabled::On);
232 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_))
233 .WillOnce(
234 DoAll(SetArgPointee<1>(microseconds(end).count()), Return(0)));
235 expectNow(now);
236 EXPECT_EQ(end - now, timer->getRemaining());
237}
238
239TEST_F(TimerTest, SetEnabled)
240{
241 expectSetEnabled(source::Enabled::On);
242 timer->setEnabled(true);
243 EXPECT_FALSE(timer->hasExpired());
244 // Value should always be passed through regardless of current state
245 expectSetEnabled(source::Enabled::On);
246 timer->setEnabled(true);
247 EXPECT_FALSE(timer->hasExpired());
248
249 expectSetEnabled(source::Enabled::Off);
250 timer->setEnabled(false);
251 EXPECT_FALSE(timer->hasExpired());
252 // Value should always be passed through regardless of current state
253 expectSetEnabled(source::Enabled::Off);
254 timer->setEnabled(false);
255 EXPECT_FALSE(timer->hasExpired());
256}
257
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700258TEST_F(TimerTest, SetEnabledUnsetTimer)
259{
260 // Force the timer to become unset
261 expectSetEnabled(source::Enabled::Off);
262 timer->restart(std::nullopt);
263
264 // Setting an interval should not update the timer directly
265 timer->setInterval(milliseconds(90));
266
267 expectSetEnabled(source::Enabled::Off);
268 timer->setEnabled(false);
269 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
270}
271
272TEST_F(TimerTest, SetEnabledOneshot)
273{
274 // Timer effectively becomes oneshot if it gets initialized but has
275 // the interval removed
276 timer->setInterval(std::nullopt);
277
278 expectSetEnabled(source::Enabled::Off);
279 timer->setEnabled(false);
280 expectSetEnabled(source::Enabled::On);
281 timer->setEnabled(true);
282}
283
William A. Kennington III81282e12018-09-19 18:28:37 -0700284TEST_F(TimerTest, SetRemaining)
285{
286 const milliseconds now(90), remaining(30);
287 expectNow(now);
288 expectSetTime(now + remaining);
289 timer->setRemaining(remaining);
290 EXPECT_EQ(interval, timer->getInterval());
291 EXPECT_FALSE(timer->hasExpired());
292}
293
294TEST_F(TimerTest, ResetRemaining)
295{
296 const milliseconds now(90);
297 expectNow(now);
298 expectSetTime(now + interval);
299 timer->resetRemaining();
300 EXPECT_EQ(interval, timer->getInterval());
301 EXPECT_FALSE(timer->hasExpired());
302}
303
304TEST_F(TimerTest, SetInterval)
305{
306 const milliseconds new_interval(40);
307 timer->setInterval(new_interval);
308 EXPECT_EQ(new_interval, timer->getInterval());
309 EXPECT_FALSE(timer->hasExpired());
310}
311
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700312TEST_F(TimerTest, SetIntervalEmpty)
313{
314 timer->setInterval(std::nullopt);
315 EXPECT_EQ(std::nullopt, timer->getInterval());
316 EXPECT_FALSE(timer->hasExpired());
317}
318
319TEST_F(TimerTest, CallbackHappensLast)
320{
321 const milliseconds new_time(90);
322 expectNow(new_time);
323 expectSetTime(new_time + interval);
324 callback = [&]() {
325 EXPECT_TRUE(timer->hasExpired());
326 expectSetEnabled(source::Enabled::On);
327 timer->setEnabled(true);
328 timer->clearExpired();
329 timer->setInterval(std::nullopt);
330 };
331 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
332 EXPECT_FALSE(timer->hasExpired());
333 EXPECT_EQ(std::nullopt, timer->getInterval());
334 expectSetEnabled(source::Enabled::On);
335 timer->setEnabled(true);
336}
337
338TEST_F(TimerTest, CallbackOneshot)
339{
340 // Make sure we try a one shot so we can test the callback
341 // correctly
342 timer->setInterval(std::nullopt);
343
344 expectSetEnabled(source::Enabled::Off);
345 callback = [&]() {
346 EXPECT_TRUE(timer->hasExpired());
347 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
348 timer->setInterval(interval);
349 };
350 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
351 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
352}
353
William A. Kennington IIIa5f85962018-10-29 20:15:45 -0700354TEST_F(TimerTest, CallbackMove)
355{
356 size_t called = 0;
357 callback = [&]() { ++called; };
358
359 expectNow(starting_time2);
William A. Kennington III5320b1f2019-03-29 20:00:37 -0700360 sd_event_destroy_t local_destroy;
361 EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source2,
362 testing::_))
363 .WillOnce(DoAll(SaveArg<1>(&local_destroy), Return(0)));
364 void* local_userdata;
William A. Kennington IIIa5f85962018-10-29 20:15:45 -0700365 EXPECT_CALL(mock,
366 sd_event_source_set_userdata(expected_source2, testing::_))
William A. Kennington III5320b1f2019-03-29 20:00:37 -0700367 .WillOnce(DoAll(SaveArg<1>(&local_userdata), Return(nullptr)));
368 EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source2))
369 .WillRepeatedly(ReturnPointee(&local_userdata));
William A. Kennington IIIa5f85962018-10-29 20:15:45 -0700370 EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_,
371 static_cast<clockid_t>(testClock),
372 microseconds(starting_time2).count(),
373 1000, testing::_, nullptr))
374 .WillOnce(DoAll(SetArgPointee<1>(expected_source2), Return(0)));
375 EXPECT_CALL(mock, sd_event_source_unref(expected_source2))
376 .WillOnce(Return(nullptr));
377 EXPECT_CALL(mock,
378 sd_event_source_set_enabled(
379 expected_source2, static_cast<int>(source::Enabled::Off)))
380 .WillOnce(Return(0))
381 .WillOnce(Return(0));
382 TestTimer local_timer(*event, nullptr);
383
384 // Move assign
385 local_timer = std::move(*timer);
William A. Kennington III5320b1f2019-03-29 20:00:37 -0700386 local_destroy(local_userdata);
William A. Kennington IIIa5f85962018-10-29 20:15:45 -0700387 timer.reset();
388
389 // Move construct
390 timer = std::make_unique<TestTimer>(std::move(local_timer));
391
392 // handler_userdata should have been updated and the callback should work
393 const milliseconds new_time(90);
394 expectNow(new_time);
395 expectSetTime(new_time + interval);
396 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
397 EXPECT_EQ(1, called);
William A. Kennington III08ebb392018-10-30 13:21:13 -0700398
399 // update the callback and make sure it still works
400 timer->set_callback(std::bind([]() {}));
401 expectNow(new_time);
402 expectSetTime(new_time + interval);
403 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
404 EXPECT_EQ(1, called);
William A. Kennington IIIa5f85962018-10-29 20:15:45 -0700405}
406
William A. Kennington III81282e12018-09-19 18:28:37 -0700407TEST_F(TimerTest, SetValuesExpiredTimer)
408{
409 const milliseconds new_time(90);
410 expectNow(new_time);
411 expectSetTime(new_time + interval);
412 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
413 EXPECT_TRUE(timer->hasExpired());
414 EXPECT_EQ(interval, timer->getInterval());
415
416 // Timer should remain expired unless clearExpired() or reset()
417 expectSetEnabled(source::Enabled::On);
418 timer->setEnabled(true);
419 EXPECT_TRUE(timer->hasExpired());
420 expectNow(milliseconds(20));
421 expectSetTime(milliseconds(50));
422 timer->setRemaining(milliseconds(30));
423 EXPECT_TRUE(timer->hasExpired());
424 timer->setInterval(milliseconds(10));
425 EXPECT_TRUE(timer->hasExpired());
426 expectNow(milliseconds(20));
427 expectSetTime(milliseconds(30));
428 timer->resetRemaining();
429 EXPECT_TRUE(timer->hasExpired());
430
431 timer->clearExpired();
432 EXPECT_FALSE(timer->hasExpired());
433}
434
435TEST_F(TimerTest, Restart)
436{
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700437 expireTimer();
William A. Kennington III81282e12018-09-19 18:28:37 -0700438
439 const milliseconds new_interval(471);
440 expectNow(starting_time);
441 expectSetTime(starting_time + new_interval);
442 expectSetEnabled(source::Enabled::On);
443 timer->restart(new_interval);
444 EXPECT_FALSE(timer->hasExpired());
445 EXPECT_EQ(new_interval, timer->getInterval());
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700446 expectSetEnabled(source::Enabled::On);
447 timer->setEnabled(true);
448}
449
450TEST_F(TimerTest, RestartEmpty)
451{
452 expireTimer();
453
454 expectSetEnabled(source::Enabled::Off);
455 timer->restart(std::nullopt);
456 EXPECT_FALSE(timer->hasExpired());
457 EXPECT_EQ(std::nullopt, timer->getInterval());
458 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
459}
460
461TEST_F(TimerTest, RestartOnce)
462{
463 expireTimer();
464
465 const milliseconds remaining(471);
466 expectNow(starting_time);
467 expectSetTime(starting_time + remaining);
468 expectSetEnabled(source::Enabled::On);
469 timer->restartOnce(remaining);
470 EXPECT_FALSE(timer->hasExpired());
471 EXPECT_EQ(std::nullopt, timer->getInterval());
472 expectSetEnabled(source::Enabled::On);
473 timer->setEnabled(true);
William A. Kennington III81282e12018-09-19 18:28:37 -0700474}
475
476} // namespace
477} // namespace utility
478} // namespace sdeventplus