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