diff options
author | Tristan Honscheid <honscheid@google.com> | 2022-10-31 15:52:50 -0600 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-11-30 23:10:45 +0000 |
commit | 91893ee143fed8e99da15f8b3b522e7750b5a1dd (patch) | |
tree | 747c1794d23d541eebcf72d58f8282fdeaa0ad1a /zephyr/test/drivers/panic_output | |
parent | b6e76ee80d897db61684668978450207a7184367 (diff) | |
download | chrome-ec-91893ee143fed8e99da15f8b3b522e7750b5a1dd.tar.gz |
zephyr: test: Test `crash` console command
Test various `crash` subcommands that cause different types of fatal
errors. Not all were possible to test due to limitations with running
these on a PC. Also had to make a tweak to the busy loops in the
watchdog and hang subcommands so that they don't interfere with the
simulated sys clock in native_posix. Add a public wrapper function for
calling the crash command outside of the shell interface so we don't
mess up its internal state when the command doesn't return.
BUG=None
BRANCH=None
TEST=./twister
Signed-off-by: Tristan Honscheid <honscheid@google.com>
Change-Id: I393e26441d44c0a5edaf1359413efe6280703add
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4053360
Reviewed-by: Keith Short <keithshort@chromium.org>
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Diffstat (limited to 'zephyr/test/drivers/panic_output')
-rw-r--r-- | zephyr/test/drivers/panic_output/CMakeLists.txt | 8 | ||||
-rw-r--r-- | zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c | 167 |
2 files changed, 175 insertions, 0 deletions
diff --git a/zephyr/test/drivers/panic_output/CMakeLists.txt b/zephyr/test/drivers/panic_output/CMakeLists.txt new file mode 100644 index 0000000000..79cf21fc5f --- /dev/null +++ b/zephyr/test/drivers/panic_output/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright 2022 The ChromiumOS Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Add source files +target_sources(app PRIVATE + src/panic_output_crash_cmd.c +) diff --git a/zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c b/zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c new file mode 100644 index 0000000000..9608869609 --- /dev/null +++ b/zephyr/test/drivers/panic_output/src/panic_output_crash_cmd.c @@ -0,0 +1,167 @@ +/* Copyright 2022 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <stdint.h> +#include <signal.h> +#include <stdio.h> +#include <zephyr/shell/shell.h> +#include <zephyr/ztest.h> +#include <zephyr/kernel.h> +#include <zephyr/ztest_assert.h> + +#include "console.h" +#include "panic.h" +#include "test/drivers/test_state.h" + +/* Special return codes for run_crash_command() */ +#define RETURN_CODE_CRASHED (-1) +#define RETURN_CODE_TIMEOUT (-2) + +/** Create a new thread for running the `crash` console command. As its name + * suggests, this command causes a number of fatal errors (e.g. divide by zero). + * Run it in a separate thread so that we can observe these crashes without + * causing the ztest thread that runs the test functions to get aborted. + */ +static struct k_thread crash_thread; + +/* Create a stack for the crash thread */ +K_THREAD_STACK_DEFINE(crash_thread_stack, 1024); + +/** Captures the last signal number received by `handle_signal()`. */ +static int signal_received; + +/** + * @brief Handler for signals sent to the process. Log the signal number and + * abort the crash test. + * + * @param sig Signal number, from signal.h + */ +void handle_signal(int sig) +{ + signal_received = sig; + + k_thread_abort(&crash_thread); +} + +/** + * @brief Worker function for the crash thread that calls the `crash` console + * command. + * + * @param a The value of `argc` (forced as a pointer type). + * @param b `argv` pointer. + * @param c Pointer to location to write the return value. + */ +static void crash_thread_worker(void *a, void *b, void *c) +{ + int argc = (int)a; + const char **argv = (const char **)b; + int *return_val = c; + + /* If the return value remains RETURN_CODE_CRASHED, then the command + * did not return. + */ + *return_val = RETURN_CODE_CRASHED; + signal_received = 0; + + *return_val = test_command_crash(argc, argv); +} + +/** + * @brief Helper function to spawn a new thread that runs the `crash` console + * command. Waits for the command to exit/fail. + * + * @param argc Number of elements in `argv` + * @param argv CLI arguments to pass to command. Include the command name. + * @param timeout Time to wait for the thread to exit, in milliseconds. + * @return int Console command's return value, or RETURN_CODE_CRASHED if caused + * a fatal error, or RETURN_CODE_TIMEOUT if it hung. + */ +static int run_crash_command(int argc, const char **argv, k_timeout_t timeout) +{ + static int return_val; + + k_thread_create(&crash_thread, crash_thread_stack, + K_THREAD_STACK_SIZEOF(crash_thread_stack), + (k_thread_entry_t)crash_thread_worker, (void *)argc, + argv, &return_val, CONFIG_ZTEST_THREAD_PRIORITY + 1, + K_INHERIT_PERMS, K_NO_WAIT); + + if (k_thread_join(&crash_thread, timeout) == -EAGAIN) { + k_thread_abort(&crash_thread); + return RETURN_CODE_TIMEOUT; + } + + return return_val; +} + +ZTEST(panic_output, test_console_cmd__unaligned) +{ + int rv; + const char *cmd[] = { "crash", "unaligned" }; + + rv = run_crash_command(2, cmd, K_FOREVER); + + zassert_equal(RETURN_CODE_CRASHED, rv, + "Command returned %d but shouldn't have exited", rv); + zassert_equal(SIGSEGV, signal_received); +} + +ZTEST(panic_output, test_console_cmd__watchdog) +{ + /* Note: this does not verify that the watchdog fired, but that is + * covered in a different test suite. + */ + + int rv; + const char *cmd[] = { "crash", "watchdog" }; + + rv = run_crash_command(2, cmd, K_MSEC(100)); + + zassert_equal(RETURN_CODE_TIMEOUT, rv, + "Command returned %d but shouldn't have exited", rv); +} + +ZTEST(panic_output, test_console_cmd__hang) +{ + int rv; + const char *cmd[] = { "crash", "hang" }; + + rv = run_crash_command(2, cmd, K_MSEC(100)); + + zassert_equal(RETURN_CODE_TIMEOUT, rv, + "Command returned %d but shouldn't have exited", rv); +} + +ZTEST(panic_output, test_console_cmd__bad_param) +{ + int rv; + const char *cmd[] = { "crash", "xyz" }; + + rv = run_crash_command(2, cmd, K_FOREVER); + + zassert_equal(EC_ERROR_PARAM1, rv, "Command returned %d", rv); +} + +ZTEST(panic_output, test_console_cmd__no_param) +{ + int rv; + const char *cmd[] = { "crash" }; + + rv = run_crash_command(1, cmd, K_FOREVER); + + zassert_equal(EC_ERROR_PARAM1, rv, "Command returned %d", rv); +} + +static void reset(void *data) +{ + ARG_UNUSED(data); + + signal(SIGSEGV, handle_signal); + signal(SIGFPE, handle_signal); + signal_received = 0; +} + +ZTEST_SUITE(panic_output, drivers_predicate_post_main, NULL, reset, reset, + NULL); |