1 #include <systemd/sd-event.h> 2 3 #include <sdeventplus/event.hpp> 4 #include <sdeventplus/exception.hpp> 5 #include <sdeventplus/source/io.hpp> 6 #include <sdeventplus/test/sdevent.hpp> 7 8 #include <cerrno> 9 #include <functional> 10 #include <memory> 11 #include <type_traits> 12 #include <utility> 13 14 #include <gmock/gmock.h> 15 #include <gtest/gtest.h> 16 17 namespace sdeventplus 18 { 19 namespace source 20 { 21 namespace 22 { 23 24 using testing::DoAll; 25 using testing::Return; 26 using testing::ReturnPointee; 27 using testing::SaveArg; 28 using testing::SetArgPointee; 29 30 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 31 32 class IOTest : public testing::Test 33 { 34 protected: 35 testing::StrictMock<test::SdEventMock> mock; 36 sd_event_source* const expected_source = 37 reinterpret_cast<sd_event_source*>(1234); 38 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 39 UniqueEvent event = make_event(expected_event); 40 41 UniqueEvent make_event(sd_event* event) 42 { 43 auto deleter = [this, event](Event* e) { 44 EXPECT_CALL(this->mock, sd_event_unref(event)) 45 .WillOnce(Return(nullptr)); 46 delete e; 47 }; 48 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 49 } 50 51 void expect_destruct() 52 { 53 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 54 .WillOnce(Return(nullptr)); 55 EXPECT_CALL(mock, sd_event_unref(expected_event)) 56 .WillOnce(Return(nullptr)); 57 } 58 }; 59 60 TEST_F(IOTest, ConstructSuccess) 61 { 62 const int fd = 10; 63 const uint32_t events = EPOLLIN | EPOLLET; 64 65 EXPECT_CALL(mock, sd_event_ref(expected_event)) 66 .WillOnce(Return(expected_event)); 67 sd_event_io_handler_t handler; 68 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, events, 69 testing::_, nullptr)) 70 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<4>(&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 int return_fd; 87 uint32_t return_revents; 88 IO::Callback callback = [&](IO&, int fd, uint32_t revents) { 89 return_fd = fd; 90 return_revents = revents; 91 completions++; 92 }; 93 IO io(*event, fd, events, std::move(callback)); 94 EXPECT_FALSE(callback); 95 EXPECT_NE(&io, userdata); 96 EXPECT_EQ(0, completions); 97 98 EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, userdata)); 99 EXPECT_EQ(1, completions); 100 EXPECT_EQ(5, return_fd); 101 EXPECT_EQ(EPOLLIN, return_revents); 102 103 io.set_callback(std::bind([]() {})); 104 EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, userdata)); 105 EXPECT_EQ(1, completions); 106 107 expect_destruct(); 108 destroy(userdata); 109 } 110 111 TEST_F(IOTest, ConstructError) 112 { 113 const int fd = 10; 114 const uint32_t events = EPOLLIN | EPOLLET; 115 116 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, events, 117 testing::_, nullptr)) 118 .WillOnce(Return(-EINVAL)); 119 int completions = 0; 120 IO::Callback callback = [&completions](IO&, int, uint32_t) { 121 completions++; 122 }; 123 EXPECT_THROW(IO(*event, fd, events, std::move(callback)), SdEventError); 124 EXPECT_TRUE(callback); 125 EXPECT_EQ(0, completions); 126 } 127 128 class IOMethodTest : public IOTest 129 { 130 protected: 131 std::unique_ptr<IO> io; 132 sd_event_destroy_t destroy; 133 void* userdata; 134 135 void SetUp() 136 { 137 const int fd = 7; 138 const int events = EPOLLOUT; 139 140 EXPECT_CALL(mock, sd_event_ref(expected_event)) 141 .WillOnce(Return(expected_event)); 142 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, 143 events, testing::_, nullptr)) 144 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 145 { 146 testing::InSequence seq; 147 EXPECT_CALL(mock, sd_event_source_set_destroy_callback( 148 expected_source, testing::_)) 149 .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0))); 150 EXPECT_CALL( 151 mock, sd_event_source_set_userdata(expected_source, testing::_)) 152 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 153 EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source)) 154 .WillRepeatedly(ReturnPointee(&userdata)); 155 } 156 io = std::make_unique<IO>(*event, fd, events, 157 [](IO&, int, uint32_t) {}); 158 } 159 160 void TearDown() 161 { 162 expect_destruct(); 163 io.reset(); 164 destroy(userdata); 165 } 166 }; 167 168 TEST_F(IOMethodTest, Copy) 169 { 170 EXPECT_CALL(mock, sd_event_ref(expected_event)) 171 .WillOnce(Return(expected_event)); 172 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 173 .WillOnce(Return(expected_source)); 174 auto io2 = std::make_unique<IO>(*io); 175 { 176 EXPECT_CALL(mock, sd_event_ref(expected_event)) 177 .WillOnce(Return(expected_event)); 178 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 179 .WillOnce(Return(expected_source)); 180 IO io3(*io); 181 182 expect_destruct(); 183 EXPECT_CALL(mock, sd_event_ref(expected_event)) 184 .WillOnce(Return(expected_event)); 185 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 186 .WillOnce(Return(expected_source)); 187 *io2 = io3; 188 189 expect_destruct(); 190 } 191 192 // Delete the original IO 193 io2.swap(io); 194 expect_destruct(); 195 io2.reset(); 196 197 // Make sure our new copy can still access data 198 io->set_callback(nullptr); 199 } 200 201 TEST_F(IOMethodTest, GetFdSuccess) 202 { 203 const int fd = 5; 204 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 205 .WillOnce(Return(fd)); 206 EXPECT_EQ(fd, io->get_fd()); 207 } 208 209 TEST_F(IOMethodTest, GetFdError) 210 { 211 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 212 .WillOnce(Return(-EINVAL)); 213 EXPECT_THROW(io->get_fd(), SdEventError); 214 } 215 216 TEST_F(IOMethodTest, SetFdSuccess) 217 { 218 const int fd = 5; 219 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 220 .WillOnce(Return(0)); 221 io->set_fd(fd); 222 } 223 224 TEST_F(IOMethodTest, SetFdError) 225 { 226 const int fd = 3; 227 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 228 .WillOnce(Return(-EINVAL)); 229 EXPECT_THROW(io->set_fd(fd), SdEventError); 230 } 231 232 TEST_F(IOMethodTest, GetEventsSuccess) 233 { 234 const uint32_t events = EPOLLIN | EPOLLOUT; 235 EXPECT_CALL(mock, 236 sd_event_source_get_io_events(expected_source, testing::_)) 237 .WillOnce(DoAll(SetArgPointee<1>(events), Return(0))); 238 EXPECT_EQ(events, io->get_events()); 239 } 240 241 TEST_F(IOMethodTest, GetEventsError) 242 { 243 EXPECT_CALL(mock, 244 sd_event_source_get_io_events(expected_source, testing::_)) 245 .WillOnce(Return(-EINVAL)); 246 EXPECT_THROW(io->get_events(), SdEventError); 247 } 248 249 TEST_F(IOMethodTest, SetEventsSuccess) 250 { 251 const uint32_t events = EPOLLIN | EPOLLOUT; 252 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 253 .WillOnce(Return(0)); 254 io->set_events(events); 255 } 256 257 TEST_F(IOMethodTest, SetEventsError) 258 { 259 const uint32_t events = EPOLLIN | EPOLLOUT; 260 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 261 .WillOnce(Return(-EINVAL)); 262 EXPECT_THROW(io->set_events(events), SdEventError); 263 } 264 265 TEST_F(IOMethodTest, GetREventsSuccess) 266 { 267 const uint32_t revents = EPOLLOUT; 268 EXPECT_CALL(mock, 269 sd_event_source_get_io_revents(expected_source, testing::_)) 270 .WillOnce(DoAll(SetArgPointee<1>(revents), Return(0))); 271 EXPECT_EQ(revents, io->get_revents()); 272 } 273 274 TEST_F(IOMethodTest, GetREventsError) 275 { 276 EXPECT_CALL(mock, 277 sd_event_source_get_io_revents(expected_source, testing::_)) 278 .WillOnce(Return(-EINVAL)); 279 EXPECT_THROW(io->get_revents(), SdEventError); 280 } 281 282 } // namespace 283 } // namespace source 284 } // namespace sdeventplus 285