blob: 9358d373b7ff85ce783fdb7dc5bf9228510c95e0 [file] [log] [blame]
/*
* Copyright (c) 2018 Nordic Semiconductor
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Test log core
*
*/
#include <tc_util.h>
#include <stdbool.h>
#include <zephyr.h>
#include <ztest.h>
#include <logging/log_backend.h>
#include <logging/log_ctrl.h>
#include <logging/log.h>
#include "test_module.h"
#define LOG_MODULE_NAME test
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
typedef void (*custom_put_callback_t)(struct log_backend const *const backend,
struct log_msg *msg, size_t counter);
static bool in_panic;
struct backend_cb {
size_t counter;
bool panic;
bool keep_msgs;
bool check_id;
uint32_t exp_id[100];
bool check_timestamp;
uint32_t exp_timestamps[100];
bool check_strdup;
bool exp_strdup[100];
custom_put_callback_t callback;
uint32_t total_drops;
};
static void put(struct log_backend const *const backend,
struct log_msg *msg)
{
log_msg_get(msg);
struct backend_cb *cb = (struct backend_cb *)backend->cb->ctx;
if (cb->check_id) {
uint32_t exp_id = cb->exp_id[cb->counter];
zassert_equal(log_msg_source_id_get(msg),
exp_id,
"Unexpected source_id");
}
if (cb->check_timestamp) {
uint32_t exp_timestamp = cb->exp_timestamps[cb->counter];
zassert_equal(log_msg_timestamp_get(msg),
exp_timestamp,
"Unexpected message index");
}
if (cb->check_strdup) {
zassert_false(cb->exp_strdup[cb->counter]
^ log_is_strdup((void *)log_msg_arg_get(msg, 0)),
NULL);
}
if (cb->callback) {
cb->callback(backend, msg, cb->counter);
}
cb->counter++;
if (!cb->keep_msgs) {
log_msg_put(msg);
}
}
static void panic(struct log_backend const *const backend)
{
struct backend_cb *cb = (struct backend_cb *)backend->cb->ctx;
cb->panic = true;
}
static void dropped(struct log_backend const *const backend, uint32_t cnt)
{
struct backend_cb *cb = (struct backend_cb *)backend->cb->ctx;
cb->total_drops += cnt;
}
const struct log_backend_api log_backend_test_api = {
.put = put,
.panic = panic,
.dropped = dropped,
};
LOG_BACKEND_DEFINE(backend1, log_backend_test_api, false);
struct backend_cb backend1_cb;
LOG_BACKEND_DEFINE(backend2, log_backend_test_api, false);
struct backend_cb backend2_cb;
static uint32_t stamp;
static uint32_t test_source_id;
static uint32_t timestamp_get(void)
{
return stamp++;
}
/**
* @brief Function for finding source ID based on source name.
*
* @param name Source name
*
* @return Source ID.
*/
static int16_t log_source_id_get(const char *name)
{
for (int16_t i = 0; i < log_src_cnt_get(CONFIG_LOG_DOMAIN_ID); i++) {
if (strcmp(log_source_name_get(CONFIG_LOG_DOMAIN_ID, i), name)
== 0) {
return i;
}
}
return -1;
}
static void log_setup(bool backend2_enable)
{
stamp = 0U;
zassert_false(in_panic, "Logger in panic state.");
log_init();
zassert_equal(0, log_set_timestamp_func(timestamp_get, 0),
"Expects successful timestamp function setting.");
memset(&backend1_cb, 0, sizeof(backend1_cb));
log_backend_enable(&backend1, &backend1_cb, LOG_LEVEL_DBG);
if (backend2_enable) {
memset(&backend2_cb, 0, sizeof(backend2_cb));
log_backend_enable(&backend2, &backend2_cb, LOG_LEVEL_DBG);
} else {
log_backend_disable(&backend2);
}
test_source_id = log_source_id_get(STRINGIFY(LOG_MODULE_NAME));
}
static void test_log_strdup_gc(void)
{
char test_str[] = "test string";
char *dstr;
uint32_t size_u0, size_u1, size_cu0, size_cu1, size_l0, size_l1;
log_setup(false);
BUILD_ASSERT(CONFIG_LOG_STRDUP_BUF_COUNT == 1,
"Test assumes certain configuration");
backend1_cb.check_strdup = true;
backend1_cb.exp_strdup[0] = true;
backend1_cb.exp_strdup[1] = false;
size_l0 = log_get_strdup_longest_string();
size_u0 = log_get_strdup_pool_utilization();
size_cu0 = log_get_strdup_pool_current_utilization();
dstr = log_strdup(test_str);
/* test if message freeing is not fooled by using value within strdup
* buffer pool but with different format specifier.
*/
LOG_INF("%s %p", dstr, dstr + 1);
LOG_INF("%s", log_strdup(test_str));
while (log_process(false)) {
}
zassert_equal(2, backend1_cb.counter,
"Unexpected amount of messages received by the backend.");
/* Processing should free strdup buffer. */
backend1_cb.exp_strdup[2] = true;
LOG_INF("%s", log_strdup(test_str));
size_cu1 = log_get_strdup_pool_current_utilization();
while (log_process(false)) {
}
zassert_equal(3, backend1_cb.counter,
"Unexpected amount of messages received by the backend.");
size_l1 = log_get_strdup_longest_string();
size_u1 = log_get_strdup_pool_utilization();
zassert_true(size_l1 > size_l0, "longest string size never changed");
zassert_true(size_u1 > size_u0, "strdup pool utilization never changed");
zassert_true(size_cu1 > size_cu0,
"strdup pool current utilization never changed");
}
#define DETECT_STRDUP_MISSED(str, do_strdup, ...) \
{\
char tmp[] = "tmp";\
uint32_t exp_cnt = backend1_cb.counter + 1 + (do_strdup ? 0 : 1); \
LOG_ERR(str, ##__VA_ARGS__, do_strdup ? log_strdup(tmp) : tmp); \
\
while (log_process(false)) { \
} \
\
zassert_equal(exp_cnt, backend1_cb.counter,\
"Unexpected amount of messages received by the backend (%d).", \
backend1_cb.counter); \
}
static void test_log_strdup_detect_miss(void)
{
if (IS_ENABLED(CONFIG_LOG_DETECT_MISSED_STRDUP)) {
return;
}
log_setup(false);
DETECT_STRDUP_MISSED("%s", true);
DETECT_STRDUP_MISSED("%s", false);
DETECT_STRDUP_MISSED("%-20s", true);
DETECT_STRDUP_MISSED("%-20s", false);
DETECT_STRDUP_MISSED("%20s", true);
DETECT_STRDUP_MISSED("%20s", false);
DETECT_STRDUP_MISSED("%20.4s", true);
DETECT_STRDUP_MISSED("%20.4s", false);
DETECT_STRDUP_MISSED("%% %s %%", true);
DETECT_STRDUP_MISSED("%% %s %%", false);
DETECT_STRDUP_MISSED("%% %08X %s", true, 4);
DETECT_STRDUP_MISSED("%% %08X %s", false, 4);
}
static void strdup_trim_callback(struct log_backend const *const backend,
struct log_msg *msg, size_t counter)
{
char *str = (char *)log_msg_arg_get(msg, 0);
size_t len = strlen(str);
zassert_equal(len, CONFIG_LOG_STRDUP_MAX_STRING,
"Expected trimmed string");
}
static void test_strdup_trimming(void)
{
char test_str[] = "123456789";
BUILD_ASSERT(CONFIG_LOG_STRDUP_MAX_STRING == 8,
"Test assumes certain configuration");
log_setup(false);
backend1_cb.callback = strdup_trim_callback;
LOG_INF("%s", log_strdup(test_str));
while (log_process(false)) {
}
zassert_equal(1, backend1_cb.counter,
"Unexpected amount of messages received by the backend.");
}
static void test_single_z_log_get_s_mask(const char *str, uint32_t nargs,
uint32_t exp_mask)
{
uint32_t mask = z_log_get_s_mask(str, nargs);
zassert_equal(mask, exp_mask, "Unexpected mask %x (expected %x)",
mask, exp_mask);
}
static void test_z_log_get_s_mask(void)
{
test_single_z_log_get_s_mask("%d%%%-10s%p%x", 4, 0x2);
test_single_z_log_get_s_mask("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
"%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%s",
32, 0x80000000);
}
/*test case main entry*/
void test_main(void)
{
ztest_test_suite(test_log_core,
ztest_unit_test(test_log_strdup_gc),
ztest_unit_test(test_log_strdup_detect_miss),
ztest_unit_test(test_strdup_trimming),
ztest_unit_test(test_z_log_get_s_mask)
);
ztest_run_test_suite(test_log_core);
}