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::SaveArg; 25 using testing::SetArgPointee; 26 27 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 28 29 class SignalTest : public testing::Test 30 { 31 protected: 32 testing::StrictMock<test::SdEventMock> mock; 33 sd_event_source* const expected_source = 34 reinterpret_cast<sd_event_source*>(1234); 35 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 36 UniqueEvent event = make_event(expected_event); 37 38 UniqueEvent make_event(sd_event* event) 39 { 40 auto deleter = [this, event](Event* e) { 41 EXPECT_CALL(this->mock, sd_event_unref(event)) 42 .WillOnce(Return(nullptr)); 43 delete e; 44 }; 45 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 46 } 47 48 void expect_destruct() 49 { 50 { 51 testing::InSequence sequence; 52 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, 53 SD_EVENT_OFF)) 54 .WillOnce(Return(0)); 55 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 56 .WillOnce(Return(nullptr)); 57 } 58 EXPECT_CALL(mock, sd_event_unref(expected_event)) 59 .WillOnce(Return(nullptr)); 60 } 61 }; 62 63 TEST_F(SignalTest, ConstructSuccess) 64 { 65 const int sig = SIGALRM; 66 67 EXPECT_CALL(mock, sd_event_ref(expected_event)) 68 .WillOnce(Return(expected_event)); 69 sd_event_signal_handler_t handler; 70 EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig, 71 testing::_, nullptr)) 72 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<3>(&handler), 73 Return(0))); 74 void* userdata; 75 EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_)) 76 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 77 int completions = 0; 78 const struct signalfd_siginfo* return_si; 79 Signal::Callback callback = [&](Signal&, 80 const struct signalfd_siginfo* si) { 81 return_si = si; 82 completions++; 83 }; 84 Signal signal(*event, sig, std::move(callback)); 85 EXPECT_FALSE(callback); 86 EXPECT_EQ(&signal, userdata); 87 EXPECT_EQ(0, completions); 88 89 const struct signalfd_siginfo* expected_si = 90 reinterpret_cast<struct signalfd_siginfo*>(865); 91 EXPECT_EQ(0, handler(nullptr, expected_si, &signal)); 92 EXPECT_EQ(1, completions); 93 EXPECT_EQ(expected_si, return_si); 94 95 signal.set_callback(std::bind([]() {})); 96 EXPECT_EQ(0, handler(nullptr, expected_si, &signal)); 97 EXPECT_EQ(1, completions); 98 99 expect_destruct(); 100 } 101 102 TEST_F(SignalTest, ConstructError) 103 { 104 const int sig = SIGALRM; 105 106 EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig, 107 testing::_, nullptr)) 108 .WillOnce(Return(-EINVAL)); 109 int completions = 0; 110 Signal::Callback callback = [&completions](Signal&, 111 const struct signalfd_siginfo*) { 112 completions++; 113 }; 114 EXPECT_THROW(Signal(*event, sig, std::move(callback)), SdEventError); 115 EXPECT_TRUE(callback); 116 EXPECT_EQ(0, completions); 117 } 118 119 class SignalMethodTest : public SignalTest 120 { 121 protected: 122 std::unique_ptr<Signal> signal; 123 124 void SetUp() 125 { 126 const int sig = SIGINT; 127 128 EXPECT_CALL(mock, sd_event_ref(expected_event)) 129 .WillOnce(Return(expected_event)); 130 EXPECT_CALL(mock, sd_event_add_signal(expected_event, testing::_, sig, 131 testing::_, nullptr)) 132 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 133 EXPECT_CALL(mock, 134 sd_event_source_set_userdata(expected_source, testing::_)) 135 .WillOnce(Return(nullptr)); 136 signal = std::make_unique<Signal>( 137 *event, sig, [](Signal&, const struct signalfd_siginfo*) {}); 138 } 139 140 void TearDown() 141 { 142 expect_destruct(); 143 signal.reset(); 144 } 145 }; 146 147 TEST_F(SignalMethodTest, GetSignalSuccess) 148 { 149 const int sig = SIGTERM; 150 EXPECT_CALL(mock, sd_event_source_get_signal(expected_source)) 151 .WillOnce(Return(sig)); 152 EXPECT_EQ(sig, signal->get_signal()); 153 } 154 155 TEST_F(SignalMethodTest, GetSignalError) 156 { 157 EXPECT_CALL(mock, sd_event_source_get_signal(expected_source)) 158 .WillOnce(Return(-EINVAL)); 159 EXPECT_THROW(signal->get_signal(), SdEventError); 160 } 161 162 } // namespace 163 } // namespace source 164 } // namespace sdeventplus 165