Add SDL developer and user guides
[ric-plt/sdl.git] / tst / timerfd_test.cpp
1 /*
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
17 /*
18  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19  * platform project (RICP).
20 */
21
22 #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
31 using namespace shareddatalayer;
32 using namespace shareddatalayer::tst;
33 using namespace testing;
34
35 namespace
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
147 TEST_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
155 TEST_F(TimerFDTest, ArmingTheFirstTimerCallsSetTimeWithProperValues)
156 {
157     expectSetTime(3, 4000);
158     arm(3, 4000);
159     Mock::VerifyAndClear(&systemMock);
160 }
161
162 TEST_F(TimerFDTest, ArmingAnotherTimerWithLongerTimeoutDoesntCallSetTime)
163 {
164     expectSetTime(3, 0);
165     arm(*timer1, 3, 0);
166     arm(*timer2, 10, 0);
167     Mock::VerifyAndClear(&systemMock);
168 }
169
170 TEST_F(TimerFDTest, DisarminTheOnlyTimerCallsSetTimeWithZeroValues)
171 {
172     arm(3, 0);
173     expectSetTime(0, 0);
174     disarm();
175 }
176
177 TEST_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
186 TEST_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
199 TEST_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
211 TEST_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
223 TEST_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
235 TEST_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 }