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 ALWAYS_SAVE_JOURNAL
=${ALWAYS_SAVE_JOURNAL-}
253 VNC_VIEWER
=${VNC_VIEWER-}
254 VNC_VIEWER_VIEWONLY
=${VNC_VIEWER_VIEWONLY-yes}
255 VNC_SERVER
=${VNC_SERVER-}
256 INTERACTIVE_DEBUGGING
=${INTERACTIVE_DEBUGGING-}
257 IMAGE_BUMPING_MODE
=${IMAGE_BUMPING_MODE-}
258 KEEP_CHUTNEY
=${KEEP_CHUTNEY-}
259 KEEP_SNAPSHOTS
=${KEEP_SNAPSHOTS-}
260 TAILS_ISO
=${TAILS_ISO-}
261 OLD_TAILS_ISO
=${OLD_TAILS_ISO-}
262 EARLY_PATCH
=${EARLY_PATCH-}
263 EXTRA_BOOT_OPTIONS
=${EXTRA_BOOT_OPTIONS-}
264 ALL_TESTS
=${ALL_TESTS-}
266 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"
267 OPTS
=$
(getopt
-o "" --longoptions $LONGOPTS -n "${NAME}" -- "$@")
269 while [ $# -gt 0 ]; do
272 if ! /sbin
/getcap
/usr
/bin
/tcpdump |
grep -q 'cap_net_raw=eip'; then
273 error
"/usr/bin/tcpdump lacks cap_net_raw=eip"
277 --artifacts-base-uri)
279 export ARTIFACTS_BASE_URI
="${1}"
283 VNC_VIEWER_VIEWONLY
=yes
296 check_dependencies x264
300 check_dependencies x264
302 export CAPTURE_ALL
="yes"
304 --interactive-debugging)
305 export INTERACTIVE_DEBUGGING
="yes"
307 --image-bumping-mode)
308 export IMAGE_BUMPING_MODE
="yes"
311 export KEEP_CHUTNEY
="yes"
314 export KEEP_CHUTNEY
="yes"
315 export KEEP_SNAPSHOTS
="yes"
318 export DISABLE_CHUTNEY
="yes"
322 if [ -n "${1:-}" ]; then
323 LATE_PATCH
="$(realpath -s "$1")"
324 if [ ! -e "$LATE_PATCH" ]; then
325 error
"--late-patch: FILE doesn't exist"
333 export EARLY_PATCH
="yes"
335 --extra-boot-options)
337 export EXTRA_BOOT_OPTIONS
="$1"
344 TMPDIR
="$(readlink -f "$1")"
349 TAILS_ISO
="$(realpath -s "$1")"
354 OLD_TAILS_ISO
="$(realpath -s "$1")"
369 trap "test_suite_cleanup" EXIT HUP INT QUIT TERM
371 if [ "${EUID}" -ne 0 ] && [ -z "${ALLOW_NON_ROOT}" ]; then
372 error
"you are not running as root; if you really know what you are" \
373 "doing, see the --allow-non-root option"
376 # shellcheck disable=SC2086
377 check_dependencies
${GENERAL_DEPENDENCIES}
379 check_virt_viewer_version
381 TARGET_DISPLAY
=$
(next_free_display
)
385 if [ -n "${VNC_SERVER:-}" ]; then
388 if [ -n "${VNC_VIEWER:-}" ]; then
393 if [ -n "${JENKINS_URL:-}" ]; then
394 . auto
/scripts
/utils.sh
396 if echo "${GIT_BRANCH}" |
grep -q -E '[+-]real-Tor$'; then
397 export DISABLE_CHUTNEY
="yes"
398 TAGS_ARGS
="--tag @supports_real_tor"
399 # The current Git state may not reflect the state at the time the
400 # upstream job was started (e.g. since then we git fetch + git
401 # reset --hard) so we trust the Git state described in Jenkins'
402 # environment variables instead.
403 elif echo "${GIT_BRANCH}" |
grep -q -E '[+-]force-all-tests$' \
405 ||
[ "${GIT_BRANCH#origin/}" = feature
/bookworm
] \
406 ||
[ "${GIT_BRANCH#origin/}" = testing
] \
407 ||
[ "${GIT_BRANCH#origin/}" = devel
] \
408 ||
[ -n "${ALL_TESTS:-}" ]; then
411 TAGS_ARGS
="${TAGS_ARGS} --tag ~@fragile --tag ~@skip_by_default"
413 if [ "${UPSTREAMJOB_GIT_COMMIT}" != "${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}" ] && \
414 git_only_doc_changes_since
"${UPSTREAMJOB_GIT_BASE_BRANCH_HEAD}"; then
415 TAGS_ARGS
="${TAGS_ARGS} --tag @doc"
419 export USER_DISPLAY
="${DISPLAY:-}"
420 export DISPLAY
=${TARGET_DISPLAY}
422 # shellcheck disable=SC2086
423 cucumber
--expand ${TAGS_ARGS} "${@}"