#!/bin/bash ## top: the root path [- /.../tina/pacakge/dragontools/tinatest -] ## com: command in private.conf [- stress -t 1 -] ## pconf: path of private.conf [- /.../tina/.../testcase/stress/io/private.conf -] ## cpath: config path [- /stress/io -] ## testcase: name of testcase [- io -] ## condir: config dir of testcase [- /.../tina/.../testcase/config/stress/io -] ## conpath: path of testcase [- /.../tina/.../testcase/config/stress/io/Config.in -] show_help() { echo -e "使用说明:" echo -e "\033[33m add_testcase.sh <配置文件1> [配置文件2] ...\033[0m\n" echo -e "配置文件:" echo -e " 记录新用例的路径以及默认配置值,一行一条键值对,格式为:" echo -e "\033[33m <配置项>[:类型] = <配置值>\033[0m" echo -e " \033[33m[配置项]\033[0m: 包含PATH/ENABLE/INFO/LIMIT/DEPENDS/DATA和测试用例的所有配置项(例如:command,run_times,run_alone等)" echo -e " 其中:" echo -e " PATH: 测试用例在配置树中的绝对路径(字符串)" echo -e " ENABLE: 默认是否使能此用例(bool)" echo -e " INFO: 默认是否使能所有的 局部信息 配置项(bool)" echo -e " LIMIT: 默认是否使能所有的 局部限制 配置项(bool)" echo -e " DEPENDS: 测试用例依赖的第三方应用包(string),多个包之间以逗号间隔" echo -e " 格式: \"<依赖的软件包1>[,<依赖的软件包2>,...]" echo -e " 例如 /stress/rw/rw-auto 依赖 rwcheck 软件包, 则 DEPENDS=\"rwcheck\"" echo -e " DATA: 测试用例需要使用的一些数据文件,文件必须保存在测试用例源码目录" echo -e " 格式: \"<数据文件1>[,<数据文件2>...]\"" echo -e " 例如: /base/production/headphonetester需要文件s16le_44100_stereo.wav" echo -e " 则 DATA = \"s16le_44100_stereo.wav\"" echo -e " \033[32m[大写字母为特定配置项][无指定类型的小写字母为用例属性项][指定类型的小写字母为私有配置项]\033[0m" echo -e " \033[33m[类型]\033[0m: \033[31m(私有配置项才需要)\033[0m为mjson支持的数据类型,包括:int/double/true/false/string/array" echo -e " \033[33m[配置值]\033[0m: 支持字符串/字符串数组/整数/浮点数/bool(见示例)" echo -e " 其中:" echo -e " 1) \033[31m字符串必须用双引号括起来\033[0m" echo -e " 2) 字符串数组以字符串形式表示,字符串之间以空格间隔" echo -e " 4) 字符串内若双引号\\转义字符等,需要有双重转义, 例如: command = \"echo \\\\\\\\\\\\\"test\\\\\\\\\\\\\"\" 表示echo \"test\"" echo -e " 4) 每一行开头不能有空格/Tab等" echo -e "\n示例如下:" echo -e " |PATH = /demo/demo-c" echo -e " |ENABLE = false" echo -e " |INFO = true" echo -e " |command = \"demo-c\"" echo -e " |run_times = 10" echo -e " |run_alone = false" echo -e " |workers:int = 2" echo -e " |words:string = \"test\"" echo -e " |right:bool = true" echo -e " |str_array:array = \"one two three\"" } #get_value # From 配置文件 get_value() { grep "^$1 *=.*$" ${pconf} | cut -d '=' -f 2- | sed -r 's/^ +//g' } #set_value # To menuconfig配置文件 set_value() { if grep ":" <<< $2 &>/dev/null; then local cname ctype ctype=${2#*:} cname="$(sed '{s#/#_#g; s/[a-z]/\u&/g; s/[^ [:alnum:]]/_/g}' <<< ${cpath})" cname="TINATEST${cname}_$(sed '{s/[a-z]/\u&/g; s/[^ [:alnum:]]/_/g}' <<< ${2%%:*})" if [ -n "$3" ] then tac $1 | \ sed '2i\\' | \ sed "2i\\ config ${cname}" | \ sed "2i\\ ${ctype} \"${2%%:*}\"" | \ sed "2i\\ default $3" | \ tac > $1.new else tac $1 | \ sed '2i\\' | \ sed "2i\\ config ${cname}" | \ sed "2i\\ ${ctype} \"${2%%:*}\"" | \ tac > $1.new fi mv $1.new $1 else eval "sed -i '/\"$2\"/{:loop; n; s/default.*$/default $3/; t; b loop}' $1" fi } add_depend() { local depends=$(get_value "DEPENDS") [ -z "${depends}" ] && return local depend for depend in $(sed 's/[,"]/ /g' <<< ${depends}) do sed -i "3a\ select PACKAGE_${depend}" ${conpath} done } fix_value() { # change config-value local oIFS line item value oIFS="${IFS}" IFS=$'\n' for line in $(grep "^[[:lower:]]" ${pconf}) do IFS=" =" item=$(awk '{print $1}' <<< ${line}) value="$(get_value "${item}")" [ "${value}" = "true" ] && value="y" [ "${value}" = "false" ] && value="n" set_value ${conpath} "${item}" "${value}" IFS=$'\n' done IFS="${oIFS}" # change INFO/LIMIT for item in "LIMIT" "INFO" do value=$(get_value "${item}") [ -n "${value}" ] && { [ "${value}" = "true" ] && value="y" [ "${value}" = "false" ] && value="n" set_value ${conpath} "${item}" "${value}" } done } create_child_config() { local upper=$(sed '{s#/#_#g; s/[a-z]/\u&/g; s/[^ [:alnum:]]/_/g}' <<< ${cpath}) cat > ${conpath} << EOF menuconfig TINATEST${upper}_ENABLE bool "${testcase}" default $([ "$(get_value "ENABLE")" = "true" ] && echo "y" || echo "n") ---help--- Settings for ${cpath} It safe to leave a blank for any settings. If not setted, TinaTest will use global settings or default settings instead. if TINATEST${upper}_ENABLE config TINATEST${upper}_COMMAND string "command" default "" ---help--- TinaTest will run this command to start testcase. It is the same as shell command which followed by argumemts. This setting is a mark of any testcase. config TINATEST${upper}_STDIN string "stdin" default "" ---help--- Redirect a string array, which is setted in this configure, to standard input. For example, "one two three four" is equivalent to enter 4 times to testcase every run_time. The first time, enter "one" with new line, the second time, enter "two" with new line, and so on. config TINATEST${upper}_FSTDIN string "fstdin" default "" ---help--- Redirect a file, which is setted in this configure, to standard input. comment " to Default && to customize" config TINATEST${upper}_INFO bool "INFO" default y if TINATEST${upper}_INFO config TINATEST${upper}_DATE bool "date" default y if TINATEST_SYS_LOCAL_INFO_DATE ---help--- Save running date and time. config TINATEST${upper}_RESOURCE bool "resource" default y if TINATEST_SYS_LOCAL_INFO_RESOURCE ---help--- Save resources for each testcase. config TINATEST${upper}_REAL_TIME_LOG bool "real_time_log" default y if TINATEST_SYS_LOCAL_INFO_REAL_TIME_LOG ---help--- Print log of testcase real time. In default, tinatest just collect all log, and print them when testcase end. endif comment " to Default && to customize" config TINATEST${upper}_LIMIT bool "LIMIT" default y if TINATEST${upper}_LIMIT config TINATEST${upper}_RUN_TIMES string "run_times" default "" ---help--- The times to run testcase. For example: To run this testcase for 3 times, we can set this value as 3. config TINATEST${upper}_RUN_ALONE bool "run_alone" default y if TINATEST_SYS_LOCAL_LIMIT_RUN_ALONE ---help--- Wait for finishing all previous testcase and run alone before do next. config TINATEST${upper}_RUN_PARALLEL bool "run_parallel" default y if TINATEST_SYS_LOCAL_LIMIT_RUN_PARALLEN ---help--- Run parallel for all run_times. For example: Testcae will run for 3 times one by one if run_times=3. However, if run_parallel is setted, tinatest will creates 3 processers in one time. config TINATEST${upper}_MAY_REBOOT bool "may_reboot" default y if TINATEST_SYS_LOCAL_LIMIT_MAY_REBOOT ---help--- It means that device will be rebooted while running testcase. All states of testcase will be saved in flash, and loaded after rebooting. Notices that, if may_reboot is setted, run_alone will be setted alway. config TINATEST${upper}_TESTCASE_RUN_ONCE_TIME string "testcase_run_once_time" default "" ---help--- Time limit for testcase to run once. It is in format: For example, 100s : 100 1m20s : 20 1 (or 80) 1d3h : 0 0 3 1 (or 0 0 28 or other) config TINATEST${upper}_TESTCASE_RUN_TIME string "testcase_run_time" default "" ---help--- Time limit for testcase to run. It is in format: For example, 100s : 100 1m20s : 20 1 (or 80) 1d3h : 0 0 3 1 (or 0 0 28 or other) choice prompt "timeout_with" default TINATEST${upper}_TIMEOUT_WITH_PASS ---help--- The result when testcase exit for timeout. config TINATEST${upper}_TIMEOUT_WITH_PASS bool "pass" config TINATEST${upper}_TIMEOUT_WITH_FAILED bool "failed" endchoice config TINATEST${upper}_EXIT_ONCE_FAILED bool "exit_once_failed" default n ---help--- Stop running testcase and exit once failed, even if runned times less than run_times. endif endif EOF } create_father_config() { local base=$(basename $2) local upper="TINATEST$(sed '{s/[a-z]/\u&/g; s/[^ [:alnum:]]/_/g}' <<< $2)" cat > $1 << EOF menuconfig ${upper} bool "${base}" if ${upper} endif EOF } recurse_father_config() { local dir=$(dirname $1) local base=$(basename $1) local cur="${top}/config${dir}/Config.in" [ "${dir}" = "/" ] && return [ -f "${cur}" ] || create_father_config ${cur} ${dir} grep -w "source ${base}/Config.in$" ${cur} &>/dev/null || \ sed -i "/endif/i\\\\ source ${base}/Config.in" ${cur} recurse_father_config ${dir} } new_config() { create_child_config recurse_father_config ${cpath} } add_config() { testcase="$(basename ${cpath})" condir="${top}/config${cpath}" conpath="${condir}/Config.in" mkdir -p ${condir} new_config fix_value } add_main() { for pconf in $@ do # get and check private.conf pconf="$(cd $(dirname ${pconf}) && pwd)/$(basename ${pconf})" [ ! -f "${pconf}" ] \ && echo -e "\033[31mNot find \"${pconf}\"\033[0m" \ && continue # get and check config-path cpath=$(dirname ${pconf} | sed 's#.*tinatest/testcase##g') [ -z "${cpath}" ] \ && echo -e "\033[31mMismatch path from ${pconf}\033[0m" \ && continue # get command com=$(get_value "command") [ -z "${com}" ] \ && echo -e "\033[31mMismatch command in ${pconf}\033[0m" \ && continue # do add config add_config add_depend done } get_top() { top=`pwd` while [ ! "${top}" = "/" ] do [ -f "${top}/Makefile" ] \ && egrep -w "PKG_NAME *[:]?= *tinatest" ${top}/Makefile >/dev/null \ && break top=$(dirname ${top}) done [ "${top}" = "/" ] && echo "Get top failed" && exit } main() { local opts opts="$(getopt -l "help" -o "h" -- $@)" || return 1 eval set -- "${opts}" while true do case "$1" in -h|--help) show_help exit 0 ;; --) shift break esac done # check usage [ "$#" -lt 1 ] && show_help && exit 0 # get top path get_top # do add add_main $@ # make it built after adding testcase touch ${top}/Makefile echo "All Done!" } main $@