From 061519b5620f594b5e5711ae6f3372ff152bc14c Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Mon, 27 Sep 2021 15:10:35 +0200 Subject: test: Add CI/demo scripts Not really quick, definitely dirty. Signed-off-by: Stefano Brivio --- test/lib/test | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100755 test/lib/test (limited to 'test/lib/test') diff --git a/test/lib/test b/test/lib/test new file mode 100755 index 0000000..2e3f4ba --- /dev/null +++ b/test/lib/test @@ -0,0 +1,378 @@ +#!/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 + +# 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 +} -- cgit v1.2.3