aboutgitcodebugslistschat
path: root/test/lib/test
blob: 93c86e8460d0e11dac09b92ba37707b11e969166 (plain) (tree)












































                                                                           
                        


























                                                                          
                

                                                                         
               










                                                                         


                     

                                                     
































































































































                                                                                                                               







                                       


                                      





                                       


                            





                             


































                                                                                                              











                                                                                                          


































































                                                                                                                           


                                    














                                                                     


                                                           
                          













                                                                      




                           
                                     

                                                   

                               
                                           




                                   


                                                                       



































                                                                                    
#!/bin/sh
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# PASST - Plug A Simple Socket Transport
#  for qemu/UNIX domain socket mode
#
# PASTA - Pack A Subtle Tap Abstraction
#  for network namespace/tap device mode
#
# test/lib/test - List tests and run them, evaluating directives from files
#
# Copyright (c) 2021 Red Hat GmbH
# Author: Stefano Brivio <sbrivio@redhat.com>

# Empty, 'passt' or 'pasta', to match against 'onlyfor' directive
MODE=

# test_iperf3() - Ugly helper for iperf3c/iperf3s directives
# $1:	Role: client or server
# $2:	Pane name, can be lowercase
# $3:	Destination name or address for client
# $4:	Port number, ${i} is translated to process index
# $5:	Number of processes to run in parallel
# $@:	Options
test_iperf3() {
	__role="${1}"; shift
	__pane="$(echo "${1}" | tr [a-z] [A-Z])"; shift
	[ "${__role}" = "client" ] && __dest="${1}" && shift || __dest=""
	__port="${1}"; shift
	__procs="$((${1} - 1))"; shift

	[ "${__role}" = "server" ] && __role_opt="-c" || __role_opt="-s1J"

	if [ ${__role} = "client" ]; then
		UDP_CLIENT=0
		for __opt in ${@}; do
			[ "${__opt}" = "-u" ] && UDP_CLIENT=1
		done
		
		(
		sleep 2
		pane_run "${__pane}" 'for i in $(seq 0 '${__procs}');'	\
			'do ( iperf3 -c '"${__dest}"' -p '"${__port}"	\
			"${@}" ' -T s${i} & echo $! > c${i}.pid & ); done'
		sleep 40
		pane_run "${__pane}" 'for i in $(seq 0 '${__procs}'); do'\
			 'kill -INT $(cat c${i}.pid) 2>/dev/null; done'
		) &
		return
	fi

	pane_run "${__pane}" 'for i in $(seq 0 '${__procs}'); do'	\
		':> s${i}.bw; done'
	pane_wait "${__pane}"

	if [ ${UDP_CLIENT} -eq 0 ]; then
		pane_run "${__pane}" 'for i in $(seq 0 '${__procs}');'	\
			'do ( ( iperf3 -s1J -p '"${__port} ${@}"	\
			'& echo $! > s${i}.pid ) 2>/dev/null'		\
			'| jq -rM ".end.sum_received.bits_per_second"'	\
			'> s${i}.bw & );'				\
			'done'
	else
		pane_run "${__pane}" 'for i in $(seq 0 '${__procs}');'	\
			'do ( ( iperf3 -s1J -i 30 -p '"${__port} ${@}"	\
			'& echo $! > s${i}.pid ) 2>/dev/null'		\
			'| jq -rM ".intervals[0].sum.bits_per_second"'	\
			'> s${i}.bw & );'				\
			'done'
	fi

	pane_wait "${__pane}"
	sleep 45
	pane_run "${__pane}" 'for i in $(seq 0 '${__procs}'); do'	\
		 'kill -INT $(cat s${i}.pid) 2>/dev/null; done'
	sleep 4
	pane_wait "${__pane}"
	pane_run "${__pane}" '(cat s*.bw |'				\
		'sed '"'"'s/\(.*\)/\1\+/g'"'"' |'			\
		'tr -d "\n"; echo 0) | bc -l'
	pane_wait "${__pane}"
	pane_parse "${__pane}"
	pane_run "${__pane}" 'for i in $(seq 0 '${__procs}'); do'	\
		'rm -f s${i}.bw; done'
	pane_wait "${__pane}"
}

