Add Redis Sentinel based database discovery
[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 #include <type_traits>
18 #include <memory>
19 #include <boost/optional.hpp>
20 #include <sys/timerfd.h>
21 #include <gmock/gmock.h>
22 #include "private/timerfd.hpp"
23 #include "private/tst/systemmock.hpp"
24 #include "private/tst/enginemock.hpp"
25
26 using namespace shareddatalayer;
27 using namespace shareddatalayer::tst;
28 using namespace testing;
29
30 namespace
31 {
32     class TimerFDTest: public testing::Test
33     {
34     public:
35         const int tfd;
36         NiceMock<SystemMock> systemMock;
37         EngineMock engineMock;
38         std::unique_ptr<TimerFD> timerFD;
39         std::unique_ptr<Timer> timer1;
40         std::unique_ptr<Timer> timer2;
41         Engine::EventHandler savedEventHandler;
42
43         TimerFDTest(): tfd(123)
44         {
45             InSequence dummy;
46             EXPECT_CALL(systemMock, timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC))
47                 .Times(1)
48                 .WillOnce(Return(tfd));
49             EXPECT_CALL(engineMock, addMonitoredFD(Matcher<FileDescriptor&>(_), Engine::EVENT_IN, _))
50                 .Times(1)
51                 .WillOnce(Invoke([this] (FileDescriptor& fd, unsigned int, const Engine::EventHandler& eh)
52                                  {
53                                      EXPECT_EQ(tfd, static_cast<int>(fd));
54                                      savedEventHandler = eh;
55                                  }));
56             timerFD.reset(new TimerFD(systemMock, engineMock));
57
58             Mock::VerifyAndClear(&systemMock);
59             Mock::VerifyAndClear(&engineMock);
60
61             EXPECT_CALL(engineMock, armTimer(_, _, _))
62                  .Times(AnyNumber())
63                  .WillRepeatedly(Invoke([this] (Timer& timer, const Timer::Duration& duration, const Timer::Callback& cb)
64                       {
65                           timerFD.get()->arm(timer, duration, cb);
66                       }));
67
68             EXPECT_CALL(engineMock, disarmTimer(_))
69                  .Times(AnyNumber())
70                  .WillRepeatedly(Invoke([this](const Timer& timer)
71                      {
72                          timerFD.get()->disarm(timer);
73                      }));
74
75             ON_CALL(systemMock, time_since_epoch())
76                 .WillByDefault(Return(std::chrono::steady_clock::duration(0)));
77
78             timer1.reset(new Timer(engineMock));
79             timer2.reset(new Timer(engineMock));
80         }
81
82         void expectSetTime(int seconds, int nanoseconds)
83         {
84             EXPECT_CALL(systemMock, timerfd_settime(tfd, TFD_TIMER_ABSTIME, NotNull(), nullptr))
85                 .Times(1)
86                 .WillOnce(Invoke([seconds, nanoseconds] (int, int, const itimerspec* new_value, itimerspec*)
87                                  {
88                                      EXPECT_EQ(0, new_value->it_interval.tv_sec);
89                                      EXPECT_EQ(0, new_value->it_interval.tv_nsec);
90                                      EXPECT_EQ(seconds, new_value->it_value.tv_sec);
91                                      EXPECT_EQ(nanoseconds, new_value->it_value.tv_nsec);
92                                  }));
93         }
94
95         void expectRead(const boost::optional<uint64_t>& count)
96         {
97             EXPECT_CALL(systemMock, read(tfd, NotNull(), sizeof(uint64_t)))
98                 .Times(1)
99                 .WillOnce(Invoke([count] (int, void* buf, size_t) -> ssize_t
100                                  {
101                                      if (count)
102                                      {
103                                          *static_cast<uint64_t *>(buf) = *count;
104                                          return sizeof(uint64_t);
105                                      }
106                                      return -1;
107                                  }));
108         }
109
110         void expectTimeSinceEpoch(const std::chrono::steady_clock::duration& ret)
111         {
112             EXPECT_CALL(systemMock, time_since_epoch())
113                 .Times(1)
114                 .WillOnce(Return(ret));
115         }
116
117         void arm(Timer& timer, int seconds, int nanoseconds, const std::string& param = std::string())
118         {
119             timer.arm(std::chrono::duration_cast<Timer::Duration>(std::chrono::seconds(seconds) + std::chrono::nanoseconds(nanoseconds)),
120                       std::bind(&TimerFDTest::callback, this, param));
121         }
122
123         void arm(int seconds, int nanoseconds, const std::string& param = std::string())
124         {
125             arm(*timer1, seconds, nanoseconds, param);
126         }
127
128         void disarm(Timer& timer)
129         {
130             timer.disarm();
131         }
132
133         void disarm()
134         {
135             disarm(*timer1);
136         }
137
138         MOCK_METHOD1(callback, void(const std::string& param));
139     };
140 }
141
142 TEST_F(TimerFDTest, IsNotCopyableAndIsNotMovable)
143 {
144     EXPECT_FALSE(std::is_copy_assignable<TimerFD>::value);
145     EXPECT_FALSE(std::is_move_assignable<TimerFD>::value);
146     EXPECT_FALSE(std::is_copy_constructible<TimerFD>::value);
147     EXPECT_FALSE(std::is_move_constructible<TimerFD>::value);
148 }
149
150 TEST_F(TimerFDTest, ArmingTheFirstTimerCallsSetTimeWithProperValues)
151 {
152     expectSetTime(3, 4000);
153     arm(3, 4000);
154     Mock::VerifyAndClear(&systemMock);
155 }
156
157 TEST_F(TimerFDTest, ArmingAnotherTimerWithLongerTimeoutDoesntCallSetTime)
158 {
159     expectSetTime(3, 0);
160     arm(*timer1, 3, 0);
161     arm(*timer2, 10, 0);
162     Mock::VerifyAndClear(&systemMock);
163 }
164
165 TEST_F(TimerFDTest, DisarminTheOnlyTimerCallsSetTimeWithZeroValues)
166 {
167     arm(3, 0);
168     expectSetTime(0, 0);
169     disarm();
170 }
171
172 TEST_F(TimerFDTest, DisarminTheFirstTimerCallsSetTimeWithProperValues)
173 {
174     arm(*timer1, 3, 0);
175     arm(*timer2, 4, 0);
176     expectSetTime(4, 0);
177     disarm(*timer1);
178     Mock::VerifyAndClear(&systemMock);
179 }
180
181 TEST_F(TimerFDTest, AfterExecutingTheFirstTimerSetTimeIsCalledWithProperValues)
182 {
183     InSequence dummy;
184     arm(*timer1, 1, 0, "first");
185     arm(*timer2, 2, 0, "second");
186     expectRead(1);
187     EXPECT_CALL(*this, callback("first"))
188         .Times(1);
189     expectSetTime(2, 0);
190     savedEventHandler(Engine::EVENT_IN);
191     Mock::VerifyAndClear(&systemMock);
192 }
193
194 TEST_F(TimerFDTest, AfterExecutingTheLastTimerSetTimeIsCalledWithZeroValues)
195 {
196     InSequence dummy;
197     arm(*timer1, 1, 0, "first");
198     expectRead(1);
199     EXPECT_CALL(*this, callback("first"))
200         .Times(1);
201     expectSetTime(0, 0);
202     savedEventHandler(Engine::EVENT_IN);
203     Mock::VerifyAndClear(&systemMock);
204 }
205
206 TEST_F(TimerFDTest, IfReadReturnsNegativeOnHandleEventsNothingIsDone)
207 {
208     arm(10, 0);
209     expectRead(boost::none);
210     EXPECT_CALL(*this, callback(_))
211         .Times(0);
212     EXPECT_CALL(systemMock, timerfd_settime(_, _, _, _))
213         .Times(0);
214     savedEventHandler(Engine::EVENT_IN);
215     Mock::VerifyAndClear(&systemMock);
216 }
217
218 TEST_F(TimerFDTest, IfReadReturnsNoEventsOnHandleEventsNothingIsDone)
219 {
220     arm(10, 0);
221     expectRead(static_cast<uint64_t>(0U));
222     EXPECT_CALL(*this, callback(_))
223         .Times(0);
224     EXPECT_CALL(systemMock, timerfd_settime(_, _, _, _))
225         .Times(0);
226     savedEventHandler(Engine::EVENT_IN);
227     Mock::VerifyAndClear(&systemMock);
228 }
229
230 TEST_F(TimerFDTest, AllTimersThatHaveExpiredDuringTheEventLoopAreExecutedWithTheSameTimerFdExpiration)
231 {
232     InSequence dummy;
233
234     /* The first timer is armed to expire after 10 seconds */
235     expectTimeSinceEpoch(std::chrono::seconds(0));
236     arm(*timer1, 10, 0, "first");
237
238     /* Time has passed 2 seconds, the second timer is armed to expire after 8 seconds */
239     expectTimeSinceEpoch(std::chrono::seconds(2));
240     arm(*timer2, 8, 0, "second");
241
242     /* Time has passed 8 more seconds, both timers expire at once */
243     expectRead(1);
244     expectTimeSinceEpoch(std::chrono::seconds(10));
245     EXPECT_CALL(*this, callback("first"))
246         .Times(1);
247     EXPECT_CALL(*this, callback("second"))
248         .Times(1);
249     savedEventHandler(Engine::EVENT_IN);
250 }