2 Copyright (c) 2018-2019 Nokia.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
22 #include <type_traits>
24 #include <boost/optional.hpp>
25 #include <sys/timerfd.h>
26 #include <gmock/gmock.h>
27 #include "private/timerfd.hpp"
28 #include "private/tst/systemmock.hpp"
29 #include "private/tst/enginemock.hpp"
31 using namespace shareddatalayer;
32 using namespace shareddatalayer::tst;
33 using namespace testing;
37 class TimerFDTest: public testing::Test
41 NiceMock<SystemMock> systemMock;
42 EngineMock engineMock;
43 std::unique_ptr<TimerFD> timerFD;
44 std::unique_ptr<Timer> timer1;
45 std::unique_ptr<Timer> timer2;
46 Engine::EventHandler savedEventHandler;
48 TimerFDTest(): tfd(123)
51 EXPECT_CALL(systemMock, timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC))
53 .WillOnce(Return(tfd));
54 EXPECT_CALL(engineMock, addMonitoredFD(Matcher<FileDescriptor&>(_), Engine::EVENT_IN, _))
56 .WillOnce(Invoke([this] (FileDescriptor& fd, unsigned int, const Engine::EventHandler& eh)
58 EXPECT_EQ(tfd, static_cast<int>(fd));
59 savedEventHandler = eh;
61 timerFD.reset(new TimerFD(systemMock, engineMock));
63 Mock::VerifyAndClear(&systemMock);
64 Mock::VerifyAndClear(&engineMock);
66 EXPECT_CALL(engineMock, armTimer(_, _, _))
68 .WillRepeatedly(Invoke([this] (Timer& timer, const Timer::Duration& duration, const Timer::Callback& cb)
70 timerFD.get()->arm(timer, duration, cb);
73 EXPECT_CALL(engineMock, disarmTimer(_))
75 .WillRepeatedly(Invoke([this](const Timer& timer)
77 timerFD.get()->disarm(timer);
80 ON_CALL(systemMock, time_since_epoch())
81 .WillByDefault(Return(std::chrono::steady_clock::duration(0)));
83 timer1.reset(new Timer(engineMock));
84 timer2.reset(new Timer(engineMock));
87 void expectSetTime(int seconds, int nanoseconds)
89 EXPECT_CALL(systemMock, timerfd_settime(tfd, TFD_TIMER_ABSTIME, NotNull(), nullptr))
91 .WillOnce(Invoke([seconds, nanoseconds] (int, int, const itimerspec* new_value, itimerspec*)
93 EXPECT_EQ(0, new_value->it_interval.tv_sec);
94 EXPECT_EQ(0, new_value->it_interval.tv_nsec);
95 EXPECT_EQ(seconds, new_value->it_value.tv_sec);
96 EXPECT_EQ(nanoseconds, new_value->it_value.tv_nsec);
100 void expectRead(const boost::optional<uint64_t>& count)
102 EXPECT_CALL(systemMock, read(tfd, NotNull(), sizeof(uint64_t)))
104 .WillOnce(Invoke([count] (int, void* buf, size_t) -> ssize_t
108 *static_cast<uint64_t *>(buf) = *count;
109 return sizeof(uint64_t);
115 void expectTimeSinceEpoch(const std::chrono::steady_clock::duration& ret)
117 EXPECT_CALL(systemMock, time_since_epoch())
119 .WillOnce(Return(ret));
122 void arm(Timer& timer, int seconds, int nanoseconds, const std::string& param = std::string())
124 timer.arm(std::chrono::duration_cast<Timer::Duration>(std::chrono::seconds(seconds) + std::chrono::nanoseconds(nanoseconds)),
125 std::bind(&TimerFDTest::callback, this, param));
128 void arm(int seconds, int nanoseconds, const std::string& param = std::string())
130 arm(*timer1, seconds, nanoseconds, param);
133 void disarm(Timer& timer)
143 MOCK_METHOD1(callback, void(const std::string& param));
147 TEST_F(TimerFDTest, IsNotCopyableAndIsNotMovable)
149 EXPECT_FALSE(std::is_copy_assignable<TimerFD>::value);
150 EXPECT_FALSE(std::is_move_assignable<TimerFD>::value);
151 EXPECT_FALSE(std::is_copy_constructible<TimerFD>::value);
152 EXPECT_FALSE(std::is_move_constructible<TimerFD>::value);
155 TEST_F(TimerFDTest, ArmingTheFirstTimerCallsSetTimeWithProperValues)
157 expectSetTime(3, 4000);
159 Mock::VerifyAndClear(&systemMock);
162 TEST_F(TimerFDTest, ArmingAnotherTimerWithLongerTimeoutDoesntCallSetTime)
167 Mock::VerifyAndClear(&systemMock);
170 TEST_F(TimerFDTest, DisarminTheOnlyTimerCallsSetTimeWithZeroValues)
177 TEST_F(TimerFDTest, DisarminTheFirstTimerCallsSetTimeWithProperValues)
183 Mock::VerifyAndClear(&systemMock);
186 TEST_F(TimerFDTest, AfterExecutingTheFirstTimerSetTimeIsCalledWithProperValues)
189 arm(*timer1, 1, 0, "first");
190 arm(*timer2, 2, 0, "second");
192 EXPECT_CALL(*this, callback("first"))
195 savedEventHandler(Engine::EVENT_IN);
196 Mock::VerifyAndClear(&systemMock);
199 TEST_F(TimerFDTest, AfterExecutingTheLastTimerSetTimeIsCalledWithZeroValues)
202 arm(*timer1, 1, 0, "first");
204 EXPECT_CALL(*this, callback("first"))
207 savedEventHandler(Engine::EVENT_IN);
208 Mock::VerifyAndClear(&systemMock);
211 TEST_F(TimerFDTest, IfReadReturnsNegativeOnHandleEventsNothingIsDone)
214 expectRead(boost::none);
215 EXPECT_CALL(*this, callback(_))
217 EXPECT_CALL(systemMock, timerfd_settime(_, _, _, _))
219 savedEventHandler(Engine::EVENT_IN);
220 Mock::VerifyAndClear(&systemMock);
223 TEST_F(TimerFDTest, IfReadReturnsNoEventsOnHandleEventsNothingIsDone)
226 expectRead(static_cast<uint64_t>(0U));
227 EXPECT_CALL(*this, callback(_))
229 EXPECT_CALL(systemMock, timerfd_settime(_, _, _, _))
231 savedEventHandler(Engine::EVENT_IN);
232 Mock::VerifyAndClear(&systemMock);
235 TEST_F(TimerFDTest, AllTimersThatHaveExpiredDuringTheEventLoopAreExecutedWithTheSameTimerFdExpiration)
239 /* The first timer is armed to expire after 10 seconds */
240 expectTimeSinceEpoch(std::chrono::seconds(0));
241 arm(*timer1, 10, 0, "first");
243 /* Time has passed 2 seconds, the second timer is armed to expire after 8 seconds */
244 expectTimeSinceEpoch(std::chrono::seconds(2));
245 arm(*timer2, 8, 0, "second");
247 /* Time has passed 8 more seconds, both timers expire at once */
249 expectTimeSinceEpoch(std::chrono::seconds(10));
250 EXPECT_CALL(*this, callback("first"))
252 EXPECT_CALL(*this, callback("second"))
254 savedEventHandler(Engine::EVENT_IN);