diff --git a/README.md b/README.md index 16e91b9..9c71c13 100644 --- a/README.md +++ b/README.md @@ -398,28 +398,52 @@ is fully configurable with command line options. ### pasta + + +
-
use pasta to create and connect a namespace
-
use Podman with pasta
+
+
+
use pasta to create and connect a namespace
+
+
+
+
+
use Podman with pasta
+
+ ### passt -

+
+ ## Continuous Integration -

- - +
+ +
Test logs [here](/builds/latest/test/). diff --git a/hooks/pre-push b/hooks/pre-push index 0498b0a..3a46922 100755 --- a/hooks/pre-push +++ b/hooks/pre-push @@ -34,11 +34,12 @@ ssh "${USER_HOST}" "mkdir -p ${WEB} ${TEST} ${BIN}" cd test ./ci -scp ci.webm perf.js ci.js ../doc/*.png "${USER_HOST}:${WEB}/" +scp ci.cast perf.js ci.js ../doc/*.png "${USER_HOST}:${WEB}/" scp test_logs/* "${USER_HOST}:${TEST}/" ./run_demo -scp demo_passt.webm demo_pasta.webm "${USER_HOST}:${WEB}/" +scp demo_pasta.cast demo_podman.cast "${USER_HOST}:${WEB}/" +scp demo_passt.cast "${USER_HOST}:${WEB}/" cd .. diff --git a/test/README.md b/test/README.md index 647100f..88270e8 100644 --- a/test/README.md +++ b/test/README.md @@ -49,21 +49,13 @@ as needed, so there's no need to actually install it. ### Special requirements for continuous integration and demo modes -Running the test suite as continuous integration or demo modes will record a -video of the steps being executed, and create binary packages. The demo mode -uses _cool-retro-term_ as terminal, whereas the continuous integration mode uses -_MATE Terminal_ by default. +Running the test suite as continuous integration or demo modes will record the +terminal with the steps being executed, using asciinema(1), and create binary +packages. -The following additional packages are commonly needed as well: +The following additional packages are commonly needed: - dbus-x11 xdotool x11-utils xvfb ffmpeg mate-terminal cool-retro-term xauth - dconf-cli alien linux-perf tshark sqlite3` - -For convenience, suitable profiles for _MATE Terminal_ and _cool-retro-term_ are -provided under the `env` directory. To source them: - - dconf load /org/mate/terminal/profiles/ < env/mate-terminal.profile - cp env/cool_retro_term.sqlite ~/.local/share/cool-retro-term/QML/OfflineStorage/Databases/*.sqlite + alien linux-perf tshark ## Regular test @@ -79,9 +71,9 @@ Issuing: ./ci -will run the whole test suite while recording a video of the execution, and it -will also build JavaScript fragments used on http://passt.top/ for performance -data tables and links to specific video offsets. +will run the whole test suite while recording the execution, and it will also +build JavaScript fragments used on http://passt.top/ for performance data tables +and links to specific offsets in the captures. ## Demo mode @@ -89,7 +81,7 @@ Issuing: ./demo -will run the demo cases under `demo`, recording videos as well. +will run the demo cases under `demo`, with terminal captures as well. # Framework diff --git a/test/lib/perf_report b/test/lib/perf_report index baa084b..9117046 100755 --- a/test/lib/perf_report +++ b/test/lib/perf_report @@ -103,19 +103,24 @@ for (var i = 0; i < perf_links.length; i++) { var obj = document.getElementById(perf_links[i][0]); obj.addEventListener("click", function(event) { - var ci_video = document.getElementById("ci_video"); + var ci_video = document.getElementById("ci"); var top = ci_video.offsetTop - 5; + var seek; - event.preventDefault(); - ci_video.play(); - ci_video.pause(); for (var i = 0; i < perf_links.length; i++) { if (this.id == perf_links[i][0]) { - ci_video.currentTime = perf_links[i][1] - 10; + seek = perf_links[i][1]; } } + + event.preventDefault(); + ci_video_player.dispose(); + ci_video_player = AsciinemaPlayer.create( + "/builds/latest/web/ci.cast", + ci_video, + { startAt: seek, autoplay: true }); + window.scrollTo({ top: top, behavior: "smooth" }) - ci_video.play(); }, false); } ' diff --git a/test/lib/term b/test/lib/term index e8a1d38..205a6a9 100755 --- a/test/lib/term +++ b/test/lib/term @@ -539,33 +539,22 @@ pause_continue() { info_nolog "" } -# run_term() - Start tmux session, X terminal if requested, running entry point +# run_term() - Start tmux session, running entry point, with recording if needed run_term() { export SHELL="/bin/sh" tmux set-option -g default-shell "/bin/sh" tmux set-option -g update-environment "PCAP DEBUG" if [ ${CI} -eq 1 ]; then - __xterm_done="$(mktemp)" - if [ ${XVFB} -eq 1 ]; then - xvfb-run -s "-screen 0 4000x4000x24 -ac" ${CI_XTERM} "$(pwd)" -e "sh -c \"printf '\e[8;50;240t'; tmux new-session -s passt_test ./ci from_term; echo >${__xterm_done}\"" - else - ${CI_XTERM} "$(pwd)" -e "sh -c \"printf '\e[8;50;240t'; tmux new-session -s passt_test ./ci from_term; echo >${__xterm_done}\"" - fi - while ! [ -s "${__xterm_done}" ]; do sleep 1; done - rm "${__xterm_done}" + printf '\e[8;50;240t' + asciinema rec --overwrite ci.uncut -c 'tmux new-session -s passt_test ./ci from_term' + video_postprocess ci.uncut elif [ ${DEMO} -eq 1 ]; then - while true; do - if [ ${XVFB} -eq 1 ]; then - xvfb-run -s "-screen 0 4000x4000x24 -ac" ${DEMO_XTERM} "$(pwd)" -e sh -c 'tmux new-session -s passt_test ./run_demo from_term' - else - ${DEMO_XTERM} "$(pwd)" -e sh -c 'tmux new-session -s passt_test ./run_demo from_term' - fi - [ $? -ne 0 ] && { tmux kill-session -t passt_test; continue; } - break - done + printf '\e[8;40;130t' + asciinema rec --overwrite demo.uncut -c 'tmux new-session -s passt_test ./run_demo from_term' + video_postprocess demo.uncut else - tmux new-session -s passt_test ./run from_term + tmux new-session -s passt_test ./run_demo from_term fi } diff --git a/test/lib/video b/test/lib/video index 6db9c1d..ec79c85 100755 --- a/test/lib/video +++ b/test/lib/video @@ -8,9 +8,9 @@ # PASTA - Pack A Subtle Tap Abstraction # for network namespace/tap device mode # -# test/lib/video - Video grabbing, JavaScript fragments with links +# test/lib/video - Session recording, JavaScript fragments with links # -# Copyright (c) 2021 Red Hat GmbH +# Copyright (c) 2021-2022 Red Hat GmbH # Author: Stefano Brivio FFMPEG_PID_FILE="$(mktemp)" @@ -33,19 +33,24 @@ for (var i = 0; i < video___VIDEO_NAME__links.length; i++) { var obj = document.getElementById(video___VIDEO_NAME__links[i][0]); obj.addEventListener("click", function(event) { - var __VIDEO_NAME___video = document.getElementById("__VIDEO_NAME___video"); - var top = __VIDEO_NAME___video.offsetTop - 5; + var __VIDEO_NAME___div = document.getElementById("__VIDEO_NAME__"); + var top = __VIDEO_NAME___div.offsetTop - 5; + var seek; - event.preventDefault(); - __VIDEO_NAME___video.play(); - __VIDEO_NAME___video.pause(); for (var i = 0; i < video___VIDEO_NAME__links.length; i++) { if (this.id == video___VIDEO_NAME__links[i][0]) { - __VIDEO_NAME___video.currentTime = video___VIDEO_NAME__links[i][1]; + seek = video___VIDEO_NAME__links[i][1]; } } + + event.preventDefault(); + __VIDEO_NAME___player.dispose(); + __VIDEO_NAME___player = AsciinemaPlayer.create( + "/builds/latest/web/__VIDEO_NAME__.cast", + __VIDEO_NAME___div, + { startAt: seek, autoplay: true }); + window.scrollTo({ top: top, behavior: "smooth" }) - __VIDEO_NAME___video.play(); }, false); } ' @@ -65,31 +70,65 @@ video_append_links_js() VIDEO_LINKS_BUF="${VIDEO_LINKS_BUF}${@}" } -# video_grab() - Fetch window geometry, start grabbing video -video_grab() { +# video_start() - Mark start of a test in capture, record start timestamp +video_start() { VIDEO_NAME="${1}" - rm -f "${BASEPATH}/${VIDEO_NAME}.mp4" "${BASEPATH}/${VIDEO_NAME}.webm" "${BASEPATH}/${VIDEO_NAME}.js" - echo "${VIDEO_LINKS_TEMPLATE}" > "${BASEPATH}/${VIDEO_NAME}.js" - - if [ ${XVFB} -eq 1 ]; then - # Grab the geometry of the first window that's at least 100px wide - eval $(xwininfo -d :99.0 -root -tree | sed -n 's/^[ ]*0x[0-f]*[^0-9]*\([0-9]\{3,\}\)x\([0-9]*\)+\([0-9]*\)+\([0-9]*\).*/__width=\1; __height=\2; __x=\3; __y=\4;/p') - else - __x=$(xwininfo -id $(xdotool getactivewindow) | sed -n 's/[ ]*Absolute upper-left X:[ ]*\([0-9]*\)$/\1/p') - __y=$(xwininfo -id $(xdotool getactivewindow) | sed -n 's/[ ]*Absolute upper-left Y:[ ]*\([0-9]*\)$/\1/p') - __width=$(xwininfo -id $(xdotool getactivewindow) | sed -n 's/[ ]*Width:[ ]*\([0-9]*\)$/\1/p') - __height=$(xwininfo -id $(xdotool getactivewindow) | sed -n 's/[ ]*Height:[ ]*\([0-9]*\)$/\1/p') - fi - - [ $((__width % 2)) ] && __width=$((__width - 1)) - [ $((__height % 2)) ] && __height=$((__height - 1)) - - sleep 3 VIDEO_START_SECONDS=$(sed -n 's/\([0-9]*\).[0-9]* [0-9]*.[0-9]*/\1/p' /proc/uptime) - [ ${XVFB} -eq 1 ] && __disp=":99.0" || __disp= - ffmpeg -f x11grab -framerate 15 -video_size "${__width}x${__height}" -i "${__disp}+${__x},${__y}" -vcodec libx264 -qp 0 -draw_mouse 0 "${BASEPATH}/${VIDEO_NAME}.mp4" & echo $! > "${FFMPEG_PID_FILE}" + + sync + [ ${DEMO} -eq 1 ] && tail -1 "${BASEPATH}/demo.uncut" > "${BASEPATH}/${VIDEO_NAME}.start" + [ ${CI} -eq 1 ] && tail -1 "${BASEPATH}/ci.uncut" > "${BASEPATH}/${VIDEO_NAME}.start" + sync + + tmux refresh-client +} + +# video_stop() - Mark stop of a test in capture, finalise JavaScript fragments +video_stop() { + tmux refresh-client + + sync + [ ${DEMO} -eq 1 ] && tail -1 "${BASEPATH}/demo.uncut" > "${BASEPATH}/${VIDEO_NAME}.stop" + [ ${CI} -eq 1 ] && tail -1 "${BASEPATH}/ci.uncut" > "${BASEPATH}/${VIDEO_NAME}.stop" + sync + + sed -i 's/^.*$/&\\/g' "${BASEPATH}/${VIDEO_NAME}.js" + echo "${VIDEO_LINKS_TEMPLATE_JS}" | sed "s/__VIDEO_NAME__/${VIDEO_NAME}/g" >> "${BASEPATH}/${VIDEO_NAME}.js" + echo "${VIDEO_LINKS_BUF}" >> "${BASEPATH}/${VIDEO_NAME}.js" + echo "${VIDEO_LINKS_TEMPLATE_POST}" | sed "s/__VIDEO_NAME__/${VIDEO_NAME}/g" >> "${BASEPATH}/${VIDEO_NAME}.js" +} + +# video_postprocess() - Cut terminal recordings based on .start and .stop files +video_postprocess() { + IFS=' +' + __cast_name= + for __l in $(cat ${1}); do + [ -z "${__header}" ] && __header="${__l}" && continue + + if [ -z "${__cast_name}" ]; then + for __cast_cut in *.start; do + [ "${__l}" != "$(cat "${__cast_cut}")" ] && continue + __cast_name="${__cast_cut%.start}" + __cast_offset= + __stop_line="$(cat ${__cast_name}.stop)" + echo "${__header}" > "${__cast_name}.cast" + break + done + continue + fi + + [ "${__l}" = "${__stop_line}" ] && __cast_name= && continue + + __l_offset="$(echo ${__l%%.*}|tr -c -d '[:digit:]')" + __l_rest="${__l#*.}" + [ -z "${__cast_offset}" ] && __cast_offset=${__l_offset} + __l_offset=$((__l_offset - __cast_offset)) + printf '[%s.%s\n' "${__l_offset}" "${__l_rest}" >> "${__cast_name}".cast + done + unset IFS } # video_time_now() - Print current video timestamp, in seconds @@ -98,22 +137,6 @@ video_time_now() { echo $((__now - VIDEO_START_SECONDS)) } -# video_stop() - Stop grabbing, finalise JavaScript templates, convert to webm -video_stop() { - sed -i 's/^.*$/&\\/g' "${BASEPATH}/${VIDEO_NAME}.js" - echo "${VIDEO_LINKS_TEMPLATE_JS}" | sed "s/__VIDEO_NAME__/${VIDEO_NAME}/g" >> "${BASEPATH}/${VIDEO_NAME}.js" - echo "${VIDEO_LINKS_BUF}" >> "${BASEPATH}/${VIDEO_NAME}.js" - echo "${VIDEO_LINKS_TEMPLATE_POST}" | sed "s/__VIDEO_NAME__/${VIDEO_NAME}/g" >> "${BASEPATH}/${VIDEO_NAME}.js" - - kill -INT $(cat "${FFMPEG_PID_FILE}") - while ps -p $(cat "${FFMPEG_PID_FILE}") >/dev/null; do sleep 1; done - rm "${FFMPEG_PID_FILE}" - - [ ${1} -ne 0 ] && return - - ffmpeg -an -fflags +genpts -i "${BASEPATH}/${VIDEO_NAME}.mp4" -c:v libvpx-vp9 -row-mt 1 -minrate 10k -maxrate 200k -b:v 200k "${BASEPATH}/${VIDEO_NAME}.webm" -} - # video_link() - Append single link to given video chapter video_link() { [ ${VIDEO_LINKS_COUNT} -eq 0 ] && __sep="" || __sep=" |" diff --git a/test/run b/test/run index c91122d..385267e 100755 --- a/test/run +++ b/test/run @@ -60,7 +60,7 @@ run() { term perf_init - [ ${CI} -eq 1 ] && video_grab ci + [ ${CI} -eq 1 ] && video_start ci setup build test build @@ -94,7 +94,7 @@ run() { teardown two_guests perf_finish - [ ${CI} -eq 1 ] && video_stop ${STATUS_FAIL} + [ ${CI} -eq 1 ] && video_stop log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}" @@ -117,24 +117,24 @@ demo() { term_demo layout_demo_passt - video_grab demo_passt + video_start demo_passt MODE=passt test demo - video_stop 0 + video_stop teardown demo_passt layout_demo_pasta - video_grab demo_pasta + video_start demo_pasta MODE=pasta test demo - video_stop 0 + video_stop teardown demo_pasta layout_demo_podman - video_grab demo_podman + video_start demo_podman MODE=podman test demo - video_stop 0 + video_stop teardown_demo_podman return 0