summaryrefslogtreecommitdiffstats
path: root/bin/lvc/run_test_suite
blob: 5b40c389147e3151822e59bf93308adde1082709 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/bin/bash

set -e
set -u
set -o pipefail

NAME=$(basename ${0})

GENERAL_DEPENDENCIES="
cucumber
devscripts
dnsmasq-base
gawk
git
i18nspector
libav-tools
libcap2-bin
libsikuli-script-java
libvirt-clients
libvirt-daemon-system
libvirt-dev
libvirt0
openjdk-7-jre
openssh-server
ovmf
python-jabberbot
python-potr
qemu-kvm
qemu-system-x86
ruby-guestfs
ruby-json
ruby-libvirt
ruby-net-irc
ruby-packetfu
ruby-rb-inotify
ruby-rjb
ruby-rspec
ruby-test-unit
seabios
tcpdump
unclutter
virt-viewer
xvfb
"

usage() {
    echo "Usage: $NAME [OPTION]... [--] [CUCUMBER_ARGS]...
Sets up an appropriate environment and invokes cucumber. Note that this script
must be run from the Tails source directory root.

Options for '@product' features:
  --artifacts-base-uri URI
                     Pretend that the artifact is located at URI when printing
                     its location during a scenario failure. This is useful if
                     you intend to serve the artifacts via the web, for
                     instance.
  --capture          Captures failed scenarios into videos stored in the
                     temporary directory (see --tmpdir below) using x264
                     encoding. Requires x264.
  --capture-all      Keep videos for all scenarios, including those that
                     succeed (implies --capture).
  --pause-on-fail    On failure, pause test suite until pressing Enter. This is
                     useful for investigating the state of the VM guest to see
                     exactly why a test failed.
  --keep-snapshots   Don't ever delete any snapshots (including ones marked as
                     temporary). This can be a big time saver when debugging new
                     features.
  --retry-find       Print a warning whenever Sikuli fails to find an image
                     and allow *one* retry after pressing ENTER. This is useful
                     for updating outdated images.
  --tmpdir           Directory where various temporary files are written
                     during a test, e.g. VM snapshots and memory dumps,
                     failure screenshots, pcap files and disk images
                     (default is TMPDIR in the environment, and if unset,
                     /tmp/DebianToaster).
  --view             Shows the test session in a windows. Requires x11vnc
                     and xtightvncviewer.
  --vnc-server-only  Starts a VNC server for the test session. Requires x11vnc.
  --iso IMAGE        Test '@product' features using IMAGE.
  --old-iso IMAGE    For some '@product' features (e.g. usb_install) we need
                     an older version of Tails, which this options sets to
                     IMAGE. If none is given, it defaults to the same IMAGE
                     given by --iso, which will be good enough for most testing
                     purposes.

Note that '@source' features has no relevant options.

