xref: /openbmc/sdeventplus/test/source/base.cpp (revision f5285c73)
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 
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 class BaseImpl : public Base
28 {
29   public:
30     BaseImpl(const Event& event, sd_event_source* source) : Base(event, source)
31     {
32     }
33     BaseImpl(const Event& event, sd_event_source* source, std::false_type) :
34         Base(event, source, std::false_type())
35     {
36     }
37 };
38 
39 class BaseTest : public testing::Test
40 {
41   protected:
42     testing::StrictMock<test::SdEventMock> mock;
43     sd_event_source* expected_source = reinterpret_cast<sd_event_source*>(1234);
44     sd_event* expected_event = reinterpret_cast<sd_event*>(2345);
45     std::unique_ptr<Event> event;
46 
47     virtual void SetUp()
48     {
49         event =
50             std::make_unique<Event>(expected_event, std::false_type(), &mock);
51     }
52     virtual void TearDown()
53     {
54         EXPECT_CALL(mock, sd_event_unref(expected_event))
55             .WillOnce(Return(nullptr));
56         event.reset();
57     }
58 };
59 
60 TEST_F(BaseTest, NewBaseRef)
61 {
62     EXPECT_CALL(mock, sd_event_ref(expected_event))
63         .WillOnce(Return(expected_event));
64     EXPECT_CALL(mock, sd_event_source_ref(expected_source))
65         .WillOnce(Return(expected_source));
66     BaseImpl source(*event, expected_source);
67     EXPECT_EQ(expected_source, source.get());
68     EXPECT_NE(event.get(), &source.get_event());
69     EXPECT_EQ(expected_event, source.get_event().get());
70     EXPECT_FALSE(source.get_prepare());
71 
72     {
73         testing::InSequence seq;
74         EXPECT_CALL(mock,
75                     sd_event_source_set_enabled(expected_source, SD_EVENT_OFF))
76             .WillOnce(Return(0));
77         EXPECT_CALL(mock, sd_event_source_unref(expected_source))
78             .WillOnce(Return(nullptr));
79     }
80     EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr));
81 }
82 
83 TEST_F(BaseTest, NewBaseNoRef)
84 {
85     EXPECT_CALL(mock, sd_event_ref(expected_event))
86         .WillOnce(Return(expected_event));
87     BaseImpl source(*event, expected_source, std::false_type());
88     EXPECT_EQ(expected_source, source.get());
89     EXPECT_NE(event.get(), &source.get_event());
90     EXPECT_EQ(expected_event, source.get_event().get());
91     EXPECT_FALSE(source.get_prepare());
92 
93     {
94         testing::InSequence seq;
95         EXPECT_CALL(mock,
96                     sd_event_source_set_enabled(expected_source, SD_EVENT_OFF))
97             .WillOnce(Return(0));
98         EXPECT_CALL(mock, sd_event_source_unref(expected_source))
99             .WillOnce(Return(nullptr));
100     }
101     EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr));
102 }
103 
104 TEST_F(BaseTest, NoSource)
105 {
106     EXPECT_CALL(mock, sd_event_ref(expected_event))
107         .WillOnce(Return(expected_event));
108     BaseImpl source(*event, nullptr, std::false_type());
109     EXPECT_EQ(nullptr, source.get());
110     EXPECT_NE(event.get(), &source.get_event());
111     EXPECT_EQ(expected_event, source.get_event().get());
112     EXPECT_FALSE(source.get_prepare());
113 
114     EXPECT_CALL(mock, sd_event_source_unref(nullptr)).WillOnce(Return(nullptr));
115     EXPECT_CALL(mock, sd_event_unref(expected_event)).WillOnce(Return(nullptr));
116 }
117 
118 class BaseMethodTest : public BaseTest
119 {
120   protected:
121     std::unique_ptr<BaseImpl> base;
122 
123     void SetUp() override
124     {
125         BaseTest::SetUp();
126         EXPECT_CALL(mock, sd_event_ref(expected_event))
127             .WillOnce(Return(expected_event));
128         base = std::make_unique<BaseImpl>(*event, expected_source,
129                                           std::false_type());
130     }
131 
132     void TearDown() override
133     {
134         {
135             testing::InSequence seq;
136             EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source,
137                                                           SD_EVENT_OFF))
138                 .WillOnce(Return(0));
139             EXPECT_CALL(mock, sd_event_source_unref(expected_source))
140                 .WillOnce(Return(nullptr));
141         }
142         EXPECT_CALL(mock, sd_event_unref(expected_event))
143             .WillOnce(Return(nullptr));
144         base.reset();
145         BaseTest::TearDown();
146     }
147 };
148 
149 TEST_F(BaseMethodTest, GetDescriptionSuccess)
150 {
151     const char* expected = "test_desc";
152     EXPECT_CALL(mock,
153                 sd_event_source_get_description(expected_source, testing::_))
154         .WillOnce(DoAll(SetArgPointee<1>(expected), Return(0)));
155     // Intentionally comparing pointers to make sure no copying is happening
156     EXPECT_EQ(expected, base->get_description());
157 }
158 
159 TEST_F(BaseMethodTest, GetDescriptionError)
160 {
161     EXPECT_CALL(mock,
162                 sd_event_source_get_description(expected_source, testing::_))
163         .WillOnce(Return(-EINVAL));
164     EXPECT_THROW(base->get_description(), SdEventError);
165 }
166 
167 TEST_F(BaseMethodTest, SetDescriptionSuccess)
168 {
169     const char* expected = "test desc";
170     // Intentionally comparing pointers to make sure no copying is happening
171     EXPECT_CALL(mock,
172                 sd_event_source_set_description(expected_source, expected))
173         .WillOnce(Return(0));
174     base->set_description(expected);
175 }
176 
177 TEST_F(BaseMethodTest, SetDescriptionError)
178 {
179     const char* expected = "test desc";
180     // Intentionally comparing pointers to make sure no copying is happening
181     EXPECT_CALL(mock,
182                 sd_event_source_set_description(expected_source, expected))
183         .WillOnce(Return(-EINVAL));
184     EXPECT_THROW(base->set_description(expected), SdEventError);
185 }
186 
187 TEST_F(BaseMethodTest, SetPrepareCallback)
188 {
189     bool completed = false;
190     Base::Callback callback = [&completed](Base&) { completed = true; };
191     sd_event_handler_t event_handler;
192     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
193         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
194     base->set_prepare(std::move(callback));
195     EXPECT_TRUE(base->get_prepare());
196     EXPECT_FALSE(callback);
197     EXPECT_FALSE(completed);
198 
199     EXPECT_EQ(0, event_handler(nullptr, base.get()));
200     EXPECT_TRUE(completed);
201 }
202 
203 TEST_F(BaseMethodTest, SetPrepareCallbackNoUserdata)
204 {
205     Base::Callback callback = [](Base&) {};
206     sd_event_handler_t event_handler;
207     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
208         .WillOnce(DoAll(SaveArg<1>(&event_handler), Return(0)));
209     base->set_prepare(std::move(callback));
210     EXPECT_TRUE(base->get_prepare());
211     EXPECT_FALSE(callback);
212 
213     EXPECT_EQ(-EINVAL, event_handler(nullptr, nullptr));
214 }
215 
216 TEST_F(BaseMethodTest, SetPrepareNull)
217 {
218     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, nullptr))
219         .WillOnce(Return(0));
220     base->set_prepare(nullptr);
221     EXPECT_EQ(-ENOSYS, base->prepareCallback());
222 }
223 
224 TEST_F(BaseMethodTest, SetPrepareSystemError)
225 {
226     Base::Callback callback = [](Base&) {
227         throw std::system_error(EBUSY, std::generic_category());
228     };
229     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
230         .WillOnce(Return(0));
231     base->set_prepare(std::move(callback));
232     EXPECT_TRUE(base->get_prepare());
233     EXPECT_FALSE(callback);
234     EXPECT_EQ(-EBUSY, base->prepareCallback());
235 }
236 
237 TEST_F(BaseMethodTest, SetPrepareUnknownException)
238 {
239     Base::Callback callback = [](Base&) { throw static_cast<int>(1); };
240     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
241         .WillOnce(Return(0));
242     base->set_prepare(std::move(callback));
243     EXPECT_TRUE(base->get_prepare());
244     EXPECT_FALSE(callback);
245     EXPECT_EQ(-ENOSYS, base->prepareCallback());
246 }
247 
248 TEST_F(BaseMethodTest, SetPrepareError)
249 {
250     Base::Callback callback = [](Base&) {};
251     EXPECT_CALL(mock, sd_event_source_set_prepare(expected_source, testing::_))
252         .WillOnce(Return(-EINVAL));
253     EXPECT_THROW(base->set_prepare(std::move(callback)), SdEventError);
254     EXPECT_FALSE(base->get_prepare());
255     EXPECT_TRUE(callback);
256     EXPECT_EQ(-ENOSYS, base->prepareCallback());
257 }
258 
259 TEST_F(BaseMethodTest, GetPendingSuccess)
260 {
261     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
262         .WillOnce(Return(0));
263     EXPECT_EQ(0, base->get_pending());
264     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
265         .WillOnce(Return(4));
266     EXPECT_EQ(4, base->get_pending());
267 }
268 
269 TEST_F(BaseMethodTest, GetPendingError)
270 {
271     EXPECT_CALL(mock, sd_event_source_get_pending(expected_source))
272         .WillOnce(Return(-EINVAL));
273     EXPECT_THROW(base->get_pending(), SdEventError);
274 }
275 
276 TEST_F(BaseMethodTest, GetPrioritySuccess)
277 {
278     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
279         .WillOnce(DoAll(SetArgPointee<1>(1024), Return(0)));
280     EXPECT_EQ(1024, base->get_priority());
281 }
282 
283 TEST_F(BaseMethodTest, GetPriorityError)
284 {
285     EXPECT_CALL(mock, sd_event_source_get_priority(expected_source, testing::_))
286         .WillOnce(Return(-EINVAL));
287     EXPECT_THROW(base->get_priority(), SdEventError);
288 }
289 
290 TEST_F(BaseMethodTest, SetPrioritySuccess)
291 {
292     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
293         .WillOnce(Return(0));
294     base->set_priority(1024);
295 }
296 
297 TEST_F(BaseMethodTest, SetPriorityError)
298 {
299     EXPECT_CALL(mock, sd_event_source_set_priority(expected_source, 1024))
300         .WillOnce(Return(-EINVAL));
301     EXPECT_THROW(base->set_priority(1024), SdEventError);
302 }
303 
304 TEST_F(BaseMethodTest, GetEnabledSuccess)
305 {
306     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
307         .WillOnce(DoAll(SetArgPointee<1>(SD_EVENT_ON), Return(0)));
308     EXPECT_EQ(SD_EVENT_ON, base->get_enabled());
309 }
310 
311 TEST_F(BaseMethodTest, GetEnabledError)
312 {
313     EXPECT_CALL(mock, sd_event_source_get_enabled(expected_source, testing::_))
314         .WillOnce(Return(-EINVAL));
315     EXPECT_THROW(base->get_enabled(), SdEventError);
316 }
317 
318 TEST_F(BaseMethodTest, SetEnabledSuccess)
319 {
320     EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON))
321         .WillOnce(Return(0));
322     base->set_enabled(SD_EVENT_ON);
323 }
324 
325 TEST_F(BaseMethodTest, SetEnabledError)
326 {
327     EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, SD_EVENT_ON))
328         .WillOnce(Return(-EINVAL));
329     EXPECT_THROW(base->set_enabled(SD_EVENT_ON), SdEventError);
330 }
331 
332 } // namespace
333 } // namespace source
334 } // namespace sdeventplus
335