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::SaveArg; 25 using testing::SetArgPointee; 26 27 using UniqueEvent = std::unique_ptr<Event, std::function<void(Event*)>>; 28 29 class TimeTest : 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_time_destroy(sd_event* event, sd_event_source* source) 49 { 50 { 51 testing::InSequence sequence; 52 EXPECT_CALL(mock, sd_event_source_set_enabled(source, SD_EVENT_OFF)) 53 .WillOnce(Return(0)); 54 EXPECT_CALL(mock, sd_event_source_unref(source)) 55 .WillOnce(Return(nullptr)); 56 } 57 EXPECT_CALL(mock, sd_event_unref(event)).WillOnce(Return(nullptr)); 58 } 59 }; 60 61 TEST_F(TimeTest, ConstructSuccess) 62 { 63 constexpr ClockId id = ClockId::RealTime; 64 const Time<id>::TimePoint expected_time(std::chrono::seconds{2}); 65 const Time<id>::Accuracy expected_accuracy(std::chrono::milliseconds{50}); 66 Time<id>::TimePoint saved_time; 67 Time<id>::Callback callback = [&saved_time](Time<id>&, 68 Time<id>::TimePoint time) { 69 saved_time = time; 70 }; 71 72 EXPECT_CALL(mock, sd_event_ref(expected_event)) 73 .WillOnce(Return(expected_event)); 74 sd_event_time_handler_t handler; 75 EXPECT_CALL(mock, 76 sd_event_add_time(expected_event, testing::_, CLOCK_REALTIME, 77 2000000, 50000, testing::_, nullptr)) 78 .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler), 79 Return(0))); 80 void* userdata; 81 EXPECT_CALL(mock, sd_event_source_set_userdata(expected_source, testing::_)) 82 .WillOnce(DoAll(SaveArg<1>(&userdata), Return(nullptr))); 83 Time<id> time(*event, expected_time, expected_accuracy, 84 std::move(callback)); 85 EXPECT_FALSE(callback); 86 EXPECT_EQ(expected_event, time.get_event().get()); 87 EXPECT_EQ(expected_source, time.get()); 88 89 EXPECT_EQ(0, handler(nullptr, 2000100, userdata)); 90 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds(2000100)), 91 saved_time); 92 93 time.set_callback(std::bind([]() {})); 94 EXPECT_EQ(0, handler(nullptr, 0, userdata)); 95 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds(2000100)), 96 saved_time); 97 98 expect_time_destroy(expected_event, expected_source); 99 } 100 101 TEST_F(TimeTest, ConstructError) 102 { 103 constexpr ClockId id = ClockId::Monotonic; 104 const Time<id>::TimePoint expected_time(std::chrono::seconds{2}); 105 const Time<id>::Accuracy expected_accuracy(std::chrono::milliseconds{50}); 106 Time<id>::Callback callback = [](Time<id>&, Time<id>::TimePoint) {}; 107 108 EXPECT_CALL(mock, 109 sd_event_add_time(expected_event, testing::_, CLOCK_MONOTONIC, 110 2000000, 50000, testing::_, nullptr)) 111 .WillOnce(Return(-ENOSYS)); 112 EXPECT_THROW( 113 Time<id>(*event, expected_time, expected_accuracy, std::move(callback)), 114 SdEventError); 115 EXPECT_TRUE(callback); 116 } 117 118 class TimeMethodTest : public TimeTest 119 { 120 protected: 121 static constexpr ClockId id = ClockId::BootTime; 122 std::unique_ptr<Time<id>> time; 123 124 void SetUp() 125 { 126 EXPECT_CALL(mock, sd_event_ref(expected_event)) 127 .WillOnce(Return(expected_event)); 128 EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_, 129 CLOCK_BOOTTIME, 2000000, 50000, 130 testing::_, nullptr)) 131 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 132 EXPECT_CALL(mock, 133 sd_event_source_set_userdata(expected_source, testing::_)) 134 .WillOnce(Return(nullptr)); 135 time = std::make_unique<Time<id>>( 136 *event, Time<id>::TimePoint(std::chrono::seconds{2}), 137 std::chrono::milliseconds{50}, 138 [](Time<id>&, Time<id>::TimePoint) {}); 139 } 140 141 void TearDown() 142 { 143 expect_time_destroy(expected_event, expected_source); 144 time.reset(); 145 } 146 }; 147 148 TEST_F(TimeMethodTest, SetTimeSuccess) 149 { 150 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 151 .WillOnce(Return(0)); 152 time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})); 153 } 154 155 TEST_F(TimeMethodTest, SetTimeError) 156 { 157 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 158 .WillOnce(Return(-EINVAL)); 159 EXPECT_THROW(time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})), 160 SdEventError); 161 } 162 163 TEST_F(TimeMethodTest, GetTimeSuccess) 164 { 165 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 166 .WillOnce(DoAll(SetArgPointee<1>(10), Return(0))); 167 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds{10}), 168 time->get_time()); 169 } 170 171 TEST_F(TimeMethodTest, GetTimeError) 172 { 173 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 174 .WillOnce(Return(-ENOSYS)); 175 EXPECT_THROW(time->get_time(), SdEventError); 176 } 177 178 TEST_F(TimeMethodTest, SetAccuracySuccess) 179 { 180 EXPECT_CALL(mock, 181 sd_event_source_set_time_accuracy(expected_source, 5000000)) 182 .WillOnce(Return(0)); 183 time->set_accuracy(std::chrono::seconds{5}); 184 } 185 186 TEST_F(TimeMethodTest, SetAccuracyError) 187 { 188 EXPECT_CALL(mock, 189 sd_event_source_set_time_accuracy(expected_source, 5000000)) 190 .WillOnce(Return(-EINVAL)); 191 EXPECT_THROW(time->set_accuracy(std::chrono::seconds{5}), SdEventError); 192 } 193 194 TEST_F(TimeMethodTest, GetAccuracySuccess) 195 { 196 EXPECT_CALL(mock, 197 sd_event_source_get_time_accuracy(expected_source, testing::_)) 198 .WillOnce(DoAll(SetArgPointee<1>(1000), Return(0))); 199 EXPECT_EQ(std::chrono::milliseconds{1}, time->get_accuracy()); 200 } 201 202 TEST_F(TimeMethodTest, GetAccuracyError) 203 { 204 EXPECT_CALL(mock, 205 sd_event_source_get_time_accuracy(expected_source, testing::_)) 206 .WillOnce(Return(-ENOSYS)); 207 EXPECT_THROW(time->get_accuracy(), SdEventError); 208 } 209 210 } // namespace 211 } // namespace source 212 } // namespace sdeventplus 213