xref: /openbmc/sdeventplus/test/utility/timer.cpp (revision 4755818e)
1 #include <chrono>
2 #include <gmock/gmock.h>
3 #include <gtest/gtest.h>
4 #include <memory>
5 #include <sdeventplus/clock.hpp>
6 #include <sdeventplus/event.hpp>
7 #include <sdeventplus/test/sdevent.hpp>
8 #include <sdeventplus/utility/timer.hpp>
9 #include <stdexcept>
10 #include <systemd/sd-event.h>
11 
12 namespace sdeventplus
13 {
14 namespace utility
15 {
16 namespace
17 {
18 
19 constexpr ClockId testClock = ClockId::Monotonic;
20 
21 using std::chrono::microseconds;
22 using std::chrono::milliseconds;
23 using testing::DoAll;
24 using testing::Return;
25 using testing::SaveArg;
26 using testing::SetArgPointee;
27 using TestTimer = Timer<testClock>;
28 
29 ssize_t event_ref_times = 0;
30 
31 ACTION(EventRef)
32 {
33     event_ref_times++;
34 }
35 
36 ACTION(EventUnref)
37 {
38     ASSERT_LT(0, event_ref_times);
39     event_ref_times--;
40 }
41 
42 class TimerTest : public testing::Test
43 {
44   protected:
45     testing::StrictMock<test::SdEventMock> mock;
46     sd_event* const expected_event = reinterpret_cast<sd_event*>(1234);
47     sd_event_source* const expected_source =
48         reinterpret_cast<sd_event_source*>(2345);
49     const milliseconds interval{134};
50     const milliseconds starting_time{10};
51     sd_event_time_handler_t handler = nullptr;
52     void* handler_userdata;
53     std::unique_ptr<TestTimer> timer;
54     std::function<void()> callback;
55 
56     void expectNow(microseconds ret)
57     {
58         EXPECT_CALL(mock,
59                     sd_event_now(expected_event,
60                                  static_cast<clockid_t>(testClock), testing::_))
61             .WillOnce(DoAll(SetArgPointee<2>(ret.count()), Return(0)));
62     }
63 
64     void expectSetTime(microseconds time)
65     {
66         EXPECT_CALL(mock,
67                     sd_event_source_set_time(expected_source, time.count()))
68             .WillOnce(Return(0));
69     }
70 
71     void expectSetEnabled(source::Enabled enabled)
72     {
73         EXPECT_CALL(mock, sd_event_source_set_enabled(
74                               expected_source, static_cast<int>(enabled)))
75             .WillOnce(Return(0));
76     }
77 
78     void expectGetEnabled(source::Enabled enabled)
79     {
80         EXPECT_CALL(mock,
81                     sd_event_source_get_enabled(expected_source, testing::_))
82             .WillOnce(
83                 DoAll(SetArgPointee<1>(static_cast<int>(enabled)), Return(0)));
84     }
85 
86     void SetUp()
87     {
88         EXPECT_CALL(mock, sd_event_ref(expected_event))
89             .WillRepeatedly(DoAll(EventRef(), Return(expected_event)));
90         EXPECT_CALL(mock, sd_event_unref(expected_event))
91             .WillRepeatedly(DoAll(EventUnref(), Return(nullptr)));
92         Event event(expected_event, &mock);
93 
94         auto runCallback = [&](TestTimer&) {
95             if (callback)
96             {
97                 callback();
98             }
99         };
100         expectNow(starting_time);
101         EXPECT_CALL(mock, sd_event_add_time(
102                               expected_event, testing::_,
103                               static_cast<clockid_t>(testClock),
104                               microseconds(starting_time + interval).count(),
105                               1000, testing::_, nullptr))
106             .WillOnce(DoAll(SetArgPointee<1>(expected_source),
107                             SaveArg<5>(&handler), Return(0)));
108         EXPECT_CALL(mock,
109                     sd_event_source_set_userdata(expected_source, testing::_))
110             .WillOnce(DoAll(SaveArg<1>(&handler_userdata), Return(nullptr)));
111         // Timer always enables the source to keep ticking
112         expectSetEnabled(source::Enabled::On);
113         timer = std::make_unique<TestTimer>(event, runCallback, interval);
114     }
115 
116     void TearDown()
117     {
118         expectSetEnabled(source::Enabled::Off);
119         EXPECT_CALL(mock, sd_event_source_unref(expected_source))
120             .WillOnce(Return(nullptr));
121         timer.reset();
122         EXPECT_EQ(0, event_ref_times);
123     }
124 };
125 
126 TEST_F(TimerTest, NewTimer)
127 {
128     EXPECT_FALSE(timer->hasExpired());
129     EXPECT_EQ(interval, timer->getInterval());
130 }
131 
132 TEST_F(TimerTest, IsEnabled)
133 {
134     expectGetEnabled(source::Enabled::On);
135     EXPECT_TRUE(timer->isEnabled());
136     expectGetEnabled(source::Enabled::Off);
137     EXPECT_FALSE(timer->isEnabled());
138 }
139 
140 TEST_F(TimerTest, GetRemainingDisabled)
141 {
142     expectGetEnabled(source::Enabled::Off);
143     EXPECT_THROW(timer->getRemaining(), std::runtime_error);
144 }
145 
146 TEST_F(TimerTest, GetRemainingNegative)
147 {
148     milliseconds now(675), end(453);
149     expectGetEnabled(source::Enabled::On);
150     EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_))
151         .WillOnce(
152             DoAll(SetArgPointee<1>(microseconds(end).count()), Return(0)));
153     expectNow(now);
154     EXPECT_EQ(milliseconds(0), timer->getRemaining());
155 }
156 
157 TEST_F(TimerTest, GetRemainingPositive)
158 {
159     milliseconds now(453), end(675);
160     expectGetEnabled(source::Enabled::On);
161     EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_))
162         .WillOnce(
163             DoAll(SetArgPointee<1>(microseconds(end).count()), Return(0)));
164     expectNow(now);
165     EXPECT_EQ(end - now, timer->getRemaining());
166 }
167 
168 TEST_F(TimerTest, SetEnabled)
169 {
170     expectSetEnabled(source::Enabled::On);
171     timer->setEnabled(true);
172     EXPECT_FALSE(timer->hasExpired());
173     // Value should always be passed through regardless of current state
174     expectSetEnabled(source::Enabled::On);
175     timer->setEnabled(true);
176     EXPECT_FALSE(timer->hasExpired());
177 
178     expectSetEnabled(source::Enabled::Off);
179     timer->setEnabled(false);
180     EXPECT_FALSE(timer->hasExpired());
181     // Value should always be passed through regardless of current state
182     expectSetEnabled(source::Enabled::Off);
183     timer->setEnabled(false);
184     EXPECT_FALSE(timer->hasExpired());
185 }
186 
187 TEST_F(TimerTest, SetRemaining)
188 {
189     const milliseconds now(90), remaining(30);
190     expectNow(now);
191     expectSetTime(now + remaining);
192     timer->setRemaining(remaining);
193     EXPECT_EQ(interval, timer->getInterval());
194     EXPECT_FALSE(timer->hasExpired());
195 }
196 
197 TEST_F(TimerTest, ResetRemaining)
198 {
199     const milliseconds now(90);
200     expectNow(now);
201     expectSetTime(now + interval);
202     timer->resetRemaining();
203     EXPECT_EQ(interval, timer->getInterval());
204     EXPECT_FALSE(timer->hasExpired());
205 }
206 
207 TEST_F(TimerTest, SetInterval)
208 {
209     const milliseconds new_interval(40);
210     timer->setInterval(new_interval);
211     EXPECT_EQ(new_interval, timer->getInterval());
212     EXPECT_FALSE(timer->hasExpired());
213 }
214 
215 TEST_F(TimerTest, SetValuesExpiredTimer)
216 {
217     const milliseconds new_time(90);
218     expectNow(new_time);
219     expectSetTime(new_time + interval);
220     EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
221     EXPECT_TRUE(timer->hasExpired());
222     EXPECT_EQ(interval, timer->getInterval());
223 
224     // Timer should remain expired unless clearExpired() or reset()
225     expectSetEnabled(source::Enabled::On);
226     timer->setEnabled(true);
227     EXPECT_TRUE(timer->hasExpired());
228     expectNow(milliseconds(20));
229     expectSetTime(milliseconds(50));
230     timer->setRemaining(milliseconds(30));
231     EXPECT_TRUE(timer->hasExpired());
232     timer->setInterval(milliseconds(10));
233     EXPECT_TRUE(timer->hasExpired());
234     expectNow(milliseconds(20));
235     expectSetTime(milliseconds(30));
236     timer->resetRemaining();
237     EXPECT_TRUE(timer->hasExpired());
238 
239     timer->clearExpired();
240     EXPECT_FALSE(timer->hasExpired());
241 }
242 
243 TEST_F(TimerTest, Restart)
244 {
245     const milliseconds new_time(90);
246     expectNow(new_time);
247     expectSetTime(new_time + interval);
248     EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
249     EXPECT_TRUE(timer->hasExpired());
250     EXPECT_EQ(interval, timer->getInterval());
251 
252     const milliseconds new_interval(471);
253     expectNow(starting_time);
254     expectSetTime(starting_time + new_interval);
255     expectSetEnabled(source::Enabled::On);
256     timer->restart(new_interval);
257     EXPECT_FALSE(timer->hasExpired());
258     EXPECT_EQ(new_interval, timer->getInterval());
259 }
260 
261 } // namespace
262 } // namespace utility
263 } // namespace sdeventplus
264