3
# Usage: test-compose [testname]
8
###############################################################################
9
# BEGIN stuff you can but probably shouldn't customize
11
# Directory where this script and all subtests live
12
TEST_ROOTDIR=$(realpath $(dirname $0))
15
PODMAN_BIN=$(realpath $TEST_ROOTDIR/../../bin)/podman
17
# Local path to docker socket with unix prefix
18
# The path will be changed for rootless users
19
DOCKER_SOCK=/var/run/docker.sock
21
# END stuff you can but probably shouldn't customize
22
###############################################################################
25
export TMPDIR=${TMPDIR:-/var/tmp}
26
WORKDIR=$(mktemp --tmpdir -d $ME.tmp.XXXXXX)
28
# Log of all HTTP requests and responses; always make '.log' point to latest
29
LOGBASE=${TMPDIR}/$ME.log
30
LOG=${LOGBASE}.$(date +'%Y%m%dT%H%M%S')
33
# Keep track of test count and failures in files, not variables, because
34
# variables don't carry back up from subshells.
35
testcounter_file=$WORKDIR/.testcounter
36
failures_file=$WORKDIR/.failures
38
echo 0 >$testcounter_file
42
###############################################################################
43
# BEGIN infrastructure code - the helper functions used in tests themselves
46
# is_rootless # Check if we run as normal user
48
function is_rootless() {
53
# die # Exit error with a message to stderr
61
# is # Simple comparison
68
if [[ "$actual" = "$expect" ]]; then
69
# On success, include expected value; this helps readers understand
70
_show_ok 1 "$testname=$expect"
73
_show_ok 0 "$testname" "$expect" "$actual"
77
# like # Compare, but allowing patterns
84
# "is" (equality) is a subset of "like", but one that expr fails on if
85
# the expected result has shell-special characters like '['. Treat it
88
if [[ "$actual" = "$expect" ]]; then
89
_show_ok 1 "$testname=$expect"
93
if expr "$actual" : ".*$expect" &>/dev/null; then
94
# On success, include expected value; this helps readers understand
95
_show_ok 1 "$testname ('$actual') ~ $expect"
98
_show_ok 0 "$testname" "~ $expect" "$actual"
102
# _show_ok # Helper for is() and like(): displays 'ok' or 'not ok'
108
# If output is a tty, colorize pass/fail
120
_bump $testcounter_file
121
count=$(<$testcounter_file)
123
# "skip" is a special case of "ok". Assume that our caller has included
124
# the magical '# skip - reason" comment string.
125
if [[ $ok == "skip" ]]; then
126
# colon-plus: replace green with yellow, but only if green is non-null
127
green="${green:+\e[33m}"
130
if [ $ok -eq 1 ]; then
131
echo -e "${green}ok $count $testname${reset}"
132
echo "ok $count $testname" >>$LOG
139
printf "${red}not ok $count $testname${reset}\n"
140
# Not all errors include actual/expect
141
if [[ -n "$expect" || -n "$actual" ]]; then
142
printf "${red}# expected: %s${reset}\n" "$expect"
143
printf "${red}# actual: ${bold}%s${reset}\n" "$actual"
146
echo "not ok $count $testname" >>$LOG
147
echo " expected: $expect" >>$LOG
153
# _bump # Increment a counter in a file
159
echo $(( $count + 1 )) >| $file
163
# test_port # Run curl against a port, check results against expectation
165
function test_port() {
166
local port="$1" # e.g. 5000
167
local op="$2" # '=' or '~'
168
local expect="$3" # what to expect from curl output
170
# -s -S means "silent, but show errors"
172
actual=$(curl --retry 3 --retry-all-errors -s -S http://127.0.0.1:$port/)
175
if [ $curl_rc -ne 0 ]; then
176
_show_ok 0 "$testname - curl (port $port) failed with status $curl_rc"
177
echo "# cat $WORKDIR/server.log:"
178
cat $WORKDIR/server.log
179
echo "# cat $logfile:"
185
'=') is "$actual" "$expect" "$testname : port $port" ;;
186
'~') like "$actual" "$expect" "$testname : port $port" ;;
187
*) die "Invalid operator '$op'" ;;
193
# start_service # Run the socket listener
196
function start_service() {
197
test -x $PODMAN_BIN || die "Not found: $PODMAN_BIN"
199
# FIXME: use ${testname} subdir but we can't: 50-char limit in runroot
200
if ! is_rootless; then
201
rm -rf $WORKDIR/{root,runroot,cni}
203
$PODMAN_BIN unshare rm -rf $WORKDIR/{root,runroot,cni}
206
mkdir --mode 0755 $WORKDIR/{root,runroot,cni}
207
chcon --reference=/var/lib/containers $WORKDIR/root
211
--storage-driver=vfs \
212
--root $WORKDIR/root \
213
--runroot $WORKDIR/runroot \
214
--cgroup-manager=systemd \
215
--network-config-dir $WORKDIR/cni \
217
--time 0 unix://$DOCKER_SOCK \
218
&> $WORKDIR/server.log &
221
# Wait (FIXME: how do we test the socket?)
223
while [ $_timeout -gt 0 ]; do
224
# FIXME: should we actually try a read or write?
225
test -S $DOCKER_SOCK && return
227
_timeout=$(( $_timeout - 1 ))
229
cat $WORKDIR/server.log
230
die "Timed out waiting for service"
234
# podman # Needed by some test scripts to invoke the actual podman binary
237
echo "\$ podman $*" >>$WORKDIR/output.log
238
output=$($PODMAN_BIN \
239
--storage-driver=vfs \
240
--root $WORKDIR/root \
241
--runroot $WORKDIR/runroot \
242
--network-config-dir $WORKDIR/cni \
246
echo -n "$output" >>$WORKDIR/output.log
250
# as rootless we want to test the remote connection so we add --connection
251
function podman_compose() {
253
$PODMAN_BIN --connection compose-sock compose "$@"
260
# random_string # Returns a pseudorandom human-readable string
262
function random_string() {
263
# Numeric argument, if present, is desired length of string
264
local length=${1:-10}
266
head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
269
# END infrastructure code
270
###############################################################################
273
for tool in curl docker-compose; do
274
type $tool &>/dev/null || die "$ME: Required tool '$tool' not found"
278
###############################################################################
279
# BEGIN entry handler (subtest invoker)
281
# When rootless use a socket path accessible by the rootless user
283
# lets test two cases here, for rootless we try to connect to the connection as this should be respected
284
DOCKER_SOCK="$WORKDIR/docker.sock"
285
# use PODMAN_CONNECTIONS_CONF so we do not overwrite user settings
286
PODMAN_CONNECTIONS_CONF="$WORKDIR/connections.json"
287
export PODMAN_CONNECTIONS_CONF
288
$PODMAN_BIN system connection add --default notexists "unix:///I/do/not/exist"
289
$PODMAN_BIN system connection add compose-sock "unix://$DOCKER_SOCK"
292
# export DOCKER_HOST docker-compose will use it
293
DOCKER_HOST="unix://$DOCKER_SOCK"
297
# hide annoying podman compose warnings, some tests want to check compose stderr and this breaks it.
298
CONTAINERS_CONF_OVERRIDE="$WORKDIR/containers.conf"
300
compose_warning_logs=false' > "$CONTAINERS_CONF_OVERRIDE"
301
export CONTAINERS_CONF_OVERRIDE
304
# Identify the tests to run. If called with args, use those as globs.
309
match=(${TEST_ROOTDIR}/*${i}*/docker-compose.yml)
310
if [ ${#match} -eq 0 ]; then
311
die "No match for $TEST_ROOTDIR/*$i*.curl"
313
tests_to_run+=("${match[@]}")
317
tests_to_run=(${TEST_ROOTDIR}/*/docker-compose.yml)
320
# Too hard to precompute the number of tests; just spit it out at the end.
323
# We aren't really TAP 13; this helps logformatter recognize our output as BATS
326
for t in "${tests_to_run[@]}"; do
327
testdir="$(dirname $t)"
328
testname="$(basename $testdir)"
330
if [ -e $testdir/SKIP ]; then
331
reason="$(<$testdir/SKIP)"
332
if [ -n "$reason" ]; then
335
_show_ok skip "$testname # skip$reason"
341
logfile=$WORKDIR/$testname.log
343
cd $testdir || die "Cannot cd $testdir"
345
if [ -e teardown.sh ]; then
347
function teardown() {
348
trap '_show_ok 0 "$testname - teardown" "[ok]" "[error]"' ERR
354
# setup file may be used for creating temporary directories/files.
355
# We source it so that envariables defined in it will get back to us.
356
if [ -e setup.sh ]; then
357
trap '_show_ok 0 "$testname - setup" "[ok]" "[error]"' ERR
362
podman_compose up -d &> $logfile
364
if [[ $docker_compose_rc -ne 0 ]]; then
365
_show_ok 0 "$testname - up" "[ok]" "status=$docker_compose_rc"
366
sed -e 's/^/# /' <$logfile
367
podman_compose down >>$logfile 2>&1 # No status check here
370
_show_ok 1 "$testname - up"
372
# Run tests. This is likely to be a series of 'test_port' checks
373
# but may also include podman commands to inspect labels, state
374
if [ -e tests.sh ]; then
375
trap '_show_ok 0 "$testname - tests" "[ok]" "[error]"' ERR
379
# FIXME: if any tests fail, try 'podman logs' on container?
381
if [ -n "${COMPOSE_WAIT:-}" ]; then
382
echo -n "Pausing due to \$COMPOSE_WAIT. Press ENTER to continue: "
387
podman_compose down &>> $logfile
389
if [[ $rc -eq 0 ]]; then
390
_show_ok 1 "$testname - down"
392
_show_ok 0 "$testname - down" "[ok]" "rc=$rc"
400
# FIXME: otherwise we get EBUSY
401
if ! is_rootless; then
402
umount $WORKDIR/root/overlay &>/dev/null
404
$PODMAN_BIN unshare umount $WORKDIR/root/overlay &>/dev/null
407
# FIXME: run 'podman ps'?
408
# rm -rf $WORKDIR/${testname}
412
###############################################################################
416
test_count=$(<$testcounter_file)
417
failure_count=$(<$failures_file)
419
if [ -z "${PODMAN_TESTS_KEEP_WORKDIR:-}" ]; then
420
if ! is_rootless; then
423
$PODMAN_BIN unshare rm -rf $WORKDIR
427
echo "1..${test_count}"