blob: 99c187d270bf2512a23e29fa84b1f7058d20b29a [file] [log] [blame]
Rolf Badorekef2bf512019-08-20 11:17:15 +03001/*
2 Copyright (c) 2018-2019 Nokia.
3
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
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
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.
15*/
16
Timo Tietavainena0745d22019-11-28 09:55:22 +020017/*
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
20*/
21
Rolf Badorekef2bf512019-08-20 11:17:15 +030022#include <type_traits>
23#include <memory>
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"
30
31using namespace shareddatalayer;
32using namespace shareddatalayer::tst;
33using namespace testing;
34
35namespace
36{
37 class TimerFDTest: public testing::Test
38 {
39 public:
40 const int tfd;
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;
47
48 TimerFDTest(): tfd(123)
49 {
50 InSequence dummy;
51 EXPECT_CALL(systemMock, timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC))
52 .Times(1)
53 .WillOnce(Return(tfd));
54 EXPECT_CALL(engineMock, addMonitoredFD(Matcher<FileDescriptor&>(_), Engine::EVENT_IN, _))
55 .Times(1)
56 .WillOnce(Invoke([this] (FileDescriptor& fd, unsigned int, const Engine::EventHandler& eh)
57 {
58 EXPECT_EQ(tfd, static_cast<int>(fd));
59 savedEventHandler = eh;
60 }));
61 timerFD.reset(new TimerFD(systemMock, engineMock));
62
63 Mock::VerifyAndClear(&systemMock);
64 Mock::VerifyAndClear(&engineMock);
65
66 EXPECT_CALL(engineMock, armTimer(_, _, _))
67 .Times(AnyNumber())
68 .WillRepeatedly(Invoke([this] (Timer& timer, const Timer::Duration& duration, const Timer::Callback& cb)
69 {
70 timerFD.get()->arm(timer, duration, cb);
71 }));
72
73 EXPECT_CALL(engineMock, disarmTimer(_))
74 .Times(AnyNumber())
75 .WillRepeatedly(Invoke([this](const Timer& timer)
76 {
77 timerFD.get()->disarm(timer);
78 }));
79
80 ON_CALL(systemMock, time_since_epoch())
81 .WillByDefault(Return(std::chrono::steady_clock::duration(0)));
82
83 timer1.reset(new Timer(engineMock));
84 timer2.reset(new Timer(engineMock));
85 }
86
87 void expectSetTime(int seconds, int nanoseconds)
88 {
89 EXPECT_CALL(systemMock, timerfd_settime(tfd, TFD_TIMER_ABSTIME, NotNull(), nullptr))
90 .Times(1)
91 .WillOnce(Invoke([seconds, nanoseconds] (int, int, const itimerspec* new_value, itimerspec*)
92 {
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);
97 }));
98 }
99
100 void expectRead(const boost::optional<uint64_t>& count)
101 {
102 EXPECT_CALL(systemMock, read(tfd, NotNull(), sizeof(uint64_t)))
103 .Times(1)
104 .WillOnce(Invoke([count] (int, void* buf, size_t) -> ssize_t
105 {
106 if (count)
107 {
108 *static_cast<uint64_t *>(buf) = *count;
109 return sizeof(uint64_t);
110 }
111 return -1;
112 }));
113 }
114
115 void expectTimeSinceEpoch(const std::chrono::steady_clock::duration& ret)
116 {
117 EXPECT_CALL(systemMock, time_since_epoch())
118 .Times(1)
119 .WillOnce(Return(ret));
120 }
121
122 void arm(Timer& timer, int seconds, int nanoseconds, const std::string& param = std::string())
123 {
124 timer.arm(std::chrono::duration_cast<Timer::Duration>(std::chrono::seconds(seconds) + std::chrono::nanoseconds(nanoseconds)),
125 std::bind(&TimerFDTest::callback, this, param));
126 }
127
128 void arm(int seconds, int nanoseconds, const std::string& param = std::string())
129 {
130 arm(*timer1, seconds, nanoseconds, param);
131 }
132
133 void disarm(Timer& timer)
134 {
135 timer.disarm();
136 }
137
138 void disarm()
139 {
140 disarm(*timer1);
141 }
142
143 MOCK_METHOD1(callback, void(const std::string& param));
144 };
145}
146
147TEST_F(TimerFDTest, IsNotCopyableAndIsNotMovable)
148{
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);
153}
154
155TEST_F(TimerFDTest, ArmingTheFirstTimerCallsSetTimeWithProperValues)
156{
157 expectSetTime(3, 4000);
158 arm(3, 4000);
159 Mock::VerifyAndClear(&systemMock);
160}
161
162TEST_F(TimerFDTest, ArmingAnotherTimerWithLongerTimeoutDoesntCallSetTime)
163{
164 expectSetTime(3, 0);
165 arm(*timer1, 3, 0);
166 arm(*timer2, 10, 0);
167 Mock::VerifyAndClear(&systemMock);
168}
169
170TEST_F(TimerFDTest, DisarminTheOnlyTimerCallsSetTimeWithZeroValues)
171{
172 arm(3, 0);
173 expectSetTime(0, 0);
174 disarm();
175}
176
177TEST_F(TimerFDTest, DisarminTheFirstTimerCallsSetTimeWithProperValues)
178{
179 arm(*timer1, 3, 0);
180 arm(*timer2, 4, 0);
181 expectSetTime(4, 0);
182 disarm(*timer1);
183 Mock::VerifyAndClear(&systemMock);
184}
185
186TEST_F(TimerFDTest, AfterExecutingTheFirstTimerSetTimeIsCalledWithProperValues)
187{
188 InSequence dummy;
189 arm(*timer1, 1, 0, "first");
190 arm(*timer2, 2, 0, "second");
191 expectRead(1);
192 EXPECT_CALL(*this, callback("first"))
193 .Times(1);
194 expectSetTime(2, 0);
195 savedEventHandler(Engine::EVENT_IN);
196 Mock::VerifyAndClear(&systemMock);
197}
198
199TEST_F(TimerFDTest, AfterExecutingTheLastTimerSetTimeIsCalledWithZeroValues)
200{
201 InSequence dummy;
202 arm(*timer1, 1, 0, "first");
203 expectRead(1);
204 EXPECT_CALL(*this, callback("first"))
205 .Times(1);
206 expectSetTime(0, 0);
207 savedEventHandler(Engine::EVENT_IN);
208 Mock::VerifyAndClear(&systemMock);
209}
210
211TEST_F(TimerFDTest, IfReadReturnsNegativeOnHandleEventsNothingIsDone)
212{
213 arm(10, 0);
214 expectRead(boost::none);
215 EXPECT_CALL(*this, callback(_))
216 .Times(0);
217 EXPECT_CALL(systemMock, timerfd_settime(_, _, _, _))
218 .Times(0);
219 savedEventHandler(Engine::EVENT_IN);
220 Mock::VerifyAndClear(&systemMock);
221}
222
223TEST_F(TimerFDTest, IfReadReturnsNoEventsOnHandleEventsNothingIsDone)
224{
225 arm(10, 0);
226 expectRead(static_cast<uint64_t>(0U));
227 EXPECT_CALL(*this, callback(_))
228 .Times(0);
229 EXPECT_CALL(systemMock, timerfd_settime(_, _, _, _))
230 .Times(0);
231 savedEventHandler(Engine::EVENT_IN);
232 Mock::VerifyAndClear(&systemMock);
233}
234
235TEST_F(TimerFDTest, AllTimersThatHaveExpiredDuringTheEventLoopAreExecutedWithTheSameTimerFdExpiration)
236{
237 InSequence dummy;
238
239 /* The first timer is armed to expire after 10 seconds */
240 expectTimeSinceEpoch(std::chrono::seconds(0));
241 arm(*timer1, 10, 0, "first");
242
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");
246
247 /* Time has passed 8 more seconds, both timers expire at once */
248 expectRead(1);
249 expectTimeSinceEpoch(std::chrono::seconds(10));
250 EXPECT_CALL(*this, callback("first"))
251 .Times(1);
252 EXPECT_CALL(*this, callback("second"))
253 .Times(1);
254 savedEventHandler(Engine::EVENT_IN);
255}