test_one_line() {
	__line="${1}"

	[ ${DEBUG} -eq 1 ] && info DEBUG: "${__line}"

	# Strip comments
	__line="${__line%%#*}"

	if [ -n "${TEST_ONE_in_def}" ]; then
		[ "${__line}" = "endef" ] && TEST_ONE_in_def= && return
		# Append $__line to variable TEST_ONE_DEF_<definition name>
		__ifs="${IFS}"
		IFS=
		eval TEST_ONE_DEF_$TEST_ONE_in_def=\"\$\(printf \"%s\\n%s\" \"\$TEST_ONE_DEF_$TEST_ONE_in_def\" \"$__line\"\)\"
		IFS="${__ifs}"
		return
	fi

	# tab-split command and arguments, apply variable substitutions
	__cmd="${__line%%$(printf '\t')*}"
	__arg="${__line#*$(printf '\t')*}"
	__arg="$(subs_apply "${TEST_ONE_subs}" "${__arg}")"

	[ ${TEST_ONE_nok} -eq 1 ] && [ "${__cmd}" != "test" ] && continue
	case ${__cmd} in
	"def")
		TEST_ONE_in_def="${__arg}"
		# Clear variable TEST_ONE_DEF_<definition name>
		__ifs="${IFS}"
		IFS= eval TEST_ONE_DEF_$TEST_ONE_in_def=
		IFS="${__ifs}"
		;;
	"tempdir")
		__tmpdir="$(mktemp -d)"
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__arg}__" "${__tmpdir}")"
		TEST_ONE_dirclean="$(list_add "${TEST_ONE_dirclean}" "${__tmpdir}")"
		;;
	"temp")
		__tmpfile="$(mktemp)"
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__arg}__" "${__tmpfile}")"
		TEST_ONE_dirclean="$(list_add "${TEST_ONE_dirclean}" "${__tmpfile}")"
		;;
	"test")
		[ ${TEST_ONE_perf_nok} -eq 0 ] || TEST_ONE_nok=1
		[ ${TEST_ONE_nok} -eq 1 ] && status_test_fail
		[ ${TEST_ONE_nok} -eq 0 ] && status_test_ok

		status_test_start "${__arg}"
		TEST_ONE_nok=0
		TEST_ONE_perf_nok=0
		;;
	"host")
		pane_run HOST "${__arg}"
		pane_wait HOST
		;;
	"hostb")
		pane_run HOST "${__arg}"
		;;
	"hostw")
		pane_wait HOST
		;;
	"hint")
		tmux send-keys -t ${PANE_HOST} "C-c"
		;;
	"htools")
		pane_run HOST 'which '"${__arg}"' >/dev/null || echo skip'
		pane_wait HOST
		[ "$(pane_parse HOST)" = "skip" ] && TEST_ONE_skip=1
		;;
	"passt")
		pane_run PASST "${__arg}"
		pane_wait PASST
		;;
	"passtb")
		pane_run PASST "${__arg}"
		;;
	"passtw")
		pane_wait PASST
		;;
	"pout")
		__varname="${__arg%% *}"
		pane_run PASST "${__arg#* }"
		pane_wait PASST
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse PASST)")"
		;;
	"guest")
		pane_run GUEST "${__arg}"
		pane_wait GUEST
		;;
	"guestb")
		pane_run GUEST "${__arg}"
		;;
	"guestw")
		pane_wait GUEST
		;;
	"guest1")
		pane_run GUEST_1 "${__arg}"
		pane_wait GUEST_1
		;;
	"guest1b")
		pane_run GUEST_1 "${__arg}"
		;;
	"guest1w")
		pane_wait GUEST_1
		;;
	"gtools")
		pane_run GUEST 'which '"${__arg}"' >/dev/null || echo skip'
		pane_wait GUEST
		[ "$(pane_parse GUEST)" = "skip" ] && TEST_ONE_skip=1
		;;
	"g1tools")
		pane_run GUEST_1 'which '"${__arg}"' >/dev/null || echo skip'
		pane_wait GUEST_1
		[ "$(pane_parse GUEST_1)" = "skip" ] && TEST_ONE_skip=1
		;;
	"g2tools")
		pane_run GUEST_2 'which '"${__arg}"' >/dev/null || echo skip'
		pane_wait GUEST_2
		[ "$(pane_parse GUEST_2)" = "skip" ] && TEST_ONE_skip=1
		;;
	"guest2")
		pane_run GUEST_2 "${__arg}"
		pane_wait GUEST_2
		;;
	"guest2b")
		pane_run GUEST_2 "${__arg}"
		;;
	"guest2w")
		pane_wait GUEST_2
		;;
	"ns")
		pane_run NS "${__arg}"
		pane_wait NS
		;;
	"ns1")
		pane_run NS1 "${__arg}"
		pane_wait NS1
		;;
	"ns2")
		pane_run NS2 "${__arg}"
		pane_wait NS2
		;;
	"nsb")
		pane_run NS "${__arg}"
		;;
	"ns1b")
		pane_run NS1 "${__arg}"
		;;
	"ns2b")
		pane_run NS2 "${__arg}"
		;;
	"nsw")
		pane_wait NS
		;;
	"ns1w")
		pane_wait NS1
		;;
	"ns2w")
		pane_wait NS2
		;;
	"nstools")
		pane_run NS 'which '"${__arg}"' >/dev/null || echo skip'
		pane_wait NS
		[ "$(pane_parse NS)" = "skip" ] && TEST_ONE_skip=1
		;;
	"gout")
		__varname="${__arg%% *}"
		pane_run GUEST "${__arg#* }"
		pane_wait GUEST
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse GUEST)")"
		;;
	"g1out")
		__varname="${__arg%% *}"
		pane_run GUEST_1 "${__arg#* }"
		pane_wait GUEST_1
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse GUEST_1)")"
		;;
	"g2out")
		__varname="${__arg%% *}"
		pane_run GUEST_2 "${__arg#* }"
		pane_wait GUEST_2
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse GUEST_2)")"
		;;
	"hout")
		__varname="${__arg%% *}"
		pane_run HOST "${__arg#* }"
		pane_wait HOST
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse HOST)")"
		;;
	"nsout")
		__varname="${__arg%% *}"
		pane_run NS "${__arg#* }"
		pane_wait NS
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse NS)")"
		;;
	"ns1out")
		__varname="${__arg%% *}"
		pane_run NS1 "${__arg#* }"
		pane_wait NS1
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse NS1)")"
		;;
	"ns2out")
		__varname="${__arg%% *}"
		pane_run NS2 "${__arg#* }"
		pane_wait NS2
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "$(pane_parse NS2)")"
		;;
	"check")
		info_check "${__arg}"
		__nok=0
		eval "${__arg} || __nok=1"
		if [ ${__nok} -eq 1 ]; then
			TEST_ONE_nok=1
			info_check_failed
		else
			info_check_passed
		fi
		;;
	"sleep")
		sleep "${__arg}"
		;;
	"info")
		info "${__arg}"
		;;
	"report")
		perf_report ${__arg}
		;;
	"th")
		table_header ${__arg}
		;;
	"tr")
		table_row "${__arg}"
		;;
	"tl")
		table_line "${__arg}"
		;;
	"te")
		table_end
		;;
	"bw")
		table_value_throughput ${__arg} || TEST_ONE_perf_nok=1
		;;
	"lat")
		table_value_latency ${__arg} || TEST_ONE_perf_nok=1
		;;
	"iperf3c")
		test_iperf3 client ${__arg}
		;;
	"iperf3s")
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__arg%% *}__" "$(test_iperf3 server ${__arg#* })" )"
		;;
	"set")
		TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__arg%% *}__" "${__arg#* }")"
		;;

	# Demo commands
	"say")
		text_write "${__arg}"
		;;
	"em")
		em_write "${__arg}"
		;;
	"nl")
		info_nolog ""
		;;
	"hl")
		pane_highlight "${__arg}"
		;;
	"bsp")
		text_backspace "${__arg}"
		;;
	"killp")
		pane_kill "${__arg}"
		;;
	"resize")
		pane_resize ${__arg}
		;;
	*)
		__def_body="$(eval printf \"\$TEST_ONE_DEF_$__cmd\")"
		if [ -n "${__def_body}" ]; then
			__ifs="${IFS}"
			IFS='
