aboutgitcodebugslistschat
path: root/test/lib/test
blob: 2e3f4baa89e3f4e6e7d92b66bb210f3eb92f5256 (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 36
		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 38
	pane_run "${__pane}" 'for i in $(seq 0 '${__procs}'); do'	\
		 'kill -INT $(cat s${i}.pid) 2>/dev/null; done'
	sleep 1
	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() - Run a single test file evaluating directives
# $1:	Name of test file, relative to test/ directory
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}"

	__subs=
	__nok=-1
	__perf_nok=0
	__skip=0
	while IFS= read -r __line; do
		# Strip comments
		__line="${__line%%#*}"

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

		[ ${__nok} -eq 1 ] && [ "${__cmd}" != "test" ] && continue
		case ${__cmd} in
		"tempdir")
			__tmpdir="$(mktemp -d)"
			__subs="$(list_add_pair "${__subs}" "__${__arg}__" "${__tmpdir}")"
			__dirclean="$(list_add "${__dirclean}" "${__tmpdir}")"
			;;
		"temp")
			__tmpfile="$(mktemp)"
			__subs="$(list_add_pair "${__subs}" "__${__arg}__" "${__tmpfile}")"
			__dirclean="$(list_add "${__dirclean}" "${__tmpfile}")"
			;;
		"test")
			[ ${__perf_nok} -eq 0 ] || __nok=1
			[ ${__nok} -eq 1 ] && status_test_fail
			[ ${__nok} -eq 0 ] && status_test_ok

			status_test_start "${__arg}"
			__nok=0
			__perf_nok=0
			;;
		"host")
			pane_run HOST "${__arg}"
			pane_wait HOST
			;;
		"hostb")
			pane_run HOST "${__arg}"
			;;
		"hostw")
			pane_wait HOST
			;;
		"htools")
			pane_run HOST 'which '"${__arg}"' >/dev/null || echo skip'
			pane_wait HOST
			[ "$(pane_parse HOST)" = "skip" ] && { __skip=1; break; }
			;;
		"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
			__subs="$(list_add_pair "${__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" ] && { __skip=1; break; }
			;;
		"g1tools")
			pane_run GUEST_1 'which '"${__arg}"' >/dev/null || echo skip'
			pane_wait GUEST_1
			[ "$(pane_parse GUEST_1)" = "skip" ] && { __skip=1; break; }
			;;
		"g2tools")
			pane_run GUEST_2 'which '"${__arg}"' >/dev/null || echo skip'
			pane_wait GUEST_2
			[ "$(pane_parse GUEST_2)" = "skip" ] && { __skip=1; break; }
			;;
		"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
			;;
		"nsb")
			pane_run NS "${__arg}"
			;;
		"nsw")
			pane_wait NS
			;;
		"nstools")
			pane_run NS 'which '"${__arg}"' >/dev/null || echo skip'
			pane_wait NS
			[ "$(pane_parse NS)" = "skip" ] && { __skip=1; break; }
			;;
		"gout")
			__varname="${__arg%% *}"
			pane_run GUEST "${__arg#* }"
			pane_wait GUEST
			__subs="$(list_add_pair "${__subs}" "__${__varname}__" "$(pane_parse GUEST)")"
			;;
		"g1out")
			__varname="${__arg%% *}"
			pane_run GUEST_1 "${__arg#* }"
			pane_wait GUEST_1
			__subs="$(list_add_pair "${__subs}" "__${__varname}__" "$(pane_parse GUEST_1)")"
			;;
		"g2out")
			__varname="${__arg%% *}"
			pane_run GUEST_2 "${__arg#* }"
			pane_wait GUEST_2
			__subs="$(list_add_pair "${__subs}" "__${__varname}__" "$(pane_parse GUEST_2)")"
			;;
		"hout")
			__varname="${__arg%% *}"
			pane_run HOST "${__arg#* }"
			pane_wait HOST
			__subs="$(list_add_pair "${__subs}" "__${__varname}__" "$(pane_parse HOST)")"
			;;
		"nsout")
			__varname="${__arg%% *}"
			pane_run NS "${__arg#* }"
			pane_wait NS
			__subs="$(list_add_pair "${__subs}" "__${__varname}__" "$(pane_parse NS)")"
			;;
		"check")
			info_check "${__arg}"
			eval "${__arg} || __nok=1"
			if [ ${__nok} -eq 1 ]; then
				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} || __perf_nok=1
			;;
		"lat")
			table_value_latency ${__arg} || __perf_nok=1
			;;
		"iperf3c")
			set -x
			test_iperf3 client ${__arg}
			set +x
			;;
		"iperf3s")
			set -x
			__subs="$(list_add_pair "${__subs}" "__${__arg%% *}__" "$(test_iperf3 server ${__arg#* })" )"
			set +x
			;;
		"set")
			__subs="$(list_add_pair "${__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}"
			;;
		esac
	done < "${__test_file}"

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

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

	[ ${__skip} -eq 1 ] && status_test_skip && return
	[ ${__perf_nok} -eq 0 ] || __nok=1
	[ ${__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
}