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