Skip to content

Commit

Permalink
tests: posix: common: separate posix timer tests into a smaller tests…
Browse files Browse the repository at this point in the history
…uite

posix.common contains testsuites that can be separated into smaller
groups of tests. This change moves clock, sleep, nanosleep and timer
into a singular testsuite at tests/posix/timer app directory.

Signed-off-by: Marvin Ouma <[email protected]>
  • Loading branch information
Pancakem committed Dec 10, 2024
1 parent 5dfd41e commit c36c16d
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 245 deletions.
216 changes: 1 addition & 215 deletions tests/posix/common/src/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,6 @@
#include <zephyr/ztest.h>
#include <zephyr/logging/log.h>

#define SLEEP_SECONDS 1
#define CLOCK_INVALID -1

LOG_MODULE_REGISTER(clock_test, LOG_LEVEL_DBG);

/* Set a particular time. In this case, the output of: `date +%s -d 2018-01-01T15:45:01Z` */
static const struct timespec ref_ts = {1514821501, NSEC_PER_SEC / 2U};

static const clockid_t clocks[] = {
CLOCK_MONOTONIC,
CLOCK_REALTIME,
};
static const bool settable[] = {
false,
true,
};

static inline int64_t ts_to_ns(const struct timespec *ts)
{
return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
Expand All @@ -47,47 +30,7 @@ static inline void tv_to_ts(const struct timeval *tv, struct timespec *ts)
return _tp_op(_a, _b, _op); \
}

_decl_op(bool, tp_eq, ==); /* a == b */
_decl_op(bool, tp_lt, <); /* a < b */
_decl_op(bool, tp_gt, >); /* a > b */
_decl_op(bool, tp_le, <=); /* a <= b */
_decl_op(bool, tp_ge, >=); /* a >= b */
_decl_op(int64_t, tp_diff, -); /* a - b */

/* lo <= (a - b) < hi */
static inline bool tp_diff_in_range_ns(const struct timespec *a, const struct timespec *b,
int64_t lo, int64_t hi)
{
int64_t diff = tp_diff(a, b);

return diff >= lo && diff < hi;
}

ZTEST(clock, test_clock_gettime)
{
struct timespec ts;

/* ensure argument validation is performed */
errno = 0;
zassert_equal(clock_gettime(CLOCK_INVALID, &ts), -1);
zassert_equal(errno, EINVAL);

if (false) {
/* undefined behaviour */
errno = 0;
zassert_equal(clock_gettime(clocks[0], NULL), -1);
zassert_equal(errno, EINVAL);
}

/* verify that we can call clock_gettime() on supported clocks */
ARRAY_FOR_EACH(clocks, i)
{
ts = (struct timespec){-1, -1};
zassert_ok(clock_gettime(clocks[i], &ts));
zassert_not_equal(ts.tv_sec, -1);
zassert_not_equal(ts.tv_nsec, -1);
}
}
_decl_op(bool, tp_ge, >=); /* a >= b */

ZTEST(clock, test_gettimeofday)
{
Expand All @@ -114,161 +57,4 @@ ZTEST(clock, test_gettimeofday)
zassert_true(tp_ge(&rts, &ts));
}

ZTEST(clock, test_clock_settime)
{
int64_t diff_ns;
struct timespec ts = {0};

BUILD_ASSERT(ARRAY_SIZE(settable) == ARRAY_SIZE(clocks));

/* ensure argument validation is performed */
errno = 0;
zassert_equal(clock_settime(CLOCK_INVALID, &ts), -1);
zassert_equal(errno, EINVAL);

if (false) {
/* undefined behaviour */
errno = 0;
zassert_equal(clock_settime(CLOCK_REALTIME, NULL), -1);
zassert_equal(errno, EINVAL);
}

/* verify nanoseconds */
errno = 0;
ts = (struct timespec){0, NSEC_PER_SEC};
zassert_equal(clock_settime(CLOCK_REALTIME, &ts), -1);
zassert_equal(errno, EINVAL);
errno = 0;
ts = (struct timespec){0, -1};
zassert_equal(clock_settime(CLOCK_REALTIME, &ts), -1);
zassert_equal(errno, EINVAL);

ARRAY_FOR_EACH(clocks, i)
{
if (!settable[i]) {
/* should fail attempting to set unsettable clocks */
errno = 0;
zassert_equal(clock_settime(clocks[i], &ts), -1);
zassert_equal(errno, EINVAL);
continue;
}

zassert_ok(clock_settime(clocks[i], &ref_ts));

/* read-back the time */
zassert_ok(clock_gettime(clocks[i], &ts));
/* dt should be >= 0, but definitely <= 1s */
diff_ns = tp_diff(&ts, &ref_ts);
zassert_true(diff_ns >= 0 && diff_ns <= NSEC_PER_SEC);
}
}

