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