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 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 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 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 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 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 159 void TearDown() 160 { 161 expect_destruct(); 162 signal.reset(); 163 destroy(userdata); 164 } 165 }; 166 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 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 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