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