replace : iotivity -> iotivity-sec
[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
40     }
41
42     virtual void execute(ExpiryTimerImpl::Id)
43     {
44
45     }
46 };
47
48 class ExpiryTimerImplTest: public TestWithMock
49 {
50 public:
51     void Proceed()
52     {
53         cond.notify_all();
54     }
55
56     void Wait(int waitingTime = TOLERANCE_IN_MILLIS)
57     {
58         std::unique_lock< std::mutex > lock{ mutex };
59         cond.wait_for(lock, std::chrono::milliseconds{ waitingTime });
60     }
61
62 private:
63     std::condition_variable cond;
64     std::mutex mutex;
65 };
66
67
68 TEST_F(ExpiryTimerImplTest, PostThrowsIfDelayIsNegative)
69 {
70     ASSERT_THROW(ExpiryTimerImpl::getInstance()->post(-1,
71             [](ExpiryTimerImpl::Id)
72             {
73             }), RCSException);
74 }
75
76 TEST_F(ExpiryTimerImplTest, PostThrowsIfCallbackIsEmpty)
77 {
78     ASSERT_THROW(ExpiryTimerImpl::getInstance()->post(1, { }), RCSException);
79 }
80
81 TEST_F(ExpiryTimerImplTest, CallbackBeInvokedWithinTolerance)
82 {
83     FunctionObject* functor = mocks.Mock< FunctionObject >();
84
85     mocks.ExpectCall(functor, FunctionObject::execute).Do(
86             [this](ExpiryTimerImpl::Id)
87             {
88                 Proceed();
89             }
90     );
91
92     ExpiryTimerImpl::getInstance()->post(10,
93             std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
94
95     Wait();
96 }
97
98 TEST_F(ExpiryTimerImplTest, CallbackBeInvokedWithTimerId)
99 {
100     ExpiryTimerImpl::Id returnedId = 0;
101     FunctionObject* functor = mocks.Mock< FunctionObject >();
102
103     mocks.ExpectCall(functor, FunctionObject::execute).Match(
104             [this, &returnedId](ExpiryTimerImpl::Id id)
105             {
106                 return returnedId == id;
107             }
108     ).Do(
109             [this](ExpiryTimerImpl::Id)
110             {
111                 Proceed();
112             }
113     );
114
115     returnedId = ExpiryTimerImpl::getInstance()->post(1,
116             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
117
118     Wait();
119 }
120
121 TEST_F(ExpiryTimerImplTest, CanceledTaskBeNotCalled)
122 {
123     FunctionObject* functor = mocks.Mock< FunctionObject >();
124
125     mocks.NeverCall(functor, FunctionObject::execute);
126
127     ExpiryTimerImpl::Id id = ExpiryTimerImpl::getInstance()->post(10,
128             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
129     ExpiryTimerImpl::getInstance()->cancel(id);
130     Wait(100);
131 }
132
133 TEST_F(ExpiryTimerImplTest, CancelReturnsTrueIfCanceledCorrectly)
134 {
135     FunctionObject* functor = mocks.Mock< FunctionObject >();
136
137     ExpiryTimerImpl::Id id = ExpiryTimerImpl::getInstance()->post(10,
138             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
139
140     ASSERT_TRUE(ExpiryTimerImpl::getInstance()->cancel(id));
141 }
142
143 TEST_F(ExpiryTimerImplTest, CancelReturnsFalseIfAlreadyExecuted)
144 {
145     FunctionObject* functor = mocks.Mock< FunctionObject >();
146
147     mocks.ExpectCall(functor, FunctionObject::execute).Do(
148         [this](ExpiryTimerImpl::Id)
149         {
150             Proceed();
151         }
152     );
153
154     ExpiryTimerImpl::Id id = ExpiryTimerImpl::getInstance()->post(1,
155             std::bind(&FunctionObject::execute, functor, std::placeholders::_1))->getId();
156     Wait();
157
158     ASSERT_FALSE(ExpiryTimerImpl::getInstance()->cancel(id));
159 }
160
161 TEST_F(ExpiryTimerImplTest, CallbackBeInvokedWithinToleranceWithMultiplePost)
162 {
163     constexpr int NUM_OF_POST{ 10000 };
164     std::atomic_int called{ 0 };
165
166     for (int i=0; i<NUM_OF_POST; ++i)
167     {
168         FunctionObject* functor = mocks.Mock< FunctionObject >();
169         mocks.OnCall(functor, FunctionObject::execute).Do(
170                 [&called](ExpiryTimerImpl::Id)
171                 {
172                     ++called;
173                 }
174         );
175
176         ExpiryTimerImpl::getInstance()->post(rand() % 20 + 5,
177                 std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
178     }
179
180     Wait(TOLERANCE_IN_MILLIS + 25);
181
182     ASSERT_EQ(NUM_OF_POST, called);
183 }
184
185 class ExpiryTimerTest: public TestWithMock
186 {
187 public:
188     ExpiryTimer timer;
189
190 public:
191     void Proceed()
192     {
193         cond.notify_all();
194     }
195
196     void Wait(int waitingTime = TOLERANCE_IN_MILLIS)
197     {
198         std::unique_lock< std::mutex > lock{ mutex };
199         cond.wait_for(lock, std::chrono::milliseconds{ waitingTime });
200     }
201
202 private:
203     std::condition_variable cond;
204     std::mutex mutex;
205 };
206
207 TEST_F(ExpiryTimerTest, PostThrowsIfDelayIsNegative)
208 {
209     ASSERT_THROW(timer.post(-1,
210             [](ExpiryTimer::Id)
211             {
212             }), RCSException);
213 }
214
215 TEST_F(ExpiryTimerTest, PostThrowsIfCallbackIsEmpty)
216 {
217     ASSERT_THROW(timer.post(1, { }), RCSException);
218 }
219
220 TEST_F(ExpiryTimerTest, CallbackBeInvokedWithinTolerance)
221 {
222     FunctionObject* functor = mocks.Mock< FunctionObject >();
223
224     mocks.ExpectCall(functor, FunctionObject::execute).Do(
225             [this](ExpiryTimer::Id)
226             {
227                 Proceed();
228             }
229     );
230
231     timer.post(10,
232             std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
233
234     Wait();
235 }
236
237 TEST_F(ExpiryTimerTest, CallbackBeInvokedWithTimerId)
238 {
239     ExpiryTimer::Id returnedId = 0;
240     FunctionObject* functor = mocks.Mock< FunctionObject >();
241
242     mocks.ExpectCall(functor, FunctionObject::execute).Match(
243             [this, &returnedId](ExpiryTimer::Id id)
244             {
245                 return returnedId == id;
246             }
247     ).Do(
248             [this](ExpiryTimer::Id)
249             {
250                 Proceed();
251             }
252     );
253
254     returnedId = timer.post(1, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
255
256     Wait();
257 }
258
259 TEST_F(ExpiryTimerTest, CanceledTaskBeNotCalled)
260 {
261     FunctionObject* functor = mocks.Mock< FunctionObject >();
262
263     mocks.NeverCall(functor, FunctionObject::execute);
264
265     auto id = timer.post(10, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
266     timer.cancel(id);
267     Wait(100);
268 }
269
270 TEST_F(ExpiryTimerTest, CancelReturnsTrueIfCanceledCorrectly)
271 {
272     FunctionObject* functor = mocks.Mock< FunctionObject >();
273
274     auto id = timer.post(10, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
275
276     ASSERT_TRUE(timer.cancel(id));
277 }
278
279 TEST_F(ExpiryTimerTest, CancelReturnsFalseIfAlreadyExecuted)
280 {
281     FunctionObject* functor = mocks.Mock< FunctionObject >();
282
283     mocks.ExpectCall(functor, FunctionObject::execute).Do(
284         [this](ExpiryTimer::Id)
285         {
286             Proceed();
287         }
288     );
289
290     auto id = timer.post(1, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
291     Wait();
292
293     ASSERT_FALSE(timer.cancel(id));
294 }
295
296 TEST_F(ExpiryTimerTest, NumOfPendingReturnsNumberOfNotExecuted)
297 {
298     constexpr size_t numOfFutureTask{ 100 };
299     constexpr size_t numOfShortDelayTask{ 100 };
300
301     for (size_t i=0; i<numOfFutureTask; ++i)
302     {
303         FunctionObject* functor = mocks.Mock< FunctionObject >();
304         mocks.OnCall(functor, FunctionObject::execute);
305
306         timer.post(1000, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
307     }
308
309     for (size_t i=0; i<numOfShortDelayTask; ++i)
310      {
311          FunctionObject* functor = mocks.Mock< FunctionObject >();
312          mocks.OnCall(functor, FunctionObject::execute);
313
314          timer.post(i, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
315      }
316
317     Wait(numOfShortDelayTask + TOLERANCE_IN_MILLIS);
318
319     ASSERT_EQ(timer.getNumOfPending(), numOfFutureTask);
320 }
321
322 TEST_F(ExpiryTimerTest, CancelAllCancelsAllTasks)
323 {
324     constexpr size_t numOfTask{ 100 };
325
326     for (size_t i=0; i<numOfTask; ++i)
327     {
328         FunctionObject* functor = mocks.Mock< FunctionObject >();
329         mocks.NeverCall(functor, FunctionObject::execute);
330
331         timer.post(50 + i, std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
332     }
333
334     timer.cancelAll();
335
336     Wait(200);
337 }
338
339 TEST_F(ExpiryTimerTest, AllTasksAreCancelledAfterTimerDestroyed)
340 {
341     {
342         ExpiryTimer localTimer;
343         FunctionObject* functor = mocks.Mock< FunctionObject >();
344
345         mocks.NeverCall(functor, FunctionObject::execute);
346
347         localTimer.post(50,
348                 std::bind(&FunctionObject::execute, functor, std::placeholders::_1));
349     }
350
351     Wait(200);
352 }