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