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