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, Copy) 166 { 167 EXPECT_CALL(mock, sd_event_ref(expected_event)) 168 .WillOnce(Return(expected_event)); 169 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 170 .WillOnce(Return(expected_source)); 171 auto io2 = std::make_unique<IO>(*io); 172 { 173 EXPECT_CALL(mock, sd_event_ref(expected_event)) 174 .WillOnce(Return(expected_event)); 175 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 176 .WillOnce(Return(expected_source)); 177 IO io3(*io); 178 179 expect_destruct(); 180 EXPECT_CALL(mock, sd_event_ref(expected_event)) 181 .WillOnce(Return(expected_event)); 182 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 183 .WillOnce(Return(expected_source)); 184 *io2 = io3; 185 186 expect_destruct(); 187 } 188 189 // Delete the original IO 190 io2.swap(io); 191 expect_destruct(); 192 io2.reset(); 193 194 // Make sure our new copy can still access data 195 io->set_callback(nullptr); 196 } 197 198 TEST_F(IOMethodTest, GetFdSuccess) 199 { 200 const int fd = 5; 201 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 202 .WillOnce(Return(fd)); 203 EXPECT_EQ(fd, io->get_fd()); 204 } 205 206 TEST_F(IOMethodTest, GetFdError) 207 { 208 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 209 .WillOnce(Return(-EINVAL)); 210 EXPECT_THROW(io->get_fd(), SdEventError); 211 } 212 213 TEST_F(IOMethodTest, SetFdSuccess) 214 { 215 const int fd = 5; 216 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 217 .WillOnce(Return(0)); 218 io->set_fd(fd); 219 } 220 221 TEST_F(IOMethodTest, SetFdError) 222 { 223 const int fd = 3; 224 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 225 .WillOnce(Return(-EINVAL)); 226 EXPECT_THROW(io->set_fd(fd), SdEventError); 227 } 228 229 TEST_F(IOMethodTest, GetEventsSuccess) 230 { 231 const uint32_t events = EPOLLIN | EPOLLOUT; 232 EXPECT_CALL(mock, 233 sd_event_source_get_io_events(expected_source, testing::_)) 234 .WillOnce(DoAll(SetArgPointee<1>(events), Return(0))); 235 EXPECT_EQ(events, io->get_events()); 236 } 237 238 TEST_F(IOMethodTest, GetEventsError) 239 { 240 EXPECT_CALL(mock, 241 sd_event_source_get_io_events(expected_source, testing::_)) 242 .WillOnce(Return(-EINVAL)); 243 EXPECT_THROW(io->get_events(), SdEventError); 244 } 245 246 TEST_F(IOMethodTest, SetEventsSuccess) 247 { 248 const uint32_t events = EPOLLIN | EPOLLOUT; 249 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 250 .WillOnce(Return(0)); 251 io->set_events(events); 252 } 253 254 TEST_F(IOMethodTest, SetEventsError) 255 { 256 const uint32_t events = EPOLLIN | EPOLLOUT; 257 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 258 .WillOnce(Return(-EINVAL)); 259 EXPECT_THROW(io->set_events(events), SdEventError); 260 } 261 262 TEST_F(IOMethodTest, GetREventsSuccess) 263 { 264 const uint32_t revents = EPOLLOUT; 265 EXPECT_CALL(mock, 266 sd_event_source_get_io_revents(expected_source, testing::_)) 267 .WillOnce(DoAll(SetArgPointee<1>(revents), Return(0))); 268 EXPECT_EQ(revents, io->get_revents()); 269 } 270 271 TEST_F(IOMethodTest, GetREventsError) 272 { 273 EXPECT_CALL(mock, 274 sd_event_source_get_io_revents(expected_source, testing::_)) 275 .WillOnce(Return(-EINVAL)); 276 EXPECT_THROW(io->get_revents(), SdEventError); 277 } 278 279 } // namespace 280 } // namespace source 281 } // namespace sdeventplus 282