xref: /openbmc/sdeventplus/test/source/signal.cpp (revision 0249f9ed)
1 #include <signal.h>
2 #include <systemd/sd-event.h>
3 
4 #include <sdeventplus/event.hpp>
5 #include <sdeventplus/exception.hpp>
6 #include <sdeventplus/source/signal.hpp>
7 #include <sdeventplus/test/sdevent.hpp>
8 
9 #include <cerrno>
10 #include <functional>
11 #include <memory>
12 #include <type_traits>
13 #include <utility>
14 
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 
18 namespace sdeventplus
19 {
20 namespace source
21 {
22 namespace
23 {
24 
25 using testing::DoAll;
26 using testing::Return;
27 using testing::ReturnPointee;
28 using testing::SaveArg;
29 using testing::SetArgPointee;
30 
31 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>;
32 
33 class SignalTest : public testing::Test
34 {
35   protected:
36     testing::StrictMock<test::SdEventMock> mock;
37     sd_event_source* const expected_source =
38         reinterpret_cast<sd_event_source*>(1234);
39     sd_event* const expected_event = reinterpret_cast<sd_event*>(2345);
40     UniqueEvent event = make_event(expected_event);
41 
make_event(sd_event * event)42     UniqueEvent make_event(sd_event* event)
43     {
44         auto deleter = [this, event](Event* e) {
45             EXPECT_CALL(this->mock, sd_event_unref(event))
46                 .WillOnce(Return(nullptr));
47             delete e;
48         };
49         return UniqueEvent(new Event(event, std::false_type(), &mock), deleter);
50     }
51 
expect_destruct()52     void expect_destruct()
53     {
54         EXPECT_CALL(mock, sd_event_source_unref(expected_source))
55             .WillOnce(Return(nullptr));
56         EXPECT_CALL(mock, sd_event_unref(expected_event))
57             .WillOnce(Return(nullptr));
58     }
59 };
60 
TEST_F(SignalTest,ConstructSuccess)61 TEST_F(SignalTest, ConstructSuccess)
62 {
63     const int sig = SIGALRM;
64 
65     EXPECT_CALL(mock, sd_event_ref(expected_event))
66         .WillOnce(Return(expected_event));
67     sd_event_signal_handler_t handler;
68     EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig,
69                                           testing::_, nullptr))
70         .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<3>(&handler),
71                         Return(0)));
72     sd_event_destroy_t destroy;
73     void* userdata;
74     {
75         testing::InSequence seq;
76         EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source,
77                                                                testing::_))
78             .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
79         EXPECT_CALL(mock,
80                     sd_event_source_set_userdata(expected_source, testing::_))
81             .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
82         EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
83             .WillRepeatedly(ReturnPointee(&userdata));
84     }
85     int completions = 0;
86     const struct signalfd_siginfo* return_si;
87     Signal::Callback callback = [&](Signal&,
88                                     const struct signalfd_siginfo* si) {
89         return_si = si;
90         completions++;
91     };
92     Signal signal(*event, sig, std::move(callback));
93     EXPECT_FALSE(callback);
94     EXPECT_NE(&signal, userdata);
95     EXPECT_EQ(0, completions);
96 
97     const struct signalfd_siginfo* expected_si =
98         reinterpret_cast<struct signalfd_siginfo*>(865);
99     EXPECT_EQ(0, handler(nullptr, expected_si, userdata));
100     EXPECT_EQ(1, completions);
101     EXPECT_EQ(expected_si, return_si);
102 
103     signal.set_callback(std::bind([]() {}));
104     EXPECT_EQ(0, handler(nullptr, expected_si, userdata));
105     EXPECT_EQ(1, completions);
106 
107     expect_destruct();
108     destroy(userdata);
109 }
110 
TEST_F(SignalTest,ConstructError)111 TEST_F(SignalTest, ConstructError)
112 {
113     const int sig = SIGALRM;
114 
115     EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig,
116                                           testing::_, nullptr))
117         .WillOnce(Return(-EINVAL));
118     int completions = 0;
119     Signal::Callback callback = [&completions](Signal&,
120                                                const struct signalfd_siginfo*) {
121         completions++;
122     };
123     EXPECT_THROW(Signal(*event, sig, std::move(callback)), SdEventError);
124     EXPECT_TRUE(callback);
125     EXPECT_EQ(0, completions);
126 }
127 
128 class SignalMethodTest : public SignalTest
129 {
130   protected:
131     std::unique_ptr<Signal> signal;
132     sd_event_destroy_t destroy;
133     void* userdata;
134 
SetUp()135     void SetUp()
136     {
137         const int sig = SIGINT;
138 
139         EXPECT_CALL(mock, sd_event_ref(expected_event))
140             .WillOnce(Return(expected_event));
141         EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig,
142                                               testing::_, nullptr))
143             .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0)));
144         {
145             testing::InSequence seq;
146             EXPECT_CALL(mock, sd_event_source_set_destroy_callback(
147                                   expected_source, testing::_))
148                 .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0)));
149             EXPECT_CALL(
150                 mock, sd_event_source_set_userdata(expected_source, testing::_))
151                 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr)));
152             EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source))
153                 .WillRepeatedly(ReturnPointee(&userdata));
154         }
155         signal = std::make_unique<Signal>(
156             *event, sig, [](Signal&, const struct signalfd_siginfo*) {});
157     }
158 
TearDown()159     void TearDown()
160     {
161         expect_destruct();
162         signal.reset();
163         destroy(userdata);
164     }
165 };
166 
TEST_F(SignalMethodTest,Copy)167 TEST_F(SignalMethodTest, Copy)
168 {
169     EXPECT_CALL(mock, sd_event_ref(expected_event))
170         .WillOnce(Return(expected_event));
171     EXPECT_CALL(mock, sd_event_source_ref(expected_source))
172         .WillOnce(Return(expected_source));
173     auto signal2 = std::make_unique<Signal>(*signal);
174     {
175         EXPECT_CALL(mock, sd_event_ref(expected_event))
176             .WillOnce(Return(expected_event));
177         EXPECT_CALL(mock, sd_event_source_ref(expected_source))
178             .WillOnce(Return(expected_source));
179         Signal signal3(*signal);
180 
181         expect_destruct();
182         EXPECT_CALL(mock, sd_event_ref(expected_event))
183             .WillOnce(Return(expected_event));
184         EXPECT_CALL(mock, sd_event_source_ref(expected_source))
185             .WillOnce(Return(expected_source));
186         *signal2 = signal3;
187 
188         expect_destruct();
189     }
190 
191     // Delete the original signal
192     signal2.swap(signal);
193     expect_destruct();
194     signal2.reset();
195 
196     // Make sure our new copy can still access data
197     signal->set_callback(nullptr);
198 }
199 
TEST_F(SignalMethodTest,GetSignalSuccess)200 TEST_F(SignalMethodTest, GetSignalSuccess)
201 {
202     const int sig = SIGTERM;
203     EXPECT_CALL(mock, sd_event_source_get_signal(expected_source))
204         .WillOnce(Return(sig));
205     EXPECT_EQ(sig, signal->get_signal());
206 }
207 
TEST_F(SignalMethodTest,GetSignalError)208 TEST_F(SignalMethodTest, GetSignalError)
209 {
210     EXPECT_CALL(mock, sd_event_source_get_signal(expected_source))
211         .WillOnce(Return(-EINVAL));
212     EXPECT_THROW(signal->get_signal(), SdEventError);
213 }
214 
215 } // namespace
216 } // namespace source
217 } // namespace sdeventplus
218