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/io.hpp> 9 #include <sdeventplus/test/sdevent.hpp> 10 #include <systemd/sd-event.h> 11 #include <type_traits> 12 #include <utility> 13 14 namespace sdeventplus 15 { 16 namespace source 17 { 18 namespace 19 { 20 21 using testing::DoAll; 22 using testing::Return; 23 using testing::ReturnPointee; 24 using testing::SaveArg; 25 using testing::SetArgPointee; 26 27 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 28 29 class IOTest : 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 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 51 .WillOnce(Return(nullptr)); 52 EXPECT_CALL(mock, sd_event_unref(expected_event)) 53 .WillOnce(Return(nullptr)); 54 } 55 }; 56 57 TEST_F(IOTest, ConstructSuccess) 58 { 59 const int fd = 10; 60 const uint32_t events = EPOLLIN | EPOLLET; 61 62 EXPECT_CALL(mock, sd_event_ref(expected_event)) 63 .WillOnce(Return(expected_event)); 64 sd_event_io_handler_t handler; 65 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, events, 66 testing::_, nullptr)) 67 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<4>(&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 int return_fd; 84 uint32_t return_revents; 85 IO::Callback callback = [&](IO&, int fd, uint32_t revents) { 86 return_fd = fd; 87 return_revents = revents; 88 completions++; 89 }; 90 IO io(*event, fd, events, std::move(callback)); 91 EXPECT_FALSE(callback); 92 EXPECT_NE(&io, userdata); 93 EXPECT_EQ(0, completions); 94 95 EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, userdata)); 96 EXPECT_EQ(1, completions); 97 EXPECT_EQ(5, return_fd); 98 EXPECT_EQ(EPOLLIN, return_revents); 99 100 io.set_callback(std::bind([]() {})); 101 EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, userdata)); 102 EXPECT_EQ(1, completions); 103 104 expect_destruct(); 105 destroy(userdata); 106 } 107 108 TEST_F(IOTest, ConstructError) 109 { 110 const int fd = 10; 111 const uint32_t events = EPOLLIN | EPOLLET; 112 113 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, events, 114 testing::_, nullptr)) 115 .WillOnce(Return(-EINVAL)); 116 int completions = 0; 117 IO::Callback callback = [&completions](IO&, int, uint32_t) { 118 completions++; 119 }; 120 EXPECT_THROW(IO(*event, fd, events, std::move(callback)), SdEventError); 121 EXPECT_TRUE(callback); 122 EXPECT_EQ(0, completions); 123 } 124 125 class IOMethodTest : public IOTest 126 { 127 protected: 128 std::unique_ptr<IO> io; 129 sd_event_destroy_t destroy; 130 void* userdata; 131 132 void SetUp() 133 { 134 const int fd = 7; 135 const int events = EPOLLOUT; 136 137 EXPECT_CALL(mock, sd_event_ref(expected_event)) 138 .WillOnce(Return(expected_event)); 139 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, 140 events, testing::_, nullptr)) 141 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 142 { 143 testing::InSequence seq; 144 EXPECT_CALL(mock, sd_event_source_set_destroy_callback( 145 expected_source, testing::_)) 146 .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0))); 147 EXPECT_CALL( 148 mock, sd_event_source_set_userdata(expected_source, testing::_)) 149 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 150 EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source)) 151 .WillRepeatedly(ReturnPointee(&userdata)); 152 } 153 io = 154 std::make_unique<IO>(*event, fd, events, [](IO&, int, uint32_t) {}); 155 } 156 157 void TearDown() 158 { 159 expect_destruct(); 160 io.reset(); 161 destroy(userdata); 162 } 163 }; 164 165 TEST_F(IOMethodTest, GetFdSuccess) 166 { 167 const int fd = 5; 168 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 169 .WillOnce(Return(fd)); 170 EXPECT_EQ(fd, io->get_fd()); 171 } 172 173 TEST_F(IOMethodTest, GetFdError) 174 { 175 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 176 .WillOnce(Return(-EINVAL)); 177 EXPECT_THROW(io->get_fd(), SdEventError); 178 } 179 180 TEST_F(IOMethodTest, SetFdSuccess) 181 { 182 const int fd = 5; 183 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 184 .WillOnce(Return(0)); 185 io->set_fd(fd); 186 } 187 188 TEST_F(IOMethodTest, SetFdError) 189 { 190 const int fd = 3; 191 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 192 .WillOnce(Return(-EINVAL)); 193 EXPECT_THROW(io->set_fd(fd), SdEventError); 194 } 195 196 TEST_F(IOMethodTest, GetEventsSuccess) 197 { 198 const uint32_t events = EPOLLIN | EPOLLOUT; 199 EXPECT_CALL(mock, 200 sd_event_source_get_io_events(expected_source, testing::_)) 201 .WillOnce(DoAll(SetArgPointee<1>(events), Return(0))); 202 EXPECT_EQ(events, io->get_events()); 203 } 204 205 TEST_F(IOMethodTest, GetEventsError) 206 { 207 EXPECT_CALL(mock, 208 sd_event_source_get_io_events(expected_source, testing::_)) 209 .WillOnce(Return(-EINVAL)); 210 EXPECT_THROW(io->get_events(), SdEventError); 211 } 212 213 TEST_F(IOMethodTest, SetEventsSuccess) 214 { 215 const uint32_t events = EPOLLIN | EPOLLOUT; 216 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 217 .WillOnce(Return(0)); 218 io->set_events(events); 219 } 220 221 TEST_F(IOMethodTest, SetEventsError) 222 { 223 const uint32_t events = EPOLLIN | EPOLLOUT; 224 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 225 .WillOnce(Return(-EINVAL)); 226 EXPECT_THROW(io->set_events(events), SdEventError); 227 } 228 229 TEST_F(IOMethodTest, GetREventsSuccess) 230 { 231 const uint32_t revents = EPOLLOUT; 232 EXPECT_CALL(mock, 233 sd_event_source_get_io_revents(expected_source, testing::_)) 234 .WillOnce(DoAll(SetArgPointee<1>(revents), Return(0))); 235 EXPECT_EQ(revents, io->get_revents()); 236 } 237 238 TEST_F(IOMethodTest, GetREventsError) 239 { 240 EXPECT_CALL(mock, 241 sd_event_source_get_io_revents(expected_source, testing::_)) 242 .WillOnce(Return(-EINVAL)); 243 EXPECT_THROW(io->get_revents(), SdEventError); 244 } 245 246 } // namespace 247 } // namespace source 248 } // namespace sdeventplus 249