blob: a3292870dfa092060b0ad455164298549bbb73d4 [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;
26using testing::SaveArg;
27using testing::SetArgPointee;
28using TestTimer = Timer<testClock>;
29
30ssize_t event_ref_times = 0;
31
32ACTION(EventRef)
33{
34 event_ref_times++;
35}
36
37ACTION(EventUnref)
38{
39 ASSERT_LT(0, event_ref_times);
40 event_ref_times--;
41}
42
43class TimerTest : public testing::Test
44{
45 protected:
46 testing::StrictMock<test::SdEventMock> mock;
47 sd_event* const expected_event = reinterpret_cast<sd_event*>(1234);
48 sd_event_source* const expected_source =
49 reinterpret_cast<sd_event_source*>(2345);
50 const milliseconds interval{134};
51 const milliseconds starting_time{10};
52 sd_event_time_handler_t handler = nullptr;
53 void* handler_userdata;
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -070054 std::unique_ptr<Event> event;
William A. Kennington III81282e12018-09-19 18:28:37 -070055 std::unique_ptr<TestTimer> timer;
56 std::function<void()> callback;
57
58 void expectNow(microseconds ret)
59 {
60 EXPECT_CALL(mock,
61 sd_event_now(expected_event,
62 static_cast<clockid_t>(testClock), testing::_))
63 .WillOnce(DoAll(SetArgPointee<2>(ret.count()), Return(0)));
64 }
65
66 void expectSetTime(microseconds time)
67 {
68 EXPECT_CALL(mock,
69 sd_event_source_set_time(expected_source, time.count()))
70 .WillOnce(Return(0));
71 }
72
73 void expectSetEnabled(source::Enabled enabled)
74 {
75 EXPECT_CALL(mock, sd_event_source_set_enabled(
76 expected_source, static_cast<int>(enabled)))
77 .WillOnce(Return(0));
78 }
79
80 void expectGetEnabled(source::Enabled enabled)
81 {
82 EXPECT_CALL(mock,
83 sd_event_source_get_enabled(expected_source, testing::_))
84 .WillOnce(
85 DoAll(SetArgPointee<1>(static_cast<int>(enabled)), Return(0)));
86 }
87
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -070088 void resetTimer()
89 {
90 if (timer)
91 {
92 expectSetEnabled(source::Enabled::Off);
93 timer.reset();
94 }
95 }
96
97 void expireTimer()
98 {
99 const milliseconds new_time(90);
100 expectNow(new_time);
101 expectSetTime(new_time + interval);
102 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
103 EXPECT_TRUE(timer->hasExpired());
104 EXPECT_EQ(interval, timer->getInterval());
105 }
106
William A. Kennington III81282e12018-09-19 18:28:37 -0700107 void SetUp()
108 {
109 EXPECT_CALL(mock, sd_event_ref(expected_event))
110 .WillRepeatedly(DoAll(EventRef(), Return(expected_event)));
111 EXPECT_CALL(mock, sd_event_unref(expected_event))
112 .WillRepeatedly(DoAll(EventUnref(), Return(nullptr)));
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700113 event = std::make_unique<Event>(expected_event, &mock);
114 EXPECT_CALL(mock, sd_event_source_unref(expected_source))
115 .WillRepeatedly(Return(nullptr));
116 EXPECT_CALL(mock,
117 sd_event_source_set_userdata(expected_source, testing::_))
118 .WillRepeatedly(
119 DoAll(SaveArg<1>(&handler_userdata), Return(nullptr)));
William A. Kennington III81282e12018-09-19 18:28:37 -0700120
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700121 // Having a callback proxy allows us to update the test callback
122 // dynamically, without changing it inside the timer
William A. Kennington III47558182018-09-25 15:18:14 -0700123 auto runCallback = [&](TestTimer&) {
William A. Kennington III81282e12018-09-19 18:28:37 -0700124 if (callback)
125 {
126 callback();
127 }
128 };
129 expectNow(starting_time);
130 EXPECT_CALL(mock, sd_event_add_time(
131 expected_event, testing::_,
132 static_cast<clockid_t>(testClock),
133 microseconds(starting_time + interval).count(),
134 1000, testing::_, nullptr))
135 .WillOnce(DoAll(SetArgPointee<1>(expected_source),
136 SaveArg<5>(&handler), Return(0)));
William A. Kennington III81282e12018-09-19 18:28:37 -0700137 expectSetEnabled(source::Enabled::On);
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700138 timer = std::make_unique<TestTimer>(*event, runCallback, interval);
William A. Kennington III81282e12018-09-19 18:28:37 -0700139 }
140
141 void TearDown()
142 {
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700143 resetTimer();
144 event.reset();
William A. Kennington III81282e12018-09-19 18:28:37 -0700145 EXPECT_EQ(0, event_ref_times);
146 }
147};
148
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700149TEST_F(TimerTest, NoCallback)
150{
151 resetTimer();
152 expectNow(starting_time);
153 EXPECT_CALL(
154 mock, sd_event_add_time(expected_event, testing::_,
155 static_cast<clockid_t>(testClock),
156 microseconds(starting_time + interval).count(),
157 1000, testing::_, nullptr))
158 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler),
159 Return(0)));
160 expectSetEnabled(source::Enabled::On);
161 timer = std::make_unique<TestTimer>(*event, nullptr, interval);
162
163 expectNow(starting_time);
164 expectSetTime(starting_time + interval);
165 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
166}
167
168TEST_F(TimerTest, NoInterval)
169{
170 resetTimer();
171 expectNow(starting_time);
172 EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_,
173 static_cast<clockid_t>(testClock),
174 microseconds(starting_time).count(),
175 1000, testing::_, nullptr))
176 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler),
177 Return(0)));
178 expectSetEnabled(source::Enabled::Off);
179 timer = std::make_unique<TestTimer>(*event, nullptr);
180
181 EXPECT_EQ(std::nullopt, timer->getInterval());
182 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
183}
184
William A. Kennington III81282e12018-09-19 18:28:37 -0700185TEST_F(TimerTest, NewTimer)
186{
187 EXPECT_FALSE(timer->hasExpired());
188 EXPECT_EQ(interval, timer->getInterval());
189}
190
191TEST_F(TimerTest, IsEnabled)
192{
193 expectGetEnabled(source::Enabled::On);
194 EXPECT_TRUE(timer->isEnabled());
195 expectGetEnabled(source::Enabled::Off);
196 EXPECT_FALSE(timer->isEnabled());
197}
198
199TEST_F(TimerTest, GetRemainingDisabled)
200{
201 expectGetEnabled(source::Enabled::Off);
202 EXPECT_THROW(timer->getRemaining(), std::runtime_error);
203}
204
205TEST_F(TimerTest, GetRemainingNegative)
206{
207 milliseconds now(675), end(453);
208 expectGetEnabled(source::Enabled::On);
209 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_))
210 .WillOnce(
211 DoAll(SetArgPointee<1>(microseconds(end).count()), Return(0)));
212 expectNow(now);
213 EXPECT_EQ(milliseconds(0), timer->getRemaining());
214}
215
216TEST_F(TimerTest, GetRemainingPositive)
217{
218 milliseconds now(453), end(675);
219 expectGetEnabled(source::Enabled::On);
220 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_))
221 .WillOnce(
222 DoAll(SetArgPointee<1>(microseconds(end).count()), Return(0)));
223 expectNow(now);
224 EXPECT_EQ(end - now, timer->getRemaining());
225}
226
227TEST_F(TimerTest, SetEnabled)
228{
229 expectSetEnabled(source::Enabled::On);
230 timer->setEnabled(true);
231 EXPECT_FALSE(timer->hasExpired());
232 // Value should always be passed through regardless of current state
233 expectSetEnabled(source::Enabled::On);
234 timer->setEnabled(true);
235 EXPECT_FALSE(timer->hasExpired());
236
237 expectSetEnabled(source::Enabled::Off);
238 timer->setEnabled(false);
239 EXPECT_FALSE(timer->hasExpired());
240 // Value should always be passed through regardless of current state
241 expectSetEnabled(source::Enabled::Off);
242 timer->setEnabled(false);
243 EXPECT_FALSE(timer->hasExpired());
244}
245
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700246TEST_F(TimerTest, SetEnabledUnsetTimer)
247{
248 // Force the timer to become unset
249 expectSetEnabled(source::Enabled::Off);
250 timer->restart(std::nullopt);
251
252 // Setting an interval should not update the timer directly
253 timer->setInterval(milliseconds(90));
254
255 expectSetEnabled(source::Enabled::Off);
256 timer->setEnabled(false);
257 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
258}
259
260TEST_F(TimerTest, SetEnabledOneshot)
261{
262 // Timer effectively becomes oneshot if it gets initialized but has
263 // the interval removed
264 timer->setInterval(std::nullopt);
265
266 expectSetEnabled(source::Enabled::Off);
267 timer->setEnabled(false);
268 expectSetEnabled(source::Enabled::On);
269 timer->setEnabled(true);
270}
271
William A. Kennington III81282e12018-09-19 18:28:37 -0700272TEST_F(TimerTest, SetRemaining)
273{
274 const milliseconds now(90), remaining(30);
275 expectNow(now);
276 expectSetTime(now + remaining);
277 timer->setRemaining(remaining);
278 EXPECT_EQ(interval, timer->getInterval());
279 EXPECT_FALSE(timer->hasExpired());
280}
281
282TEST_F(TimerTest, ResetRemaining)
283{
284 const milliseconds now(90);
285 expectNow(now);
286 expectSetTime(now + interval);
287 timer->resetRemaining();
288 EXPECT_EQ(interval, timer->getInterval());
289 EXPECT_FALSE(timer->hasExpired());
290}
291
292TEST_F(TimerTest, SetInterval)
293{
294 const milliseconds new_interval(40);
295 timer->setInterval(new_interval);
296 EXPECT_EQ(new_interval, timer->getInterval());
297 EXPECT_FALSE(timer->hasExpired());
298}
299
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700300TEST_F(TimerTest, SetIntervalEmpty)
301{
302 timer->setInterval(std::nullopt);
303 EXPECT_EQ(std::nullopt, timer->getInterval());
304 EXPECT_FALSE(timer->hasExpired());
305}
306
307TEST_F(TimerTest, CallbackHappensLast)
308{
309 const milliseconds new_time(90);
310 expectNow(new_time);
311 expectSetTime(new_time + interval);
312 callback = [&]() {
313 EXPECT_TRUE(timer->hasExpired());
314 expectSetEnabled(source::Enabled::On);
315 timer->setEnabled(true);
316 timer->clearExpired();
317 timer->setInterval(std::nullopt);
318 };
319 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
320 EXPECT_FALSE(timer->hasExpired());
321 EXPECT_EQ(std::nullopt, timer->getInterval());
322 expectSetEnabled(source::Enabled::On);
323 timer->setEnabled(true);
324}
325
326TEST_F(TimerTest, CallbackOneshot)
327{
328 // Make sure we try a one shot so we can test the callback
329 // correctly
330 timer->setInterval(std::nullopt);
331
332 expectSetEnabled(source::Enabled::Off);
333 callback = [&]() {
334 EXPECT_TRUE(timer->hasExpired());
335 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
336 timer->setInterval(interval);
337 };
338 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
339 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
340}
341
William A. Kennington III81282e12018-09-19 18:28:37 -0700342TEST_F(TimerTest, SetValuesExpiredTimer)
343{
344 const milliseconds new_time(90);
345 expectNow(new_time);
346 expectSetTime(new_time + interval);
347 EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
348 EXPECT_TRUE(timer->hasExpired());
349 EXPECT_EQ(interval, timer->getInterval());
350
351 // Timer should remain expired unless clearExpired() or reset()
352 expectSetEnabled(source::Enabled::On);
353 timer->setEnabled(true);
354 EXPECT_TRUE(timer->hasExpired());
355 expectNow(milliseconds(20));
356 expectSetTime(milliseconds(50));
357 timer->setRemaining(milliseconds(30));
358 EXPECT_TRUE(timer->hasExpired());
359 timer->setInterval(milliseconds(10));
360 EXPECT_TRUE(timer->hasExpired());
361 expectNow(milliseconds(20));
362 expectSetTime(milliseconds(30));
363 timer->resetRemaining();
364 EXPECT_TRUE(timer->hasExpired());
365
366 timer->clearExpired();
367 EXPECT_FALSE(timer->hasExpired());
368}
369
370TEST_F(TimerTest, Restart)
371{
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700372 expireTimer();
William A. Kennington III81282e12018-09-19 18:28:37 -0700373
374 const milliseconds new_interval(471);
375 expectNow(starting_time);
376 expectSetTime(starting_time + new_interval);
377 expectSetEnabled(source::Enabled::On);
378 timer->restart(new_interval);
379 EXPECT_FALSE(timer->hasExpired());
380 EXPECT_EQ(new_interval, timer->getInterval());
William A. Kennington IIIba04ffb2018-09-20 11:35:11 -0700381 expectSetEnabled(source::Enabled::On);
382 timer->setEnabled(true);
383}
384
385TEST_F(TimerTest, RestartEmpty)
386{
387 expireTimer();
388
389 expectSetEnabled(source::Enabled::Off);
390 timer->restart(std::nullopt);
391 EXPECT_FALSE(timer->hasExpired());
392 EXPECT_EQ(std::nullopt, timer->getInterval());
393 EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
394}
395
396TEST_F(TimerTest, RestartOnce)
397{
398 expireTimer();
399
400 const milliseconds remaining(471);
401 expectNow(starting_time);
402 expectSetTime(starting_time + remaining);
403 expectSetEnabled(source::Enabled::On);
404 timer->restartOnce(remaining);
405 EXPECT_FALSE(timer->hasExpired());
406 EXPECT_EQ(std::nullopt, timer->getInterval());
407 expectSetEnabled(source::Enabled::On);
408 timer->setEnabled(true);
William A. Kennington III81282e12018-09-19 18:28:37 -0700409}
410
411} // namespace
412} // namespace utility
413} // namespace sdeventplus