1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <atomic>
17 #include <gtest/gtest.h>
18 #include <thread>
19
20 #include "db_errno.h"
21 #include "distributeddb_tools_unit_test.h"
22 #include "evloop/include/ievent.h"
23 #include "evloop/include/ievent_loop.h"
24 #include "log_print.h"
25 #include "platform_specific.h"
26
27 using namespace testing::ext;
28 using namespace DistributedDB;
29
30 namespace {
31 IEventLoop *g_loop = nullptr;
32 constexpr int MAX_RETRY_TIMES = 1000;
33 constexpr int RETRY_TIMES_5 = 5;
34 constexpr EventTime TIME_INACCURACY = 100LL;
35 constexpr EventTime TIME_PIECE_1 = 1LL;
36 constexpr EventTime TIME_PIECE_10 = 10LL;
37 constexpr EventTime TIME_PIECE_50 = 50LL;
38 constexpr EventTime TIME_PIECE_100 = 100LL;
39 constexpr EventTime TIME_PIECE_1000 = 1000LL;
40 constexpr EventTime TIME_PIECE_10000 = 10000LL;
41 }
42
43 class TimerTester {
44 public:
45 static EventTime GetCurrentTime();
46 };
47
GetCurrentTime()48 EventTime TimerTester::GetCurrentTime()
49 {
50 uint64_t now;
51 int errCode = OS::GetCurrentSysTimeInMicrosecond(now);
52 if (errCode != E_OK) {
53 LOGE("Get current time failed.");
54 return 0;
55 }
56 return now / 1000; // 1 ms equals to 1000 us
57 }
58
59 class DistributedDBEventLoopTimerTest : public testing::Test {
60 public:
61 static void SetUpTestCase(void);
62 static void TearDownTestCase(void);
63 void SetUp();
64 void TearDown();
65 };
66
SetUpTestCase(void)67 void DistributedDBEventLoopTimerTest::SetUpTestCase(void) {}
68
TearDownTestCase(void)69 void DistributedDBEventLoopTimerTest::TearDownTestCase(void) {}
70
SetUp(void)71 void DistributedDBEventLoopTimerTest::SetUp(void)
72 {
73 DistributedDBUnitTest::DistributedDBToolsUnitTest::PrintTestCaseInfo();
74 /**
75 * @tc.setup: Create a loop object.
76 */
77 if (g_loop == nullptr) {
78 int errCode = E_OK;
79 g_loop = IEventLoop::CreateEventLoop(errCode);
80 if (g_loop == nullptr) {
81 LOGE("Prepare loop in SetUp() failed.");
82 }
83 }
84 }
85
TearDown(void)86 void DistributedDBEventLoopTimerTest::TearDown(void)
87 {
88 /**
89 * @tc.teardown: Destroy the loop object.
90 */
91 if (g_loop != nullptr) {
92 g_loop->KillAndDecObjRef(g_loop);
93 g_loop = nullptr;
94 }
95 }
96
97 /**
98 * @tc.name: EventLoopTimerTest001
99 * @tc.desc: Create and destroy the event loop object.
100 * @tc.type: FUNC
101 * @tc.require: AR000CKRTB AR000CQE0C
102 * @tc.author: fangyi
103 */
104 HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest001, TestSize.Level0)
105 {
106 /**
107 * @tc.steps: step1. create a loop.
108 * @tc.expected: step1. create successfully.
109 */
110 int errCode = E_OK;
111 IEventLoop *loop = IEventLoop::CreateEventLoop(errCode);
112 ASSERT_EQ(loop != nullptr, true);
113
114 /**
115 * @tc.steps: step2. destroy the loop.
116 * @tc.expected: step2. destroy successfully.
117 */
118 bool finalized = false;
__anon7e8eee710202() 119 loop->OnLastRef([&finalized]() { finalized = true; });
120 loop->DecObjRef(loop);
121 loop = nullptr;
122 EXPECT_EQ(finalized, true);
123 }
124
125 /**
126 * @tc.name: EventLoopTimerTest002
127 * @tc.desc: Start and stop the loop
128 * @tc.type: FUNC
129 * @tc.require: AR000CKRTB AR000CQE0C
130 * @tc.author: fangyi
131 */
132 HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest002, TestSize.Level1)
133 {
134 // ready data
135 ASSERT_EQ(g_loop != nullptr, true);
136
137 /**
138 * @tc.steps: step1. create a loop.
139 * @tc.expected: step1. create successfully.
140 */
141 std::atomic<bool> running(false);
142 EventTime delta = 0;
__anon7e8eee710302() 143 std::thread loopThread([&running, &delta]() {
144 running = true;
145 EventTime start = TimerTester::GetCurrentTime();
146 g_loop->Run();
147 EventTime end = TimerTester::GetCurrentTime();
148 delta = end - start;
149 });
150 while (!running) {
151 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_1));
152 }
153 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_100));
154 g_loop->KillObj();
155 loopThread.join();
156 EXPECT_EQ(delta > TIME_PIECE_50, true);
157 }
158
159 /**
160 * @tc.name: EventLoopTimerTest003
161 * @tc.desc: Create and destroy a timer object.
162 * @tc.type: FUNC
163 * @tc.require: AR000CKRTB AR000CQE0C
164 * @tc.author: fangyi
165 */
166 HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest003, TestSize.Level0)
167 {
168 /**
169 * @tc.steps: step1. create event(timer) object.
170 * @tc.expected: step1. create successfully.
171 */
172 int errCode = E_OK;
173 IEvent *timer = IEvent::CreateEvent(TIME_PIECE_1, errCode);
174 ASSERT_EQ(timer != nullptr, true);
175
176 /**
177 * @tc.steps: step2. destroy the event object.
178 * @tc.expected: step2. destroy successfully.
179 */
180 bool finalized = false;
__anon7e8eee710402(EventsMask revents) 181 errCode = timer->SetAction([](EventsMask revents) -> int {
182 return E_OK;
183 }, [&finalized]() {
184 finalized = true;
185 });
186 EXPECT_EQ(errCode, E_OK);
187 timer->KillAndDecObjRef(timer);
188 timer = nullptr;
189 EXPECT_EQ(finalized, true);
190 }
191
192 /**
193 * @tc.name: EventLoopTimerTest004
194 * @tc.desc: Start a timer
195 * @tc.type: FUNC
196 * @tc.require: AR000CKRTB AR000CQE0C
197 * @tc.author: fangyi
198 */
199 HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest004, TestSize.Level1)
200 {
201 // ready data
202 ASSERT_EQ(g_loop != nullptr, true);
203
204 /**
205 * @tc.steps: step1. start the loop.
206 * @tc.expected: step1. start successfully.
207 */
208 std::atomic<bool> running(false);
__anon7e8eee710602() 209 std::thread loopThread([&running]() {
210 running = true;
211 g_loop->Run();
212 });
213
214 int tryCounter = 0;
215 while (!running && ++tryCounter < MAX_RETRY_TIMES) {
216 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_1));
217 }
218 EXPECT_EQ(running, true);
219
220 /**
221 * @tc.steps: step2. create and start a timer.
222 * @tc.expected: step2. start successfully.
223 */
224 int errCode = E_OK;
225 IEvent *timer = IEvent::CreateEvent(TIME_PIECE_10, errCode);
226 ASSERT_EQ(timer != nullptr, true);
227 std::atomic<int> counter(0);
__anon7e8eee710702(EventsMask revents) 228 errCode = timer->SetAction([&counter](EventsMask revents) -> int { ++counter; return E_OK; }, nullptr);
229 EXPECT_EQ(errCode, E_OK);
230 errCode = g_loop->Add(timer);
231 EXPECT_EQ(errCode, E_OK);
232
233 /**
234 * @tc.steps: step3. wait and check.
235 * @tc.expected: step3. 'counter' increased by the timer.
236 */
237 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_100));
238 EXPECT_EQ(counter > 0, true);
239 g_loop->KillObj();
240 loopThread.join();
241 timer->DecObjRef(timer);
242 }
243
244 /**
245 * @tc.name: EventLoopTimerTest005
246 * @tc.desc: Stop a timer
247 * @tc.type: FUNC
248 * @tc.require: AR000CKRTB AR000CQE0C
249 * @tc.author: fangyi
250 */
251 HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest005, TestSize.Level1)
252 {
253 // ready data
254 ASSERT_EQ(g_loop != nullptr, true);
255
256 /**
257 * @tc.steps: step1. start the loop.
258 * @tc.expected: step1. start successfully.
259 */
260 std::atomic<bool> running(false);
__anon7e8eee710802() 261 std::thread loopThread([&running]() {
262 running = true;
263 g_loop->Run();
264 });
265
266 int tryCounter = 0;
267 while (!running && ++tryCounter <= MAX_RETRY_TIMES) {
268 std::this_thread::sleep_for(std::chrono::milliseconds(1));
269 }
270 EXPECT_EQ(running, true);
271
272 /**
273 * @tc.steps: step2. create and start a timer.
274 * @tc.expected: step2. start successfully.
275 */
276 int errCode = E_OK;
277 IEvent *timer = IEvent::CreateEvent(10, errCode);
278 ASSERT_EQ(timer != nullptr, true);
279 std::atomic<int> counter(0);
280 std::atomic<bool> finalize(false);
281 errCode = timer->SetAction(
__anon7e8eee710902(EventsMask revents) 282 [&counter](EventsMask revents) -> int {
283 ++counter;
284 return E_OK;
285 }, [&finalize]() { finalize = true; });
286 EXPECT_EQ(errCode, E_OK);
287 errCode = g_loop->Add(timer);
288 EXPECT_EQ(errCode, E_OK);
289
290 /**
291 * @tc.steps: step3. wait and check.
292 * @tc.expected: step3. 'counter' increased by the timer and the timer object finalized.
293 */
294 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_100));
295 timer->KillAndDecObjRef(timer);
296 timer = nullptr;
297 g_loop->KillObj();
298 loopThread.join();
299 EXPECT_EQ(counter > 0, true);
300 EXPECT_EQ(finalize, true);
301 }
302
303 /**
304 * @tc.name: EventLoopTimerTest006
305 * @tc.desc: Stop a timer
306 * @tc.type: FUNC
307 * @tc.require: AR000CKRTB AR000CQE0C
308 * @tc.author: fangyi
309 */
310 HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest006, TestSize.Level1)
311 {
312 // ready data
313 ASSERT_EQ(g_loop != nullptr, true);
314
315 /**
316 * @tc.steps: step1. start the loop.
317 * @tc.expected: step1. start successfully.
318 */
319 std::atomic<bool> running(false);
__anon7e8eee710b02() 320 std::thread loopThread([&running]() {
321 running = true;
322 g_loop->Run();
323 });
324
325 int tryCounter = 0;
326 while (!running && ++tryCounter <= MAX_RETRY_TIMES) {
327 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_10));
328 }
329 EXPECT_EQ(running, true);
330
331 /**
332 * @tc.steps: step2. create and start a timer.
333 * @tc.expected: step2. start successfully.
334 */
335 int errCode = E_OK;
336 IEvent *timer = IEvent::CreateEvent(TIME_PIECE_10, errCode);
337 ASSERT_EQ(timer != nullptr, true);
338 std::atomic<int> counter(0);
339 std::atomic<bool> finalize(false);
__anon7e8eee710c02(EventsMask revents) 340 errCode = timer->SetAction([&counter](EventsMask revents) -> int { ++counter; return -E_STALE; },
__anon7e8eee710d02() 341 [&finalize]() { finalize = true; });
342 EXPECT_EQ(errCode, E_OK);
343 errCode = g_loop->Add(timer);
344 EXPECT_EQ(errCode, E_OK);
345
346 /**
347 * @tc.steps: step3. wait and check.
348 * @tc.expected: step3. 'counter' increased by the timer and the timer object finalized.
349 */
350 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_100));
351 g_loop->KillObj();
352 loopThread.join();
353 timer->DecObjRef(timer);
354 timer = nullptr;
355 EXPECT_EQ(finalize, true);
356 EXPECT_EQ(counter > 0, true);
357 }
358
359 /**
360 * @tc.name: EventLoopTimerTest007
361 * @tc.desc: Modify a timer
362 * @tc.type: FUNC
363 * @tc.require: AR000CKRTB AR000CQE0C
364 * @tc.author: fangyi
365 */
366 HWTEST_F(DistributedDBEventLoopTimerTest, EventLoopTimerTest007, TestSize.Level2)
367 {
368 // ready data
369 ASSERT_EQ(g_loop != nullptr, true);
370
371 /**
372 * @tc.steps: step1. start the loop.
373 * @tc.expected: step1. start successfully.
374 */
375 std::atomic<bool> running(false);
__anon7e8eee710e02() 376 std::thread loopThread([&running]() {
377 running = true;
378 g_loop->Run();
379 });
380
381 int tryCounter = 0;
382 while (!running && ++tryCounter <= MAX_RETRY_TIMES) {
383 std::this_thread::sleep_for(std::chrono::milliseconds(1));
384 }
385 EXPECT_EQ(running, true);
386
387 /**
388 * @tc.steps: step2. create and start a timer.
389 * @tc.expected: step2. start successfully.
390 */
391 int errCode = E_OK;
392 IEvent *timer = IEvent::CreateEvent(TIME_PIECE_1000, errCode);
393 ASSERT_EQ(timer != nullptr, true);
394 int counter = 1; // Interval: 1 * TIME_PIECE_100
395 EventTime lastTime = TimerTester::GetCurrentTime();
396 errCode = timer->SetAction(
__anon7e8eee710f02(EventsMask revents) 397 [timer, &counter, &lastTime](EventsMask revents) -> int {
398 EventTime now = TimerTester::GetCurrentTime();
399 EventTime delta = now - lastTime;
400 delta -= counter * TIME_PIECE_1000;
401 EXPECT_EQ(delta >= -TIME_INACCURACY && delta <= TIME_INACCURACY, true);
402 if (++counter > RETRY_TIMES_5) {
403 return -E_STALE;
404 }
405 lastTime = TimerTester::GetCurrentTime();
406 int ret = timer->SetTimeout(counter * TIME_PIECE_1000);
407 EXPECT_EQ(ret, E_OK);
408 return E_OK;
409 }, nullptr);
410 EXPECT_EQ(errCode, E_OK);
411 errCode = g_loop->Add(timer);
412 EXPECT_EQ(errCode, E_OK);
413
414 std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PIECE_10000));
415 g_loop->KillObj();
416 loopThread.join();
417 timer->DecObjRef(timer);
418 }
419