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 <gtest/gtest.h>
17#include "timer.h"
18#include "common_timer_errors.h"
19#include <iostream>
20#include <thread>
21#include <chrono>
22#include <stdatomic.h>
23#include <sys/time.h>
24using namespace testing::ext;
25using namespace std;
26
27namespace OHOS {
28namespace {
29int64_t CurMs()
30{
31    struct timeval tpend;
32    gettimeofday(&tpend, nullptr);
33    return (tpend.tv_sec * 1000000 + tpend.tv_usec) / 1000;
34}
35
36class UtilsTimerTest : public testing::Test {
37public :
38    static void SetUpTestCase(void);
39    static void TearDownTestCase(void);
40    void SetUp();
41    void TearDown();
42};
43
44void UtilsTimerTest::SetUpTestCase(void)
45{
46}
47
48void UtilsTimerTest::TearDownTestCase(void)
49{
50}
51
52void UtilsTimerTest::SetUp(void)
53{
54}
55
56void UtilsTimerTest::TearDown(void)
57{
58}
59
60std::atomic<int> g_data1(0);
61void TimeOutCallback1()
62{
63    g_data1 = g_data1 + 1;
64}
65
66std::atomic<int> g_data2(0);
67void TimeOutCallback2()
68{
69    g_data2 = g_data2 + 1;
70}
71
72/*
73 * @tc.name: testTimer001
74 * @tc.desc: timer unit test
75 *
76 * temporarily offline for kernel difference
77HWTEST_F(UtilsTimerTest, testTimer001, TestSize.Level0)
78{
79    g_data1 = 0;
80    Utils::Timer timer("test_timer");
81    uint32_t ret = timer.Setup();
82    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
83    uint32_t timerId = timer.Register(TimeOutCallback1, 1);
84    std::this_thread::sleep_for(std::chrono::milliseconds(8));
85    timer.Unregister(timerId);
86    std::this_thread::sleep_for(std::chrono::milliseconds(10));
87    timer.Shutdown();
88    EXPECT_GE(g_data1, 2);
89    EXPECT_GE(10, g_data1);
90*/
91
92/*
93 * @tc.name: testTimer002
94 * @tc.desc: timer unit test
95 */
96HWTEST_F(UtilsTimerTest, testTimer002, TestSize.Level0)
97{
98    g_data1 = 0;
99    Utils::Timer timer("test_timer");
100    uint32_t ret = timer.Setup();
101    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
102    timer.Register(TimeOutCallback1, 1, true);
103    std::this_thread::sleep_for(std::chrono::milliseconds(15));
104    timer.Shutdown();
105    EXPECT_EQ(1, g_data1);
106}
107
108/*
109 * @tc.name: testTimer003
110 * @tc.desc: timer unit test
111 */
112HWTEST_F(UtilsTimerTest, testTimer003, TestSize.Level0)
113{
114    g_data1 = 0;
115    g_data2 = 0;
116    Utils::Timer timer("test_timer");
117    uint32_t ret = timer.Setup();
118    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
119    timer.Register(TimeOutCallback1, 1);
120    timer.Register(TimeOutCallback2, 50);
121    std::this_thread::sleep_for(std::chrono::milliseconds(500));
122    timer.Shutdown();
123    EXPECT_GE(g_data1, 8);
124    EXPECT_GE(g_data2, 2);
125}
126
127static void TestTimerEvent(Utils::Timer& timer)
128{
129    uint32_t interval = 1;
130    timer.Register(TimeOutCallback1, interval);
131    uint32_t interval2 = 2;
132    timer.Register(TimeOutCallback1, interval2);
133    int sleepTime = 30;
134    std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
135    timer.Shutdown();
136}
137
138/*
139 * @tc.name: testTimer004
140 * @tc.desc: timer unit test
141 */
142HWTEST_F(UtilsTimerTest, testTimer004, TestSize.Level0)
143{
144    g_data1 = 0;
145    Utils::Timer timer("test_timer");
146    uint32_t ret = timer.Setup();
147    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
148    TestTimerEvent(timer);
149    EXPECT_GE(g_data1, 5);
150}
151
152class A {
153public:
154    explicit A(int data) : data_(data), timer_("ATimer") {}
155    ~A() = default;
156    bool Init();
157    bool StartTimer(int milliseconds, bool once);
158    void StopTimer();
159    int GetData() const
160    {
161        return data_;
162    }
163private:
164    void TimeOutProc()
165    {
166        data_ -= 1;
167    };
168    int data_;
169    Utils::Timer timer_;
170};
171
172bool A::Init()
173{
174    return timer_.Setup() == Utils::TIMER_ERR_OK;
175}
176
177bool A::StartTimer(int milliseconds, bool once)
178{
179    uint32_t timerId = timer_.Register(std::bind(&A::TimeOutProc, this), milliseconds, once);
180    return timerId != Utils::TIMER_ERR_DEAL_FAILED;
181}
182
183void A::StopTimer()
184{
185    timer_.Shutdown();
186}
187
188/*
189 * @tc.name: testTimer005
190 * @tc.desc: timer unit test
191 *
192 * temporarily offline for kernel difference
193HWTEST_F(UtilsTimerTest, testTimer005, TestSize.Level0)
194{
195    A a(10);
196    EXPECT_TRUE(a.Init());
197    EXPECT_TRUE(a.StartTimer(1, false));
198    std::this_thread::sleep_for(std::chrono::milliseconds(10));
199    a.StopTimer();
200    EXPECT_GE(8, a.GetData());
201}
202*/
203
204/*
205 * @tc.name: testTimer006
206 * @tc.desc: timer unit test
207 */
208HWTEST_F(UtilsTimerTest, testTimer006, TestSize.Level0)
209{
210    A a(10);
211    EXPECT_TRUE(a.Init());
212    EXPECT_TRUE(a.StartTimer(1, true));
213    std::this_thread::sleep_for(std::chrono::milliseconds(20));
214    a.StopTimer();
215    EXPECT_EQ(9, a.GetData());
216}
217
218static void TimerEventFun(Utils::Timer& timer)
219{
220    uint32_t timerId = 0;
221    uint32_t loops = 10;
222    uint32_t interval = 7;
223    int sleepTime = 10;
224    for (uint32_t i = 0; i < loops; i++) {
225        timerId = timer.Register(TimeOutCallback1, interval, true);
226        std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
227    }
228    timer.Unregister(timerId);
229    timer.Unregister(timerId);
230}
231
232/*
233 * @tc.name: testTimer007
234 * @tc.desc: abnormal case
235 */
236HWTEST_F(UtilsTimerTest, testTimer007, TestSize.Level0)
237{
238    g_data1 = 0;
239    Utils::Timer timer("test_timer");
240    uint32_t ret = timer.Setup();
241    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
242    TimerEventFun(timer);
243    timer.Shutdown();
244    timer.Shutdown(false);
245    EXPECT_GE(g_data1, 5);
246}
247
248static void SleepLoopFunc()
249{
250    int loops = 11;
251    int sleepTime = 10;
252    int64_t desiredVal = 10;
253    for (int i = 0; i < loops; i++) {
254        int64_t pre = CurMs();
255        std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
256        int64_t cur = CurMs();
257        EXPECT_GE(cur - pre, desiredVal);
258    }
259}
260
261/*
262 * @tc.name: testTimer008
263 * @tc.desc: timer sleep test for ivi
264 */
265HWTEST_F(UtilsTimerTest, testTimer008, TestSize.Level0)
266{
267    g_data1 = 0;
268    Utils::Timer timer("test_timer");
269    uint32_t ret = timer.Setup();
270    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
271    timer.Register(TimeOutCallback1, 10);
272
273    SleepLoopFunc();
274    timer.Shutdown();
275    EXPECT_GE(g_data1, 10);
276}
277
278/*
279 * @tc.name: testTimer009
280 * @tc.desc: recursive test
281 */
282void DoFunc(Utils::Timer &timer, int &count)
283{
284    (void)timer.Register(
285        [&timer, &count]() {
286            count += 1;
287            if (count > 9) {
288                return;
289            }
290            DoFunc(timer, count);
291        },
292        10, true);
293    g_data1++;
294}
295
296void DoFunc2(Utils::Timer &timer, int &count)
297{
298    (void)timer.Register(
299        [&timer, &count]() {
300            count += 1;
301            if (count > 9) {
302                return;
303            }
304            DoFunc2(timer, count);
305        },
306        10, true);
307    g_data1++;
308}
309
310HWTEST_F(UtilsTimerTest, testTimer009, TestSize.Level0)
311{
312    g_data1 = 0;
313    Utils::Timer timer("test_timer");
314    uint32_t ret = timer.Setup();
315    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
316
317    int cnt = 0, cnt1 = 0;
318    DoFunc(timer, cnt);
319    DoFunc2(timer, cnt1);
320    std::this_thread::sleep_for(std::chrono::milliseconds(50));
321    EXPECT_GE(g_data1, 5);  /* 8 for max */
322    EXPECT_GE(14, g_data1); /* 10 for min */
323    std::this_thread::sleep_for(std::chrono::milliseconds(50));
324    timer.Shutdown();
325    EXPECT_GE(g_data1, 10); /* 18 for max */
326}
327
328static void TimerRegisterMechanism(Utils::Timer& timer, bool once)
329{
330    uint32_t interval = 10;
331    timer.Register(TimeOutCallback1, interval, once);
332    timer.Register(TimeOutCallback1, interval, !once);
333    timer.Register(TimeOutCallback1, interval, once);
334    timer.Register(TimeOutCallback1, interval, !once);
335}
336
337/*
338 * @tc.name: testTimer010
339 * @tc.desc: once timer register
340 */
341HWTEST_F(UtilsTimerTest, testTimer010, TestSize.Level0)
342{
343    g_data1 = 0;
344    Utils::Timer timer("test_timer");
345    uint32_t ret = timer.Setup();
346    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
347    bool once = true;
348    TimerRegisterMechanism(timer, once);
349    std::this_thread::sleep_for(std::chrono::milliseconds(52));
350    timer.Shutdown();
351    EXPECT_GE(g_data1, 8); /* 12 for max */
352}
353
354/*
355 * @tc.name: testTimer011
356 * @tc.desc: once timer register
357 */
358HWTEST_F(UtilsTimerTest, testTimer011, TestSize.Level0)
359{
360    g_data1 = 0;
361    Utils::Timer timer("test_timer");
362    uint32_t ret = timer.Setup();
363    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
364    bool once = false;
365    TimerRegisterMechanism(timer, once);
366    std::this_thread::sleep_for(std::chrono::milliseconds(52));
367    timer.Shutdown();
368    EXPECT_GE(g_data1, 8); /* 12 for max */
369}
370
371/*
372 * @tc.name: testTimer012
373 * @tc.desc: Test double setup.
374 */
375HWTEST_F(UtilsTimerTest, testTimer012, TestSize.Level0)
376{
377    g_data1 = 0;
378    Utils::Timer timer("test_timer");
379    uint32_t ret = timer.Setup();
380    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
381    ret = timer.Setup();
382    EXPECT_EQ(Utils::TIMER_ERR_INVALID_VALUE, ret);
383
384    timer.Shutdown();
385}
386
387/*
388 * @tc.name: testTimer013
389 * @tc.desc: Test uncommon operations.
390 */
391HWTEST_F(UtilsTimerTest, testTimer013, TestSize.Level0)
392{
393    g_data1 = 0;
394    Utils::Timer timer("test_timer", -1);
395    uint32_t ret = timer.Setup();
396    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
397    std::this_thread::sleep_for(std::chrono::milliseconds(1));
398    timer.Shutdown();
399
400    Utils::Timer timer1("test_timer_1");
401    ret = timer1.Setup();
402    EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
403    std::this_thread::sleep_for(std::chrono::milliseconds(1));
404    timer1.Shutdown(false);
405}
406}  // namespace
407}  // namespace OHOS