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.
91 Copies files into the VM before running the test suite,
92 which often can avoid a rebuild.
93 FILE is a text file where each line contains tab-separated
94 source and destination. If only a source is given, it is
95 assumed to be a file inside config/chroot_local-includes,
96 and the corresponding destination is inferred. Lines with
97 a leading \"#\" are ignored.
98 FILE is optional, and if not given we copy in all files in
99 config/chroot_local-includes that have changed since the
100 commit the system under testing was built from, including
102 --early-patch Boots the system with the \"early_patch=umount\" cmdline option.
103 See wiki/src/contribute/build/early-patch.mdwn for details
104 This is useful when you need something to be patched early
105 in the boot process; or if you need to run arbitrary
106 commands, not just copying files
107 --all-tests Don't skip tests which have a @fragile or @skip_by_default tag.
108 --tmpdir Directory where various temporary files are written
109 during a test, e.g. VM snapshots and memory dumps,
110 failure screenshots, pcap files and disk images
111 (default is TMPDIR in the environment, and if unset,
113 --view Shows the test session in a windows. Requires x11vnc
115 --view-interact The test session can be \"touched\". For debugging purposes
117 --vnc-server-only Starts a VNC server for the test session. Requires x11vnc.
118 --iso IMAGE Test '@product' features using IMAGE.
119 --old-iso IMAGE For some '@product' features (e.g. usb_install) we need
120 an older version of Tails, which this options sets to
121 IMAGE. If none is given, it defaults to the same IMAGE
122 given by --iso, which will be good enough for most testing
125 Note that '@source' features has no relevant options.
127 CUCUMBER_ARGS can be used to specify which features to be run, but also any
128 cucumber option, although then you must pass \`--\` first to let this wrapper
129 script know that we're done with *its* options. For debugging purposes, a
130 'debug' formatter has been added so pretty debugging can be enabled with
131 \`--format debug\`. You could even combine the default (pretty) formatter with
132 pretty debugging printed to a file with \`--format pretty --format debug
138 echo "${NAME}: error: ${*}" >&2
142 package_installed
() {
145 if dpkg
-s "${1}" 2>/dev
/null |
grep -q "^Status:.*installed"; then
154 check_dependencies
() {
155 while [ -n "${1:-}" ]; do
156 if ! command -v "${1}" >/dev
/null
&& ! package_installed
"${1}" ; then
157 error
"'${1}' is missing, please install it and run again."
163 check_tor_version
() {
165 tor_version
=$
(tor
--version |
grep -Po '^Tor version \K.*' |
sed --regexp-extended 's,[.]$,,')
166 echo "tor version: $tor_version"
167 if dpkg
--compare-versions "$tor_version" lt
"$MINIMUM_TOR_VERSION"; then
168 error
"Please upgrade to tor ${MINIMUM_TOR_VERSION} or newer."
172 check_virt_viewer_version
() {
174 version
="$(dpkg-query --show --showformat='${VERSION}' virt-viewer)"
175 if dpkg
--compare-versions "${version}" ge
10.0; then
176 if ! echo "${version}" |
grep -q 'tails$'; then
177 error
'Please install virt-viewer from the isotester-bookworm APT suite' \
178 '(instructions: https://tails.net/contribute/release_process/test/setup/' \
179 'details: https://gitlab.tails.boum.org/tails/tails/-/issues/19064)'
185 [ -e "/tmp/.X${1#:}-lock" ] ||
[ -e "/tmp/.X11-unix/X${1#:}" ]
188 next_free_display
() {
190 while display_in_use
":${display_nr}"; do
191 display_nr
=$
((display_nr
+1))
193 echo ":${display_nr}"
196 test_suite_cleanup
() {
197 if [ -n "${XVFB_PID:-}" ]; then
198 (kill -0 "${XVFB_PID}" 2>/dev
/null
&& kill "${XVFB_PID}") ||
/bin
/true
204 Xvfb
"$TARGET_DISPLAY" -screen 0 1024x768x24
+32 -noreset >/dev
/null
2>&1 &
206 # Wait for Xvfb to run on TARGET_DISPLAY
207 until display_in_use
"$TARGET_DISPLAY"; do
210 echo "Virtual X framebuffer started on display ${TARGET_DISPLAY}"
211 # Hide the mouse cursor so it won't be in the way when we are
212 # trying to match images.
213 unclutter
-display "$TARGET_DISPLAY" -root -idle 0.1 >/dev
/null
2>&1 &
217 check_dependencies x11vnc
218 # shellcheck disable=SC2086
219 VNC_SERVER_PORT
="$(env -u WAYLAND_DISPLAY x11vnc \
220 -listen localhost -display "${TARGET_DISPLAY}" \
221 -bg -nopw -forever ${TAILS_X11VNC_OPTS:-} 2>&1 | \
222 grep -m 1 "^PORT
=[0-9]\
+" | sed 's/^PORT=//')"
223 echo "VNC server running on: localhost:${VNC_SERVER_PORT}"
228 if [[ "${VNC_VIEWER_VIEWONLY}" = yes ]]; then
231 check_dependencies tigervnc-viewer
239 "localhost:${VNC_SERVER_PORT}" 1>/dev
/null
2>&1 &
244 # Set default values of environment variables used by this script to
245 # pass options to cucumber (unless they are already set).
246 ALLOW_NON_ROOT
=${ALLOW_NON_ROOT-}
247 ARTIFACTS_BASE_URI
=${ARTIFACTS_BASE_URI-}
249 CAPTURE_ALL
=${CAPTURE_ALL-}
250 VNC_VIEWER
=${VNC_VIEWER-}
251 VNC_VIEWER_VIEWONLY
=${VNC_VIEWER_VIEWONLY-yes}
252 VNC_SERVER
=${VNC_SERVER-}
253 INTERACTIVE_DEBUGGING
=${INTERACTIVE_DEBUGGING-}
254 IMAGE_BUMPING_MODE
=${IMAGE_BUMPING_MODE-}
255 KEEP_CHUTNEY
=${KEEP_CHUTNEY-}
256 KEEP_SNAPSHOTS
=${KEEP_SNAPSHOTS-}
257 TAILS_ISO
=${TAILS_ISO-}
258 OLD_TAILS_ISO
=${OLD_TAILS_ISO-}
259 EARLY_PATCH
=${EARLY_PATCH-}
260 EXTRA_BOOT_OPTIONS
=${EXTRA_BOOT_OPTIONS-}
261 ALL_TESTS
=${ALL_TESTS-}
263 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"
264 OPTS
=$
(getopt
-o "" --longoptions $LONGOPTS -n "${NAME}" -- "$@")
266 while [ $# -gt 0 ]; do
269 if ! /sbin
/getcap
/usr
/bin
/tcpdump |
grep -q 'cap_net_raw=eip'; then
270 error
"/usr/bin/tcpdump lacks cap_net_raw=eip"
274 --artifacts-base-uri)
276 export ARTIFACTS_BASE_URI
="${1}"
280 VNC_VIEWER_VIEWONLY
=yes
293 check_dependencies x264
297 check_dependencies x264
299 export CAPTURE_ALL
="yes"
301 --interactive-debugging)
302 export INTERACTIVE_DEBUGGING
="yes"
304 --image-bumping-mode)
305 export IMAGE_BUMPING_MODE
="yes"
308 export KEEP_CHUTNEY
="yes"
311 export KEEP_CHUTNEY
="yes"
312 export KEEP_SNAPSHOTS
="yes"
315 export DISABLE_CHUTNEY
="yes"
319 if [ -n "${1:-}" ]; then
320 LATE_PATCH
="$(realpath -s "$1")"
321 if [ ! -e "$LATE_PATCH" ]; then
322 error
"--late-patch: FILE doesn't exist"
330 export EARLY_PATCH
="yes"
332 --extra-boot-options)
334 export EXTRA_BOOT_OPTIONS
="$1"
341 TMPDIR
="$(readlink -f "$1")"
346 TAILS_ISO
="$(realpath -s "$1")"
351 OLD_TAILS_ISO
="$(realpath -s "$1")"
366 trap "test_suite_cleanup" EXIT HUP INT QUIT TERM
368 if [ "${EUID}" -ne 0 ] && [ -z "${ALLOW_NON_ROOT}" ]; then
369 error
"you are not running as root; if you really know what you are" \
370 "doing, see the --allow-non-root option"
373 # shellcheck disable=SC2086
374 check_dependencies
${GENERAL_DEPENDENCIES}
376 check_virt_viewer_version
378 TARGET_DISPLAY
=$
(next_free_display
)
382 if [ -n "${VNC_SERVER:-}" ]; then
385 if [ -n "${VNC_VIEWER:-}" ]; then
390 if [ -n "${JENKINS_URL:-}" ]; then
391 . auto
/scripts
/utils.sh
393 if echo "${GIT_BRANCH}" |
grep -q -E '[+-]real-Tor$'; then
394 export DISABLE_CHUTNEY
="yes"
395 TAGS_ARGS
="--tag @supports_real_tor"
396 # The current Git state may not reflect the state at the time the
397 # upstream job was started (e.g. since then we git fetch + git
398 # reset --hard) so we trust the Git state described in Jenkins'
399 # environment variables instead.
400 elif echo "${GIT_BRANCH}" |
grep -q -E '[+-]force-all-tests$' \
402 ||
[ "${GIT_BRANCH#origin/}" = feature
/bookworm
] \
403 ||
[ "${GIT_BRANCH#origin/}" = testing
] \
404 ||
[ "${GIT_BRANCH#origin/}" = devel
] \
405 ||
[ -n "${ALL_TESTS:-}" ]; then
408 TAGS_ARGS
="${TAGS_ARGS} --tag ~@fragile --tag ~@skip_by_default"
410 if [ "${UPSTREAMJOB_GIT_COMMIT}" != "${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}" ] && \
411 git_only_doc_changes_since
"${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}"; then
412 TAGS_ARGS
="${TAGS_ARGS} --tag @doc"
416 export USER_DISPLAY
="${DISPLAY:-}"
417 export DISPLAY
=${TARGET_DISPLAY}
419 # shellcheck disable=SC2086
420 cucumber
--expand ${TAGS_ARGS} "${@}"