Imported Upstream version 0.9.2
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / common / expiryTimer / unittests / ExpiryTimerTest.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <UnitTestHelper.h>
22
23 #include <mutex>
24 #include <atomic>
25
26 #include "RCSException.h"
27 #include "ExpiryTimer.h"
28 #include "ExpiryTimerImpl.h"
29
30 using namespace OIC::Service;
31
32 constexpr int TOLERANCE_IN_MILLIS{ 50 };
33
34 class FunctionObject
35 {
36 public:
37     virtual ~FunctionObject() { }
38
39     virtual void execute(ExpiryTimerImpl::Id) { }
40 };
41
42 class ExpiryTimerImplTest: public TestWithMock
43 {
44 public:
45     void Proceed()
46     {
47         cond.notify_all();
48     }
49
50     void Wait(int waitingTime = TOLERANCE_IN_MILLIS)
51     {
52         std::unique_lock< std::mutex > lock{ mutex };
53         cond.wait_for(lock, std::chrono::milliseconds{ waitingTime });
54     }
55
56 private:
57     std::condition_variable cond;
58     std::mutex mutex;
59 };
60
61
62 TEST_F(ExpiryTimerImplTest, PostThrowsIfDelayIsNegative)
63 {
64     ASSERT_THROW(ExpiryTimerImpl::getInstance()->post(-1, [](ExpiryTimerImpl::Id){}), RCSException);
65 }
66
67 TEST_F(ExpiryTimerImplTest, PostThrowsIfCallbackIsEmpty)
68 {
69     ASSERT_THROW(ExpiryTimerImpl::getInstance()->post(1, { }), RCSException);
70 }
71
72 TEST_F(ExpiryTimerImplTest, CallbackBeInvokedWithinTolerance)
73 {
74     FunctionObject* functor = mocks.Mock< FunctionObject >();
75
76     mocks.ExpectCall(functor, FunctionObject::execute).Do(
77             [this](ExpiryTimerImpl::Id){
78                 Proceed();
79             }
80     );
81
82     ExpiryTimerImpl::getInstance()->post(10,
83             std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
84
85     Wait();
86 }
87
88 TEST_F(ExpiryTimerImplTest, CallbackBeInvokedWithTimerId)
89 {
90     ExpiryTimerImpl::Id returnedId;
91     FunctionObject* functor = mocks.Mock< FunctionObject >();
92
93     mocks.ExpectCall(functor, FunctionObject::execute).Match(
94             [this, &returnedId](ExpiryTimerImpl::Id id){
95                 return returnedId == id;
96             }
97     ).Do(
98             [this](ExpiryTimerImpl::Id){
99                 Proceed();
100             }
101     );
102
103     returnedId = ExpiryTimerImpl::getInstance()->post(1,
104             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
105
106     Wait();
107 }
108
109 TEST_F(ExpiryTimerImplTest, CanceledTaskBeNotCalled)
110 {
111     FunctionObject* functor = mocks.Mock< FunctionObject >();
112
113     mocks.NeverCall(functor, FunctionObject::execute);
114
115     ExpiryTimerImpl::Id id = ExpiryTimerImpl::getInstance()->post(10,
116             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
117     ExpiryTimerImpl::getInstance()->cancel(id);
118     Wait(100);
119 }
120
121 TEST_F(ExpiryTimerImplTest, CancelReturnsTrueIfCanceledCorrectly)
122 {
123     FunctionObject* functor = mocks.Mock< FunctionObject >();
124
125     ExpiryTimerImpl::Id id = ExpiryTimerImpl::getInstance()->post(10,
126             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
127
128     ASSERT_TRUE(ExpiryTimerImpl::getInstance()->cancel(id));
129 }
130
131 TEST_F(ExpiryTimerImplTest, CancelReturnsFalseIfAlreadyExecuted)
132 {
133     FunctionObject* functor = mocks.Mock< FunctionObject >();
134
135     mocks.ExpectCall(functor, FunctionObject::execute).Do(
136         [this](ExpiryTimerImpl::Id){
137             Proceed();
138         }
139     );
140
141     ExpiryTimerImpl::Id id = ExpiryTimerImpl::getInstance()->post(1,
142             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
143     Wait();
144
145     ASSERT_FALSE(ExpiryTimerImpl::getInstance()->cancel(id));
146 }
147
148 TEST_F(ExpiryTimerImplTest, CallbackBeInvokedWithinToleranceWithMultiplePost)
149 {
150     constexpr int NUM_OF_POST{ 10000 };
151     std::atomic_int called{ 0 };
152
153     for (int i=0; i<NUM_OF_POST; ++i)
154     {
155         FunctionObject* functor = mocks.Mock< FunctionObject >();
156         mocks.OnCall(functor, FunctionObject::execute).Do(
157                 [&called](ExpiryTimerImpl::Id)
158                 {
159                     ++called;
160                 }
161         );
162
163         ExpiryTimerImpl::getInstance()->post(rand() % 20 + 5,
164                 std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
165     }
166
167     Wait(TOLERANCE_IN_MILLIS + 25);
168
169     ASSERT_EQ(NUM_OF_POST, called);
170 }
171
172 class ExpiryTimerTest: public TestWithMock
173 {
174 public:
175     ExpiryTimer timer;
176
177 public:
178     void Proceed()
179     {
180         cond.notify_all();
181     }
182
183     void Wait(int waitingTime = TOLERANCE_IN_MILLIS)
184     {
185         std::unique_lock< std::mutex > lock{ mutex };
186         cond.wait_for(lock, std::chrono::milliseconds{ waitingTime });
187     }
188
189 private:
190     std::condition_variable cond;
191     std::mutex mutex;
192 };
193
194 TEST_F(ExpiryTimerTest, PostThrowsIfDelayIsNegative)
195 {
196     ASSERT_THROW(timer.post(-1, [](ExpiryTimer::Id){}), RCSException);
197 }
198
199 TEST_F(ExpiryTimerTest, PostThrowsIfCallbackIsEmpty)
200 {
201     ASSERT_THROW(timer.post(1, { }), RCSException);
202 }
203
204 TEST_F(ExpiryTimerTest, CallbackBeInvokedWithinTolerance)
205 {
206     FunctionObject* functor = mocks.Mock< FunctionObject >();
207
208     mocks.ExpectCall(functor, FunctionObject::execute).Do(
209             [this](ExpiryTimer::Id){
210                 Proceed();
211             }
212     );
213
214     timer.post(10,
215             std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
216
217     Wait();
218 }
219
220 TEST_F(ExpiryTimerTest, CallbackBeInvokedWithTimerId)
221 {
222     ExpiryTimer::Id returnedId;
223     FunctionObject* functor = mocks.Mock< FunctionObject >();
224
225     mocks.ExpectCall(functor, FunctionObject::execute).Match(
226             [this, &returnedId](ExpiryTimer::Id id){
227                 return returnedId == id;
228             }
229     ).Do(
230             [this](ExpiryTimer::Id){
231                 Proceed();
232             }
233     );
234
235     returnedId = timer.post(1, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
236
237     Wait();
238 }
239
240 TEST_F(ExpiryTimerTest, CanceledTaskBeNotCalled)
241 {
242     FunctionObject* functor = mocks.Mock< FunctionObject >();
243
244     mocks.NeverCall(functor, FunctionObject::execute);
245
246     auto id = timer.post(10, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
247     timer.cancel(id);
248     Wait(100);
249 }
250
251 TEST_F(ExpiryTimerTest, CancelReturnsTrueIfCanceledCorrectly)
252 {
253     FunctionObject* functor = mocks.Mock< FunctionObject >();
254
255     auto id = timer.post(10, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
256
257     ASSERT_TRUE(timer.cancel(id));
258 }
259
260 TEST_F(ExpiryTimerTest, CancelReturnsFalseIfAlreadyExecuted)
261 {
262     FunctionObject* functor = mocks.Mock< FunctionObject >();
263
264     mocks.ExpectCall(functor, FunctionObject::execute).Do(
265         [this](ExpiryTimer::Id){
266             Proceed();
267         }
268     );
269
270     auto id = timer.post(1, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
271     Wait();
272
273     ASSERT_FALSE(timer.cancel(id));
274 }
275
276 TEST_F(ExpiryTimerTest, NumOfPendingReturnsNumberOfNotExecuted)
277 {
278     constexpr size_t numOfFutureTask{ 100 };
279     constexpr size_t numOfShortDelayTask{ 100 };
280
281     for (size_t i=0; i<numOfFutureTask; ++i)
282     {
283         FunctionObject* functor = mocks.Mock< FunctionObject >();
284         mocks.OnCall(functor, FunctionObject::execute);
285
286         timer.post(1000, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
287     }
288
289     for (size_t i=0; i<numOfShortDelayTask; ++i)
290      {
291          FunctionObject* functor = mocks.Mock< FunctionObject >();
292          mocks.OnCall(functor, FunctionObject::execute);
293
294          timer.post(i, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
295      }
296
297     Wait(numOfShortDelayTask + TOLERANCE_IN_MILLIS);
298
299     ASSERT_EQ(timer.getNumOfPending(), numOfFutureTask);
300 }
301
302 TEST_F(ExpiryTimerTest, CancelAllCancelsAllTasks)
303 {
304     constexpr size_t numOfTask{ 100 };
305
306     for (size_t i=0; i<numOfTask; ++i)
307     {
308         FunctionObject* functor = mocks.Mock< FunctionObject >();
309         mocks.NeverCall(functor, FunctionObject::execute);
310
311         timer.post(50 + i, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
312     }
313
314     timer.cancelAll();
315
316     Wait(200);
317 }
318
319 TEST_F(ExpiryTimerTest, AllTasksAreCancelledAfterTimerDestroyed)
320 {
321     {
322         ExpiryTimer localTimer;
323         FunctionObject* functor = mocks.Mock< FunctionObject >();
324
325         mocks.NeverCall(functor, FunctionObject::execute);
326
327         localTimer.post(50,
328                 std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
329     }
330
331     Wait(200);
332 }