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::SaveArg; 24 using testing::SetArgPointee; 25 26 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 27 28 class IOTest : public testing::Test 29 { 30 protected: 31 testing::StrictMock<test::SdEventMock> mock; 32 sd_event_source* const expected_source = 33 reinterpret_cast<sd_event_source*>(1234); 34 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 35 UniqueEvent event = make_event(expected_event); 36 37 UniqueEvent make_event(sd_event* event) 38 { 39 auto deleter = [this, event](Event* e) { 40 EXPECT_CALL(this->mock, sd_event_unref(event)) 41 .WillOnce(Return(nullptr)); 42 delete e; 43 }; 44 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 45 } 46 47 void expect_destruct() 48 { 49 { 50 testing::InSequence sequence; 51 EXPECT_CALL(mock, sd_event_source_set_enabled(expected_source, 52 SD_EVENT_OFF)) 53 .WillOnce(Return(0)); 54 EXPECT_CALL(mock, sd_event_source_unref(expected_source)) 55 .WillOnce(Return(nullptr)); 56 } 57 EXPECT_CALL(mock, sd_event_unref(expected_event)) 58 .WillOnce(Return(nullptr)); 59 } 60 }; 61 62 TEST_F(IOTest, ConstructSuccess) 63 { 64 const int fd = 10; 65 const uint32_t events = EPOLLIN | EPOLLET; 66 67 EXPECT_CALL(mock, sd_event_ref(expected_event)) 68 .WillOnce(Return(expected_event)); 69 sd_event_io_handler_t handler; 70 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, events, 71 testing::_, nullptr)) 72 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<4>(&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 int return_fd; 79 uint32_t return_revents; 80 IO::Callback callback = [&](IO&, int fd, uint32_t revents) { 81 return_fd = fd; 82 return_revents = revents; 83 completions++; 84 }; 85 IO io(*event, fd, events, std::move(callback)); 86 EXPECT_FALSE(callback); 87 EXPECT_EQ(&io, userdata); 88 EXPECT_EQ(0, completions); 89 90 EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, &io)); 91 EXPECT_EQ(1, completions); 92 EXPECT_EQ(5, return_fd); 93 EXPECT_EQ(EPOLLIN, return_revents); 94 95 io.set_callback(std::bind([]() {})); 96 EXPECT_EQ(0, handler(nullptr, 5, EPOLLIN, &io)); 97 EXPECT_EQ(1, completions); 98 99 expect_destruct(); 100 } 101 102 TEST_F(IOTest, ConstructError) 103 { 104 const int fd = 10; 105 const uint32_t events = EPOLLIN | EPOLLET; 106 107 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, events, 108 testing::_, nullptr)) 109 .WillOnce(Return(-EINVAL)); 110 int completions = 0; 111 IO::Callback callback = [&completions](IO&, int, uint32_t) { 112 completions++; 113 }; 114 EXPECT_THROW(IO(*event, fd, events, std::move(callback)), SdEventError); 115 EXPECT_TRUE(callback); 116 EXPECT_EQ(0, completions); 117 } 118 119 class IOMethodTest : public IOTest 120 { 121 protected: 122 std::unique_ptr<IO> io; 123 124 void SetUp() 125 { 126 const int fd = 7; 127 const int events = EPOLLOUT; 128 129 EXPECT_CALL(mock, sd_event_ref(expected_event)) 130 .WillOnce(Return(expected_event)); 131 EXPECT_CALL(mock, sd_event_add_io(expected_event, testing::_, fd, 132 events, testing::_, nullptr)) 133 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 134 EXPECT_CALL(mock, 135 sd_event_source_set_userdata(expected_source, testing::_)) 136 .WillOnce(Return(nullptr)); 137 io = 138 std::make_unique<IO>(*event, fd, events, [](IO&, int, uint32_t) {}); 139 } 140 141 void TearDown() 142 { 143 expect_destruct(); 144 io.reset(); 145 } 146 }; 147 148 TEST_F(IOMethodTest, GetFdSuccess) 149 { 150 const int fd = 5; 151 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 152 .WillOnce(Return(fd)); 153 EXPECT_EQ(fd, io->get_fd()); 154 } 155 156 TEST_F(IOMethodTest, GetFdError) 157 { 158 EXPECT_CALL(mock, sd_event_source_get_io_fd(expected_source)) 159 .WillOnce(Return(-EINVAL)); 160 EXPECT_THROW(io->get_fd(), SdEventError); 161 } 162 163 TEST_F(IOMethodTest, SetFdSuccess) 164 { 165 const int fd = 5; 166 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 167 .WillOnce(Return(0)); 168 io->set_fd(fd); 169 } 170 171 TEST_F(IOMethodTest, SetFdError) 172 { 173 const int fd = 3; 174 EXPECT_CALL(mock, sd_event_source_set_io_fd(expected_source, fd)) 175 .WillOnce(Return(-EINVAL)); 176 EXPECT_THROW(io->set_fd(fd), SdEventError); 177 } 178 179 TEST_F(IOMethodTest, GetEventsSuccess) 180 { 181 const uint32_t events = EPOLLIN | EPOLLOUT; 182 EXPECT_CALL(mock, 183 sd_event_source_get_io_events(expected_source, testing::_)) 184 .WillOnce(DoAll(SetArgPointee<1>(events), Return(0))); 185 EXPECT_EQ(events, io->get_events()); 186 } 187 188 TEST_F(IOMethodTest, GetEventsError) 189 { 190 EXPECT_CALL(mock, 191 sd_event_source_get_io_events(expected_source, testing::_)) 192 .WillOnce(Return(-EINVAL)); 193 EXPECT_THROW(io->get_events(), SdEventError); 194 } 195 196 TEST_F(IOMethodTest, SetEventsSuccess) 197 { 198 const uint32_t events = EPOLLIN | EPOLLOUT; 199 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 200 .WillOnce(Return(0)); 201 io->set_events(events); 202 } 203 204 TEST_F(IOMethodTest, SetEventsError) 205 { 206 const uint32_t events = EPOLLIN | EPOLLOUT; 207 EXPECT_CALL(mock, sd_event_source_set_io_events(expected_source, events)) 208 .WillOnce(Return(-EINVAL)); 209 EXPECT_THROW(io->set_events(events), SdEventError); 210 } 211 212 TEST_F(IOMethodTest, GetREventsSuccess) 213 { 214 const uint32_t revents = EPOLLOUT; 215 EXPECT_CALL(mock, 216 sd_event_source_get_io_revents(expected_source, testing::_)) 217 .WillOnce(DoAll(SetArgPointee<1>(revents), Return(0))); 218 EXPECT_EQ(revents, io->get_revents()); 219 } 220 221 TEST_F(IOMethodTest, GetREventsError) 222 { 223 EXPECT_CALL(mock, 224 sd_event_source_get_io_revents(expected_source, testing::_)) 225 .WillOnce(Return(-EINVAL)); 226 EXPECT_THROW(io->get_revents(), SdEventError); 227 } 228 229 } // namespace 230 } // namespace source 231 } // namespace sdeventplus 232