From fe6555b680f579599ccf3cb73c6710bdf3047eef Mon Sep 17 00:00:00 2001 From: Tommi Rantanen Date: Tue, 24 Sep 2024 18:50:31 +0300 Subject: [PATCH] tests: lib: date_time: Tests for scheduled updates Adding tests for scheduled date-time updates verifying that they occur at configured intervals. Some small clean-up and additional logging into date-time library. Branch coverage is going from ~44% to ~98% having 3 branches untested. These are related to failure of clock_gettime/clock_settime which cannot really be achieved without creating a different test set and mocking those APIs. With default configuration, the tests run almost 30s due to update intervals that we need to wait. Jira: NCSDK-28887 Signed-off-by: Tommi Rantanen --- doc/nrf/libraries/others/date_time.rst | 8 + lib/date_time/date_time_core.c | 20 +- lib/date_time/date_time_modem.c | 18 +- tests/lib/date_time/prj.conf | 5 + tests/lib/date_time/src/main.c | 855 ++++++++++++++++++++++--- tests/lib/date_time/testcase.yaml | 25 + 6 files changed, 823 insertions(+), 108 deletions(-) diff --git a/doc/nrf/libraries/others/date_time.rst b/doc/nrf/libraries/others/date_time.rst index 51351395cbb9..456715cd6de9 100644 --- a/doc/nrf/libraries/others/date_time.rst +++ b/doc/nrf/libraries/others/date_time.rst @@ -57,6 +57,14 @@ See the API documentation for more information on these functions. If an application has time-dependent operations immediately after connecting to the LTE network, it should wait for a confirmation indicating that time has been updated. If the :kconfig:option:`CONFIG_DATE_TIME_AUTO_UPDATE` option is not set, the first date-time update cycle (after boot) does not occur until the time set by the :kconfig:option:`CONFIG_DATE_TIME_UPDATE_INTERVAL_SECONDS` option has elapsed. +.. note:: + + Exceptions to the regular date-time update interval set by the :kconfig:option:`CONFIG_DATE_TIME_UPDATE_INTERVAL_SECONDS` Kconfig option occur when + the :c:func:`date_time_update_async` function is called and a new date-time update is triggered and scheduled. + Either retry or regular update interval is used depending on the outcome of the date-time update procedure. + Date-time update from modem through an ``AT%XTIME`` notification, + or from the client through the :c:func:`date_time_set` function does not disturb the regular update interval. + Configuration ************* diff --git a/lib/date_time/date_time_core.c b/lib/date_time/date_time_core.c index 0953e6e062b5..dbcbcfdba44d 100644 --- a/lib/date_time/date_time_core.c +++ b/lib/date_time/date_time_core.c @@ -59,11 +59,18 @@ static void date_time_core_notify_event(enum date_time_evt_type time_source) if (app_evt_handler != NULL) { app_evt_handler(&evt); + } else { + LOG_DBG("No date-time event handler registered"); } } static int date_time_core_schedule_work(int interval) { + if (!IS_ENABLED(CONFIG_DATE_TIME_MODEM) && !IS_ENABLED(CONFIG_DATE_TIME_NTP)) { + LOG_DBG("Skipping requested date time update, modem and NTP are disabled"); + return -ENOTSUP; + } + /* If a scheduled update is blocking reschedules, exit. * Otherwise set the reschedule_blocked flag to true, then proceed with the reschedule. */ @@ -104,10 +111,11 @@ static void date_time_core_schedule_retry(void) return; } - if (date_time_core_schedule_work(CONFIG_DATE_TIME_RETRY_INTERVAL_SECONDS) == 0) { - LOG_DBG("Date time update retry in: %d seconds", - CONFIG_DATE_TIME_RETRY_INTERVAL_SECONDS); - } + /* Scheduling new update cannot fail because we are never doing retries + * if we have fresh enough time + */ + date_time_core_schedule_work(CONFIG_DATE_TIME_RETRY_INTERVAL_SECONDS); + LOG_DBG("Date time update retry in: %d seconds", CONFIG_DATE_TIME_RETRY_INTERVAL_SECONDS); } static void date_time_update_work_fn(struct k_work *work) @@ -169,6 +177,8 @@ void date_time_lte_ind_handler(const struct lte_lc_evt *const evt) case LTE_LC_NW_REG_REGISTERED_HOME: case LTE_LC_NW_REG_REGISTERED_ROAMING: if (!date_time_is_valid()) { + LOG_DBG("Date time update scheduled in 1 second " + "due to LTE registration"); k_work_reschedule_for_queue( &date_time_work_q, &date_time_update_work, @@ -241,6 +251,8 @@ int date_time_core_now_local(int64_t *local_time_ms) int date_time_core_update_async(date_time_evt_handler_t evt_handler) { + LOG_DBG("Requesting date-time update asynchronously"); + if (evt_handler) { app_evt_handler = evt_handler; } else if (app_evt_handler == NULL) { diff --git a/lib/date_time/date_time_modem.c b/lib/date_time/date_time_modem.c index 594841e2e910..23c63eafd0a8 100644 --- a/lib/date_time/date_time_modem.c +++ b/lib/date_time/date_time_modem.c @@ -76,7 +76,7 @@ int date_time_modem_get(int64_t *date_time_ms, int *date_time_tz) /* Want to match 6 or 7 args */ if (rc != 6 && rc != 7) { LOG_WRN("Did not get time from cellular network (error: %d). " - "This is normal as some cellular networks don't provide it or " + "This may be normal as some cellular networks don't provide it or " "time may not be available yet.", rc); return -ENODATA; } @@ -125,9 +125,6 @@ static void date_time_at_xtime_handler(const char *notif) int err; int tz; - if (notif == NULL) { - return; - } modem_valid_network_time = true; /* Check if current time is valid */ @@ -163,7 +160,8 @@ static void date_time_at_xtime_handler(const char *notif) time_buf_len = hex2bin(time_str_start, 14, time_buf, sizeof(time_buf)); if (time_buf_len < sizeof(time_buf)) { - LOG_ERR("%%XTIME notification decoding failed (ret=%d): %s", time_buf_len, notif); + LOG_ERR("Time value decoding failed from %%XTIME notification (ret=%d): %s", + time_buf_len, notif); return; } @@ -174,6 +172,12 @@ static void date_time_at_xtime_handler(const char *notif) date_time.tm_min = semioctet_to_dec(time_buf[4]); date_time.tm_sec = semioctet_to_dec(time_buf[5]); + /* 3GPP TS 23.040 Section 9.2.3.11 says about the time zone as follows: + * The Time Zone indicates the difference, expressed in quarters of an hour, + * between the local time and GMT. In the first of the two semi octets, + * the first bit (bit 3 of the seventh octet of the TP Service Centre Time Stamp field) + * represents the algebraic sign of this difference (0: positive, 1: negative). + */ tz = semioctet_to_dec(time_buf[6] & 0xF7); if (time_buf[6] & 0x08) { tz = -tz; @@ -238,9 +242,13 @@ void date_time_modem_xtime_subscribe_work_fn(struct k_work *work_item) } } +#if defined(CONFIG_UNITY) +void date_time_modem_on_cfun(int mode, void *ctx) +#else NRF_MODEM_LIB_ON_CFUN(date_time_cfun_hook, date_time_modem_on_cfun, NULL); static void date_time_modem_on_cfun(int mode, void *ctx) +#endif { ARG_UNUSED(ctx); diff --git a/tests/lib/date_time/prj.conf b/tests/lib/date_time/prj.conf index 6753a689cb5e..7b3f8b41c672 100644 --- a/tests/lib/date_time/prj.conf +++ b/tests/lib/date_time/prj.conf @@ -14,6 +14,11 @@ CONFIG_MOCK_NRF_MODEM_AT=y CONFIG_LTE_LINK_CONTROL=y CONFIG_POSIX_API=y +CONFIG_DATE_TIME_UPDATE_INTERVAL_SECONDS=3 +CONFIG_DATE_TIME_TOO_OLD_SECONDS=1 +CONFIG_DATE_TIME_RETRY_COUNT=2 +CONFIG_DATE_TIME_RETRY_INTERVAL_SECONDS=1 + # Enable logs if you want to explore them CONFIG_LOG=n CONFIG_DATE_TIME_LOG_LEVEL_DBG=n diff --git a/tests/lib/date_time/src/main.c b/tests/lib/date_time/src/main.c index 1d271c6252da..5bdd5c3e97ee 100644 --- a/tests/lib/date_time/src/main.c +++ b/tests/lib/date_time/src/main.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -16,17 +18,15 @@ #include #include "cmock_nrf_modem_at.h" +#include "cmock_socket.h" +#include "cmock_sntp.h" -#define TEST_EVENT_MAX_COUNT 10 - -struct test_date_time_cb { - enum date_time_evt_type type; -}; - -struct test_date_time_cb test_date_time_cb_data[TEST_EVENT_MAX_COUNT] = {0}; +/* NOTE: These tests run for few tens of seconds because we are waiting for the + * date-time update and retry intervals. + */ -static int date_time_cb_count_occurred; -static int date_time_cb_count_expected; +#define TEST_EVENT_MAX_COUNT 10 +#define TEST_CB_WAIT_TIME (CONFIG_DATE_TIME_UPDATE_INTERVAL_SECONDS * 1000 + 1000) static void date_time_callback(const struct date_time_evt *evt); @@ -40,15 +40,80 @@ extern void at_monitor_dispatch(const char *at_notif); */ extern void date_time_modem_on_cfun(int mode, void *ctx); -K_SEM_DEFINE(date_time_callback_sem, 0, 1); +struct test_date_time_cb { + enum date_time_evt_type type; + int64_t uptime_start; + int64_t uptime_current; + int64_t time_expected; +}; + +static struct test_date_time_cb test_date_time_cb_data[TEST_EVENT_MAX_COUNT] = {0}; + +static int date_time_cb_count_occurred; +static int date_time_cb_count_expected; + +static K_SEM_DEFINE(date_time_callback_sem, 0, 1); + +static char at_notif[128]; + +/** Fri Aug 07 2020 15:11:30 UTC. */ +static struct tm date_time_global = { + .tm_year = 120, + .tm_mon = 7, + .tm_mday = 7, + .tm_hour = 15, + .tm_min = 11, + .tm_sec = 30 +}; +/** UNIX timestamp equivalent to tm structure date_time_global. */ +static int64_t date_time_global_unix = 1596813090000; + +#if defined(CONFIG_DATE_TIME_NTP) +static struct sockaddr ai_addr_uio_ntp = { + .sa_family = AF_INET, + .data = "100.101.102.103" +}; + +static struct zsock_addrinfo res_data_uio_ntp = { + .ai_addr = &ai_addr_uio_ntp, + .ai_addrlen = sizeof(struct sockaddr), +}; + +static struct zsock_addrinfo *res_uio_ntp = &res_data_uio_ntp; + +static struct sockaddr ai_addr_google_ntp = { + .sa_family = AF_INET, + .data = "1.2.3.4" +}; + +static struct zsock_addrinfo res_data_google_ntp = { + .ai_addr = &ai_addr_google_ntp, + .ai_addrlen = sizeof(struct sockaddr), +}; + +static struct zsock_addrinfo *res_google_ntp = &res_data_google_ntp; + +static struct zsock_addrinfo hints = { + .ai_flags = AI_NUMERICSERV, + .ai_family = AF_UNSPEC /* Allow both IPv4 and IPv6 addresses */ +}; + +static struct sntp_time sntp_time_value = { + .seconds = 42900180919421 +}; +#endif void setUp(void) { mock_nrf_modem_at_Init(); + memset(test_date_time_cb_data, 0, sizeof(test_date_time_cb_data)); + date_time_cb_count_occurred = 0; date_time_cb_count_expected = 0; + test_date_time_cb_data[0].uptime_start = k_uptime_get(); + date_time_register_handler(date_time_callback); } @@ -67,12 +132,22 @@ static void date_time_callback(const struct date_time_evt *evt) TEST_ASSERT_MESSAGE(date_time_cb_count_occurred < date_time_cb_count_expected, "date-time event callback called more times than expected"); + TEST_ASSERT_MESSAGE(date_time_cb_count_occurred < TEST_EVENT_MAX_COUNT, + "date-time event callback called more times than TEST_EVENT_MAX_COUNT"); + TEST_ASSERT_EQUAL(test_date_time_cb_data[date_time_cb_count_occurred].type, evt->type); + /* Check time when callback occurred compared to expected time since the test case start */ + TEST_ASSERT_INT64_WITHIN( + 100, + test_date_time_cb_data[date_time_cb_count_occurred].time_expected, + k_uptime_get() - test_date_time_cb_data[0].uptime_start); + date_time_cb_count_occurred++; k_sem_give(&date_time_callback_sem); } +/** Reset to: Fri Aug 07 2020 15:11:30 UTC. */ static void reset_to_valid_time(struct tm *time) { time->tm_year = 120; @@ -83,104 +158,81 @@ static void reset_to_valid_time(struct tm *time) time->tm_sec = 30; } -void test_date_time_invalid_input(void) +void test_date_time_set_invalid_input_fail(void) { int ret; struct tm date_time_dummy; reset_to_valid_time(&date_time_dummy); - /** Invalid year. */ + /** Invalid year */ date_time_dummy.tm_year = 2020; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); date_time_dummy.tm_year = 114; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); reset_to_valid_time(&date_time_dummy); - /**********************************************************************/ - - /** Invalid month. */ + /** Invalid month */ date_time_dummy.tm_mon = 12; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); date_time_dummy.tm_mon = -1; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); reset_to_valid_time(&date_time_dummy); - /**********************************************************************/ - - /** Invalid day. */ + /** Invalid day */ date_time_dummy.tm_mday = 0; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); date_time_dummy.tm_mday = 32; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); reset_to_valid_time(&date_time_dummy); - /**********************************************************************/ - - /** Invalid hour. */ + /** Invalid hour */ date_time_dummy.tm_hour = -1; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); date_time_dummy.tm_hour = 24; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); reset_to_valid_time(&date_time_dummy); - /**********************************************************************/ - /** Invalid minutes. */ date_time_dummy.tm_min = -1; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); date_time_dummy.tm_min = 60; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); reset_to_valid_time(&date_time_dummy); - /**********************************************************************/ - - /** Invalid seconds. */ + /** Invalid seconds */ date_time_dummy.tm_sec = -1; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); date_time_dummy.tm_sec = 62; - ret = date_time_set(&date_time_dummy); TEST_ASSERT_EQUAL(-EINVAL, ret); reset_to_valid_time(&date_time_dummy); - } -void test_date_time_null_input(void) +void test_date_time_null_input_fail(void) { int ret; @@ -200,7 +252,7 @@ void test_date_time_null_input(void) TEST_ASSERT_EQUAL(-EINVAL, ret); } -void test_date_time_premature_request(void) +void test_date_time_no_valid_time_fail(void) { int ret; int64_t ts_unix_ms = 0; @@ -209,47 +261,40 @@ void test_date_time_premature_request(void) TEST_ASSERT_EQUAL(-ENODATA, ret); TEST_ASSERT_EQUAL(0, ts_unix_ms); - ret = date_time_uptime_to_unix_time_ms(&ts_unix_ms); + ret = date_time_now_local(&ts_unix_ms); TEST_ASSERT_EQUAL(-ENODATA, ret); TEST_ASSERT_EQUAL(0, ts_unix_ms); + ret = date_time_uptime_to_unix_time_ms(&ts_unix_ms); + TEST_ASSERT_EQUAL(-ENODATA, ret); + TEST_ASSERT_EQUAL(0, ts_unix_ms); } -void test_date_time_already_converted(void) +void test_date_time_uptime_to_unix_time_ms_already_converted(void) { + int ret; + /* Wait to get uptime non-zero for date_time_uptime_to_unix_time_ms() call */ k_sleep(K_MSEC(10)); date_time_register_handler(NULL); date_time_clear(); - int ret; - - date_time_register_handler(NULL); - - struct tm date_time_dummy = { - .tm_year = 120, - .tm_mon = 7, - .tm_mday = 7, - .tm_hour = 15, - .tm_min = 11, - .tm_sec = 30 - }; +#if defined(CONFIG_DATE_TIME_MODEM) __mock_nrf_modem_at_printf_ExpectAndReturn("AT+CCLK=\"20/08/07,15:11:30+99\"", 0); - - ret = date_time_set(&date_time_dummy); +#endif + ret = date_time_set(&date_time_global); TEST_ASSERT_EQUAL(0, ret); /** Fri Aug 07 2020 15:11:30 UTC. */ - int64_t ts_unix_ms = 1596813090000; - int64_t ts_unix_ms_prev = 1596813090000; + int64_t ts_unix_ms = date_time_global_unix; ret = date_time_uptime_to_unix_time_ms(&ts_unix_ms); TEST_ASSERT_EQUAL(-EINVAL, ret); - TEST_ASSERT_EQUAL(ts_unix_ms_prev, ts_unix_ms); + TEST_ASSERT_EQUAL(date_time_global_unix, ts_unix_ms); } -void test_date_time_negative_uptime(void) +void test_date_time_uptime_to_unix_time_ms_negative_fail(void) { int ret; @@ -259,7 +304,7 @@ void test_date_time_negative_uptime(void) TEST_ASSERT_EQUAL(-EINVAL, ret); } -void test_date_time_clear(void) +void test_date_time_timestamp_clear(void) { int ret; @@ -275,38 +320,27 @@ void test_date_time_clear(void) TEST_ASSERT_EQUAL(0, ts_unix_ms); } -void test_date_time_conversion(void) +void test_date_time_uptime_to_unix_time_ms(void) { - date_time_register_handler(NULL); - date_time_clear(); - int ret; - struct tm date_time_dummy = { - .tm_year = 120, - .tm_mon = 7, - .tm_mday = 7, - .tm_hour = 15, - .tm_min = 11, - .tm_sec = 30 - }; - - /** UNIX timestamp equivalent to tm structure date_time_dummy. */ - /** Fri Aug 07 2020 15:11:30 UTC. */ - int64_t date_time_utc_unix = 1596813090000; - int64_t date_time_utc_unix_origin = k_uptime_get(); + int64_t date_time_global_unix_origin = k_uptime_get(); int64_t uptime = k_uptime_get(); int64_t ts_unix_ms = 0; int64_t ts_expect = 0; - __mock_nrf_modem_at_printf_ExpectAndReturn("AT+CCLK=\"20/08/07,15:11:30+99\"", 0); + date_time_register_handler(NULL); + date_time_clear(); - ret = date_time_set(&date_time_dummy); +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_printf_ExpectAndReturn("AT+CCLK=\"20/08/07,15:11:30+99\"", 0); +#endif + ret = date_time_set(&date_time_global); TEST_ASSERT_EQUAL(0, ret); ret = date_time_now(&ts_unix_ms); TEST_ASSERT_EQUAL(0, ret); - ts_expect = date_time_utc_unix - date_time_utc_unix_origin + k_uptime_get(); + ts_expect = date_time_global_unix - date_time_global_unix_origin + k_uptime_get(); /* We cannot compare exact conversions given by the date time library due to the fact that * the comparing values are based on k_uptime_get(). Use range instead and compare agains an @@ -324,7 +358,7 @@ void test_date_time_conversion(void) ret = date_time_uptime_to_unix_time_ms(&uptime); TEST_ASSERT_EQUAL(0, ret); - ts_expect = date_time_utc_unix - date_time_utc_unix_origin; + ts_expect = date_time_global_unix - date_time_global_unix_origin; TEST_ASSERT_INT64_WITHIN(100, ts_expect, uptime); @@ -333,7 +367,7 @@ void test_date_time_conversion(void) ret = date_time_uptime_to_unix_time_ms(&uptime); TEST_ASSERT_EQUAL(0, ret); - ts_expect = date_time_utc_unix - date_time_utc_unix_origin + k_uptime_get(); + ts_expect = date_time_global_unix - date_time_global_unix_origin + k_uptime_get(); TEST_ASSERT_INT64_WITHIN(100, ts_expect, uptime); @@ -344,40 +378,663 @@ void test_date_time_conversion(void) ret = date_time_uptime_to_unix_time_ms(&uptime); TEST_ASSERT_EQUAL(0, ret); - ts_expect = date_time_utc_unix - date_time_utc_unix_origin + k_uptime_get(); + ts_expect = date_time_global_unix - date_time_global_unix_origin + k_uptime_get(); TEST_ASSERT_INT64_WITHIN(100, ts_expect, uptime); } -void test_date_time_validity(void) +void test_date_time_is_valid(void) { + int ret; + int64_t ts_unix_ms = 0; + /* Wait to get uptime non-zero for last date_time_is_valid() call */ k_sleep(K_MSEC(10)); date_time_register_handler(NULL); date_time_clear(); - int ret; - struct tm date_time_dummy = { - .tm_year = 120, - .tm_mon = 7, - .tm_mday = 7, - .tm_hour = 15, - .tm_min = 11, - .tm_sec = 30 - }; - ret = date_time_is_valid(); TEST_ASSERT_EQUAL(false, ret); + /* Local time not valid here because there is no valid time */ + ret = date_time_is_valid_local(); + TEST_ASSERT_EQUAL(false, ret); + +#if defined(CONFIG_DATE_TIME_MODEM) __mock_nrf_modem_at_printf_ExpectAndReturn("AT+CCLK=\"20/08/07,15:11:30+99\"", 0); +#endif + ret = date_time_set(&date_time_global); + TEST_ASSERT_EQUAL(0, ret); - /** UNIX timestamp equavivalent to tm structure date_time_dummy. */ - /** Fri Aug 07 2020 15:11:30 UTC. */ - ret = date_time_set(&date_time_dummy); + ret = date_time_is_valid(); + TEST_ASSERT_EQUAL(true, ret); + + /* Local time still not valid here because timezone is not set with date_time_set() + * but it requires modem time so that's checked elsewhere. + */ + ret = date_time_is_valid_local(); + TEST_ASSERT_EQUAL(false, ret); + + ret = date_time_now(&ts_unix_ms); TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_INT64_WITHIN(100, date_time_global_unix, ts_unix_ms); + + ts_unix_ms = 0; + ret = date_time_now_local(&ts_unix_ms); + TEST_ASSERT_EQUAL(-EAGAIN, ret); + TEST_ASSERT_EQUAL(0, ts_unix_ms); +} + +void test_date_time_xtime_subscribe_fail(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) + TEST_IGNORE(); +#endif + /* %XTIME subscription not sent with wrong functional mode */ + date_time_modem_on_cfun(LTE_LC_FUNC_MODE_OFFLINE, NULL); + k_sleep(K_MSEC(1)); + + /* %XTIME subscription fails */ + __mock_nrf_modem_at_printf_ExpectAndReturn("AT%XTIME=1", -ENOMEM); + date_time_modem_on_cfun(LTE_LC_FUNC_MODE_NORMAL, NULL); + k_sleep(K_MSEC(1)); +} + +/** + * Test initial auto update 1 second from the boot. + * Using modem or NTP time depending on the configuration. + * NTP is used if both are configured because modem time is used in that case only + * if XTIME notification has been received, which is not the case here. + * + * Note: This test must be before any %XTIME notification tests because it will set + * modem_valid_network_time and we cannot revert it back to 'false' anymore. + */ +void test_date_time_initial_auto_update_at_1s_from_boot(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) && !defined(CONFIG_DATE_TIME_NTP) + TEST_IGNORE(); +#endif + date_time_cb_count_expected = 1; +#if defined(CONFIG_DATE_TIME_NTP) + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_NTP; +#else /* CONFIG_DATE_TIME_MODEM */ + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_MODEM; +#endif + test_date_time_cb_data[0].time_expected = 1000; + date_time_clear(); + +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_printf_ExpectAndReturn("AT%XTIME=1", 0); + date_time_modem_on_cfun(LTE_LC_FUNC_MODE_NORMAL, NULL); + + k_sleep(K_MSEC(1)); +#endif + +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", 1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_REGISTERED_HOME); + + __cmock_zsock_getaddrinfo_ExpectAndReturn("ntp.uio.no", "123", &hints, NULL, 0); + __cmock_zsock_getaddrinfo_IgnoreArg_res(); + __cmock_zsock_getaddrinfo_ReturnThruPtr_res(&res_uio_ntp); + + __cmock_sntp_init_ExpectAndReturn(NULL, &ai_addr_uio_ntp, sizeof(struct sockaddr), 0); + __cmock_sntp_init_IgnoreArg_ctx(); + + __cmock_sntp_query_ExpectAndReturn(NULL, 5000, NULL, 0); + __cmock_sntp_query_IgnoreArg_ctx(); + __cmock_sntp_query_IgnoreArg_time(); + __cmock_sntp_query_ReturnThruPtr_time(&sntp_time_value); + + __cmock_zsock_freeaddrinfo_ExpectAnyArgs(); + __cmock_sntp_close_ExpectAnyArgs(); +#else /* CONFIG_DATE_TIME_MODEM */ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 7); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(12); +#endif + +#if defined(CONFIG_DATE_TIME_MODEM) && defined(CONFIG_DATE_TIME_NTP) + /* Setting modem time fails */ + __mock_nrf_modem_at_printf_ExpectAndReturn("AT+CCLK=\"22/08/13,18:03:41+99\"", -ENOMEM); +#endif + strcpy(at_notif, "+CEREG: 1,\"002F\",\"0012BEEF\",7,,,\"00000101\",\"00010011\"\r\n"); + at_monitor_dispatch(at_notif); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +/** Test initial auto update from modem. */ +void test_date_time_initial_auto_update_xtime_notif(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) + TEST_IGNORE(); +#endif + int ret; + + date_time_cb_count_expected = 1; + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_MODEM; + + date_time_clear(); + + ret = date_time_is_valid(); + TEST_ASSERT_EQUAL(false, ret); + + ret = date_time_is_valid_local(); + TEST_ASSERT_EQUAL(false, ret); + + __mock_nrf_modem_at_printf_ExpectAndReturn("AT%XTIME=1", 0); + date_time_modem_on_cfun(LTE_LC_FUNC_MODE_ACTIVATE_LTE, NULL); + + k_sleep(K_MSEC(1)); + + /* Negative timezone. */ + strcpy(at_notif, "%XTIME: \"0A\",\"4290018091940A\",\"01\"\r\n"); + at_monitor_dispatch(at_notif); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); ret = date_time_is_valid(); TEST_ASSERT_EQUAL(true, ret); + + ret = date_time_is_valid_local(); + TEST_ASSERT_EQUAL(true, ret); +} + +/** Test update from modem. */ +void test_date_time_1st_update_modem(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) + TEST_IGNORE(); +#endif + date_time_cb_count_expected = 1; + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[0].time_expected = 3000; + + /* Not home or roaming so ignored. */ + strcpy(at_notif, "+CEREG: 2\r\n"); + at_monitor_dispatch(at_notif); + k_sleep(K_MSEC(1)); + + strcpy(at_notif, "+CEREG: 5,\"002F\",\"0012BEEF\",7,,,\"00000101\",\"00010011\"\r\n"); + at_monitor_dispatch(at_notif); + k_sleep(K_MSEC(1)); + + /* %XTIME notification ignored because current time is not too old */ + k_sleep(K_MSEC(300)); + strcpy(at_notif, "%XTIME: ,\"42900180919421\",\"01\"\r\n"); + at_monitor_dispatch(at_notif); + k_sleep(K_MSEC(1)); + + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 7); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(12); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +/* This is after XTIME test because we get timezone there so local time works. */ +void test_date_time_now_local(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) + TEST_IGNORE(); +#endif + int ret; + int64_t ts_unix_ms = 0; + + ret = date_time_is_valid_local(); + TEST_ASSERT_EQUAL(true, ret); + + ret = date_time_now_local(&ts_unix_ms); + TEST_ASSERT_EQUAL(0, ret); + + /* TODO: Verify the time */ +} + +/** Test initial auto update from modem. */ +void test_date_time_use_previously_obtained_time(void) +{ + /* Previously found time is available and source is the same */ + date_time_cb_count_expected = 1; +#if defined(CONFIG_DATE_TIME_MODEM) + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_MODEM; +#elif defined(CONFIG_DATE_TIME_NTP) + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_NTP; +#else + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_EXT; +#endif + + date_time_update_async(NULL); + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +K_SEM_DEFINE(date_time_callback_custom_sem, 0, 1); + +/** Callback that date_time library will call when an event is received. */ +static void date_time_callback_custom(const struct date_time_evt *evt) +{ + /* Verify that type is previously returned type */ +#if defined(CONFIG_DATE_TIME_MODEM) + TEST_ASSERT_EQUAL(DATE_TIME_OBTAINED_MODEM, evt->type); +#elif defined(CONFIG_DATE_TIME_NTP) + TEST_ASSERT_EQUAL(DATE_TIME_OBTAINED_NTP, evt->type); +#endif + k_sem_give(&date_time_callback_custom_sem); +} + +void test_date_time_update_async_different_handler(void) +{ + /* Normal handler not used in this test case so no callbacks there */ + date_time_cb_count_expected = 0; + + /* Custom date-time callback handler */ + date_time_update_async(date_time_callback_custom); + k_sem_take(&date_time_callback_custom_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* No date-time callback handler at all. We cannot really verify that the procedure has + * been executed properly but at least we can check that it doesn't crash or send events. + */ + date_time_register_handler(NULL); + date_time_update_async(NULL); + k_sleep(K_MSEC(1)); +} + +void test_date_time_set_dont_set_modem_time_when_it_exists(void) +{ + int ret; + int64_t ts_unix_ms = 0; + + date_time_cb_count_expected = 1; + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_EXT; + test_date_time_cb_data[0].time_expected = 0; + + /* Modem has time so check that modem time is not set anymore with "AT+CCLK="*/ + ret = date_time_set(&date_time_global); + TEST_ASSERT_EQUAL(0, ret); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + ret = date_time_now(&ts_unix_ms); + TEST_ASSERT_EQUAL(0, ret); + + TEST_ASSERT_INT64_WITHIN(100, date_time_global_unix, ts_unix_ms); +} + +void test_date_time_update_cycle_and_async(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) + TEST_IGNORE(); +#endif + date_time_cb_count_expected = 6; + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[0].time_expected = 3000; + test_date_time_cb_data[1].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[1].time_expected = 3500; + test_date_time_cb_data[2].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[2].time_expected = 5000; + test_date_time_cb_data[3].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[3].time_expected = 8000; + test_date_time_cb_data[4].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[4].time_expected = 9000; + test_date_time_cb_data[5].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[5].time_expected = 11000; + + /* Normal cycle at 3s */ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 7); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(12); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Asynchronous update with previous time at 3.5s */ + k_sleep(K_MSEC(500)); + date_time_update_async(NULL); + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Asynchronous update at 5s*/ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 6); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + + k_sleep(K_MSEC(1500)); + date_time_update_async(NULL); + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Normal cycle at 8s*/ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 7); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(12); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Time taken into use from %XTIME notification at 9s */ + k_sleep(K_MSEC(1000)); + strcpy(at_notif, "%XTIME: ,\"42900180919421\",\"01\"\r\n"); + at_monitor_dispatch(at_notif); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* XTIME doesn't delay normal cycle unlike date_time_update_async */ + + /* Normal cycle at 11s */ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 7); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(12); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +void test_date_time_update_cycle_with_failing_async(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) + TEST_IGNORE(); +#endif + date_time_cb_count_expected = 5; + test_date_time_cb_data[0].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[0].time_expected = 3000; + test_date_time_cb_data[1].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[1].time_expected = 4000; + test_date_time_cb_data[2].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[2].time_expected = 5000; + test_date_time_cb_data[3].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[3].time_expected = 6000; + test_date_time_cb_data[4].type = DATE_TIME_OBTAINED_MODEM; + test_date_time_cb_data[4].time_expected = 9000; + + /* Normal cycle at 3s */ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 7); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(12); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Failing asynchronous update at 4s */ + k_sleep(K_MSEC(1000)); + + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", -ENOMEM); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_UNKNOWN); +#endif + date_time_update_async(NULL); + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Failing retry after asynchronous update at 5s */ + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", -ENOMEM); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_UNKNOWN); +#endif + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Failing retry after asynchronous update at 6s */ + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", -ENOMEM); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_UNKNOWN); +#endif + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* Normal cycle at 6s*/ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", 7); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(24); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(30); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(20); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(40); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(52); + __mock_nrf_modem_at_scanf_ReturnVarg_uint32(12); + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +/** Test all retries failing with different NTP failures. */ +void test_date_time_update_all_retry_ntp_fail(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) && !defined(CONFIG_DATE_TIME_NTP) + TEST_IGNORE(); +#endif + date_time_cb_count_expected = 3; + test_date_time_cb_data[0].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[0].time_expected = 3000; + test_date_time_cb_data[1].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[1].time_expected = 4000; + test_date_time_cb_data[2].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[2].time_expected = 4500; + + /* 1st date-time update */ +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#endif +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", 1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_REGISTERED_HOME); + + /* NTP fails in NTP query for UIO */ + __cmock_zsock_getaddrinfo_ExpectAndReturn("ntp.uio.no", "123", &hints, NULL, 0); + __cmock_zsock_getaddrinfo_IgnoreArg_res(); + __cmock_zsock_getaddrinfo_ReturnThruPtr_res(&res_uio_ntp); + + __cmock_sntp_init_ExpectAnyArgsAndReturn(0); + __cmock_sntp_query_ExpectAndReturn(NULL, 5000, NULL, -1); + __cmock_sntp_query_IgnoreArg_ctx(); + __cmock_sntp_query_IgnoreArg_time(); + __cmock_sntp_query_ReturnThruPtr_time(&sntp_time_value); + + __cmock_zsock_freeaddrinfo_ExpectAnyArgs(); + __cmock_sntp_close_ExpectAnyArgs(); + + /* NTP fails in DNS query for Google */ + __cmock_zsock_getaddrinfo_ExpectAndReturn("time.google.com", "123", &hints, NULL, -1); + __cmock_zsock_getaddrinfo_IgnoreArg_res(); + __cmock_zsock_getaddrinfo_ReturnThruPtr_res(&res_google_ntp); +#endif + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* 1st retry */ +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#endif +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", 1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_REGISTERED_ROAMING); + + /* NTP fails in SNTP init for UIO */ + __cmock_zsock_getaddrinfo_ExpectAndReturn("ntp.uio.no", "123", &hints, NULL, 0); + __cmock_zsock_getaddrinfo_IgnoreArg_res(); + __cmock_zsock_getaddrinfo_ReturnThruPtr_res(&res_uio_ntp); + + __cmock_sntp_init_ExpectAnyArgsAndReturn(-1); + + __cmock_zsock_freeaddrinfo_ExpectAnyArgs(); + __cmock_sntp_close_ExpectAnyArgs(); + + /* NTP fails in NTP query for Google */ + __cmock_zsock_getaddrinfo_ExpectAndReturn("time.google.com", "123", &hints, NULL, 0); + __cmock_zsock_getaddrinfo_IgnoreArg_res(); + __cmock_zsock_getaddrinfo_ReturnThruPtr_res(&res_google_ntp); + + __cmock_sntp_init_ExpectAnyArgsAndReturn(0); + __cmock_sntp_query_ExpectAndReturn(NULL, 5000, NULL, -1); + __cmock_sntp_query_IgnoreArg_ctx(); + __cmock_sntp_query_IgnoreArg_time(); + __cmock_sntp_query_ReturnThruPtr_time(&sntp_time_value); + + __cmock_zsock_freeaddrinfo_ExpectAnyArgs(); + __cmock_sntp_close_ExpectAnyArgs(); +#endif + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* 2nd retry with asynchronous update at 4.5s */ +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#endif +#if defined(CONFIG_DATE_TIME_NTP) + /* NTP not even tried because no connection to LTE network */ + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", 1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_REGISTERED_HOME); + + /* NTP fails in NTP query for UIO */ + __cmock_zsock_getaddrinfo_ExpectAndReturn("ntp.uio.no", "123", &hints, NULL, 0); + __cmock_zsock_getaddrinfo_IgnoreArg_res(); + __cmock_zsock_getaddrinfo_ReturnThruPtr_res(&res_uio_ntp); + + __cmock_sntp_init_ExpectAnyArgsAndReturn(0); + __cmock_sntp_query_ExpectAndReturn(NULL, 5000, NULL, -1); + __cmock_sntp_query_IgnoreArg_ctx(); + __cmock_sntp_query_IgnoreArg_time(); + __cmock_sntp_query_ReturnThruPtr_time(&sntp_time_value); + + __cmock_zsock_freeaddrinfo_ExpectAnyArgs(); + __cmock_sntp_close_ExpectAnyArgs(); + + /* NTP fails in NTP query for Google */ + __cmock_zsock_getaddrinfo_ExpectAndReturn("time.google.com", "123", &hints, NULL, 0); + __cmock_zsock_getaddrinfo_IgnoreArg_res(); + __cmock_zsock_getaddrinfo_ReturnThruPtr_res(&res_google_ntp); + + __cmock_sntp_init_ExpectAnyArgsAndReturn(0); + __cmock_sntp_query_ExpectAndReturn(NULL, 5000, NULL, -1); + __cmock_sntp_query_IgnoreArg_ctx(); + __cmock_sntp_query_IgnoreArg_time(); + __cmock_sntp_query_ReturnThruPtr_time(&sntp_time_value); + + __cmock_zsock_freeaddrinfo_ExpectAnyArgs(); + __cmock_sntp_close_ExpectAnyArgs(); +#endif + k_sleep(K_MSEC(500)); + date_time_update_async(NULL); + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +/* Test all retries failing due to LTE status checked by NTP procedure. */ +void test_date_time_update_all_retry_ntp_ltestatus_fail(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) && !defined(CONFIG_DATE_TIME_NTP) + TEST_IGNORE(); +#endif + date_time_cb_count_expected = 3; + test_date_time_cb_data[0].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[0].time_expected = 3000; + test_date_time_cb_data[1].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[1].time_expected = 4000; + test_date_time_cb_data[2].type = DATE_TIME_NOT_OBTAINED; + test_date_time_cb_data[2].time_expected = 5000; + + /* 1st trial */ +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#endif +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", -ENOMEM); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_UNKNOWN); +#endif + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* 1st retry */ +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#endif +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", 1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_UNKNOWN); +#endif + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); + + /* 2nd retry */ +#if defined(CONFIG_DATE_TIME_MODEM) + __mock_nrf_modem_at_scanf_ExpectAndReturn( + "AT+CCLK?", "+CCLK: \"%u/%u/%u,%u:%u:%u%d", -ENOMEM); +#endif +#if defined(CONFIG_DATE_TIME_NTP) + __mock_nrf_modem_at_scanf_ExpectAndReturn("AT+CEREG?", "+CEREG: %*u,%hu,%*[^,],\"%x\",", 1); + __mock_nrf_modem_at_scanf_ReturnVarg_uint16(LTE_LC_NW_REG_SEARCHING); +#endif + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +/* Test that the scheduled updates are not done when modem and NTP time are disabled. */ +void test_date_time_update_cycle_no_ntp_no_modem(void) +{ +#if defined(CONFIG_DATE_TIME_MODEM) || defined(CONFIG_DATE_TIME_NTP) + TEST_IGNORE(); +#endif + date_time_cb_count_expected = 0; + + k_sem_take(&date_time_callback_sem, K_MSEC(TEST_CB_WAIT_TIME)); +} + +/** Test initial auto update from modem. */ +void test_date_time_xtime_notif_fail(void) +{ +#if !defined(CONFIG_DATE_TIME_MODEM) + TEST_IGNORE(); +#endif + /* No comma */ + strcpy(at_notif, "%XTIME: \"42900180919421\" \"01\"\r\n"); + at_monitor_dispatch(at_notif); + k_sleep(K_MSEC(1)); + + /* Too short */ + strcpy(at_notif, "%XTIME: ,\"321\",\"01\"\r\n"); + at_monitor_dispatch(at_notif); + k_sleep(K_MSEC(1)); + + /* Time value contains letters */ + strcpy(at_notif, "%XTIME: ,\"42900180moikka\",\"01\"\r\n"); + at_monitor_dispatch(at_notif); + k_sleep(K_MSEC(1)); + + /* No double quotes for time value */ + strcpy(at_notif, "%XTIME: ,42900180919421,\"01\"\r\n"); + at_monitor_dispatch(at_notif); + k_sleep(K_MSEC(1)); } /* This is needed because AT Monitor library is initialized in SYS_INIT. */ diff --git a/tests/lib/date_time/testcase.yaml b/tests/lib/date_time/testcase.yaml index 4480758f1d72..5d503f5501d5 100644 --- a/tests/lib/date_time/testcase.yaml +++ b/tests/lib/date_time/testcase.yaml @@ -5,3 +5,28 @@ tests: integration_platforms: - native_sim tags: date_time_unity sysbuild ci_tests_lib_date_time_unity + date_time.unit_test.no_modem_time: + sysbuild: true + platform_allow: native_sim + integration_platforms: + - native_sim + extra_configs: + - CONFIG_DATE_TIME_MODEM=n + tags: date_time_unity sysbuild ci_tests_lib_date_time_unity + date_time.unit_test.no_ntp_time: + sysbuild: true + platform_allow: native_sim + integration_platforms: + - native_sim + extra_configs: + - CONFIG_DATE_TIME_NTP=n + tags: date_time_unity sysbuild ci_tests_lib_date_time_unity + date_time.unit_test.no_modem_or_ntp_time: + sysbuild: true + platform_allow: native_sim + integration_platforms: + - native_sim + extra_configs: + - CONFIG_DATE_TIME_MODEM=n + - CONFIG_DATE_TIME_NTP=n + tags: date_time_unity sysbuild ci_tests_lib_date_time_unity