'
			for __def_line in ${__def_body}; do
				IFS= test_one_line "${__def_line}"
			done
			IFS="${__ifs}"
		fi
		;;
	esac
}

# test_one() - Run a single test file evaluating directives
# $1:	Name of test file, relative to test/ directory
test_one() {
	TEST_ONE_dirclean=
	__test_file="test/${1}"

	__type="$(file -b --mime-type ${__test_file})"
	if [ "${__type}" = "text/x-shellscript" ]; then
		status_file_start "${1}" 1
		"${__test_file}" && status_test_ok || status_test_fail
		return
	fi

	__ntests="$(grep -c "^test$(printf '\t')" "${__test_file}")"
	[ ${DEMO} -eq 0 ] && status_file_start "${1}" "${__ntests}"

	[ ${CI} -eq 1 ] && video_link "${1}"

	TEST_ONE_subs=
	TEST_ONE_nok=-1
	TEST_ONE_perf_nok=0
	TEST_ONE_skip=0
	TEST_ONE_in_def=
	while IFS= read -r __line; do
		test_one_line "${__line}"
		[ ${TEST_ONE_skip} -eq 1 ] && break
	done < "${__test_file}"

	for __d in ${TEST_ONE_dirclean}; do
		rm -rf ${__d}
	done

	[ ${DEMO} -eq 1 ] && return

	[ ${TEST_ONE_skip} -eq 1 ] && status_test_skip && return
	[ ${TEST_ONE_perf_nok} -eq 0 ] || TEST_ONE_nok=1
	[ ${TEST_ONE_nok} -eq 0 ] && status_test_ok || status_test_fail
}

# test() - Build list of tests to run, in order, then issue test_one()
# $1:	Name of directory containing set of test files, relative to test/
test() {
	__list=
	__rem=1

	cd test
	while [ ${__rem} -eq 1 ]; do
		__rem=0
		for __f in "${1}"/*; do
			__type="$(file -b --mime-type ${__f})"
			if [ "${__type}" = "text/x-shellscript" ]; then
				__list="$(list_add "${__list}" "${__f}")"
				continue
			fi

			if [ -n "$(file_def "${__f}" onlyfor)" ] && \
			   ! list_has "$(file_def "${__f}" onlyfor)" "${MODE}"; then
				continue
			fi

			if list_has_all "${__list}" "$(file_def "${__f}" req)"; then
				__list="$(list_add "${__list}" "${__f}")"
			else
				__rem=1
			fi
		done
	done
	cd ..

	for __f in ${__list}; do
		test_one "${__f}"
	done
}