xref: /openbmc/sdeventplus/test/source/base.cpp (revision e04cb03ba08f61f9d07e61764fee545c55f62f35)
1 #include <cerrno>
2 #include <gmock/gmock.h>
3 #include <gtest/gtest.h>
4 #include <memory>
5 #include <optional>
6 #include <sdeventplus/event.hpp>
7 #include <sdeventplus/exception.hpp>
8 #include <sdeventplus/internal/sdevent.hpp>
9 #include <sdeventplus/source/base.hpp>
10 #include <sdeventplus/test/sdevent.hpp>
11 #include <string>
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 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>;
29 
30 class BaseImpl : public Base
31 {
32   public:
33     BaseImpl(const Event& event, sd_event_source* source) : Base(event, source)
34     {
35     }
36     BaseImpl(const Event& event, sd_event_source* source, std::false_type) :
37         Base(event, source, std::false_type())
38     {
39     }
40 
41     using Base::get_prepare;
42 };
43 
44 class BaseTest : public testing::Test
45 {
46   protected:
47     testing::StrictMock<test::SdEventMock> mock;
48     sd_event_source* const expected_source =
49         reinterpret_cast<sd_event_source*>(1234);
50     sd_event* const expected_event = reinterpret_cast<sd_event*>(2345);
51     UniqueEvent event = make_event(expected_event);
52 
53     UniqueEvent make_event(sd_event* event)
54     {
55         auto deleter = [this, event](Event* e) {
56             EXPECT_CALL(this->mock, sd_event_unref(event))
57                 .WillOnce(Return(nullptr));
58             delete e;
59         };
60         return UniqueEvent(new Event(event, std::false_type(), &mock), deleter);
61     }
62 
63     // Using a unique_ptr to make sure we don't get any superfluous moves or
64     // copies.
65     std::unique_ptr<BaseImpl> make_base(const Event& event,
66                                         sd_event_source* source)
67     {
68         EXPECT_CALL(mock, sd_event_ref(event.get()))
69             .WillOnce(Return(event.get()));
70         void* userdata;
71         EXPECT_CALL(mock, sd_event_source_set_userdata(source, testing::_))
72             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
73         auto ret = std::make_unique<BaseImpl>(event, source, std::false_type());
74         EXPECT_EQ(ret.get(), userdata);
75         EXPECT_EQ(source, ret->get());
76         EXPECT_NE(&event, &ret->get_event());
77         EXPECT_EQ(event.get(), ret->get_event().get());
78         EXPECT_FALSE(ret->get_prepare());
79         return ret;
80     }
81 
82     void set_prepare_placeholder(BaseImpl& base)
83     {
84         EXPECT_CALL(mock, sd_event_source_set_prepare(base.get(), testing::_))
85             .WillOnce(Return(0));
86         base.set_prepare([](Base&) {});
87         EXPECT_TRUE(base.get_prepare());
88     }
89 
90     void empty_base(BaseImpl&& other)
91     {
92         void* userdata;
93         EXPECT_CALL(mock, sd_event_source_set_userdata(other.get(), testing::_))
94             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
95         BaseImpl mover(std::move(other));
96         EXPECT_EQ(&mover, userdata);
97         EXPECT_THROW(other.get(), std::bad_optional_access);
98         EXPECT_THROW(other.get_event().get(), std::bad_optional_access);
99         EXPECT_FALSE(other.get_prepare());
100 
101         expect_base_destruct(mover.get_event(), mover.get());
102     }
103 
104     void expect_base_destruct(const Event& event, sd_event_source* source)
105     {
106         {
107             testing::InSequence seq;
108             EXPECT_CALL(mock, sd_event_source_set_enabled(source, SD_EVENT_OFF))
109                 .WillOnce(Return(0));
110             EXPECT_CALL(mock, sd_event_source_unref(source))
111                 .WillOnce(Return(nullptr));
112         }
113         EXPECT_CALL(mock, sd_event_unref(event.get()))
114             .WillOnce(Return(nullptr));
115     }
116 };
117 
118 TEST_F(BaseTest, NewBaseRef)
119 {
120     EXPECT_CALL(mock, sd_event_ref(expected_event))
121         .WillOnce(Return(expected_event));
122     EXPECT_CALL(mock, sd_event_source_ref(expected_source))
123         .WillOnce(Return(expected_source));
124     void* userdata;
125     EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
126         .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
127     BaseImpl source(*event, expected_source);
128     EXPECT_EQ(&source, userdata);
129     EXPECT_EQ(expected_source, source.get());
130     EXPECT_NE(event.get(), &source.get_event());
131     EXPECT_EQ(expected_event, source.get_event().get());
132     EXPECT_FALSE(source.get_prepare());
133 
134     expect_base_destruct(*event, expected_source);
135 }
136 
137 TEST_F(BaseTest, NewBaseNoRef)
138 {
139     EXPECT_CALL(mock, sd_event_ref(expected_event))
140         .WillOnce(Return(expected_event));
141     void* userdata;
142     EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
143         .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
144     BaseImpl source(*event, expected_source, std::false_type());
145     EXPECT_EQ(&source, userdata);
146     EXPECT_EQ(expected_source, source.get());
147     EXPECT_NE(event.get(), &source.get_event());
148     EXPECT_EQ(expected_event, source.get_event().get());
149     EXPECT_FALSE(source.get_prepare());
150 
151     expect_base_destruct(*event, expected_source);
152 }
153 
154 TEST_F(BaseTest, MoveConstruct)
155 {
156     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
157     set_prepare_placeholder(*source1);
158 
159     void* userdata;
160     EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
161         .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
162     BaseImpl source2(std::move(*source1));
163     EXPECT_EQ(&source2, userdata);
164     EXPECT_THROW(source1->get(), std::bad_optional_access);
165     EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
166     EXPECT_FALSE(source1->get_prepare());
167     EXPECT_EQ(expected_source, source2.get());
168     EXPECT_EQ(expected_event, source2.get_event().get());
169     EXPECT_TRUE(source2.get_prepare());
170 
171     expect_base_destruct(*event, expected_source);
172 }
173 
174 TEST_F(BaseTest, MoveAssignSelf)
175 {
176     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
177     set_prepare_placeholder(*source1);
178 
179     *source1 = std::move(*source1);
180     EXPECT_EQ(expected_source, source1->get());
181     EXPECT_EQ(expected_event, source1->get_event().get());
182     EXPECT_TRUE(source1->get_prepare());
183 
184     expect_base_destruct(*event, expected_source);
185 }
186 
187 TEST_F(BaseTest, MoveAssignEmpty)
188 {
189     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
190     set_prepare_placeholder(*source1);
191 
192     std::unique_ptr<BaseImpl> source2 = make_base(*event, expected_source);
193     empty_base(std::move(*source2));
194 
195     {
196         void* userdata;
197         EXPECT_CALL(mock,
198                     sd_event_source_set_userdata(expected_source, testing::_))
199             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
200         *source2 = std::move(*source1);
201         EXPECT_EQ(source2.get(), userdata);
202     }
203     EXPECT_THROW(source1->get(), std::bad_optional_access);
204     EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
205     EXPECT_FALSE(source1->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     // Make sure source1 is deleted to ensure it isn't holding a reference
211     source1.reset();
212     expect_base_destruct(*event, expected_source);
213 }
214 
215 TEST_F(BaseTest, MoveAssignExisting)
216 {
217     sd_event_source* const expected_source2 =
218         reinterpret_cast<sd_event_source*>(3456);
219     sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567);
220 
221     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
222     set_prepare_placeholder(*source1);
223 
224     UniqueEvent event2 = make_event(expected_event2);
225     std::unique_ptr<BaseImpl> source2 = make_base(*event2, expected_source2);
226 
227     {
228         expect_base_destruct(*event2, expected_source2);
229         void* userdata;
230         EXPECT_CALL(mock,
231                     sd_event_source_set_userdata(expected_source, testing::_))
232             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
233         *source2 = std::move(*source1);
234         EXPECT_EQ(source2.get(), userdata);
235     }
236     EXPECT_THROW(source1->get(), std::bad_optional_access);
237     EXPECT_THROW(source1->get_event().get(), std::bad_optional_access);
238     EXPECT_FALSE(source1->get_prepare());
239     EXPECT_EQ(expected_source, source2->get());
240     EXPECT_EQ(expected_event, source2->get_event().get());
241     EXPECT_TRUE(source2->get_prepare());
242 
243     // Make sure source1 is deleted to ensure it isn't holding a reference
244     source1.reset();
245     expect_base_destruct(*event, expected_source);
246 }
247 
248 class BaseMethodTest : public BaseTest
249 {
250   protected:
251     std::unique_ptr<BaseImpl> base = make_base(*event, expected_source);
252 
253     void TearDown()
254     {
255         expect_base_destruct(base->get_event(), base->get());
256         base.reset();
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 } // namespace
430 } // namespace source
431 } // namespace sdeventplus
432