Simple, on-target validation framework for embedded Linux systems
Cukinia is designed to help embedded Linux firmware developers run simple system-level validation tests on their systems.
It integrates well with embedded system generation frameworks such as Yocto and Buildroot, and can be run manually, or by your favourite CI framework.
Cukinia works if it offers the following value:
- It is very simple to use
- It requires no dependencies other than a POSIX shell (e.g. Busybox)
- It integrates easily with CI/CD pipelines
- It helps developers creating better systems
USAGE:
cukinia [options] [config file]
OPTIONS:
-h, --help display this message
-v, --version display the version string
-o <file> output results to <file>
-f <format> set output format to <format>, currently supported:
csv junitxml
--no-header do not print headers in concerned output formats
--trace trace execution (for debugging)
By default, Cukinia uses /etc/cukinia.conf.
A sample screenshot when running Cukinia in interactive mode:
Cukinia provides a set of simple statements for validating runtime aspects of a Linux system:
Verify the presence and configuration of system users and groups.
cukinia_user <name>β validate that a user existscukinia_group <name>β validate that a group existscukinia_user_memberof <user> <group>[ ...]β validate that a user is member of one or more groups
Example:
cukinia_user appuser
cukinia_group dialout
cukinia_user_memberof appuser dialout videocukinia_kthread <name>β validate that a kernel thread is runningcukinia_process <name> [user]β validate that a process is running (optional owner)cukinia_process_with_args "<args>" [user]β validate that a process with specific arguments is running (optional owner)
Examples
cukinia_kthread kworker/0:1
cukinia_process sshd
cukinia_process_with_args "gpsd --nodaemon" appusercukinia_cmdline <param>[=<value>]β validate that kernel cmdline contains a parameter (optional value)cukinia_kconf <symbol> <y|m|n>β validate that a kernel config symbol has a given tristate valuecukinia_kmod <module>β validate that a kernel module is loadedcukinia_knoerror <priority>β validate that kernel boot has no important errors at or above the given log prioritycukinia_kversion <maj.min>β validate kernel version (checks major.minor, e.g. 5.14)cukinia_sysctl <key> <value>β validate that a kernel sysctl parameter is set to value
Examples
cukinia_cmdline console=ttyS0
cukinia_kconf CONFIG_IPV6 y
cukinia_kmod i2c_dev
cukinia_kversion 6.6
cukinia_sysctl net.ipv4.ip_forward 0The cukinia_test statement wraps the shell test command, allowing for
generic tests, while cukinia_cmd allows for running arbitrary commands.
cukinia_test <test(1) expression>β validate a generictestexpressioncukinia_cmd <command...>β validate that an arbitrary command returns success
Examples
cukinia_test -f /etc/os-release
result_string=$(some_command)
as "The remote sensor was detected" \
cukinia_test "$result_string" = "Detected"
as "The root user's password field is not empty" \
not cukinia_cmd "grep -q ^root:: /etc/passwd"cukinia_mount <device> <target> [fstype] [options]β validate the presence of a mountcukinia_symlink <path> <expected_target>β validate the target of a symlink
Examples
cukinia_mount sysfs /sys
cukinia_mount /dev/sda5 /mnt/maps ext4 ro
cukinia_symlink /etc/alternatives/editor /usr/bin/vimcukinia_dns_resolve <hostname>β validate that a hostname can be resolvedcukinia_http_request <url>β validate that an HTTP(S) request returns HTTP 200cukinia_listen4 <tcp|udp> <port>β validate that a TCP/UDP v4 port is open locallycukinia_netif_has_ip <ifname> [-4|-6] [flags]β validate that an interface has IP configuration (examples below)cukinia_netif_is_up <ifname>β validate interface state is UP
Examples
cukinia_dns_resolve example.org
cukinia_http_request http://localhost:8080/health
cukinia_listen4 tcp 22
cukinia_netif_has_ip eth0 -4 dynamic
cukinia_netif_has_ip eth0 -6 "scope global"
cukinia_netif_is_up eth2cukinia_gpio_libgpiod -i <in_pins> -l <out_low> -h <out_high> -g <gpiochip>β validate GPIO via libgpiodcukinia_gpio_sysfs -i <in_pins> -l <out_low> -h <out_high> -g <gpiochip>β validate GPIO via legacy sysfscukinia_i2c <bus> [device_address] [driver_name]β check IΒ²C bus or (optional) device and (optionally) that it uses the indicated driver
Examples
cukinia_gpio_libgpiod -i "0 3 4" -l "10" -h "2 50" -g gpiochip1
cukinia_gpio_sysfs -i "20 34" -h "3 99 55"
as "Remote MCU is visible on I2C2 bus address 3c" \
cukinia_i2c 1 0x3ccukinia_systemd_unit <unit>β validate that a systemd unit is activecukinia_systemd_failedβ fail if any systemd unit is in failed state
Examples
cukinia_systemd_unit sshd.service
cukinia_systemd_failedcukinia_python_pkg <package>β validate that a Python package is installed
Examples
cukinia_python_pkg requestsThese prefix any test statement and may be combined:
as "<description>"β change a test's textual descriptionnotβ invert the test result (appends[!]in the default description)test_id "<id>"β set a test id for outputs (useful for mapping your system requirements)verboseβ preserve test stdout/stderr in the console output
Examples
as "Checking embedded webapp is up (with connect logs)" \
verbose \
cukinia_http_request http://localhost:8080/sanitycheck
not cukinia_user baduser
test_id "SWR_001" \
cukinia_systemd_unit sshd.serviceThese may also prefix any test statement, and can be combined:
when "<shell_expr>"β¦ test β run test only if expression returns successunless "<shell_expr>"β¦ test β run test only if expression returns failure (reported as SKIP when not executed)on <result>β execute statements conditionally on test result (e.g.,on success,on failure)retry <count> [after <interval>]β retry a testcounttimes with optional interval (e.g.,2s,1m,3h,1d)
Examples
on_eval_board() { grep -q EVK /sys/firmware/devicetree/base/model; }
on_arm64 { test "$(uname -m)" = "aarch64"; }
when "on_arm64 && !on_eval_board" \
as "Custom LED controller was probed" \
cukinia_test -d /sys/class/leds/customled
on failure retry 3 after 2s \
cukinia_systemd_unit big-app.servicecukinia_run_dir <dir>β run all executables in given directory as individual testscukinia_conf_include <glob>β include additional config files, useful for splitting your tests into domain-specific filescukinia_log "<message>"β log a message to stdout
Examples
cukinia_conf_include /etc/cukinia/conf.d/*.conf
cukinia_log "Starting graphics tests, $cukinia_failures failures so far"
cukinia_run_dir /opt/gfx_tests/For the console output:
logging prefix "string"β set prefix for following test results / cukinia_log outputs
For the JunitXML output:
logging class "string"β set JUnitXML class name for following testslogging suite "string"β set JUnitXML test suite for following tests
$cukinia_testsβ number of tests attempted$cukinia_failuresβ number of tests that failed
Those shell functions may be useful in your test suite:
$(_colorize color_name string)"β colorize string argument for console display, useful withcukinia_log- Most colors have a '2' variant which is brighter$(_ver2int x.y.z)"β creates integer version of numeric version string, useful for comparing stuff withcukinia_test
Examples
cukinia_log "$(_colorize yellow2 "Starting Graphics Test Suite")"
cukinia_test $(_ver2int ${kernel_version}) -ge $(_ver2int 6.6.38)$CUKINIA_ALWAYS_PASSβ if set, every test will succeed
A Cukinia config file is actually a POSIX shell script that is sourced by cukinia, so any shell logic can be used in a test file scenario.
This is useful for example to make certain groups of tests depend on preliminary checks:
if cukinia_test -x /usr/bin/myapp; then
cukinia_user myuser
cukinia_process myapp myuser
cukinia_http_request http://localhost:8080/testme
else
cukinia_log "$(_colorize red "myapp not found :(")"
fi
cukinia_log "----> Base System Requirements <----"
cukinia_user pipewire
cukinia_group dialout
test_id SYS_033 \
cukinia_process sshd
test_id SYS_049 \
cukinia_kthread kaudit
cukinia_log "----> Kernel Requirements <----"
test_id KRN_002 \
as "Linux kernel version is 6.12 for LTS support" \
cukinia_kversion 6.12
test_id KRN_044 \
cukinia_kmod snd_usb_audio
cukinia_log "----> Misc. tests <----"
cukinia_test -f /etc/os-release
test_id SYS_037 \
as "/etc/os-release contains custom SYSVER= key" \
cukinia_cmd grep -q '^SYSVER=[0-9\.]+$' /etc/os-release
Cukinia is validated using bats. The non-regression tests can be run with:
git submodule update --init
bats bats/cukinia.batsCukinia is released under the Apache 2 license.
Copyright (C) 2017-2025 Savoir-faire Linux, Inc.

