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 <time.h>
17#include <sys/timeb.h>
18#include <sys/times.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <errno.h>
22#include <gtest/gtest.h>
23#include "log.h"
24#include "utils.h"
25#include "ClockID.h"
26
27using namespace testing::ext;
28
29const char* DATEMSK_FILE = "/storage/getdate_mask";
30
31// Resolution of: CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_MONOTONIC_RAW: 1 us
32const int CLOCK_RESOLUTION_HIGH = 1000;
33// Resolution of: CLOCK_MONOTONIC_COARSE, CLOCK_REALTIME_COARSE: 1 tick = 10 ms
34const int CLOCK_RESOLUTION_LOW = 1000 * 1000;
35
36class ClockTimeTest : public testing::Test {
37protected:
38    static struct timespec mTestStatTime;
39    // SetUpTestCase: Testsuit setup, run before 1st testcase
40    static void SetUpTestCase(void)
41    {
42        clock_gettime(CLOCK_REALTIME, &mTestStatTime);
43        LOG("test start at %ld\n", (long)mTestStatTime.tv_sec);
44    }
45    // TearDownTestCase: Testsuit teardown, run after last testcase
46    static void TearDownTestCase(void)
47    {
48        struct timespec time1 = {0, 0};
49        clock_gettime(CLOCK_REALTIME, &time1);
50        LOG("test end at %ld", (long)time1.tv_sec);
51
52        mTestStatTime.tv_sec += 10; // approximate total test time
53        if (!clock_settime(CLOCK_REALTIME, &mTestStatTime)) {
54            LOG("restore time ok\n");
55        } else {
56            LOG("restore time failed\n");
57        }
58    }
59};
60struct timespec ClockTimeTest::mTestStatTime;
61
62/**
63 * @tc.number SUB_KERNEL_TIME_API_CLOCK_GETRES_0100
64 * @tc.name   test all supported clockid of clock_getres
65 * @tc.desc   [C- SOFTWARE -0200]
66 */
67HWTEST_P(SupportedClockIDTest, testClockGetresAll, Function | MediumTest | Level1)
68{
69    clockid_t cid = GetParam();
70    const char* cname = ALL_CLOCKS_NAME[cid];
71
72    struct timespec time1 = {0, 0};
73    int rt = clock_getres(cid, &time1);
74    LOG("%s Resolution: %ld nanosecond\n", cname, time1.tv_nsec);
75    EXPECT_EQ(rt, 0) << "clock_getres of " << cname << "failed, errno =" <<errno;
76
77    EXPECT_EQ(time1.tv_sec, 0);
78    if (cid == CLOCK_MONOTONIC || cid == CLOCK_REALTIME || cid == CLOCK_MONOTONIC_RAW) {
79        EXPECT_EQ(time1.tv_nsec, CLOCK_RESOLUTION_HIGH) << "Resolution check failed";
80    } else {
81        EXPECT_EQ(time1.tv_nsec, CLOCK_RESOLUTION_LOW) << "Resolution check failed";
82    }
83}
84
85/**
86 * @tc.number SUB_KERNEL_TIME_API_CLOCK_GETTIME_0100
87 * @tc.name   test all supported clockid of clock_gettime
88 * @tc.desc   [C- SOFTWARE -0200]
89 */
90HWTEST_P(SupportedClockIDTest, testClockGettimeAll, Function | MediumTest | Level1)
91{
92    clockid_t cid = GetParam();
93    const char* cname = ALL_CLOCKS_NAME[cid];
94
95    struct timespec time1 = {0, 0};
96    int rt = clock_gettime(cid, &time1);
97    if (rt == 0) {
98        LOG("clock_gettime(%s) : tv_sec=%ld, tv_nsec=%ld\n", cname, time1.tv_sec, time1.tv_nsec);
99    } else {
100        LOG("%s return error, rt=%d, errno=%d:%s\n", cname, rt, errno, strerror(errno));
101    }
102    EXPECT_EQ(rt, 0);
103}
104
105INSTANTIATE_TEST_CASE_P(ClockTimeTest, SupportedClockIDTest, ALL_SUPPORTED_IDS);
106
107
108/**
109 * @tc.number SUB_KERNEL_TIME_API_CLOCK_SETTIME_0100
110 * @tc.name   test clock_settime basic
111 * @tc.desc   [C- SOFTWARE -0200]
112 */
113HWTEST_F(ClockTimeTest, testClockSettime, Function | MediumTest | Level1)
114{
115    struct timespec time1 = {0, 0};
116    int rt = clock_gettime(CLOCK_REALTIME, &time1);
117    ASSERT_EQ(rt, 0) << "clock_gettime failed, errno=" << errno;
118    LOG("current time: sec=%llu, nsec=%ld", time1.tv_sec, time1.tv_nsec);
119    time_t sec = time1.tv_sec;
120    time1.tv_sec -= 1;
121    time1.tv_nsec = 1;
122    rt = clock_settime(CLOCK_REALTIME, &time1);
123    ASSERT_EQ(rt, 0) << "clock_settime failed, errno=" << errno;
124    sleep(1);
125    rt = clock_gettime(CLOCK_REALTIME, &time1);
126    ASSERT_EQ(rt, 0) << "clock_gettime failed, errno=" << errno;
127    ASSERT_EQ(sec, time1.tv_sec);
128}
129
130/**
131 * @tc.number SUB_KERNEL_TIME_API_FTIME_0100
132 * @tc.name   test ftime basic
133 * @tc.desc   [C- SOFTWARE -0200]
134 */
135HWTEST_F(ClockTimeTest, testFtime, Function | MediumTest | Level1)
136{
137    Msleep(10); // hopefully to let the flowing code not scheduled-out
138    struct timeb tb = {0};
139    struct timespec ts = {0};
140    int rt = clock_gettime(CLOCK_REALTIME, &ts);
141    ASSERT_EQ(rt, 0) << "clock_gettime failed, errno=" << errno;
142    ts.tv_sec -= 1;
143    ts.tv_nsec = 1000000;
144    rt = clock_settime(CLOCK_REALTIME, &ts);
145    ASSERT_EQ(rt, 0) << "clock_settime failed, errno=" << errno;
146    rt = clock_gettime(CLOCK_REALTIME, &ts);
147    int rt2 = ftime(&tb);
148    EXPECT_EQ(rt, 0) << "clock_gettime failed, errno=" << errno;
149    EXPECT_EQ(rt2, 0) << "ftime failed, errno=" << errno;
150    LOG("current time: sec=%llu, nsec=%ld", ts.tv_sec, (long)ts.tv_nsec);
151    LOG("current time: sec=%llu, millitm=%d", tb.time, (int)tb.millitm);
152    EXPECT_EQ(ts.tv_sec, tb.time);
153    EXPECT_NEAR((int)ts.tv_nsec/1000000, (int)tb.millitm, 1);
154}
155
156/**
157 * @tc.number SUB_KERNEL_TIME_API_STIME_0100
158 * @tc.name   test stime basic
159 * @tc.desc   [C- SOFTWARE -0200]
160 */
161HWTEST_F(ClockTimeTest, testStime, Function | MediumTest | Level1)
162{
163    Msleep(10); // hopefully to let the flowing code not scheduled-out
164    struct timespec ts = {0};
165    int rt = clock_gettime(CLOCK_REALTIME, &ts);
166    LOG("current time: sec=%llu, nsec=%ld", ts.tv_sec, (long)ts.tv_nsec);
167    ASSERT_EQ(rt, 0) << "clock_gettime failed, errno=" << errno;
168    time_t t = ts.tv_sec + 1;
169    rt = stime(&t);
170    ASSERT_EQ(rt, 0) << "stime failed, errno=" << errno;
171    Msleep(10);
172    rt = clock_gettime(CLOCK_REALTIME, &ts);
173    EXPECT_EQ(rt, 0) << "clock_gettime failed, errno=" << errno;
174    LOG("current time: sec=%llu, nsec=%ld", ts.tv_sec, (long)ts.tv_nsec);
175    EXPECT_EQ(ts.tv_sec, t);
176}
177
178/**
179 * @tc.number SUB_KERNEL_TIME_API_TIME_0100
180 * @tc.name   test time basic
181 * @tc.desc   [C- SOFTWARE -0200]
182 */
183HWTEST_F(ClockTimeTest, testTime, Function | MediumTest | Level1)
184{
185    Msleep(10); // hopefully to let the flowing code not scheduled-out
186    struct timespec ts = {0};
187    int rt = clock_gettime(CLOCK_REALTIME, &ts);
188    ASSERT_EQ(rt, 0) << "clock_gettime failed, errno=" << errno;
189    rt = stime(&ts.tv_sec); // set ts.tv_nsec to 0
190    ASSERT_EQ(rt, 0) << "stime failed, errno=" << errno;
191
192    time_t t1, t2;
193    t1 = time(&t2);
194    EXPECT_EQ(t1, ts.tv_sec) << "time failed";
195    EXPECT_EQ(t1, t2) << "time failed";
196
197    t2 = 1;
198    rt = stime(&t2);
199    EXPECT_EQ(rt, 0) << "stime failed, errno=" << errno;
200
201    t1 = time(&t2);
202    EXPECT_EQ(t1, 1);
203    EXPECT_EQ(t1, t2);
204
205    t1 = time(nullptr);
206    EXPECT_EQ(t1, 1);
207
208    rt = stime(&ts.tv_sec); // restore time
209    ASSERT_EQ(rt, 0) << "stime failed, errno=" << errno;
210}
211
212/**
213 * @tc.number SUB_KERNEL_TIME_API_TIMES_0100
214 * @tc.name   test times basic
215 * @tc.desc   [C- SOFTWARE -0200]
216 */
217HWTEST_F(ClockTimeTest, testTimes, Function | MediumTest | Level1)
218{
219    // this test should run in a child process
220    pid_t pid = fork();
221    ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
222    if (pid == 0) { // child
223        int exitCode = 0;
224        const int testClockt = 100;
225        const int msPerClock = 10;
226        struct tms start = {0};
227        struct tms end = {0};
228        clock_t stTime = times(&start);
229        LOG("start_clock: stTime: %ld", stTime);
230        LOG("start_clock: tms_utime: %ld, tms_stime: %ld, tms_cutime:%ld, tms_cstime:%ld",
231            start.tms_utime, start.tms_stime, start.tms_cutime, start.tms_cstime);
232
233        KeepRun(testClockt * msPerClock);
234
235        clock_t endTime = times(&end);
236        LOG("end_clock: endTime: %ld", endTime);
237        LOG("end_clock: tms_utime: %ld, tms_stime: %ld, tms_cutime:%ld, tms_cstime:%ld",
238            end.tms_utime, end.tms_stime, end.tms_cutime, end.tms_cstime);
239
240        LOG("Real Time: %ld, User Time %ld, System Time %ld\n", (long)(endTime - stTime),
241            (long)(end.tms_utime - start.tms_utime),
242            (long)(end.tms_stime - start.tms_stime));
243
244        if (start.tms_utime != 0 || start.tms_stime != 0 || start.tms_cutime != 0 || start.tms_cstime != 0) {
245            LOG("init value check failed");
246        }
247        if (!CheckValueClose(end.tms_utime, testClockt, 0.02)) {
248            LOG("tms_utime value check failed");
249        }
250        if (!CheckValueClose((endTime - stTime), testClockt, 0.02)) {
251            LOG("Real Time value check failed");
252        }
253        exit(exitCode);
254    } else { // parent
255        WaitProcExitedOK(pid);
256    }
257}
258
259/**
260* @tc.number     SUB_KERNEL_TIME_API_GETTIMEOFDAY_0100
261* @tc.name       test gettimeofday api
262* @tc.desc       [C- SOFTWARE -0200]
263*/
264HWTEST_F(ClockTimeTest, testGettimeofday, Function | MediumTest | Level1) {
265    int sleepSec = 1;
266    struct timeval tvalStart = {0};
267    struct timeval tvalEnd = {0};
268    struct timezone tzone;
269
270    int ret1 = gettimeofday(&tvalStart, &tzone);
271    sleep(sleepSec);
272    int ret2 = gettimeofday(&tvalEnd, &tzone);
273    EXPECT_EQ(0, ret1);
274    EXPECT_EQ(0, ret2);
275    EXPECT_TRUE((tvalEnd.tv_sec - tvalStart.tv_sec) >= sleepSec)
276        << "check end-start>=1 fail, start[" << tvalStart.tv_sec << "],end[" << tvalEnd.tv_sec << "]";
277    EXPECT_TRUE((tvalEnd.tv_sec - tvalStart.tv_sec) < sleepSec+1)
278        << "check end-start<2 fail, start[" << tvalStart.tv_sec << "],end[" << tvalEnd.tv_sec << "]";
279}
280
281/**
282* @tc.number     SUB_KERNEL_TIME_API_SETTIMEOFDAY_0100
283* @tc.name       test settimeofday api
284* @tc.desc       [C- SOFTWARE -0200]
285*/
286HWTEST_F(ClockTimeTest, testSettimeofday, Function | MediumTest | Level1) {
287    int setSec = 100;
288    int sleepSec = 2;
289    struct timeval tvalStart = {0};
290    struct timeval tvalEnd = {0};
291    struct timeval set = {.tv_sec = setSec, .tv_usec = 0};
292
293    int ret1 = settimeofday(&set, NULL);
294    int ret2 = gettimeofday(&tvalStart, NULL);
295    sleep(sleepSec);
296    int ret3 = gettimeofday(&tvalEnd, NULL);
297    EXPECT_EQ(0, ret1);
298    EXPECT_EQ(0, ret2);
299    EXPECT_EQ(0, ret3);
300    EXPECT_EQ(setSec, tvalStart.tv_sec)
301        << "settimeofday set[" << setSec << "],get[" << tvalStart.tv_sec << "]";
302    EXPECT_TRUE((tvalEnd.tv_sec - tvalStart.tv_sec) >= sleepSec)
303        << "check end-start>=2 fail, start[" << tvalStart.tv_sec << "],end[" << tvalEnd.tv_sec << "]";
304    EXPECT_TRUE((tvalEnd.tv_sec - tvalStart.tv_sec) < sleepSec+1)
305        << "check end-start<3 fail, start[" << tvalStart.tv_sec << "],end[" << tvalEnd.tv_sec << "]";
306}
307
308/**
309* @tc.number     SUB_KERNEL_TIME_API_LOCALTIME_0100
310* @tc.name       test localtime api
311* @tc.desc       [C- SOFTWARE -0200]
312*/
313HWTEST_F(ClockTimeTest, testLocaltime, Function | MediumTest | Level1) {
314    char cTime[32];
315    time_t tStart;
316    time_t tEnd;
317    struct timeval tSet = {.tv_sec = 86399, .tv_usec = 0};
318
319    int ret = settimeofday(&tSet, NULL);
320    time(&tStart);
321    sleep(2);
322    time(&tEnd);
323    EXPECT_EQ(0, ret);
324
325    struct tm *tmStart = localtime(&tStart);
326    ASSERT_NE(nullptr, tmStart);
327    strftime(cTime, sizeof(cTime), "%H:%M:%S", tmStart);
328    EXPECT_STREQ("23:59:59", cTime);
329    struct tm *tmEnd = localtime(&tEnd);
330    ASSERT_NE(nullptr, tmEnd);
331    strftime(cTime, sizeof(cTime), "%H:%M:%S", tmEnd);
332    EXPECT_STREQ("00:00:01", cTime);
333}
334
335/**
336* @tc.number     SUB_KERNEL_TIME_API_LOCALTIMER_0100
337* @tc.name       test localtime_r api
338* @tc.desc       [C- SOFTWARE -0200]
339*/
340HWTEST_F(ClockTimeTest, testLocaltimer, Function | MediumTest | Level1) {
341    char cTime[32];
342    time_t tStart;
343    time_t tEnd;
344    struct tm tmrStart = {0};
345    struct tm tmrEnd = {0};
346
347    struct timeval tSet = {.tv_sec = 86399, .tv_usec = 0};
348    int ret = settimeofday(&tSet, NULL);
349    time(&tStart);
350    sleep(1);
351    time(&tEnd);
352    struct tm *tmrStartPtr = localtime_r(&tStart, &tmrStart);
353    ASSERT_NE(nullptr, tmrStartPtr);
354    struct tm *tmrEndPtr = localtime_r(&tEnd, &tmrEnd);
355    ASSERT_NE(nullptr, tmrEndPtr);
356
357    EXPECT_EQ(0, ret);
358    strftime(cTime, sizeof(cTime), "%H:%M:%S", &tmrStart);
359    EXPECT_STREQ("23:59:59", cTime);
360    strftime(cTime, sizeof(cTime), "%H:%M:%S", tmrStartPtr);
361    EXPECT_STREQ("23:59:59", cTime);
362    strftime(cTime, sizeof(cTime), "%H:%M:%S", &tmrEnd);
363    EXPECT_STREQ("00:00:00", cTime);
364    strftime(cTime, sizeof(cTime), "%H:%M:%S", tmrEndPtr);
365    EXPECT_STREQ("00:00:00", cTime);
366    strftime(cTime, sizeof(cTime), "%F %T", &tmrStart);
367    LOG("   result[%s]", cTime);
368}
369
370/**
371* @tc.number     SUB_KERNEL_TIME_API_GETDATE_0100
372* @tc.name       test getdate api
373* @tc.desc       [C- SOFTWARE -0200]
374*/
375HWTEST_F(ClockTimeTest, testGetdateBasic, Function | MediumTest | Level1) {
376    // set DATEMSK env
377    FILE *fp = nullptr;
378    char mask[20] = "%Y-%m-%d %H:%M:%S";
379    fp = fopen(DATEMSK_FILE, "w+");
380    ASSERT_NE(nullptr, fp);
381    int ret = fwrite(mask, sizeof(mask), 1, fp);
382    EXPECT_TRUE(ret > 0);
383    ret = setenv("DATEMSK", DATEMSK_FILE, 1);
384    EXPECT_EQ(0, ret);
385    ret = fclose(fp);
386    EXPECT_NE(-1, ret);
387
388    // test getdate
389    char cTime[30];
390    struct tm *retTm = nullptr;
391    const char *cInput = "2020-10-26 00:01:01";
392    retTm = getdate(cInput);
393    ASSERT_NE(nullptr, retTm) << "   getdate fail errno:" << getdate_err;
394    strftime(cTime, sizeof(cTime), mask, retTm);
395    EXPECT_STREQ(cInput, cTime);
396    strftime(cTime, sizeof(cTime), "%D %A %H:%M:%S", retTm);
397    EXPECT_STREQ("10/26/20 Sunday 00:01:01", cTime);
398
399    // restore
400    ret = remove(DATEMSK_FILE);
401    EXPECT_EQ(0, ret);
402    ret = unsetenv("DATEMSK");
403    EXPECT_EQ(0, ret);
404}
405
406/**
407* @tc.number     SUB_KERNEL_TIME_API_GETDATE_0200
408* @tc.name       getdate error test
409* @tc.desc       [C- SOFTWARE -0200]
410*/
411HWTEST_F(ClockTimeTest, testGetdateError, Function | MediumTest | Level2) {
412    // no env
413    struct tm *retTm = nullptr;
414    const char *cInput = "2020-10-26 00:01:01";
415    retTm = getdate(cInput);
416    EXPECT_EQ(nullptr, retTm);
417    EXPECT_EQ(1, getdate_err);
418
419    // set env, but file not exist
420    int ret = setenv("DATEMSK", DATEMSK_FILE, 1);
421    EXPECT_EQ(0, ret);
422    retTm = getdate(cInput);
423    EXPECT_EQ(nullptr, retTm);
424    EXPECT_EQ(2, getdate_err);
425
426    // creat file and set env
427    FILE *fp = nullptr;
428    char mask[10] = "%H:%M:%S";
429    fp = fopen(DATEMSK_FILE, "w+");
430    ASSERT_NE(nullptr, fp);
431    ret = fwrite(mask, sizeof(mask), 1, fp);
432    EXPECT_TRUE(ret > 0);
433    ret = fclose(fp);
434    EXPECT_NE(-1, ret);
435
436    // test getdate
437    retTm = getdate("10/26/20 00:01:01");
438    EXPECT_EQ(nullptr, retTm);
439    EXPECT_EQ(7, getdate_err);
440
441    // restore
442    ret = remove(DATEMSK_FILE);
443    EXPECT_EQ(0, ret);
444    ret = unsetenv("DATEMSK");
445    EXPECT_EQ(0, ret);
446}
447