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