7 NAME
=$
(basename "${0}")
32 ruby-binding-of-caller
51 # Recent tor client require a Chutney network with tor >= 0.4.4.6 (#18190)
52 MINIMUM_TOR_VERSION
=0.4.4.6
55 echo "Usage: $NAME [OPTION]... [--] [CUCUMBER_ARGS]...
56 Sets up an appropriate environment and invokes cucumber. Note that this script
57 must be run from the Tails source directory root.
59 Options for '@product' features:
60 --allow-non-root Normally the test suite must be run as root, but if you
61 really know what you are doing this option allows any
63 --artifacts-base-uri URI
64 Pretend that the artifact is located at URI when printing
65 its location during a scenario failure. This is useful if
66 you intend to serve the artifacts via the web, for
68 --capture Captures failed scenarios into videos stored in the
69 temporary directory (see --tmpdir below) using x264
70 encoding. Requires x264.
71 --capture-all Keep videos for all scenarios, including those that
72 succeed (implies --capture).
73 --interactive-debugging
74 On failure, pause test suite until pressing Enter. Also
75 offer the option to open an interactive Ruby shell (pry)
76 in the Cucumber world's context.
78 When any image matching fails, enter an interactive mode
79 that allows to update the image. If run from a graphical
80 environment, any found candidate image will be displayed
82 --keep-chutney Don't ever clean Chutney data directory.
83 This can be a big time saver when debugging steps
84 when --keep-snapshots is not an option.
85 --keep-snapshots Don't ever delete any snapshots (including ones marked as
86 temporary). This can be a big time saver when debugging new
87 features. Implies --keep-chutney.
88 --disable-chutney EXPERIMENTAL: All tests will be run using the real Tor
89 network, not a simulated one.
90 Expect this to break many test cases.
93 Copies files into the VM before running the test suite,
94 which often can avoid a rebuild.
95 FILE is a text file where each line contains tab-separated
96 source and destination. If only a source is given, it is
97 assumed to be a file inside config/chroot_local-includes,
98 and the corresponding destination is inferred. Lines with
99 a leading \"#\" are ignored.
100 FILE is optional, and if not given we copy in all files in
101 config/chroot_local-includes that have changed since the
102 commit the system under testing was built from, including
104 --early-patch Boots the system with the \"early_patch=umount\" cmdline option.
105 See wiki/src/contribute/build/early-patch.mdwn for details
106 This is useful when you need something to be patched early
107 in the boot process; or if you need to run arbitrary
108 commands, not just copying files
109 --all-tests Don't skip tests which have a @fragile or @skip_by_default tag.
110 --tmpdir Directory where various temporary files are written
111 during a test, e.g. VM snapshots and memory dumps,
112 failure screenshots, pcap files and disk images
113 (default is TMPDIR in the environment, and if unset,
115 --view Shows the test session in a windows. Requires x11vnc
117 --view-interact The test session can be \"touched\". For debugging purposes
119 --vnc-server-only Starts a VNC server for the test session. Requires x11vnc.
120 --iso IMAGE Test '@product' features using IMAGE.
121 --old-iso IMAGE For some '@product' features (e.g. usb_install) we need
122 an older version of Tails, which this options sets to
123 IMAGE. If none is given, it defaults to the same IMAGE
124 given by --iso, which will be good enough for most testing
127 Note that '@source' features has no relevant options.
129 CUCUMBER_ARGS can be used to specify which features to be run, but also any
130 cucumber option, although then you must pass \`--\` first to let this wrapper
131 script know that we're done with *its* options. For debugging purposes, a
132 'debug' formatter has been added so pretty debugging can be enabled with
133 \`--format debug\`. You could even combine the default (pretty) formatter with
134 pretty debugging printed to a file with \`--format pretty --format debug
140 echo "${NAME}: error: ${*}" >&2
144 package_installed
() {
147 if dpkg
-s "${1}" 2>/dev
/null |
grep -q "^Status:.*installed"; then
156 check_dependencies
() {
157 while [ -n "${1:-}" ]; do
158 if ! command -v "${1}" >/dev
/null
&& ! package_installed
"${1}" ; then
159 error
"'${1}' is missing, please install it and run again."
165 check_tor_version
() {
167 tor_version
=$
(tor
--version |
grep -Po '^Tor version \K.*' |
sed --regexp-extended 's,[.]$,,')
168 echo "tor version: $tor_version"
169 if dpkg
--compare-versions "$tor_version" lt
"$MINIMUM_TOR_VERSION"; then
170 error
"Please upgrade to tor ${MINIMUM_TOR_VERSION} or newer."
174 check_virt_viewer_version
() {
176 version
="$(dpkg-query --show --showformat='${VERSION}' virt-viewer)"
177 if dpkg
--compare-versions "${version}" ge
10.0; then
178 if ! echo "${version}" |
grep -q 'tails$'; then
179 error
'Please install virt-viewer from the isotester-bookworm APT suite' \
180 '(instructions: https://tails.net/contribute/release_process/test/setup/' \
181 'details: https://gitlab.tails.boum.org/tails/tails/-/issues/19064)'
187 [ -e "/tmp/.X${1#:}-lock" ] ||
[ -e "/tmp/.X11-unix/X${1#:}" ]
190 next_free_display
() {
192 while display_in_use
":${display_nr}"; do
193 display_nr
=$
((display_nr
+1))
195 echo ":${display_nr}"
198 test_suite_cleanup
() {
199 if [ -n "${XVFB_PID:-}" ]; then
200 (kill -0 "${XVFB_PID}" 2>/dev
/null
&& kill "${XVFB_PID}") ||
/bin
/true
206 Xvfb
"$TARGET_DISPLAY" -screen 0 1024x768x24
+32 -noreset >/dev
/null
2>&1 &
208 # Wait for Xvfb to run on TARGET_DISPLAY
209 until display_in_use
"$TARGET_DISPLAY"; do
212 echo "Virtual X framebuffer started on display ${TARGET_DISPLAY}"
213 # Hide the mouse cursor so it won't be in the way when we are
214 # trying to match images.
215 unclutter
-display "$TARGET_DISPLAY" -root -idle 0.1 >/dev
/null
2>&1 &
219 check_dependencies x11vnc
220 # shellcheck disable=SC2086
221 VNC_SERVER_PORT
="$(env -u WAYLAND_DISPLAY x11vnc \
222 -listen localhost -display "${TARGET_DISPLAY}" \
223 -bg -nopw -forever ${TAILS_X11VNC_OPTS:-} 2>&1 | \
224 grep -m 1 "^PORT
=[0-9]\
+" | sed 's/^PORT=//')"
225 echo "VNC server running on: localhost:${VNC_SERVER_PORT}"
230 if [[ "${VNC_VIEWER_VIEWONLY}" = yes ]]; then
233 check_dependencies tigervnc-viewer
241 "localhost:${VNC_SERVER_PORT}" 1>/dev
/null
2>&1 &
246 # Set default values of environment variables used by this script to
247 # pass options to cucumber (unless they are already set).
248 ALLOW_NON_ROOT
=${ALLOW_NON_ROOT-}
249 ARTIFACTS_BASE_URI
=${ARTIFACTS_BASE_URI-}
251 CAPTURE_ALL
=${CAPTURE_ALL-}
252 VNC_VIEWER
=${VNC_VIEWER-}
253 VNC_VIEWER_VIEWONLY
=${VNC_VIEWER_VIEWONLY-yes}
254 VNC_SERVER
=${VNC_SERVER-}
255 INTERACTIVE_DEBUGGING
=${INTERACTIVE_DEBUGGING-}
256 IMAGE_BUMPING_MODE
=${IMAGE_BUMPING_MODE-}
257 KEEP_CHUTNEY
=${KEEP_CHUTNEY-}
258 KEEP_SNAPSHOTS
=${KEEP_SNAPSHOTS-}
259 TAILS_ISO
=${TAILS_ISO-}
260 OLD_TAILS_ISO
=${OLD_TAILS_ISO-}
261 EARLY_PATCH
=${EARLY_PATCH-}
262 EXTRA_BOOT_OPTIONS
=${EXTRA_BOOT_OPTIONS-}
263 ALL_TESTS
=${ALL_TESTS-}
265 LONGOPTS
="allow-non-root,artifacts-base-uri:,view,view-interact,vnc-server-only,capture,capture-all,help,tmpdir:,keep-chutney,keep-snapshots,disable-chutney,late-patch::,early-patch,extra-boot-options:,all-tests,iso:,old-iso:,interactive-debugging,image-bumping-mode"
266 OPTS
=$
(getopt
-o "" --longoptions $LONGOPTS -n "${NAME}" -- "$@")
268 while [ $# -gt 0 ]; do
271 if ! /sbin
/getcap
/usr
/bin
/tcpdump |
grep -q 'cap_net_raw=eip'; then
272 error
"/usr/bin/tcpdump lacks cap_net_raw=eip"
276 --artifacts-base-uri)
278 export ARTIFACTS_BASE_URI
="${1}"
282 VNC_VIEWER_VIEWONLY
=yes
295 check_dependencies x264
299 check_dependencies x264
301 export CAPTURE_ALL
="yes"
303 --interactive-debugging)
304 export INTERACTIVE_DEBUGGING
="yes"
306 --image-bumping-mode)
307 export IMAGE_BUMPING_MODE
="yes"
310 export KEEP_CHUTNEY
="yes"
313 export KEEP_CHUTNEY
="yes"
314 export KEEP_SNAPSHOTS
="yes"
317 export DISABLE_CHUTNEY
="yes"
321 if [ -n "${1:-}" ]; then
322 LATE_PATCH
="$(realpath -s "$1")"
323 if [ ! -e "$LATE_PATCH" ]; then
324 error
"--late-patch: FILE doesn't exist"
332 export EARLY_PATCH
="yes"
334 --extra-boot-options)
336 export EXTRA_BOOT_OPTIONS
="$1"
343 TMPDIR
="$(readlink -f "$1")"
348 TAILS_ISO
="$(realpath -s "$1")"
353 OLD_TAILS_ISO
="$(realpath -s "$1")"
368 trap "test_suite_cleanup" EXIT HUP INT QUIT TERM
370 if [ "${EUID}" -ne 0 ] && [ -z "${ALLOW_NON_ROOT}" ]; then
371 error
"you are not running as root; if you really know what you are" \
372 "doing, see the --allow-non-root option"
375 # shellcheck disable=SC2086
376 check_dependencies
${GENERAL_DEPENDENCIES}
378 check_virt_viewer_version
380 TARGET_DISPLAY
=$
(next_free_display
)
384 if [ -n "${VNC_SERVER:-}" ]; then
387 if [ -n "${VNC_VIEWER:-}" ]; then
392 if [ -n "${JENKINS_URL:-}" ]; then
393 . auto
/scripts
/utils.sh
395 if echo "${GIT_BRANCH}" |
grep -q -E '[+-]real-Tor$'; then
396 export DISABLE_CHUTNEY
="yes"
397 TAGS_ARGS
="--tag @supports_real_tor"
398 # The current Git state may not reflect the state at the time the
399 # upstream job was started (e.g. since then we git fetch + git
400 # reset --hard) so we trust the Git state described in Jenkins'
401 # environment variables instead.
402 elif echo "${GIT_BRANCH}" |
grep -q -E '[+-]force-all-tests$' \
404 ||
[ "${GIT_BRANCH#origin/}" = feature
/bookworm
] \
405 ||
[ "${GIT_BRANCH#origin/}" = testing
] \
406 ||
[ "${GIT_BRANCH#origin/}" = devel
] \
407 ||
[ -n "${ALL_TESTS:-}" ]; then
410 TAGS_ARGS
="${TAGS_ARGS} --tag ~@fragile --tag ~@skip_by_default"
412 if [ "${UPSTREAMJOB_GIT_COMMIT}" != "${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}" ] && \
413 git_only_doc_changes_since
"${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}"; then
414 TAGS_ARGS
="${TAGS_ARGS} --tag @doc"
418 export USER_DISPLAY
="${DISPLAY:-}"
419 export DISPLAY
=${TARGET_DISPLAY}
421 # shellcheck disable=SC2086
422 cucumber
--expand ${TAGS_ARGS} "${@}"