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