1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <ztest.h>
7 #include <posix/time.h>
8 #include <posix/sys/time.h>
9 #include <posix/unistd.h>
10 
11 #define SLEEP_SECONDS 1
12 #define CLOCK_INVALID -1
13 
test_posix_clock(void)14 void test_posix_clock(void)
15 {
16 	int64_t nsecs_elapsed, secs_elapsed;
17 	struct timespec ts, te;
18 
19 	printk("POSIX clock APIs\n");
20 
21 	/* TESTPOINT: Pass invalid clock type */
22 	zassert_equal(clock_gettime(CLOCK_INVALID, &ts), -1,
23 			NULL);
24 	zassert_equal(errno, EINVAL, NULL);
25 
26 	zassert_ok(clock_gettime(CLOCK_MONOTONIC, &ts), NULL);
27 	zassert_ok(k_sleep(K_SECONDS(SLEEP_SECONDS)), NULL);
28 	zassert_ok(clock_gettime(CLOCK_MONOTONIC, &te), NULL);
29 
30 	if (te.tv_nsec >= ts.tv_nsec) {
31 		secs_elapsed = te.tv_sec - ts.tv_sec;
32 		nsecs_elapsed = te.tv_nsec - ts.tv_nsec;
33 	} else {
34 		nsecs_elapsed = NSEC_PER_SEC + te.tv_nsec - ts.tv_nsec;
35 		secs_elapsed = (te.tv_sec - ts.tv_sec - 1);
36 	}
37 
38 	/*TESTPOINT: Check if POSIX clock API test passes*/
39 	zassert_equal(secs_elapsed, SLEEP_SECONDS,
40 			"POSIX clock API test failed");
41 
42 	printk("POSIX clock APIs test done\n");
43 }
44 
test_posix_realtime(void)45 void test_posix_realtime(void)
46 {
47 	int ret;
48 	struct timespec rts, mts;
49 	struct timeval tv;
50 
51 	ret = clock_gettime(CLOCK_MONOTONIC, &mts);
52 	zassert_equal(ret, 0, "Fail to get monotonic clock");
53 
54 	ret = clock_gettime(CLOCK_REALTIME, &rts);
55 	zassert_equal(ret, 0, "Fail to get realtime clock");
56 
57 	/* Set a particular time.  In this case, the output of:
58 	 * `date +%s -d 2018-01-01T15:45:01Z`
59 	 */
60 	struct timespec nts;
61 	nts.tv_sec = 1514821501;
62 	nts.tv_nsec = NSEC_PER_SEC / 2U;
63 
64 	/* TESTPOINT: Pass invalid clock type */
65 	zassert_equal(clock_settime(CLOCK_INVALID, &nts), -1,
66 			NULL);
67 	zassert_equal(errno, EINVAL, NULL);
68 
69 	ret = clock_settime(CLOCK_MONOTONIC, &nts);
70 	zassert_not_equal(ret, 0, "Should not be able to set monotonic time");
71 
72 	ret = clock_settime(CLOCK_REALTIME, &nts);
73 	zassert_equal(ret, 0, "Fail to set realtime clock");
74 
75 	/*
76 	 * Loop 20 times, sleeping a little bit for each, making sure
77 	 * that the arithmetic roughly makes sense.  This tries to
78 	 * catch all of the boundary conditions of the clock to make
79 	 * sure there are no errors in the arithmetic.
80 	 */
81 	int64_t last_delta = 0;
82 	for (int i = 1; i <= 20; i++) {
83 		usleep(USEC_PER_MSEC * 90U);
84 		ret = clock_gettime(CLOCK_REALTIME, &rts);
85 		zassert_equal(ret, 0, "Fail to read realitime clock");
86 
87 		int64_t delta =
88 			((int64_t)rts.tv_sec * NSEC_PER_SEC -
89 			 (int64_t)nts.tv_sec * NSEC_PER_SEC) +
90 			((int64_t)rts.tv_nsec - (int64_t)nts.tv_nsec);
91 
92 		/* Make the delta milliseconds. */
93 		delta /= (NSEC_PER_SEC / 1000U);
94 
95 		zassert_true(delta > last_delta, "Clock moved backward");
96 		int64_t error = delta - last_delta;
97 
98 		/* printk("Delta %d: %lld\n", i, delta); */
99 
100 		/* Allow for a little drift upward, but not
101 		 * downward
102 		 */
103 		zassert_true(error >= 90, "Clock inaccurate %d", error);
104 		zassert_true(error <= 110, "Clock inaccurate %d", error);
105 
106 		last_delta = delta;
107 	}
108 
109 	/* Validate gettimeofday API */
110 	ret = gettimeofday(&tv, NULL);
111 	zassert_equal(ret, 0, NULL);
112 
113 	ret = clock_gettime(CLOCK_REALTIME, &rts);
114 	zassert_equal(ret, 0, NULL);
115 
116 	/* TESTPOINT: Check if time obtained from
117 	 * gettimeofday is same or more than obtained
118 	 * from clock_gettime
119 	 */
120 	zassert_true(rts.tv_sec >= tv.tv_sec, "gettimeofday didn't"
121 			" provide correct result");
122 	zassert_true(rts.tv_nsec >= tv.tv_usec * NSEC_PER_USEC,
123 			"gettimeofday didn't provide correct result");
124 }
125