xref: /openbmc/sdeventplus/test/source/base.cpp (revision a8c11e3c)
1 #include <systemd/sd-event.h>
2 
3 #include <sdeventplus/event.hpp>
4 #include <sdeventplus/exception.hpp>
5 #include <sdeventplus/internal/sdevent.hpp>
6 #include <sdeventplus/source/base.hpp>
7 #include <sdeventplus/test/sdevent.hpp>
8 #include <sdeventplus/types.hpp>
9 
10 #include <cerrno>
11 #include <functional>
12 #include <memory>
13 #include <optional>
14 #include <string>
15 #include <tuple>
16 #include <type_traits>
17 #include <utility>
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 
22 namespace sdeventplus
23 {
24 namespace source
25 {
26 namespace
27 {
28 
29 using testing::DoAll;
30 using testing::Return;
31 using testing::SaveArg;
32 using testing::SetArgPointee;
33 
34 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>;
35 
36 class BaseImplData;
37 
38 class BaseImpl : public Base
39 {
40   public:
41     BaseImpl(const Event& event, sd_event_source* source, std::false_type);
42 
BaseImpl(const BaseImpl & other,sdeventplus::internal::NoOwn)43     BaseImpl(const BaseImpl& other, sdeventplus::internal::NoOwn) :
44         Base(other, sdeventplus::internal::NoOwn())
45     {}
46 
47     using Base::get_prepare;
48 };
49 
50 class BaseImplData : public BaseImpl, public detail::BaseData
51 {
52   public:
BaseImplData(const BaseImpl & base)53     BaseImplData(const BaseImpl& base) :
54         BaseImpl(base, sdeventplus::internal::NoOwn()), BaseData(base)
55     {}
56 };
57 
BaseImpl(const Event & event,sd_event_source * source,std::false_type)58 BaseImpl::BaseImpl(const Event& event, sd_event_source* source,
59                    std::false_type) :
60     Base(event, source, std::false_type())
61 {
62     set_userdata(std::make_unique<BaseImplData>(*this));
63 }
64 
65 class BaseTest : public testing::Test
66 {
67   protected:
68     testing::StrictMock<test::SdEventMock> mock;
69     sd_event_source* const expected_source =
70         reinterpret_cast<sd_event_source*>(1234);
71     sd_event_source* const expected_source2 =
72         reinterpret_cast<sd_event_source*>(3456);
73     sd_event* const expected_event = reinterpret_cast<sd_event*>(2345);
74     sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567);
75 
76     UniqueEvent event = make_event(expected_event);
77 
make_event(sd_event * event)78     UniqueEvent make_event(sd_event* event)
79     {
80         auto deleter = [this, event](Event* e) {
81             EXPECT_CALL(this->mock, sd_event_unref(event))
82                 .WillOnce(Return(nullptr));
83             delete e;
84         };
85         return UniqueEvent(new Event(event, std::false_type(), &mock), deleter);
86     }
87 
88     // Using a unique_ptr to make sure we don't get any superfluous moves or
89     // copies.
90     std::tuple<std::unique_ptr<BaseImpl>, std::function<void()>>
make_base(const Event & event,sd_event_source * source)91         make_base(const Event& event, sd_event_source* source)
92     {
93         EXPECT_CALL(mock, sd_event_ref(event.get()))
94             .WillOnce(Return(event.get()));
95         sd_event_destroy_t destroy;
96         void* userdata;
97         {
98             testing::InSequence seq;
99             EXPECT_CALL(
100                 mock, sd_event_source_set_destroy_callback(source, testing::_))
101                 .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
102             EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_))
103                 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
104         }
105         auto ret = std::make_unique<BaseImpl>(event, source, std::false_type());
106         EXPECT_CALL(mock, sd_event_source_get_userdata(source))
107             .WillRepeatedly(Return(userdata));
108         EXPECT_NE(ret.get(), userdata);
109         EXPECT_EQ(source, ret->get());
110         EXPECT_NE(&event, &ret->get_event());
111         EXPECT_EQ(event.get(), ret->get_event().get());
112         EXPECT_FALSE(ret->get_prepare());
113         return {std::move(ret), std::bind(destroy, userdata)};
114     }
115 
set_prepare_placeholder(BaseImpl & base)116     void set_prepare_placeholder(BaseImpl& base)
117     {
118         EXPECT_CALL(mock, sd_event_source_set_prepare(base.get(), testing::_))
119             .WillOnce(Return(0));
120         base.set_prepare([](Base&) {});
121         EXPECT_TRUE(base.get_prepare());
122     }
123 
empty_base(BaseImpl && other)124     void empty_base(BaseImpl&& other)
125     {
126         BaseImpl mover(std::move(other));
127         EXPECT_THROW(other.get(), std::bad_optional_access);
128         EXPECT_THROW(other.get_event().get(), std::bad_optional_access);
129         EXPECT_THROW(other.get_prepare(), std::bad_optional_access);
130 
131         expect_base_destruct(mover.get_event(), mover.get());
132     }
133 
expect_base_destruct(const Event & event,sd_event_source * source)134     void expect_base_destruct(const Event& event, sd_event_source* source)
135     {
136         EXPECT_CALL(mock, sd_event_source_unref(source))
137             .WillOnce(Return(nullptr));
138         EXPECT_CALL(mock, sd_event_unref(event.get()))
139             .WillOnce(Return(nullptr));
140     }
141 };
142 
TEST_F(BaseTest,NewBaseFail)143 TEST_F(BaseTest, NewBaseFail)
144 {
145     EXPECT_CALL(mock, sd_event_ref(expected_event))
146         .WillOnce(Return(expected_event));
147     EXPECT_CALL(
148         mock, sd_event_source_set_destroy_callback(expected_source, testing::_))
149         .WillOnce(Return(-EINVAL));
150     expect_base_destruct(*event, expected_source);
151     EXPECT_THROW(BaseImpl(*event, expected_source, std::false_type()),
152                  SdEventError);
153 }
154 
TEST_F(BaseTest,NewBaseNoRef)155 TEST_F(BaseTest, NewBaseNoRef)
156 {
157     EXPECT_CALL(mock, sd_event_ref(expected_event))
158         .WillOnce(Return(expected_event));
159     sd_event_destroy_t destroy;
160     void* userdata;
161     {
162         testing::InSequence seq;
163         EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
164                                                                testing::_))
165             .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
166         EXPECT_CALL(mock,
167                     sd_event_source_set_userdata(expected_source, testing::_))
168             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
169     }
170     BaseImpl source(*event, expected_source, std::false_type());
171     EXPECT_NE(&source, userdata);
172     EXPECT_EQ(expected_source, source.get());
173     EXPECT_NE(event.get(), &source.get_event());
174     EXPECT_EQ(expected_event, source.get_event().get());
175 
176     EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
177         .WillOnce(Return(userdata));
178     EXPECT_FALSE(source.get_prepare());
179 
180     expect_base_destruct(*event, expected_source);
181     destroy(userdata);
182 }
183 
TEST_F(BaseTest,UserdataOutlives)184 TEST_F(BaseTest, UserdataOutlives)
185 {
186     EXPECT_CALL(mock, sd_event_ref(expected_event))
187         .WillOnce(Return(expected_event));
188     sd_event_destroy_t destroy;
189     void* userdata;
190     {
191         testing::InSequence seq;
192         EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
193                                                                testing::_))
194             .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
195         EXPECT_CALL(mock,
196                     sd_event_source_set_userdata(expected_source, testing::_))
197             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
198     }
199     auto source = std::make_unique<BaseImpl>(*event, expected_source,
200                                              std::false_type());
201     EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
202         .WillRepeatedly(Return(userdata));
203     EXPECT_FALSE(source->get_prepare());
204 
205     expect_base_destruct(*event, expected_source);
206     source.reset();
207     EXPECT_FALSE(reinterpret_cast<BaseImpl*>(userdata)->get_prepare());
208     destroy(userdata);
209 }
210 
TEST_F(BaseTest,CopyCorrectness)211 TEST_F(BaseTest, CopyCorrectness)
212 {
213     std::unique_ptr<BaseImpl> base1, base2;
214     std::function<void()> destroy;
215     std::tie(base1, destroy) = make_base(*event, expected_source);
216     set_prepare_placeholder(*base1);
217     EXPECT_TRUE(base1->get_prepare());
218 
219     EXPECT_CALL(mock, sd_event_ref(expected_event))
220         .WillOnce(Return(expected_event));
221     EXPECT_CALL(mock, sd_event_source_ref(expected_source))
222         .WillOnce(Return(expected_source));
223     base2 = std::make_unique<BaseImpl>(*base1);
224     EXPECT_EQ(&base1->get_prepare(), &base2->get_prepare());
225 
226     empty_base(std::move(*base1));
227     EXPECT_THROW(base1->get_prepare(), std::bad_optional_access);
228     EXPECT_CALL(mock, sd_event_ref(expected_event))
229         .WillOnce(Return(expected_event));
230     EXPECT_CALL(mock, sd_event_source_ref(expected_source))
231         .WillOnce(Return(expected_source));
232     *base1 = *base2;
233     EXPECT_EQ(&base1->get_prepare(), &base2->get_prepare());
234 
235     expect_base_destruct(*event, expected_source);
236     base2.reset();
237     expect_base_destruct(*event, expected_source);
238     base1.reset();
239     destroy();
240 }
241 
242 class BaseMethodTest : public BaseTest
243 {
244   protected:
245     std::unique_ptr<BaseImpl> base;
246     std::function<void()> destroy;
247 
SetUp()248     void SetUp()
249     {
250         std::tie(base, destroy) = make_base(*event, expected_source);
251     }
252 
TearDown()253     void TearDown()
254     {
255         expect_base_destruct(base->get_event(), base->get());
256         base.reset();
257         destroy();
258     }
259 };
260 
TEST_F(BaseMethodTest,GetDescriptionSuccess)261 TEST_F(BaseMethodTest, GetDescriptionSuccess)
262 {
263     const char* expected = "test_desc";
264     EXPECT_CALL(mock,
265                 sd_event_source_get_description(expected_source, testing::_))
266         .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0)));
267     // Intentionally comparing pointers to make sure no copying is happening
268     EXPECT_EQ(expected, base->get_description());
269 }
270 
TEST_F(BaseMethodTest,GetDescriptionError)271 TEST_F(BaseMethodTest, GetDescriptionError)
272 {
273     EXPECT_CALL(mock,
274                 sd_event_source_get_description(expected_source, testing::_))
275         .WillOnce(Return(-EINVAL));
276     EXPECT_THROW(base->get_description(), SdEventError);
277 }
278 
TEST_F(BaseMethodTest,SetDescriptionSuccess)279 TEST_F(BaseMethodTest, SetDescriptionSuccess)
280 {
281     const char* expected = "test desc";
282     // Intentionally comparing pointers to make sure no copying is happening
283     EXPECT_CALL(mock,
284                 sd_event_source_set_description(expected_source, expected))
285         .WillOnce(Return(0));
286     base->set_description(expected);
287 }
288 
TEST_F(BaseMethodTest,SetDescriptionError)289 TEST_F(BaseMethodTest, SetDescriptionError)
290 {
291     const char* expected = "test desc";
292     // Intentionally comparing pointers to make sure no copying is happening
293     EXPECT_CALL(mock,
294                 sd_event_source_set_description(expected_source, expected))
295         .WillOnce(Return(-EINVAL));
296     EXPECT_THROW(base->set_description(expected), SdEventError);
297 }
298 
TEST_F(BaseMethodTest,SetPrepareCallback)299 TEST_F(BaseMethodTest, SetPrepareCallback)
300 {
301     bool completed = false;
302     Base::Callback callback = [&completed](Base&) { completed = true; };
303     sd_event_handler_t event_handler;
304     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
305         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
306     base->set_prepare(std::move(callback));
307     EXPECT_TRUE(base->get_prepare());
308     EXPECT_FALSE(callback);
309     EXPECT_FALSE(completed);
310 
311     EXPECT_EQ(0, event_handler(nullptr, base.get()));
312     EXPECT_TRUE(completed);
313 }
314 
TEST_F(BaseMethodTest,SetPrepareCallbackNoUserdata)315 TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata)
316 {
317     Base::Callback callback = [](Base&) {};
318     sd_event_handler_t event_handler;
319     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
320         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
321     base->set_prepare(std::move(callback));
322     EXPECT_TRUE(base->get_prepare());
323     EXPECT_FALSE(callback);
324 
325     EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr));
326 }
327 
TEST_F(BaseMethodTest,SetPrepareError)328 TEST_F(BaseMethodTest, SetPrepareError)
329 {
330     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
331         .WillOnce(Return(0));
332     base->set_prepare([](Base&) {});
333     EXPECT_TRUE(base->get_prepare());
334 
335     Base::Callback callback = [](Base&) {};
336     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
337         .WillOnce(Return(-EINVAL));
338     EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError);
339     EXPECT_FALSE(base->get_prepare());
340     EXPECT_TRUE(callback);
341 }
342 
TEST_F(BaseMethodTest,SetPrepareNull)343 TEST_F(BaseMethodTest, SetPrepareNull)
344 {
345     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
346         .WillOnce(Return(0));
347     base->set_prepare([](Base&) {});
348     EXPECT_TRUE(base->get_prepare());
349 
350     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr))
351         .WillOnce(Return(0));
352     base->set_prepare(nullptr);
353     EXPECT_FALSE(base->get_prepare());
354 }
355 
TEST_F(BaseMethodTest,GetPendingSuccess)356 TEST_F(BaseMethodTest, GetPendingSuccess)
357 {
358     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
359         .WillOnce(Return(0));
360     EXPECT_FALSE(base->get_pending());
361     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
362         .WillOnce(Return(4));
363     EXPECT_TRUE(base->get_pending());
364 }
365 
TEST_F(BaseMethodTest,GetPendingError)366 TEST_F(BaseMethodTest, GetPendingError)
367 {
368     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
369         .WillOnce(Return(-EINVAL));
370     EXPECT_THROW(base->get_pending(), SdEventError);
371 }
372 
TEST_F(BaseMethodTest,GetPrioritySuccess)373 TEST_F(BaseMethodTest, GetPrioritySuccess)
374 {
375     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
376         .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0)));
377     EXPECT_EQ(1024, base->get_priority());
378 }
379 
TEST_F(BaseMethodTest,GetPriorityError)380 TEST_F(BaseMethodTest, GetPriorityError)
381 {
382     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
383         .WillOnce(Return(-EINVAL));
384     EXPECT_THROW(base->get_priority(), SdEventError);
385 }
386 
TEST_F(BaseMethodTest,SetPrioritySuccess)387 TEST_F(BaseMethodTest, SetPrioritySuccess)
388 {
389     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
390         .WillOnce(Return(0));
391     base->set_priority(1024);
392 }
393 
TEST_F(BaseMethodTest,SetPriorityError)394 TEST_F(BaseMethodTest, SetPriorityError)
395 {
396     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
397         .WillOnce(Return(-EINVAL));
398     EXPECT_THROW(base->set_priority(1024), SdEventError);
399 }
400 
TEST_F(BaseMethodTest,GetEnabledSuccess)401 TEST_F(BaseMethodTest, GetEnabledSuccess)
402 {
403     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
404         .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0)));
405     EXPECT_EQ(Enabled::On, base->get_enabled());
406 }
407 
TEST_F(BaseMethodTest,GetEnabledError)408 TEST_F(BaseMethodTest, GetEnabledError)
409 {
410     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
411         .WillOnce(Return(-EINVAL));
412     EXPECT_THROW(base->get_enabled(), SdEventError);
413 }
414 
TEST_F(BaseMethodTest,SetEnabledSuccess)415 TEST_F(BaseMethodTest, SetEnabledSuccess)
416 {
417     EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON))
418         .WillOnce(Return(0));
419     base->set_enabled(Enabled::On);
420 }
421 
TEST_F(BaseMethodTest,SetEnabledError)422 TEST_F(BaseMethodTest, SetEnabledError)
423 {
424     EXPECT_CALL(mock,
425                 sd_event_source_set_enabled(expected_source, SD_EVENT_ONESHOT))
426         .WillOnce(Return(-EINVAL));
427     EXPECT_THROW(base->set_enabled(Enabled::OneShot), SdEventError);
428 }
429 
TEST_F(BaseMethodTest,GetFloatingSuccess)430 TEST_F(BaseMethodTest, GetFloatingSuccess)
431 {
432     EXPECT_CALL(mock, sd_event_source_get_floating(expected_source))
433         .WillOnce(Return(2));
434     EXPECT_TRUE(base->get_floating());
435     EXPECT_CALL(mock, sd_event_source_get_floating(expected_source))
436         .WillOnce(Return(0));
437     EXPECT_FALSE(base->get_floating());
438 }
439 
TEST_F(BaseMethodTest,GetFloatingError)440 TEST_F(BaseMethodTest, GetFloatingError)
441 {
442     EXPECT_CALL(mock, sd_event_source_get_floating(expected_source))
443         .WillOnce(Return(-EINVAL));
444     EXPECT_THROW(base->get_floating(), SdEventError);
445 }
446 
TEST_F(BaseMethodTest,SetFloatingSuccess)447 TEST_F(BaseMethodTest, SetFloatingSuccess)
448 {
449     EXPECT_CALL(mock, sd_event_source_set_floating(expected_source, 1))
450         .WillOnce(Return(0));
451     base->set_floating(true);
452 }
453 
TEST_F(BaseMethodTest,SetFloatingError)454 TEST_F(BaseMethodTest, SetFloatingError)
455 {
456     EXPECT_CALL(mock, sd_event_source_set_floating(expected_source, 1))
457         .WillOnce(Return(-EINVAL));
458     EXPECT_THROW(base->set_floating(true), SdEventError);
459 }
460 
461 } // namespace
462 } // namespace source
463 } // namespace sdeventplus
464