xref: /openbmc/sdeventplus/test/source/base.cpp (revision 5320b1f5d7ed05faba9fcb0919792d55955ff7d1)
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 class BaseMethodTest : public BaseTest
211 {
212   protected:
213     std::unique_ptr<BaseImpl> base;
214     std::function<void()> destroy;
215 
216     void SetUp()
217     {
218         std::tie(base, destroy) = make_base(*event, expected_source);
219     }
220 
221     void TearDown()
222     {
223         expect_base_destruct(base->get_event(), base->get());
224         base.reset();
225         destroy();
226     }
227 };
228 
229 TEST_F(BaseMethodTest, GetDescriptionSuccess)
230 {
231     const char* expected = "test_desc";
232     EXPECT_CALL(mock,
233                 sd_event_source_get_description(expected_source, testing::_))
234         .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0)));
235     // Intentionally comparing pointers to make sure no copying is happening
236     EXPECT_EQ(expected, base->get_description());
237 }
238 
239 TEST_F(BaseMethodTest, GetDescriptionError)
240 {
241     EXPECT_CALL(mock,
242                 sd_event_source_get_description(expected_source, testing::_))
243         .WillOnce(Return(-EINVAL));
244     EXPECT_THROW(base->get_description(), SdEventError);
245 }
246 
247 TEST_F(BaseMethodTest, SetDescriptionSuccess)
248 {
249     const char* expected = "test desc";
250     // Intentionally comparing pointers to make sure no copying is happening
251     EXPECT_CALL(mock,
252                 sd_event_source_set_description(expected_source, expected))
253         .WillOnce(Return(0));
254     base->set_description(expected);
255 }
256 
257 TEST_F(BaseMethodTest, SetDescriptionError)
258 {
259     const char* expected = "test desc";
260     // Intentionally comparing pointers to make sure no copying is happening
261     EXPECT_CALL(mock,
262                 sd_event_source_set_description(expected_source, expected))
263         .WillOnce(Return(-EINVAL));
264     EXPECT_THROW(base->set_description(expected), SdEventError);
265 }
266 
267 TEST_F(BaseMethodTest, SetPrepareCallback)
268 {
269     bool completed = false;
270     Base::Callback callback = [&completed](Base&) { completed = true; };
271     sd_event_handler_t event_handler;
272     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
273         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
274     base->set_prepare(std::move(callback));
275     EXPECT_TRUE(base->get_prepare());
276     EXPECT_FALSE(callback);
277     EXPECT_FALSE(completed);
278 
279     EXPECT_EQ(0, event_handler(nullptr, base.get()));
280     EXPECT_TRUE(completed);
281 }
282 
283 TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata)
284 {
285     Base::Callback callback = [](Base&) {};
286     sd_event_handler_t event_handler;
287     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
288         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
289     base->set_prepare(std::move(callback));
290     EXPECT_TRUE(base->get_prepare());
291     EXPECT_FALSE(callback);
292 
293     EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr));
294 }
295 
296 TEST_F(BaseMethodTest, SetPrepareError)
297 {
298     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
299         .WillOnce(Return(0));
300     base->set_prepare([](Base&) {});
301     EXPECT_TRUE(base->get_prepare());
302 
303     Base::Callback callback = [](Base&) {};
304     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
305         .WillOnce(Return(-EINVAL));
306     EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError);
307     EXPECT_FALSE(base->get_prepare());
308     EXPECT_TRUE(callback);
309 }
310 
311 TEST_F(BaseMethodTest, SetPrepareNull)
312 {
313     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
314         .WillOnce(Return(0));
315     base->set_prepare([](Base&) {});
316     EXPECT_TRUE(base->get_prepare());
317 
318     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr))
319         .WillOnce(Return(0));
320     base->set_prepare(nullptr);
321     EXPECT_FALSE(base->get_prepare());
322 }
323 
324 TEST_F(BaseMethodTest, GetPendingSuccess)
325 {
326     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
327         .WillOnce(Return(0));
328     EXPECT_FALSE(base->get_pending());
329     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
330         .WillOnce(Return(4));
331     EXPECT_TRUE(base->get_pending());
332 }
333 
334 TEST_F(BaseMethodTest, GetPendingError)
335 {
336     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
337         .WillOnce(Return(-EINVAL));
338     EXPECT_THROW(base->get_pending(), SdEventError);
339 }
340 
341 TEST_F(BaseMethodTest, GetPrioritySuccess)
342 {
343     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
344         .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0)));
345     EXPECT_EQ(1024, base->get_priority());
346 }
347 
348 TEST_F(BaseMethodTest, GetPriorityError)
349 {
350     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
351         .WillOnce(Return(-EINVAL));
352     EXPECT_THROW(base->get_priority(), SdEventError);
353 }
354 
355 TEST_F(BaseMethodTest, SetPrioritySuccess)
356 {
357     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
358         .WillOnce(Return(0));
359     base->set_priority(1024);
360 }
361 
362 TEST_F(BaseMethodTest, SetPriorityError)
363 {
364     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
365         .WillOnce(Return(-EINVAL));
366     EXPECT_THROW(base->set_priority(1024), SdEventError);
367 }
368 
369 TEST_F(BaseMethodTest, GetEnabledSuccess)
370 {
371     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
372         .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0)));
373     EXPECT_EQ(Enabled::On, base->get_enabled());
374 }
375 
376 TEST_F(BaseMethodTest, GetEnabledError)
377 {
378     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
379         .WillOnce(Return(-EINVAL));
380     EXPECT_THROW(base->get_enabled(), SdEventError);
381 }
382 
383 TEST_F(BaseMethodTest, SetEnabledSuccess)
384 {
385     EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON))
386         .WillOnce(Return(0));
387     base->set_enabled(Enabled::On);
388 }
389 
390 TEST_F(BaseMethodTest, SetEnabledError)
391 {
392     EXPECT_CALL(mock,
393                 sd_event_source_set_enabled(expected_source, SD_EVENT_ONESHOT))
394         .WillOnce(Return(-EINVAL));
395     EXPECT_THROW(base->set_enabled(Enabled::OneShot), SdEventError);
396 }
397 
398 } // namespace
399 } // namespace source
400 } // namespace sdeventplus
401