CUCUMBER_ARGS can be used to specify which features to be run, but also any
cucumber option, although then you must pass \`--\` first to let this wrapper
script know that we're done with *its* options. For debugging purposes, a
'debug' formatter has been added so pretty debugging can be enabled with
\`--format debug\`. You could even combine the default (pretty) formatter with
pretty debugging printed to a file with \`--format pretty --format debug
--out debug.log\`.
"
}

error() {
    echo "${NAME}: error: ${*}" >&2
    usage
    exit 1
}

package_installed() {
    local ret
    set +o pipefail
    if dpkg -s "${1}" 2>/dev/null | grep -q "^Status:.*installed"; then
        ret=0
    else
        ret=1
    fi
    set -o pipefail
    return ${ret}
}

check_dependencies() {
    while [ -n "${1:-}" ]; do
        if ! which "${1}" >/dev/null && ! package_installed "${1}" ; then
            error "'${1}' is missing, please install it and run again."
        fi
        shift
    done
}

display_in_use() {
    [ -e "/tmp/.X${1#:}-lock" ] || [ -e "/tmp/.X11-unix/X${1#:}" ]
}

next_free_display() {
    display_nr=0
    while display_in_use ":${display_nr}"; do
	display_nr=$((display_nr+1))
    done
    echo ":${display_nr}"
}

test_suite_cleanup() {
    (kill -0 ${XVFB_PID} 2>/dev/null && kill ${XVFB_PID}) || /bin/true
}

start_xvfb() {
    Xvfb $TARGET_DISPLAY -screen 0 1024x768x24+32 >/dev/null 2>&1 &
    XVFB_PID=$!
    # Wait for Xvfb to run on TARGET_DISPLAY
    until display_in_use $TARGET_DISPLAY; do
	sleep 1
    done
    echo "Virtual X framebuffer started on display ${TARGET_DISPLAY}"
    # Hide the mouse cursor so it won't mess up Sikuli's screen scanning
    unclutter -display $TARGET_DISPLAY -root -idle 0 >/dev/null 2>&1 &
}

start_vnc_server() {
    check_dependencies x11vnc
    VNC_SERVER_PORT="$(x11vnc -listen localhost -display ${TARGET_DISPLAY} \
                              -bg -nopw -forever 2>&1 | \
                                  grep -m 1 "^PORT=[0-9]\+" | sed 's/^PORT=//')"
    echo "VNC server running on: localhost:${VNC_SERVER_PORT}"
}

start_vnc_viewer() {
    check_dependencies xtightvncviewer
    xtightvncviewer -viewonly localhost:${VNC_SERVER_PORT} 1>/dev/null 2>&1 &
}

capture_session() {
    check_dependencies libvpx1
    echo "Capturing guest display into ${CAPTURE_FILE}"
    avconv -f x11grab -s 1024x768 -r 15 -i ${TARGET_DISPLAY}.0 -an \
        -vcodec libvpx -y "${CAPTURE_FILE}" >/dev/null 2>&1 &
}

# main script

# Unset all environment variables used by this script to pass options
# to cucumber, except TMPDIR since we explicitly want to support
# setting it that way.
ARTIFACTS_BASE_URI=
CAPTURE=
CAPTURE_ALL=
LOG_FILE=
VNC_VIEWER=
VNC_SERVER=
PAUSE_ON_FAIL=
KEEP_SNAPSHOTS=
SIKULI_RETRY_FINDFAILED=
ISO=
OLD_ISO=

LONGOPTS="artifacts-base-uri:,view,vnc-server-only,capture,capture-all,help,tmpdir:,keep-snapshots,retry-find,iso:,old-iso:,pause-on-fail"
OPTS=$(getopt -o "" --longoptions $LONGOPTS -n "${NAME}" -- "$@")
eval set -- "$OPTS"
while [ $# -gt 0 ]; do
    case $1 in
        --artifacts-base-uri)
            shift
            export ARTIFACTS_BASE_URI="${1}"
            ;;
        --view)
            VNC_VIEWER=yes
            VNC_SERVER=yes
            ;;
        --vnc-server-only)
            VNC_VIEWER=
            VNC_SERVER=yes
            ;;
        --capture)
            check_dependencies x264
            export CAPTURE="yes"
            ;;
        --capture-all)
            check_dependencies x264
            export CAPTURE="yes"
            export CAPTURE_ALL="yes"
            ;;
        --pause-on-fail)
            export PAUSE_ON_FAIL="yes"
            ;;
        --keep-snapshots)
            export KEEP_SNAPSHOTS="yes"
            ;;
        --retry-find)
            export SIKULI_RETRY_FINDFAILED="yes"
            ;;
        --tmpdir)
            shift
            export TMPDIR="$(readlink -f $1)"
            ;;
        --iso)
            shift
            export ISO="$(readlink -f $1)"
            ;;
        --old-iso)
            shift
            export OLD_ISO="$(readlink -f $1)"
            ;;
        --help)
	    usage
            exit 0
            ;;
        --)
            shift
            break
            ;;
    esac
    shift
done

trap "test_suite_cleanup" EXIT HUP INT QUIT TERM

check_dependencies ${GENERAL_DEPENDENCIES}

TARGET_DISPLAY=$(next_free_display)

start_xvfb

if [ -n "${VNC_SERVER:-}" ]; then
    start_vnc_server
fi
if [ -n "${VNC_VIEWER:-}" ]; then
    start_vnc_viewer
fi

export SIKULI_HOME="/usr/share/java"
export SIKULI_IMAGE_PATH="/srv/jenkins/features/images/"
export RUBYLIB="/srv/jenkins"
export VM_XML_PATH="/srv/jenkins/features/domains"
export DISPLAY=${TARGET_DISPLAY}
check_dependencies cucumber

# cludge ruby to stop buffering output
RUBY_STDOUT_SYNC=$TMPDIR/.stdout-sync.rb
echo STDOUT.sync = true > $RUBY_STDOUT_SYNC
export RUBYOPT="-r $RUBY_STDOUT_SYNC"

cucumber ${@}