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 expect_time_destroy(expected_event, expected_source); 94 } 95 96 TEST_F(TimeTest, ConstructError) 97 { 98 constexpr ClockId id = ClockId::Monotonic; 99 const Time<id>::TimePoint expected_time(std::chrono::seconds{2}); 100 const Time<id>::Accuracy expected_accuracy(std::chrono::milliseconds{50}); 101 Time<id>::Callback callback = [](Time<id>&, Time<id>::TimePoint) {}; 102 103 EXPECT_CALL(mock, 104 sd_event_add_time(expected_event, testing::_, CLOCK_MONOTONIC, 105 2000000, 50000, testing::_, nullptr)) 106 .WillOnce(Return(-ENOSYS)); 107 EXPECT_THROW( 108 Time<id>(*event, expected_time, expected_accuracy, std::move(callback)), 109 SdEventError); 110 EXPECT_TRUE(callback); 111 } 112 113 class TimeMethodTest : public TimeTest 114 { 115 protected: 116 static constexpr ClockId id = ClockId::BootTime; 117 std::unique_ptr<Time<id>> time; 118 119 void SetUp() 120 { 121 EXPECT_CALL(mock, sd_event_ref(expected_event)) 122 .WillOnce(Return(expected_event)); 123 EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_, 124 CLOCK_BOOTTIME, 2000000, 50000, 125 testing::_, nullptr)) 126 .WillOnce(DoAll(SetArgPointee<1>(expected_source), Return(0))); 127 EXPECT_CALL(mock, 128 sd_event_source_set_userdata(expected_source, testing::_)) 129 .WillOnce(Return(nullptr)); 130 time = std::make_unique<Time<id>>( 131 *event, Time<id>::TimePoint(std::chrono::seconds{2}), 132 std::chrono::milliseconds{50}, 133 [](Time<id>&, Time<id>::TimePoint) {}); 134 } 135 136 void TearDown() 137 { 138 expect_time_destroy(expected_event, expected_source); 139 time.reset(); 140 } 141 }; 142 143 TEST_F(TimeMethodTest, SetTimeSuccess) 144 { 145 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 146 .WillOnce(Return(0)); 147 time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})); 148 } 149 150 TEST_F(TimeMethodTest, SetTimeError) 151 { 152 EXPECT_CALL(mock, sd_event_source_set_time(expected_source, 1000000)) 153 .WillOnce(Return(-EINVAL)); 154 EXPECT_THROW(time->set_time(Time<id>::TimePoint(std::chrono::seconds{1})), 155 SdEventError); 156 } 157 158 TEST_F(TimeMethodTest, GetTimeSuccess) 159 { 160 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 161 .WillOnce(DoAll(SetArgPointee<1>(10), Return(0))); 162 EXPECT_EQ(Time<id>::TimePoint(std::chrono::microseconds{10}), 163 time->get_time()); 164 } 165 166 TEST_F(TimeMethodTest, GetTimeError) 167 { 168 EXPECT_CALL(mock, sd_event_source_get_time(expected_source, testing::_)) 169 .WillOnce(Return(-ENOSYS)); 170 EXPECT_THROW(time->get_time(), SdEventError); 171 } 172 173 TEST_F(TimeMethodTest, SetAccuracySuccess) 174 { 175 EXPECT_CALL(mock, 176 sd_event_source_set_time_accuracy(expected_source, 5000000)) 177 .WillOnce(Return(0)); 178 time->set_accuracy(std::chrono::seconds{5}); 179 } 180 181 TEST_F(TimeMethodTest, SetAccuracyError) 182 { 183 EXPECT_CALL(mock, 184 sd_event_source_set_time_accuracy(expected_source, 5000000)) 185 .WillOnce(Return(-EINVAL)); 186 EXPECT_THROW(time->set_accuracy(std::chrono::seconds{5}), SdEventError); 187 } 188 189 TEST_F(TimeMethodTest, GetAccuracySuccess) 190 { 191 EXPECT_CALL(mock, 192 sd_event_source_get_time_accuracy(expected_source, testing::_)) 193 .WillOnce(DoAll(SetArgPointee<1>(1000), Return(0))); 194 EXPECT_EQ(std::chrono::milliseconds{1}, time->get_accuracy()); 195 } 196 197 TEST_F(TimeMethodTest, GetAccuracyError) 198 { 199 EXPECT_CALL(mock, 200 sd_event_source_get_time_accuracy(expected_source, testing::_)) 201 .WillOnce(Return(-ENOSYS)); 202 EXPECT_THROW(time->get_accuracy(), SdEventError); 203 } 204 205 } // namespace 206 } // namespace source 207 } // namespace sdeventplus 208