ZTEST(clock, test_realtime)
{
struct timespec then, now;
/*
* For calculating cumulative moving average
* Note: we do not want to assert any individual samples due to scheduler noise.
* The CMA filters out the noise so we can make an assertion (on average).
* https://en.wikipedia.org/wiki/Moving_average#Cumulative_moving_average
*/
int64_t cma_prev = 0;
int64_t cma;
int64_t x_i;
/* lower and uppoer boundary for assertion */
int64_t lo = CONFIG_TEST_CLOCK_RT_SLEEP_MS;
int64_t hi = CONFIG_TEST_CLOCK_RT_SLEEP_MS + CONFIG_TEST_CLOCK_RT_ERROR_MS;
/* lower and upper watermark */
int64_t lo_wm = INT64_MAX;
int64_t hi_wm = INT64_MIN;

/* Loop n times, sleeping a little bit for each */
(void)clock_gettime(CLOCK_REALTIME, &then);
for (int i = 0; i < CONFIG_TEST_CLOCK_RT_ITERATIONS; ++i) {

zassert_ok(k_usleep(USEC_PER_MSEC * CONFIG_TEST_CLOCK_RT_SLEEP_MS));
(void)clock_gettime(CLOCK_REALTIME, &now);

/* Make the delta milliseconds. */
x_i = tp_diff(&now, &then) / NSEC_PER_MSEC;
then = now;

if (x_i < lo_wm) {
/* update low watermark */
lo_wm = x_i;
}

if (x_i > hi_wm) {
/* update high watermark */
hi_wm = x_i;
}

/* compute cumulative running average */
cma = (x_i + i * cma_prev) / (i + 1);
cma_prev = cma;
}

LOG_INF("n: %d, sleep: %d, margin: %d, lo: %lld, avg: %lld, hi: %lld",
CONFIG_TEST_CLOCK_RT_ITERATIONS, CONFIG_TEST_CLOCK_RT_SLEEP_MS,
CONFIG_TEST_CLOCK_RT_ERROR_MS, lo_wm, cma, hi_wm);
zassert_between_inclusive(cma, lo, hi);
}

ZTEST(clock, test_clock_getcpuclockid)
{
int ret = 0;
clockid_t clock_id = CLOCK_INVALID;

ret = clock_getcpuclockid((pid_t)0, &clock_id);
zassert_equal(ret, 0, "POSIX clock_getcpuclock id failed");
zassert_equal(clock_id, CLOCK_PROCESS_CPUTIME_ID, "POSIX clock_getcpuclock id failed");

ret = clock_getcpuclockid((pid_t)2482, &clock_id);
zassert_equal(ret, EPERM, "POSIX clock_getcpuclock id failed");
}

ZTEST(clock, test_clock_getres)
{
int ret;
struct timespec res;
const struct timespec one_ns = {
.tv_sec = 0,
.tv_nsec = 1,
};

struct arg {
clockid_t clock_id;
struct timespec *res;
int expect;
};

const struct arg args[] = {
/* permuting over "invalid" inputs */
{CLOCK_INVALID, NULL, -1},
{CLOCK_INVALID, &res, -1},
{CLOCK_REALTIME, NULL, 0},
{CLOCK_MONOTONIC, NULL, 0},
{CLOCK_PROCESS_CPUTIME_ID, NULL, 0},

/* all valid inputs */
{CLOCK_REALTIME, &res, 0},
{CLOCK_MONOTONIC, &res, 0},
{CLOCK_PROCESS_CPUTIME_ID, &res, 0},
};

ARRAY_FOR_EACH_PTR(args, arg) {
errno = 0;
res = (struct timespec){0};
ret = clock_getres(arg->clock_id, arg->res);
zassert_equal(ret, arg->expect);
if (ret != 0) {
zassert_equal(errno, EINVAL);
continue;
}
if (arg->res != NULL) {
zassert_true(tp_ge(arg->res, &one_ns));
}
}
}

ZTEST_SUITE(clock, NULL, NULL, NULL, NULL, NULL);
11 changes: 11 additions & 0 deletions tests/posix/timers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(posix_timers)

FILE(GLOB app_sources src/*.c)

target_sources(app PRIVATE ${app_sources})

target_compile_options(app PRIVATE -U_POSIX_C_SOURCE -D_POSIX_C_SOURCE=200809L)
27 changes: 27 additions & 0 deletions tests/posix/timers/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (c) 2023, Meta
# SPDX-License-Identifier: Apache-2.0

# Options specific to clock.c / test_realtime

config TEST_CLOCK_RT_ITERATIONS
int "Number of iterations to check clock_gettime() reliability"
range 10 100
default 20
help
This option is specific to posix_apis.test_realtime in clock.c

config TEST_CLOCK_RT_SLEEP_MS
int "Time to sleep between iterations in milliseconds"
range 50 1000
default 100
help
This option is specific to posix_apis.test_realtime in clock.c

config TEST_CLOCK_RT_ERROR_MS
int "Maximum overshoot (error) in milliseconds"
range 10 500
default 10
help
This option is specific to posix_apis.test_realtime in clock.c

source "Kconfig.zephyr"
5 changes: 5 additions & 0 deletions tests/posix/timers/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CONFIG_POSIX_API=y
CONFIG_ZTEST=y

CONFIG_POSIX_AEP_CHOICE_BASE=y
CONFIG_POSIX_TIMERS=y
Loading

0 comments on commit c36c16d

Please sign in to comment.