xref: /openbmc/sdeventplus/test/source/base.cpp (revision feef68f7)
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 
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(Base& 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_EQ(nullptr, other.get());
95         EXPECT_EQ(nullptr, other.get_event().get());
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, NewBaseRef)
116 {
117     EXPECT_CALL(mock, sd_event_ref(expected_event))
118         .WillOnce(Return(expected_event));
119     EXPECT_CALL(mock, sd_event_source_ref(expected_source))
120         .WillOnce(Return(expected_source));
121     void* userdata;
122     EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
123         .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
124     BaseImpl source(*event, expected_source);
125     EXPECT_EQ(&source, userdata);
126     EXPECT_EQ(expected_source, source.get());
127     EXPECT_NE(event.get(), &source.get_event());
128     EXPECT_EQ(expected_event, source.get_event().get());
129     EXPECT_FALSE(source.get_prepare());
130 
131     expect_base_destruct(*event, expected_source);
132 }
133 
134 TEST_F(BaseTest, NewBaseNoRef)
135 {
136     EXPECT_CALL(mock, sd_event_ref(expected_event))
137         .WillOnce(Return(expected_event));
138     void* userdata;
139     EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
140         .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
141     BaseImpl source(*event, expected_source, std::false_type());
142     EXPECT_EQ(&source, userdata);
143     EXPECT_EQ(expected_source, source.get());
144     EXPECT_NE(event.get(), &source.get_event());
145     EXPECT_EQ(expected_event, source.get_event().get());
146     EXPECT_FALSE(source.get_prepare());
147 
148     expect_base_destruct(*event, expected_source);
149 }
150 
151 TEST_F(BaseTest, MoveConstruct)
152 {
153     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
154     set_prepare_placeholder(*source1);
155 
156     void* userdata;
157     EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_))
158         .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
159     BaseImpl source2(std::move(*source1));
160     EXPECT_EQ(&source2, userdata);
161     EXPECT_EQ(nullptr, source1->get());
162     EXPECT_EQ(nullptr, source1->get_event().get());
163     EXPECT_FALSE(source1->get_prepare());
164     EXPECT_EQ(expected_source, source2.get());
165     EXPECT_EQ(expected_event, source2.get_event().get());
166     EXPECT_TRUE(source2.get_prepare());
167 
168     expect_base_destruct(*event, expected_source);
169 }
170 
171 TEST_F(BaseTest, MoveAssignSelf)
172 {
173     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
174     set_prepare_placeholder(*source1);
175 
176     *source1 = std::move(*source1);
177     EXPECT_EQ(expected_source, source1->get());
178     EXPECT_EQ(expected_event, source1->get_event().get());
179     EXPECT_TRUE(source1->get_prepare());
180 
181     expect_base_destruct(*event, expected_source);
182 }
183 
184 TEST_F(BaseTest, MoveAssignEmpty)
185 {
186     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
187     set_prepare_placeholder(*source1);
188 
189     std::unique_ptr<BaseImpl> source2 = make_base(*event, expected_source);
190     empty_base(std::move(*source2));
191 
192     {
193         void* userdata;
194         EXPECT_CALL(mock,
195                     sd_event_source_set_userdata(expected_source, testing::_))
196             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
197         *source2 = std::move(*source1);
198         EXPECT_EQ(source2.get(), userdata);
199     }
200     EXPECT_EQ(nullptr, source1->get());
201     EXPECT_EQ(nullptr, source1->get_event().get());
202     EXPECT_FALSE(source1->get_prepare());
203     EXPECT_EQ(expected_source, source2->get());
204     EXPECT_EQ(expected_event, source2->get_event().get());
205     EXPECT_TRUE(source2->get_prepare());
206 
207     // Make sure source1 is deleted to ensure it isn't holding a reference
208     source1.reset();
209     expect_base_destruct(*event, expected_source);
210 }
211 
212 TEST_F(BaseTest, MoveAssignExisting)
213 {
214     sd_event_source* const expected_source2 =
215         reinterpret_cast<sd_event_source*>(3456);
216     sd_event* const expected_event2 = reinterpret_cast<sd_event*>(4567);
217 
218     std::unique_ptr<BaseImpl> source1 = make_base(*event, expected_source);
219     set_prepare_placeholder(*source1);
220 
221     UniqueEvent event2 = make_event(expected_event2);
222     std::unique_ptr<BaseImpl> source2 = make_base(*event2, expected_source2);
223 
224     {
225         expect_base_destruct(*event2, expected_source2);
226         void* userdata;
227         EXPECT_CALL(mock,
228                     sd_event_source_set_userdata(expected_source, testing::_))
229             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
230         *source2 = std::move(*source1);
231         EXPECT_EQ(source2.get(), userdata);
232     }
233     EXPECT_EQ(nullptr, source1->get());
234     EXPECT_EQ(nullptr, source1->get_event().get());
235     EXPECT_FALSE(source1->get_prepare());
236     EXPECT_EQ(expected_source, source2->get());
237     EXPECT_EQ(expected_event, source2->get_event().get());
238     EXPECT_TRUE(source2->get_prepare());
239 
240     // Make sure source1 is deleted to ensure it isn't holding a reference
241     source1.reset();
242     expect_base_destruct(*event, expected_source);
243 }
244 
245 class BaseMethodTest : public BaseTest
246 {
247   protected:
248     std::unique_ptr<BaseImpl> base = make_base(*event, expected_source);
249 
250     void TearDown()
251     {
252         expect_base_destruct(base->get_event(), base->get());
253         base.reset();
254     }
255 };
256 
257 TEST_F(BaseMethodTest, GetDescriptionSuccess)
258 {
259     const char* expected = "test_desc";
260     EXPECT_CALL(mock,
261                 sd_event_source_get_description(expected_source, testing::_))
262         .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0)));
263     // Intentionally comparing pointers to make sure no copying is happening
264     EXPECT_EQ(expected, base->get_description());
265 }
266 
267 TEST_F(BaseMethodTest, GetDescriptionError)
268 {
269     EXPECT_CALL(mock,
270                 sd_event_source_get_description(expected_source, testing::_))
271         .WillOnce(Return(-EINVAL));
272     EXPECT_THROW(base->get_description(), SdEventError);
273 }
274 
275 TEST_F(BaseMethodTest, SetDescriptionSuccess)
276 {
277     const char* expected = "test desc";
278     // Intentionally comparing pointers to make sure no copying is happening
279     EXPECT_CALL(mock,
280                 sd_event_source_set_description(expected_source, expected))
281         .WillOnce(Return(0));
282     base->set_description(expected);
283 }
284 
285 TEST_F(BaseMethodTest, SetDescriptionError)
286 {
287     const char* expected = "test desc";
288     // Intentionally comparing pointers to make sure no copying is happening
289     EXPECT_CALL(mock,
290                 sd_event_source_set_description(expected_source, expected))
291         .WillOnce(Return(-EINVAL));
292     EXPECT_THROW(base->set_description(expected), SdEventError);
293 }
294 
295 TEST_F(BaseMethodTest, SetPrepareCallback)
296 {
297     bool completed = false;
298     Base::Callback callback = [&completed](Base&) { completed = true; };
299     sd_event_handler_t event_handler;
300     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
301         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
302     base->set_prepare(std::move(callback));
303     EXPECT_TRUE(base->get_prepare());
304     EXPECT_FALSE(callback);
305     EXPECT_FALSE(completed);
306 
307     EXPECT_EQ(0, event_handler(nullptr, base.get()));
308     EXPECT_TRUE(completed);
309 }
310 
311 TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata)
312 {
313     Base::Callback callback = [](Base&) {};
314     sd_event_handler_t event_handler;
315     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
316         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
317     base->set_prepare(std::move(callback));
318     EXPECT_TRUE(base->get_prepare());
319     EXPECT_FALSE(callback);
320 
321     EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr));
322 }
323 
324 TEST_F(BaseMethodTest, SetPrepareError)
325 {
326     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
327         .WillOnce(Return(0));
328     base->set_prepare(std::move([](Base&) {}));
329     EXPECT_TRUE(base->get_prepare());
330 
331     Base::Callback callback = [](Base&) {};
332     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
333         .WillOnce(Return(-EINVAL));
334     EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError);
335     EXPECT_FALSE(base->get_prepare());
336     EXPECT_TRUE(callback);
337 }
338 
339 TEST_F(BaseMethodTest, SetPrepareNull)
340 {
341     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
342         .WillOnce(Return(0));
343     base->set_prepare(std::move([](Base&) {}));
344     EXPECT_TRUE(base->get_prepare());
345 
346     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr))
347         .WillOnce(Return(0));
348     base->set_prepare(nullptr);
349     EXPECT_FALSE(base->get_prepare());
350 }
351 
352 TEST_F(BaseMethodTest, GetPendingSuccess)
353 {
354     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
355         .WillOnce(Return(0));
356     EXPECT_EQ(0, base->get_pending());
357     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
358         .WillOnce(Return(4));
359     EXPECT_EQ(4, base->get_pending());
360 }
361 
362 TEST_F(BaseMethodTest, GetPendingError)
363 {
364     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
365         .WillOnce(Return(-EINVAL));
366     EXPECT_THROW(base->get_pending(), SdEventError);
367 }
368 
369 TEST_F(BaseMethodTest, GetPrioritySuccess)
370 {
371     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
372         .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0)));
373     EXPECT_EQ(1024, base->get_priority());
374 }
375 
376 TEST_F(BaseMethodTest, GetPriorityError)
377 {
378     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
379         .WillOnce(Return(-EINVAL));
380     EXPECT_THROW(base->get_priority(), SdEventError);
381 }
382 
383 TEST_F(BaseMethodTest, SetPrioritySuccess)
384 {
385     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
386         .WillOnce(Return(0));
387     base->set_priority(1024);
388 }
389 
390 TEST_F(BaseMethodTest, SetPriorityError)
391 {
392     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
393         .WillOnce(Return(-EINVAL));
394     EXPECT_THROW(base->set_priority(1024), SdEventError);
395 }
396 
397 TEST_F(BaseMethodTest, GetEnabledSuccess)
398 {
399     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
400         .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0)));
401     EXPECT_EQ(SD_EVENT_ON, base->get_enabled());
402 }
403 
404 TEST_F(BaseMethodTest, GetEnabledError)
405 {
406     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
407         .WillOnce(Return(-EINVAL));
408     EXPECT_THROW(base->get_enabled(), SdEventError);
409 }
410 
411 TEST_F(BaseMethodTest, SetEnabledSuccess)
412 {
413     EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON))
414         .WillOnce(Return(0));
415     base->set_enabled(SD_EVENT_ON);
416 }
417 
418 TEST_F(BaseMethodTest, SetEnabledError)
419 {
420     EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON))
421         .WillOnce(Return(-EINVAL));
422     EXPECT_THROW(base->set_enabled(SD_EVENT_ON), SdEventError);
423 }
424 
425 } // namespace
426 } // namespace source
427 } // namespace sdeventplus
428