1 #include <cerrno> 2 #include <chrono> 3 #include <functional> 4 #include <gmock/gmock.h> 5 #include <gtest/gtest.h> 6 #include <memory> 7 #include <sdeventplus/clock.hpp> 8 #include <sdeventplus/exception.hpp> 9 #include <sdeventplus/source/time.hpp> 10 #include <sdeventplus/test/sdevent.hpp> 11 #include <systemd/sd-event.h> 12 #include <time.h> 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::ReturnPointee; 25 using testing::SaveArg; 26 using testing::SetArgPointee; 27 28 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 29 30 class TimeTest : public testing::Test 31 { 32 protected: 33 testing::StrictMock<test::SdEventMock> mock; 34 sd_event_source* const expected_source = 35 reinterpret_cast<sd_event_source*>(1234); 36 sd_event* const expected_event = reinterpret_cast<sd_event*>(2345); 37 UniqueEvent event = make_event(expected_event); 38 39 UniqueEvent make_event(sd_event* event) 40 { 41 auto deleter = [this, event](Event* e) { 42 EXPECT_CALL(this->mock, sd_event_unref(event)) 43 .WillOnce(Return(nullptr)); 44 delete e; 45 }; 46 return UniqueEvent(new Event(event, std::false_type(), &mock), deleter); 47 } 48 49 void expect_time_destroy(sd_event* event, sd_event_source* source) 50 { 51 EXPECT_CALL(mock, sd_event_source_unref(source)) 52 .WillOnce(Return(nullptr)); 53 EXPECT_CALL(mock, sd_event_unref(event)).WillOnce(Return(nullptr)); 54 } 55 }; 56 57 TEST_F(TimeTest, ConstructSuccess) 58 { 59 constexpr ClockId id = ClockId::RealTime; 60 const Time<id>::TimePoint expected_time(std::chrono::seconds{2}); 61 const Time<id>::Accuracy expected_accuracy(std::chrono::milliseconds{50}); 62 Time<id>::TimePoint saved_time; 63 Time<id>::Callback callback = [&saved_time](Time<id>&, 64 Time<id>::TimePoint time) { 65 saved_time = time; 66 }; 67 68 EXPECT_CALL(mock, sd_event_ref(expected_event)) 69 .WillOnce(Return(expected_event)); 70 sd_event_time_handler_t handler; 71 EXPECT_CALL(mock, 72 sd_event_add_time(expected_event, testing::_, CLOCK_REALTIME, 73 2000000, 50000, testing::_, nullptr)) 74 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler), 75 Return(0))); 76 sd_event_destroy_t destroy; 77 void* userdata; 78 { 79 testing::InSequence seq; 80 EXPECT_CALL(mock, sd_event_source_set_destroy_callback(expected_source, 81 testing::_)) 82 .WillOnce(DoAll(SaveArg<1>(&destroy), Return(0))); 83 EXPECT_CALL(mock, 84 sd_event_source_set_userdata(expected_source, testing::_)) 85 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 86 EXPECT_CALL(mock, sd_event_source_get_userdata(expected_source)) 87 .WillRepeatedly(ReturnPointee(&userdata)); 88 } 89 Time<id> time(*event, expected_time, expected_accuracy, 90 std::move(callback)); 91 EXPECT_FALSE(callback); 92 EXPECT_NE(&time, userdata); 93 EXPECT_EQ(expected_event, time.get_event().get()); 94 EXPECT_EQ(expected_source, time.get()); 95 96 EXPECT_EQ(0, handler(nullptr, 2000100, userdata)); 97 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds(2000100)), 98 saved_time); 99 100 time.set_callback(std::bind([]() {})); 101 EXPECT_EQ(0, handler(nullptr, 0, userdata)); 102 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds(2000100)), 103 saved_time); 104 105 expect_time_destroy(expected_event, expected_source); 106 destroy(userdata); 107 } 108 109 TEST_F(TimeTest, ConstructError) 110 { 111 constexpr ClockId id = ClockId::Monotonic; 112 const Time<id>::TimePoint expected_time(std::chrono::seconds{2}); 113 const Time<id>::Accuracy expected_accuracy(std::chrono::milliseconds{50}); 114 Time<id>::Callback callback = [](Time<id>&, Time<id>::TimePoint) {}; 115 116 EXPECT_CALL(mock, 117 sd_event_add_time(expected_event, testing::_, CLOCK_MONOTONIC, 118 2000000, 50000, testing::_, nullptr)) 119 .WillOnce(Return(-ENOSYS)); 120 EXPECT_THROW( 121 Time<id>(*event, expected_time, expected_accuracy, std::move(callback)), 122 SdEventError); 123 EXPECT_TRUE(callback); 124 } 125 126 class TimeMethodTest : public TimeTest 127 { 128 protected: 129 static constexpr ClockId id = ClockId::BootTime; 130 std::unique_ptr<Time<id>> time; 131 sd_event_destroy_t destroy; 132 void* userdata; 133 134 void SetUp() 135 { 136 EXPECT_CALL(mock, sd_event_ref(expected_event)) 137 .WillOnce(Return(expected_event)); 138 EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_, 139 CLOCK_BOOTTIME, 2000000, 50000, 140 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 time = std::make_unique<Time<id>>( 154 *event, Time<id>::TimePoint(std::chrono::seconds{2}), 155 std::chrono::milliseconds{50}, 156 [](Time<id>&, Time<id>::TimePoint) {}); 157 } 158 159 void TearDown() 160 { 161 expect_time_destroy(expected_event, expected_source); 162 time.reset(); 163 destroy(userdata); 164 } 165 }; 166 167 TEST_F(TimeMethodTest, Copy) 168 { 169 EXPECT_CALL(mock, sd_event_ref(expected_event)) 170 .WillOnce(Return(expected_event)); 171 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 172 .WillOnce(Return(expected_source)); 173 auto time2 = std::make_unique<Time<id>>(*time); 174 { 175 EXPECT_CALL(mock, sd_event_ref(expected_event)) 176 .WillOnce(Return(expected_event)); 177 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 178 .WillOnce(Return(expected_source)); 179 Time<id> time3(*time); 180 181 expect_time_destroy(expected_event, expected_source); 182 EXPECT_CALL(mock, sd_event_ref(expected_event)) 183 .WillOnce(Return(expected_event)); 184 EXPECT_CALL(mock, sd_event_source_ref(expected_source)) 185 .WillOnce(Return(expected_source)); 186 *time2 = time3; 187 188 expect_time_destroy(expected_event, expected_source); 189 } 190 191 // Delete the original time 192 time2.swap(time); 193 expect_time_destroy(expected_event, expected_source); 194 time2.reset(); 195 196 // Make sure our new copy can still access data 197 time->set_callback(nullptr); 198 } 199 200 TEST_F(TimeMethodTest, SetTimeSuccess) 201 { 202 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 203 .WillOnce(Return(0)); 204 time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})); 205 } 206 207 TEST_F(TimeMethodTest, SetTimeError) 208 { 209 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 210 .WillOnce(Return(-EINVAL)); 211 EXPECT_THROW(time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})), 212 SdEventError); 213 } 214 215 TEST_F(TimeMethodTest, GetTimeSuccess) 216 { 217 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 218 .WillOnce(DoAll(SetArgPointee<1>(10), Return(0))); 219 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds{10}), 220 time->get_time()); 221 } 222 223 TEST_F(TimeMethodTest, GetTimeError) 224 { 225 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 226 .WillOnce(Return(-ENOSYS)); 227 EXPECT_THROW(time->get_time(), SdEventError); 228 } 229 230 TEST_F(TimeMethodTest, SetAccuracySuccess) 231 { 232 EXPECT_CALL(mock, 233 sd_event_source_set_time_accuracy(expected_source, 5000000)) 234 .WillOnce(Return(0)); 235 time->set_accuracy(std::chrono::seconds{5}); 236 } 237 238 TEST_F(TimeMethodTest, SetAccuracyError) 239 { 240 EXPECT_CALL(mock, 241 sd_event_source_set_time_accuracy(expected_source, 5000000)) 242 .WillOnce(Return(-EINVAL)); 243 EXPECT_THROW(time->set_accuracy(std::chrono::seconds{5}), SdEventError); 244 } 245 246 TEST_F(TimeMethodTest, GetAccuracySuccess) 247 { 248 EXPECT_CALL(mock, 249 sd_event_source_get_time_accuracy(expected_source, testing::_)) 250 .WillOnce(DoAll(SetArgPointee<1>(1000), Return(0))); 251 EXPECT_EQ(std::chrono::milliseconds{1}, time->get_accuracy()); 252 } 253 254 TEST_F(TimeMethodTest, GetAccuracyError) 255 { 256 EXPECT_CALL(mock, 257 sd_event_source_get_time_accuracy(expected_source, testing::_)) 258 .WillOnce(Return(-ENOSYS)); 259 EXPECT_THROW(time->get_accuracy(), SdEventError); 260 } 261 262 } // namespace 263 } // namespace source 264 } // namespace sdeventplus 265