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