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