7 NAME
=$
(basename "${0}")
49 # Recent tor client require a Chutney network with tor >= 0.4.4.6 (#18190)
50 MINIMUM_TOR_VERSION
=0.4.4.6
53 echo "Usage: $NAME [OPTION]... [--] [CUCUMBER_ARGS]...
54 Sets up an appropriate environment and invokes cucumber. Note that this script
55 must be run from the Tails source directory root.
57 Options for '@product' features:
58 --allow-non-root Normally the test suite must be run as root, but if you
59 really know what you are doing this option allows any
61 --artifacts-base-uri URI
62 Pretend that the artifact is located at URI when printing
63 its location during a scenario failure. This is useful if
64 you intend to serve the artifacts via the web, for
66 --capture Captures failed scenarios into videos stored in the
67 temporary directory (see --tmpdir below) using x264
68 encoding. Requires x264.
69 --capture-all Keep videos for all scenarios, including those that
70 succeed (implies --capture).
71 --interactive-debugging
72 On failure, pause test suite until pressing Enter. Also
73 offer the option to open an interactive Ruby shell (pry)
74 in the Cucumber world's context.
76 When any image matching fails, enter an interactive mode
77 that allows to update the image. If run from a graphical
78 environment, any found candidate image will be displayed
80 --keep-chutney Don't ever clean Chutney data directory.
81 This can be a big time saver when debugging steps
82 when --keep-snapshots is not an option.
83 --keep-snapshots Don't ever delete any snapshots (including ones marked as
84 temporary). This can be a big time saver when debugging new
85 features. Implies --keep-chutney.
86 --disable-chutney EXPERIMENTAL: All tests will be run using the real Tor
87 network, not a simulated one.
88 Expect this to break many test cases.
89 --late-patch FILE Copies files into the VM before running the test suite.
90 This often can avoid a rebuild.
91 FILE is a text file where each line contains tab-separated
92 source and destination.
93 lines without a tab are ignored.
94 lines with a leading \"#\" are ignored.
95 --early-patch Boots the system with the \"early_patch=umount\" cmdline option.
96 See wiki/src/contribute/build/early-patch.mdwn for details
97 This is useful when you need something to be patched early
98 in the boot process; or if you need to run arbitrary
99 commands, not just copying files
100 --all-tests Don't skip tests which have a @fragile or @skip_by_default tag.
101 --tmpdir Directory where various temporary files are written
102 during a test, e.g. VM snapshots and memory dumps,
103 failure screenshots, pcap files and disk images
104 (default is TMPDIR in the environment, and if unset,
106 --view Shows the test session in a windows. Requires x11vnc
108 --view-interact The test session can be \"touched\". For debugging purposes
110 --vnc-server-only Starts a VNC server for the test session. Requires x11vnc.
111 --iso IMAGE Test '@product' features using IMAGE.
112 --old-iso IMAGE For some '@product' features (e.g. usb_install) we need
113 an older version of Tails, which this options sets to
114 IMAGE. If none is given, it defaults to the same IMAGE
115 given by --iso, which will be good enough for most testing
118 Note that '@source' features has no relevant options.
120 CUCUMBER_ARGS can be used to specify which features to be run, but also any
121 cucumber option, although then you must pass \`--\` first to let this wrapper
122 script know that we're done with *its* options. For debugging purposes, a
123 'debug' formatter has been added so pretty debugging can be enabled with
124 \`--format debug\`. You could even combine the default (pretty) formatter with
125 pretty debugging printed to a file with \`--format pretty --format debug
131 echo "${NAME}: error: ${*}" >&2
135 package_installed
() {
138 if dpkg
-s "${1}" 2>/dev
/null |
grep -q "^Status:.*installed"; then
147 check_dependencies
() {
148 while [ -n "${1:-}" ]; do
149 if ! command -v "${1}" >/dev
/null
&& ! package_installed
"${1}" ; then
150 error
"'${1}' is missing, please install it and run again."
156 check_tor_version
() {
158 tor_version
=$
(tor
--version |
grep -Po '^Tor version \K.*' |
sed --regexp-extended 's,[.]$,,')
159 echo "tor version: $tor_version"
160 if dpkg
--compare-versions "$tor_version" lt
"$MINIMUM_TOR_VERSION"; then
161 error
"Please upgrade to tor ${MINIMUM_TOR_VERSION} or newer."
165 check_virt_viewer_version
() {
167 version
="$(dpkg-query --show --showformat='${VERSION}' virt-viewer)"
168 if dpkg
--compare-versions "${version}" ge
10.0; then
169 if ! echo "${version}" |
grep -q 'tails$'; then
170 error
'Please install virt-viewer from the isotester-bookworm APT suite' \
171 '(instructions: https://tails.net/contribute/release_process/test/setup/' \
172 'details: https://gitlab.tails.boum.org/tails/tails/-/issues/19064)'
178 [ -e "/tmp/.X${1#:}-lock" ] ||
[ -e "/tmp/.X11-unix/X${1#:}" ]
181 next_free_display
() {
183 while display_in_use
":${display_nr}"; do
184 display_nr
=$
((display_nr
+1))
186 echo ":${display_nr}"
189 test_suite_cleanup
() {
190 if [ -n "${XVFB_PID:-}" ]; then
191 (kill -0 "${XVFB_PID}" 2>/dev
/null
&& kill "${XVFB_PID}") ||
/bin
/true
197 Xvfb
"$TARGET_DISPLAY" -screen 0 1024x768x24
+32 -noreset >/dev
/null
2>&1 &
199 # Wait for Xvfb to run on TARGET_DISPLAY
200 until display_in_use
"$TARGET_DISPLAY"; do
203 echo "Virtual X framebuffer started on display ${TARGET_DISPLAY}"
204 # Hide the mouse cursor so it won't be in the way when we are
205 # trying to match images.
206 unclutter
-display "$TARGET_DISPLAY" -root -idle 0.1 >/dev
/null
2>&1 &
210 check_dependencies x11vnc
211 # shellcheck disable=SC2086
212 VNC_SERVER_PORT
="$(env -u WAYLAND_DISPLAY x11vnc \
213 -listen localhost -display "${TARGET_DISPLAY}" \
214 -bg -nopw -forever ${TAILS_X11VNC_OPTS:-} 2>&1 | \
215 grep -m 1 "^PORT
=[0-9]\
+" | sed 's/^PORT=//')"
216 echo "VNC server running on: localhost:${VNC_SERVER_PORT}"
221 if [[ "${VNC_VIEWER_VIEWONLY}" = yes ]]; then
224 check_dependencies tigervnc-viewer
232 "localhost:${VNC_SERVER_PORT}" 1>/dev
/null
2>&1 &
237 # Set default values of environment variables used by this script to
238 # pass options to cucumber (unless they are already set).
239 ALLOW_NON_ROOT
=${ALLOW_NON_ROOT-}
240 ARTIFACTS_BASE_URI
=${ARTIFACTS_BASE_URI-}
242 CAPTURE_ALL
=${CAPTURE_ALL-}
243 VNC_VIEWER
=${VNC_VIEWER-}
244 VNC_VIEWER_VIEWONLY
=${VNC_VIEWER_VIEWONLY-yes}
245 VNC_SERVER
=${VNC_SERVER-}
246 INTERACTIVE_DEBUGGING
=${INTERACTIVE_DEBUGGING-}
247 IMAGE_BUMPING_MODE
=${IMAGE_BUMPING_MODE-}
248 KEEP_CHUTNEY
=${KEEP_CHUTNEY-}
249 KEEP_SNAPSHOTS
=${KEEP_SNAPSHOTS-}
250 TAILS_ISO
=${TAILS_ISO-}
251 OLD_TAILS_ISO
=${OLD_TAILS_ISO-}
252 EARLY_PATCH
=${EARLY_PATCH-}
253 EXTRA_BOOT_OPTIONS
=${EXTRA_BOOT_OPTIONS-}
254 ALL_TESTS
=${ALL_TESTS-}
256 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"
257 OPTS
=$
(getopt
-o "" --longoptions $LONGOPTS -n "${NAME}" -- "$@")
259 while [ $# -gt 0 ]; do
262 if ! /sbin
/getcap
/usr
/bin
/tcpdump |
grep -q 'cap_net_raw=eip'; then
263 error
"/usr/bin/tcpdump lacks cap_net_raw=eip"
267 --artifacts-base-uri)
269 export ARTIFACTS_BASE_URI
="${1}"
273 VNC_VIEWER_VIEWONLY
=yes
286 check_dependencies x264
290 check_dependencies x264
292 export CAPTURE_ALL
="yes"
294 --interactive-debugging)
295 export INTERACTIVE_DEBUGGING
="yes"
297 --image-bumping-mode)
298 export IMAGE_BUMPING_MODE
="yes"
301 export KEEP_CHUTNEY
="yes"
304 export KEEP_CHUTNEY
="yes"
305 export KEEP_SNAPSHOTS
="yes"
308 export DISABLE_CHUTNEY
="yes"
312 LATE_PATCH
="$(realpath -s "$1")"
313 if ! [[ -f "$LATE_PATCH" ]]; then
314 echo "--late-patch requires a valid FILE as argument"
320 export EARLY_PATCH
="yes"
322 --extra-boot-options)
324 export EXTRA_BOOT_OPTIONS
="$1"
331 TMPDIR
="$(readlink -f "$1")"
336 TAILS_ISO
="$(realpath -s "$1")"
341 OLD_TAILS_ISO
="$(realpath -s "$1")"
356 trap "test_suite_cleanup" EXIT HUP INT QUIT TERM
358 if [ "${EUID}" -ne 0 ] && [ -z "${ALLOW_NON_ROOT}" ]; then
359 error
"you are not running as root; if you really know what you are" \
360 "doing, see the --allow-non-root option"
363 # shellcheck disable=SC2086
364 check_dependencies
${GENERAL_DEPENDENCIES}
366 check_virt_viewer_version
368 TARGET_DISPLAY
=$
(next_free_display
)
372 if [ -n "${VNC_SERVER:-}" ]; then
375 if [ -n "${VNC_VIEWER:-}" ]; then
380 if [ -n "${JENKINS_URL:-}" ]; then
381 . auto
/scripts
/utils.sh
383 if echo "${GIT_BRANCH}" |
grep -q -E '[+-]real-Tor$'; then
384 export DISABLE_CHUTNEY
="yes"
385 TAGS_ARGS
="--tag @supports_real_tor"
386 # The current Git state may not reflect the state at the time the
387 # upstream job was started (e.g. since then we git fetch + git
388 # reset --hard) so we trust the Git state described in Jenkins'
389 # environment variables instead.
390 elif echo "${GIT_BRANCH}" |
grep -q -E '[+-]force-all-tests$' \
392 ||
[ "${GIT_BRANCH#origin/}" = feature
/bullseye
] \
393 ||
[ "${GIT_BRANCH#origin/}" = testing
] \
394 ||
[ "${GIT_BRANCH#origin/}" = devel
] \
395 ||
[ -n "${ALL_TESTS:-}" ]; then
398 TAGS_ARGS
="${TAGS_ARGS} --tag ~@fragile --tag ~@skip_by_default"
400 if [ "${UPSTREAMJOB_GIT_COMMIT}" != "${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}" ] && \
401 git_only_doc_changes_since
"${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}"; then
402 TAGS_ARGS
="${TAGS_ARGS} --tag @doc"
406 export USER_DISPLAY
="${DISPLAY:-}"
407 export DISPLAY
=${TARGET_DISPLAY}
409 # shellcheck disable=SC2086
410 cucumber
--expand ${TAGS_ARGS} "${@}"