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, SetTimeSuccess) 168 { 169 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 170 .WillOnce(Return(0)); 171 time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})); 172 } 173 174 TEST_F(TimeMethodTest, SetTimeError) 175 { 176 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 177 .WillOnce(Return(-EINVAL)); 178 EXPECT_THROW(time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})), 179 SdEventError); 180 } 181 182 TEST_F(TimeMethodTest, GetTimeSuccess) 183 { 184 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 185 .WillOnce(DoAll(SetArgPointee<1>(10), Return(0))); 186 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds{10}), 187 time->get_time()); 188 } 189 190 TEST_F(TimeMethodTest, GetTimeError) 191 { 192 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 193 .WillOnce(Return(-ENOSYS)); 194 EXPECT_THROW(time->get_time(), SdEventError); 195 } 196 197 TEST_F(TimeMethodTest, SetAccuracySuccess) 198 { 199 EXPECT_CALL(mock, 200 sd_event_source_set_time_accuracy(expected_source, 5000000)) 201 .WillOnce(Return(0)); 202 time->set_accuracy(std::chrono::seconds{5}); 203 } 204 205 TEST_F(TimeMethodTest, SetAccuracyError) 206 { 207 EXPECT_CALL(mock, 208 sd_event_source_set_time_accuracy(expected_source, 5000000)) 209 .WillOnce(Return(-EINVAL)); 210 EXPECT_THROW(time->set_accuracy(std::chrono::seconds{5}), SdEventError); 211 } 212 213 TEST_F(TimeMethodTest, GetAccuracySuccess) 214 { 215 EXPECT_CALL(mock, 216 sd_event_source_get_time_accuracy(expected_source, testing::_)) 217 .WillOnce(DoAll(SetArgPointee<1>(1000), Return(0))); 218 EXPECT_EQ(std::chrono::milliseconds{1}, time->get_accuracy()); 219 } 220 221 TEST_F(TimeMethodTest, GetAccuracyError) 222 { 223 EXPECT_CALL(mock, 224 sd_event_source_get_time_accuracy(expected_source, testing::_)) 225 .WillOnce(Return(-ENOSYS)); 226 EXPECT_THROW(time->get_accuracy(), SdEventError); 227 } 228 229 } // namespace 230 } // namespace source 231 } // namespace sdeventplus 232