blob: bce0e716efa907c5672aefaaf68130ad7de3b5ab [file] [log] [blame]
#!/bin/sh
LANG=C
export LANG
error_fatal() {
# shellcheck disable=SC2039
local msg="$1"
[ -z "${msg}" ] && msg="Unknown error"
if command -v lava-test-raise; then
lava-test-raise "${msg}"
else
printf "FATAL ERROR: %s\n" "${msg}" >&2
fi
exit 1
}
error_msg() {
# shellcheck disable=SC2039
local msg="$1"
[ -z "${msg}" ] && msg="Unknown error"
printf "ERROR: %s\n" "${msg}" >&2
exit 1
}
warn_msg() {
# shellcheck disable=SC2039
local msg="$1"
[ -z "${msg}" ] && msg="Unknown error"
printf "WARNING: %s\n" "${msg}" >&2
}
info_msg() {
# shellcheck disable=SC2039
local msg="$1"
[ -z "${msg}" ] && msg="Unknown info"
printf "INFO: %s\n" "${msg}" >&1
}
check_root() {
if [ "$(id -ru)" -eq 0 ]; then
return 0
else
return 1
fi
}
exit_on_fail() {
# shellcheck disable=SC2039
local exit_code="$?"
[ "$#" -lt 1 ] && error_msg "Usage: exit_on_fail test_case [skip_list]"
# shellcheck disable=SC2039
local test_case="$1"
# shellcheck disable=SC2039
local skip_list="$2"
if [ "${exit_code}" -ne 0 ]; then
echo "${test_case} fail" | tee -a "${RESULT_FILE}"
# skip_list is a list of tests sepereated by space. This might be
# useful when exiting on prerequisite not met.
if [ -n "${skip_list}" ]; then
for i in ${skip_list}; do
echo "$i skip" | tee -a "${RESULT_FILE}"
done
fi
# Exit normally to continue to run the following steps defined in test
# definition file.
exit 0
else
echo "${test_case} pass" | tee -a "${RESULT_FILE}"
return 0
fi
}
exit_on_skip() {
# shellcheck disable=SC2039
local exit_code="$?"
[ "$#" -lt 1 ] && error_msg "Usage: exit_on_skip test_case [msg]"
# shellcheck disable=SC2039
local test_case="$1"
# shellcheck disable=SC2039
local msg="$2"
if [ "${exit_code}" -ne 0 ]; then
echo "${test_case} skip" | tee -a "${RESULT_FILE}"
if [ -n "${msg}" ]; then
warn_msg "${msg}"
fi
# Exit normally to continue to run the following steps defined in test
# definition file.
exit 0
else
echo "${test_case} pass" | tee -a "${RESULT_FILE}"
return 0
fi
}
check_return() {
# shellcheck disable=SC2039
local exit_code="$?"
[ "$#" -ne 1 ] && error_msg "Usage: check_return test_case"
# shellcheck disable=SC2039
local test_case="$1"
if [ "${exit_code}" -ne 0 ]; then
echo "${test_case} fail" | tee -a "${RESULT_FILE}"
return "${exit_code}"
else
echo "${test_case} pass" | tee -a "${RESULT_FILE}"
return 0
fi
}
# When shell argument "-e" set in test script, check_return and exit_on_fail
# would NOT work. run_test_case should be used instead.
run_test_case() {
[ "$#" -lt 2 ] && error_msg "Usage: run_test_case <test_command> <test_case_id> [skip_list]"
# shellcheck disable=SC2039
local test_command="$1"
# shellcheck disable=SC2039
local test_case_id="$2"
# shellcheck disable=SC2039
local skip_list="$3"
if eval "${test_command}"; then
echo "${test_case_id} pass" | tee -a "${RESULT_FILE}"
else
echo "${test_case_id} fail" | tee -a "${RESULT_FILE}"
# When skip_list isn't empty, skip the tests and exit.
if [ -n "${skip_list}" ]; then
for i in ${skip_list}; do
echo "$i skip" | tee -a "${RESULT_FILE}"
done
exit 0
fi
fi
return 0
}
report_pass() {
[ "$#" -ne 1 ] && error_msg "Usage: report_pass test_case"
# shellcheck disable=SC2039
local test_case="$1"
echo "${test_case} pass" | tee -a "${RESULT_FILE}"
}
report_fail() {
[ "$#" -ne 1 ] && error_msg "Usage: report_fail test_case"
# shellcheck disable=SC2039
local test_case="$1"
echo "${test_case} fail" | tee -a "${RESULT_FILE}"
}
report_skip() {
[ "$#" -ne 1 ] && error_msg "Usage: report_skip test_case"
# shellcheck disable=SC2039
local test_case="$1"
echo "${test_case} skip" | tee -a "${RESULT_FILE}"
}
report_unknown() {
[ "$#" -ne 1 ] && error_msg "Usage: report_unknown test_case"
# shellcheck disable=SC2039
local test_case="$1"
echo "${test_case} unknown" | tee -a "${RESULT_FILE}"
}
report_set_start() {
[ "$#" -ne 1 ] && error_msg "Usage: report_set_start <test_set>"
# shellcheck disable=SC2039
local test_set_name="$1"
echo "lava-test-set start ${test_set_name}" | tee -a "${RESULT_FILE}"
}
report_set_stop() {
[ "$#" -ne 0 ] && error_msg "Usage: report_set_stop"
echo "lava-test-set stop" | tee -a "${RESULT_FILE}"
}
add_metric() {
if [ "$#" -lt 3 ]; then
warn_msg "The number of parameters less then 3"
error_msg "Usage: add_metric test_case result measurement [units]"
fi
# shellcheck disable=SC2039
local test_case="$1"
# shellcheck disable=SC2039
local result="$2"
# shellcheck disable=SC2039
local measurement="$3"
# shellcheck disable=SC2039
local units="$4"
echo "${test_case} ${result} ${measurement} ${units}" | tee -a "${RESULT_FILE}"
}
detect_abi() {
abi=$(uname -m)
case "${abi}" in
armv8l) abi="armeabi" ;;
armv*l) abi="armeabi" ;;
#armv8b) abi="armeabibe" ;;
#armv*b) abi="armeabibe" ;;
aarch64) abi="arm64" ;;
#aarch64_be) abi="arm64be" ;;
i*86) abi="i386" ;;
m68k) abi="m68k" ;;
x86_64) abi="x86_64" ;;
riscv64) abi="riscv64" ;;
*) error_msg "Unsupported architecture: ${abi}" ;;
esac
}
dist_name() {
if [ -f /etc/os-release ]; then
# shellcheck disable=SC1091
dist=$(. /etc/os-release && echo "${ID}")
elif [ -x /usr/bin/lsb_release ]; then
dist="$(lsb_release -si)"
elif [ -f /etc/lsb-release ]; then
# shellcheck disable=SC1091
dist="$(. /etc/lsb-release && echo "${DISTRIB_ID}")"
elif [ -f /etc/debian_version ]; then
dist="debian"
elif [ -f /etc/fedora-release ]; then
dist="fedora"
elif [ -f /etc/centos-release ]; then
dist="centos"
else
dist="unknown"
warn_msg "Unsupported distro: cannot determine distribution name"
fi
# convert dist to lower case
dist=$(echo ${dist} | tr '[:upper:]' '[:lower:]')
case "${dist}" in
rpb*) dist="oe-rpb" ;;
esac
}
install_deps() {
# shellcheck disable=SC2039
local pkgs="$1"
[ -z "${pkgs}" ] && error_msg "Usage: install_deps pkgs"
# skip_install parmater is optional.
# shellcheck disable=SC2039
local skip_install="${2:-false}"
if [ "${skip_install}" = "True" ] || [ "${skip_install}" = "true" ]; then
info_msg "install_deps skipped"
else
! check_root && \
error_msg "About to install packages, please run this script as root."
info_msg "Installing ${pkgs}"
dist_name
case "${dist}" in
debian|ubuntu)
last_apt_time=/tmp/apt-get-updated.last
apt_cache_time=21600 # 6 hours
# Only run apt-get update if it hasn't been run in $apt_cache_time seconds
if [ ! -e ${last_apt_time} ] || \
[ "$(stat --format=%Y ${last_apt_time})" -lt $(( $(date +%s) - apt_cache_time )) ]; then
DEBIAN_FRONTEND=noninteractive apt-get update -q -y && touch ${last_apt_time}
fi
# shellcheck disable=SC2086
DEBIAN_FRONTEND=noninteractive apt-get install -q -y ${pkgs}
;;
centos)
# shellcheck disable=SC2086
yum -e 0 -y install ${pkgs}
;;
fedora)
# shellcheck disable=SC2086
dnf -e 0 -y install ${pkgs}
;;
*)
warn_msg "Unsupported distro: ${dist}! Package installation skipped."
;;
esac
# shellcheck disable=SC2181
if [ $? -ne 0 ]; then
error_msg "Failed to install dependencies, exiting..."
fi
fi
}
remove_pkgs() {
pkgs="$1"
[ -z "${pkgs}" ] && error_msg "Usage: remove_pkgs pkgs"
! check_root && error_msg "remove_pkgs() requires root permission."
info_msg "Removing ${pkgs} ..."
dist_name
case "${dist}" in
debian|ubuntu)
# shellcheck disable=SC2086
DEBIAN_FRONTEND=noninteractive apt-get -y purge ${pkgs}
;;
centos)
# shellcheck disable=SC2086
yum -y remove ${pkgs}
;;
fedora)
# shellcheck disable=SC2086
dnf -y remove ${pkgs}
;;
*)
warn_msg "Unsupported distro: ${dist}! Package uninstallation skipped."
;;
esac
}
# Return the exit code of the first command when using pipe.
pipe0_status() {
[ "$#" -ne 2 ] && error_msg "Usage: pipe0_status cmd1 cmd2"
# shellcheck disable=SC2039
local cmd1="$1"
# shellcheck disable=SC2039
local cmd2="$2"
exec 4>&1
# shellcheck disable=SC2039
local ret_val
ret_val=$({ { eval "${cmd1}" 3>&-; echo "$?" 1>&3; } 4>&- \
| eval "${cmd2}" 1>&4; } 3>&1)
exec 4>&-
return "${ret_val}"
}
validate_check_sum() {
if [ "$#" -ne 2 ]; then
warn_msg "The number of parameters should be 2"
error_msg "Usage: validate_check_sum filename known_sha256sum"
return 1
fi
# shellcheck disable=SC2039
local OUTPUT_FILE_NAME="$1"
# shellcheck disable=SC2039
local SHA256SUM_CHECK="$2"
# Get sha256sum of output_file
# shellcheck disable=SC2039
local GET_SHA256SUM
GET_SHA256SUM=$(sha256sum "${OUTPUT_FILE_NAME}" | awk '{print $1}')
echo "GET_SHA256SUM is ${GET_SHA256SUM}"
if [ "${SHA256SUM_CHECK}" = "${GET_SHA256SUM}" ] ; then
return 0
else
echo "checksum did not match"
return 1
fi
}
convert_to_mb() {
[ "$#" -ne 2 ] && error_msg "Usage: convert_to_mb value units"
if ! echo "$1" | grep -E -q "^[0-9.]+$"; then
error_msg "The first argument isn't a number"
fi
# shellcheck disable=SC2039
local value="$1"
# shellcheck disable=SC2039
local units="$2"
case "${units}" in
KB|kb) value=$(echo "${value}" | awk '{print $1/1024}') ;;
MB|mb) ;;
GB|gb) value=$(echo "${value}" | awk '{print $1*1024}') ;;
TB|tb) value=$(echo "${value}" | awk '{print $1*1024*1024}') ;;
*) error_msg "Unsupported units" ;;
esac
echo "${value}"
}
convert_to_sec() {
[ "$#" -ne 1 ] && error_msg "Usage: convert_to_sec value (including unit)"
# shellcheck disable=SC2039,SC2155
local value="$(echo "$1" | sed 's/[smhdSMHD]$//')"
# shellcheck disable=SC2039,SC2155
local unit="$(echo "$1" | sed -n 's/^[0-9]*\([smhdSMHD]\)/\1/p' )"
if ! echo "$value" | grep -E -q "^[0-9.]+$"; then
error_msg "The argument isn't a valid (number optionally with unit)"
fi
case "${unit}" in
S|s|"") ;;
M|m) value=$(echo "${value}" | awk '{print $1 * 60}') ;;
H|h) value=$(echo "${value}" | awk '{print $1 * 60 * 60}') ;;
D|d) value=$(echo "${value}" | awk '{print $1 * 60 * 60 * 24}') ;;
*) error_msg "Unsupported time unit \"${unit}\"" ;;
esac
echo "${value}"
}
dist_info() {
if ! command -v lsb_release > /dev/null; then
dist_name
case "${dist}" in
debian|ubuntu) install_deps "lsb-release" ;;
centos|fedora) install_deps "redhat-lsb-core" ;;
*) warn_msg "Unsupported distro: dist_info skipped"
esac
fi
# shellcheck disable=SC2034
Release=$(lsb_release -r | awk '{print $2}')
Codename=$(lsb_release -c | awk '{print $2}')
}
add_key() {
[ "$#" -ne 1 ] && error_msg "Usage: add_key url"
# shellcheck disable=SC2039
local url="$1"
! check_root && \
error_msg "About to use apt-key, please run this script as root."
dist_name
case "${dist}" in
debian|ubuntu) wget -O - "${url}" | apt-key add - ;;
centos|fedora) infor_msg "add_key isn't needed on ${dist}" ;;
*) warn_msg "Unsupported distro: add_key skipped"
esac
}
add_repo() {
[ "$#" -lt 1 ] && error_msg "Usage: add_repo <url> [backports]"
# shellcheck disable=SC2039
local url="$1"
! check_root && \
error_msg "About to add a repo, please run this script as root."
dist_name
case "${dist}" in
# Detect Debian/Ubuntu codename and add repo automatically. The same url
# should work on all distributions supported by the repo.
debian|ubuntu)
dist_info
if [ -z "$2" ]; then
# shellcheck disable=SC2039
local backports=""
elif [ "$2" = "backports" ]; then
# shellcheck disable=SC2039
local backports="-backports"
else
echo "Usage: add_repo <url> [backports]"
error_msg "$2 is not a supported argument, should be 'backports'"
fi
echo "deb ${url} ${Codename}${backports} main" \
>> "/etc/apt/sources.list.d/3rd-party-repo.list"
;;
# It is not easy to amend url with distro version as its format may vary
# by repo. Test definition/plan should provide a correct repo url.
centos|fedora)
wget -O - "${url}" >> "/etc/yum.repos.d/3rd-party.repo"
;;
*)
warn_msg "Unsupported distro: ${dist}! add_repo skipped"
;;
esac
}
create_out_dir() {
[ -z "$1" ] && error_msg "Usage: create_out_dir output_dir"
# shellcheck disable=SC2039
local OUTPUT="$1"
[ -d "${OUTPUT}" ] &&
mv "${OUTPUT}" "${OUTPUT}_$(date -r "${OUTPUT}" +%Y%m%d%H%M%S)"
mkdir -p "${OUTPUT}"
[ -d "${OUTPUT}" ] || error_msg "Could not create output directory ${OUTPUT}"
}
generate_skipfile() {
# Generate a skipfile and set the SKIPFILE variable based on SKIPFILE_YAML,
# BOARD, BRANCH, and ENVIRONMENT.
#
# In:
# SKIPFILE_YAML: (required) skipgen/yaml formatted skipfile
# SKIPFILE_PATH: (required) destination file for generated skipfile
# BOARD: (optional) board name to pass to skipgen
# BRANCH: (optional) branch name to pass to skipgen
# ENVIRONMENT: (optional) environment name to pass to skipgen
#
info_msg "Generating a skipfile based on ${SKIPFILE_YAML}"
detect_abi
# shellcheck disable=SC2039
local SKIPGEN_ARGS=""
test -n "${BOARD}" && SKIPGEN_ARGS="${SKIPGEN_ARGS} --board ${BOARD}"
test -n "${BRANCH}" && SKIPGEN_ARGS="${SKIPGEN_ARGS} --branch ${BRANCH}"
test -n "${ENVIRONMENT}" && SKIPGEN_ARGS="${SKIPGEN_ARGS} --environment ${ENVIRONMENT}"
# shellcheck disable=SC2086
../../bin/${abi}/skipgen ${SKIPGEN_ARGS} "${SKIPFILE_YAML}" > "${SKIPFILE_PATH}"
res=$?
test ${res} -eq 0 || error_msg "skipgen failed to generate a skipfile: ${res}"
info_msg "Using the following generated skipfile contents (until EOF):"
cat "${SKIPFILE_PATH}"
info_msg "EOF"
}
# Description: parted is not working on SSD (Solid-State Drives) this is the
# reason to use fdisk instead.
# Dependency packages for fdisk and mkfs are "fdisk e2fsprogs dosfstools"
# fdisk and mkfs commands might be in $PATH /sbin or /usr/sbin or
# /usr/local/sbin export PATH for better usage.
export PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
# Usage:
# partition_disk "/dev/sdb" "+5G +10G"
# shellcheck disable=SC2039
partition_disk() {
# when sizes is empty it creates single partitions with total disk size
[ "$#" -ne 1 ] && error_msg "Usage: <block-device> <sizes>"
local device="$1"
local sizes="$2"
command -v fdisk
exit_on_fail "fdisk not in ${PATH} or not installed"
# Create a new empty DOS partition table
(
echo o
echo w) | fdisk "${device}"
if [ -n "${sizes}" ]; then
# Create partitions as per sizes
for size in ${sizes}; do
# Create patitions with ${size}
(
echo n
echo p
echo
echo
echo "${size}"
echo w) | fdisk "${device}"
check_return "fdisk-${device}-${size}-partition"
# sync and wait 5 sec
sync
sleep 5
done
fi
# Create a partition at the end.
# Use the rest of the disk.
(
echo n
echo p
echo
echo
echo
echo w) | fdisk "${device}"
check_return "fdisk-${device}-end-partition"
# sync and wait 5 sec
sync
sleep 5
}
# Usage:
# format_partitions "/dev/sdb" "ext4"
# shellcheck disable=SC2039
format_partitions() {
[ "$#" -ne 2 ] && error_msg "Usage: <block-device> <filesystem-type>"
local device="$1"
local filesystem="$2"
local partition=""
local total_partitions=""
command -v mkfs
exit_on_fail "mkfs not in ${PATH} or not installed"
# Total partitions in a block device
total_partitions=$(find "${device}"* | grep "[0-9]" | tr '\n' ' ' )
# Format each partition in a given block device
for partition in ${total_partitions} ; do
echo "Formatting ${partition} to ${filesystem}"
if [ "${filesystem}" = "fat32" ]; then
echo "y" | mkfs -t vfat -F 32 "${partition}"
check_return " mkfs-t-vfat-F-32-${partition}"
else
echo "y" | mkfs -t "${filesystem}" "${partition}"
check_return "mkfs-${filesystem}-${partition}"
fi
# sync and wait 5 sec
sync
sleep 5
done
}
background_process_start() {
NAME="$1"
shift
if [ -z "$NAME" ]; then
err_msg "Usage: background-process-start NAME --cmd PROCESS"
fi
while [ $# -gt 0 ]; do
case $1 in
--cmd)
shift
PROCESS="$*"
shift
;;
*)
err_msg "Unhandled argument"
;;
esac
done
if [ -z "${PROCESS}" ]; then
return
fi
result_dir="${OUTPUT}/results/$NAME"
mkdir -p "${result_dir}"
cat <<EOF > "${result_dir}/bg_run.sh"
set -e
trap "exit" SIGHUP SIGINT SIGTERM
while true; do
$PROCESS > /dev/null
sleep 1
done
EOF
/bin/bash "${result_dir}/bg_run.sh" &
echo $! > "${result_dir}/pid"
}
background_process_stop() {
NAME="$1"
shift
if [ -z "${NAME}" ]; then
err_msg "Usage: background-process-stop NAME"
fi
result_dir="${OUTPUT}/results/${NAME}"
if [ ! -d "${result_dir}" ] ; then
return
fi
PID=$(cat "${result_dir}/pid")
if ps -p "${PID}" > /dev/null;
then
kill "${PID}" > /dev/null 2>&1
fi
}
# register the current dmesg
dmesg_capture_start()
{
dmesg --console-off
dmesg > "$OUTPUT/dmesg.test.start"
}
# Print all kernel messages that appears since last dmesg_capture_start
dmesg_capture_result() {
echo "=============================================="
dmesg > "$OUTPUT/dmesg.test.result"
diff -u "$OUTPUT/dmesg.test.start" "$OUTPUT/dmesg.test.result"
# restore normal dmesg behavour
dmesg --console-on
echo "=============================================="
}
# shellcheck disable=SC2039
get_test_program() {
local test_git_url="$1"
local test_dir="$2"
local test_prog_version="$3"
local test_program="$4"
if [ ! -d "$test_dir" ] || [ -d "$test_dir"/.git ]; then
if [ "$test_prog_version" != "" ]; then
if [ -d "$test_dir"/.git ]; then
echo Using repository "$PATH"
else
git clone "$test_git_url" "$test_dir"
fi
cd "$test_dir" || exit 1
if [ "$test_prog_version" != "" ]; then
if ! git reset --hard "$test_prog_version"; then
echo Failed to set "${test_program}" to commit "$test_prog_version", sorry
exit 1
fi
else
echo Using "$PATH"
fi
else
echo Assuming "${test_program}" is pre-installed in "$test_dir"
cd "$test_dir" || exit 1
fi
else
if [ ! -d "$test_dir" ]; then
echo No "${test_program}" suite in "$test_dir", sorry
exit 1
fi
echo Assuming "${test_program}" is pre-installed in "$test_dir"
cd "$test_dir" || exit 1
fi
}
exit_cleanup()
{
# cleanup the temp decompressed config & kernel image
[ "$mounted_debugfs" = 1 ] && umount /sys/kernel/debug 2>/dev/null
}
mount_debugfs()
{
mount | grep -q debugfs
ret=$?
if [ ${ret} -ne 0 ]; then
# try to mount the debugfs hierarchy ourselves and remember it to umount afterwards
mounted_debugfs=0
mount -t debugfs debugfs /sys/kernel/debug && mounted_debugfs=1
if [ $mounted_debugfs -eq 1 ]; then
return
else
error_msg "not able to mount debugfs"
fi
else
return
fi
}
kernel_config=""
# Find the location of the kernel's config file based on various standard
# locations.
find_config_file() {
if [ -e "/boot/config-$(uname -r)" ]; then
kernel_config="/boot/config-$(uname -r)"
elif [ -e "/lib/modules/$(uname -r)/config" ]; then
kernel_config="/lib/modules/$(uname -r)/config"
elif [ -e "/lib/kernel/config-$(uname -r)" ]; then
kernel_config="/lib/kernel/config-$(uname -r)"
elif [ -e "/proc/config.gz" ]; then
tmpfile=$(mktemp /tmp/config.XXXXX)
zcat /proc/config.gz > "${tmpfile}"
kernel_config=${tmpfile}
fi
}
check_config() {
# Fetch the config file.
find_config_file
if [ ! -f "${kernel_config}" ]; then
exit_on_fail "Kernel Config File ${kernel_config} does not exist..."
fi
info_msg "Found kernel config file in $kernel_config."
# shellcheck disable=SC2068
for c in ${@}; do
info_msg "Checking config option ${c}..."
cat < "${kernel_config}" | grep "${c}=[y|m]" > /dev/null
check_return "config_value_${c}"
done
}
# this function allows to use u-boot variables in
# linux shell. It gets the value of variable using
# UBOOT_VAR_TOOL. This should be set to fw_printenv
# or a tool with a similar function
uboot_variable_value() {
# shellcheck disable=SC2039
local var="$1"
result=$("${UBOOT_VAR_TOOL}" "${var}")
if [ -n "${result}" ]; then
echo "${result#*=}"
else
echo ""
fi
}
# this function compares values of 2 arguments
# it reports pass if the arguments are identical
compare_test_value() {
# shellcheck disable=SC2039
local test_name="$1"
# shellcheck disable=SC2039
local expected_value="$2"
# shellcheck disable=SC2039
local tested_value="$3"
echo "Testing: #${test_name}#"
echo "Expected: #${expected_value}#"
echo "Actual: #${tested_value}#"
if [ "${expected_value}" = "${tested_value}" ]; then
report_pass "${test_name}"
else
report_fail "${test_name}"
fi
}