summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/compose/README.md47
-rw-r--r--test/compose/elasticsearch-logstash-kibana.curl3
-rw-r--r--test/compose/flask.curl1
-rw-r--r--test/compose/gitea-postgres.curl1
-rw-r--r--test/compose/react-rust-postgres.skip1
-rw-r--r--test/compose/simple_port_map/frontend/app.py10
-rw-r--r--test/compose/simple_port_map/setup.sh3
-rw-r--r--test/compose/simple_port_map/teardown.sh4
-rw-r--r--test/compose/simple_port_map/tests.sh3
-rwxr-xr-xtest/compose/test-compose284
10 files changed, 160 insertions, 197 deletions
diff --git a/test/compose/README.md b/test/compose/README.md
new file mode 100644
index 000000000..863decf2c
--- /dev/null
+++ b/test/compose/README.md
@@ -0,0 +1,47 @@
+Tests for docker-compose
+========================
+
+This directory contains tests for docker-compose under podman.
+
+Each subdirectory must contain one docker-compose.yml file along with
+all necessary infrastructure for it (e.g. Containerfile, any files
+to be copied into the container, and so on.
+
+The `test-compose` script will, for each test subdirectory:
+
+* set up a fresh podman root under an empty working directory;
+* run a podman server rooted therein;
+* cd to the test subdirectory, and run `docker-compose up -d`;
+* source `tests.sh`;
+* run `docker-compose down`.
+
+As a special case, `setup.sh` and `teardown.sh` in the test directory
+will contain commands to be executed prior to `docker-compose up` and
+after `docker-compose down` respectively.
+
+tests.sh will probably contain commands of the form
+
+ test_port 12345 = 'hello there'
+
+Where 12345 is the port to curl to; '=' checks equality, '~' uses `expr`
+to check substrings; and 'hello there' is a string to look for in
+the curl results.
+
+Usage:
+
+ $ sudo test/compose/test-compose [pattern]
+
+By default, all subdirs will be run. If given a pattern, only those
+subdirectories matching 'pattern' will be run.
+
+If `$COMPOSE_WAIT` is set, `test-compose` will pause before running
+`docker-compose down`. This can be helpful for you to debug failing tests:
+
+ $ env COMPOSE_WAIT=1 sudo --preserve-env=COMPOSE_WAIT test/compose/test-compose
+
+Then, in another window,
+
+ # ls -lt /var/tmp/
+ # X=/var/tmp/test-compose.tmp.XXXXXX <--- most recent results of above
+ # podman --root $X/root --runroot $X/runroot ps -a
+ # podman --root $X/root --runroot $X/runroot logs -l
diff --git a/test/compose/elasticsearch-logstash-kibana.curl b/test/compose/elasticsearch-logstash-kibana.curl
deleted file mode 100644
index ddb7a96b0..000000000
--- a/test/compose/elasticsearch-logstash-kibana.curl
+++ /dev/null
@@ -1,3 +0,0 @@
-9200 You Know, for Search
-9600 "status":"green"
-5601 Kibana
diff --git a/test/compose/flask.curl b/test/compose/flask.curl
deleted file mode 100644
index b50ddbf1d..000000000
--- a/test/compose/flask.curl
+++ /dev/null
@@ -1 +0,0 @@
-5000 Hello World!
diff --git a/test/compose/gitea-postgres.curl b/test/compose/gitea-postgres.curl
deleted file mode 100644
index a0a58b3fd..000000000
--- a/test/compose/gitea-postgres.curl
+++ /dev/null
@@ -1 +0,0 @@
-3000 .* Gitea: Git with a cup of tea
diff --git a/test/compose/react-rust-postgres.skip b/test/compose/react-rust-postgres.skip
deleted file mode 100644
index 57f89ed17..000000000
--- a/test/compose/react-rust-postgres.skip
+++ /dev/null
@@ -1 +0,0 @@
-broken
diff --git a/test/compose/simple_port_map/frontend/app.py b/test/compose/simple_port_map/frontend/app.py
index 895556a89..97b17c440 100644
--- a/test/compose/simple_port_map/frontend/app.py
+++ b/test/compose/simple_port_map/frontend/app.py
@@ -1,9 +1,15 @@
from flask import Flask
+import os
app = Flask(__name__)
@app.route('/')
def hello():
- return "Podman rulez!"
+ passthru = "ERROR: Could not get $ENV_PASSTHRU envariable"
+ try:
+ passthru = os.getenv("ENV_PASSTHRU")
+ except Exception as e:
+ passthru = passthru + ": " + str(e)
+ return "Podman rulez!--" + passthru + "--!"
if __name__ == '__main__':
- app.run(host='0.0.0.0')
+ app.run(host='0.0.0.0')
diff --git a/test/compose/simple_port_map/setup.sh b/test/compose/simple_port_map/setup.sh
new file mode 100644
index 000000000..9004b1e76
--- /dev/null
+++ b/test/compose/simple_port_map/setup.sh
@@ -0,0 +1,3 @@
+# -*- bash -*-
+
+export ENV_PASSTHRU=$(random_string 20)
diff --git a/test/compose/simple_port_map/teardown.sh b/test/compose/simple_port_map/teardown.sh
new file mode 100644
index 000000000..3f8153fa0
--- /dev/null
+++ b/test/compose/simple_port_map/teardown.sh
@@ -0,0 +1,4 @@
+# -*- bash -*-
+
+# FIXME: this is completely unnecessary; it's just an example of a teardown
+unset ENV_PASSTHRU
diff --git a/test/compose/simple_port_map/tests.sh b/test/compose/simple_port_map/tests.sh
new file mode 100644
index 000000000..959b429d6
--- /dev/null
+++ b/test/compose/simple_port_map/tests.sh
@@ -0,0 +1,3 @@
+# -*- bash -*-
+
+test_port 5000 = "Podman rulez!--$ENV_PASSTHRU--!"
diff --git a/test/compose/test-compose b/test/compose/test-compose
index f7643b078..9558fbf58 100755
--- a/test/compose/test-compose
+++ b/test/compose/test-compose
@@ -1,32 +1,26 @@
#!/usr/bin/env bash
#
-# Usage: test-docker-compose [testname]
-#
-# DEVELOPER NOTE: you almost certainly don't need to play in here. See README.
+# Usage: test-compose [testname]
#
ME=$(basename $0)
###############################################################################
# BEGIN stuff you can but probably shouldn't customize
-# Directory where this script (and extra test configs) live
+# Directory where this script and all subtests live
TEST_ROOTDIR=$(realpath $(dirname $0))
# Podman executable
-PODMAN_BIN=$(realpath bin)/podman
-
-# Github repo containing sample docker-compose setups
-# FIXME: we should probably version this
-AWESOME_COMPOSE=https://github.com/docker/awesome-compose
+PODMAN_BIN=$(realpath $TEST_ROOTDIR/../../bin)/podman
-# Local path to docker socket
+# Local path to docker socket (we will add the unix:/ prefix when we need it)
DOCKER_SOCK=/var/run/docker.sock
# END stuff you can but probably shouldn't customize
###############################################################################
# BEGIN setup
-TMPDIR=${TMPDIR:-/var/tmp}
+export TMPDIR=${TMPDIR:-/var/tmp}
WORKDIR=$(mktemp --tmpdir -d $ME.tmp.XXXXXX)
# Log of all HTTP requests and responses; always make '.log' point to latest
@@ -153,145 +147,30 @@ function _bump() {
echo $(( $count + 1 )) >| $file
}
-#############
-# jsonify # convert 'foo=bar,x=y' to json {"foo":"bar","x":"y"}
-#############
-function jsonify() {
- # split by comma
- local -a settings_in
- read -ra settings_in <<<"$1"
-
- # convert each to double-quoted form
- local -a settings_out
- for i in ${settings_in[*]}; do
- settings_out+=$(sed -e 's/\(.*\)=\(.*\)/"\1":"\2"/' <<<$i)
- done
-
- # ...and wrap inside braces.
- # FIXME: handle commas
- echo "{${settings_out[*]}}"
-}
-
-#######
-# t # Main test helper
-#######
-function t() {
- local method=$1; shift
- local path=$1; shift
- local curl_args
-
- local testname="$method $path"
- # POST requests require an extra params arg
- if [[ $method = "POST" ]]; then
- curl_args="-d $(jsonify $1)"
- testname="$testname [$curl_args]"
- shift
- fi
-
- # entrypoint path can include a descriptive comment; strip it off
- path=${path%% *}
-
- # curl -X HEAD but without --head seems to wait for output anyway
- if [[ $method == "HEAD" ]]; then
- curl_args="--head"
- fi
- local expected_code=$1; shift
-
- # If given path begins with /, use it as-is; otherwise prepend /version/
- local url=http://$HOST:$PORT
- if expr "$path" : "/" >/dev/null; then
- url="$url$path"
- else
- url="$url/v1.40/$path"
- fi
-
- # Log every action we do
- echo "-------------------------------------------------------------" >>$LOG
- echo "\$ $testname" >>$LOG
- rm -f $WORKDIR/curl.*
- # -s = silent, but --write-out 'format' gives us important response data
- response=$(curl -s -X $method ${curl_args} \
- -H 'Content-type: application/json' \
- --dump-header $WORKDIR/curl.headers.out \
- --write-out '%{http_code}^%{content_type}^%{time_total}' \
- -o $WORKDIR/curl.result.out "$url")
-
- # Any error from curl is instant bad news, from which we can't recover
- rc=$?
- if [[ $rc -ne 0 ]]; then
- echo "FATAL: curl failure ($rc) on $url - cannot continue" >&2
- exit 1
- fi
-
- # Show returned headers (without trailing ^M or empty lines) in log file.
- # Sometimes -- I can't remember why! -- we don't get headers.
- if [[ -e $WORKDIR/curl.headers.out ]]; then
- tr -d '\015' < $WORKDIR/curl.headers.out | egrep '.' >>$LOG
- fi
-
- IFS='^' read actual_code content_type time_total <<<"$response"
- printf "X-Response-Time: ${time_total}s\n\n" >>$LOG
-
- # Log results, if text. If JSON, filter through jq for readability.
- if [[ $content_type =~ /octet ]]; then
- output="[$(file --brief $WORKDIR/curl.result.out)]"
- echo "$output" >>$LOG
- else
- output=$(< $WORKDIR/curl.result.out)
-
- if [[ $content_type =~ application/json ]]; then
- jq . <<<"$output" >>$LOG
- else
- echo "$output" >>$LOG
- fi
- fi
-
- # Test return code
- is "$actual_code" "$expected_code" "$testname : status"
-
- # Special case: 204/304, by definition, MUST NOT return content (rfc2616)
- if [[ $expected_code = 204 || $expected_code = 304 ]]; then
- if [ -n "$*" ]; then
- die "Internal error: ${expected_code} status returns no output; fix your test."
- fi
- if [ -n "$output" ]; then
- _show_ok 0 "$testname: ${expected_code} status returns no output" "''" "$output"
- fi
- return
- fi
-
- local i
-
- # Special case: if response code does not match, dump the response body
- # and skip all further subtests.
- if [[ $actual_code != $expected_code ]]; then
- echo -e "# response: $output"
- for i; do
- _show_ok skip "$testname: $i # skip - wrong return code"
- done
- return
+###############
+# test_port # Run curl against a port, check results against expectation
+###############
+function test_port() {
+ local port="$1" # e.g. 5000
+ local op="$2" # '=' or '~'
+ local expect="$3" # what to expect from curl output
+
+ local actual=$(curl --retry 5 --retry-connrefused -s http://127.0.0.1:$port/)
+ local curl_rc=$?
+ if [ $curl_rc -ne 0 ]; then
+ _show_ok 0 "$testname - curl failed with status $curl_rc"
+### docker-compose down >>$logfile 2>&1
+### exit 1
fi
- for i; do
- if expr "$i" : "[^=~]\+=.*" >/dev/null; then
- # Exact match on json field
- json_field=$(expr "$i" : "\([^=]*\)=")
- expect=$(expr "$i" : '[^=]*=\(.*\)')
- actual=$(jq -r "$json_field" <<<"$output")
- is "$actual" "$expect" "$testname : $json_field"
- elif expr "$i" : "[^=~]\+~.*" >/dev/null; then
- # regex match on json field
- json_field=$(expr "$i" : "\([^~]*\)~")
- expect=$(expr "$i" : '[^~]*~\(.*\)')
- actual=$(jq -r "$json_field" <<<"$output")
- like "$actual" "$expect" "$testname : $json_field"
- else
- # Direct string comparison
- is "$output" "$i" "$testname : output"
- fi
- done
+ case "$op" in
+ '=') is "$actual" "$expect" "$testname : port $port" ;;
+ '~') like "$actual" "$expect" "$testname : port $port" ;;
+ *) die "Invalid operator '$op'" ;;
+ esac
}
+
###################
# start_service # Run the socket listener
###################
@@ -299,8 +178,10 @@ service_pid=
function start_service() {
test -x $PODMAN_BIN || die "Not found: $PODMAN_BIN"
- rm -rf $WORKDIR/{root,runroot,cni}
- mkdir $WORKDIR/cni
+ # FIXME: use ${testname} subdir but we can't: 50-char limit in runroot
+ rm -rf $WORKDIR/{root,runroot,cni}
+ mkdir --mode 0755 $WORKDIR/{root,runroot,cni}
+ chcon --reference=/var/lib/containers $WORKDIR/root
cp /etc/cni/net.d/*podman*conflist $WORKDIR/cni/
$PODMAN_BIN \
@@ -329,8 +210,21 @@ function start_service() {
# podman # Needed by some test scripts to invoke the actual podman binary
############
function podman() {
- echo "\$ $PODMAN_BIN $*" >>$WORKDIR/output.log
- $PODMAN_BIN --root $WORKDIR "$@" >>$WORKDIR/output.log 2>&1
+ echo "\$ podman $*" >>$WORKDIR/output.log
+ $PODMAN_BIN \
+ --root $WORKDIR/root \
+ --runroot $WORKDIR/runroot \
+ "$@" >>$WORKDIR/output.log 2>&1
+}
+
+###################
+# random_string # Returns a pseudorandom human-readable string
+###################
+function random_string() {
+ # Numeric argument, if present, is desired length of string
+ local length=${1:-10}
+
+ head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
}
# END infrastructure code
@@ -345,17 +239,12 @@ done
###############################################################################
# BEGIN entry handler (subtest invoker)
-TESTS_DIR=$WORKDIR/awesome-compose
-
-git clone $AWESOME_COMPOSE $TESTS_DIR
-git -C $TESTS_DIR checkout -q a3c38822277bcca04abbadf34120dcff808db3ec
-
# Identify the tests to run. If called with args, use those as globs.
tests_to_run=()
if [ -n "$*" ]; then
shopt -s nullglob
for i; do
- match=(${TEST_ROOTDIR}/*${i}*.curl)
+ match=(${TEST_ROOTDIR}/*${i}*/docker-compose.yml)
if [ ${#match} -eq 0 ]; then
die "No match for $TEST_ROOTDIR/*$i*.curl"
fi
@@ -363,56 +252,68 @@ if [ -n "$*" ]; then
done
shopt -u nullglob
else
- tests_to_run=(${TEST_ROOTDIR}/*.curl)
+ tests_to_run=(${TEST_ROOTDIR}/*/docker-compose.yml)
fi
-# Test count: each of those tests might have a local set of subtests
-n_tests=$((2 * ${#tests_to_run[*]}))
+# Too hard to precompute the number of tests; just spit it out at the end.
+n_tests=0
for t in ${tests_to_run[@]}; do
- n_curls=$(wc -l $t | awk '{print $1}')
- n_tests=$(( n_tests + n_curls ))
-done
+ testdir="$(dirname $t)"
+ testname="$(basename $testdir)"
-
-echo "1..$n_tests"
-
-for t in ${tests_to_run[@]}; do
- testname="$(basename $t .curl)"
+ if [ -e $test_dir/SKIP ]; then
+ local reason="$(<$test_dir/SKIP)"
+ if [ -n "$reason" ]; then
+ reason=" - $reason"
+ fi
+ _show_ok skip "$testname # skip$reason"
+ continue
+ fi
start_service
logfile=$WORKDIR/$testname.log
(
- cd $TESTS_DIR/$testname || die "Cannot cd $TESTS_DIR/$testname"
+ cd $testdir || die "Cannot cd $testdir"
+
+ # setup file may be used for creating temporary directories/files.
+ # We source it so that envariables defined in it will get back to us.
+ if [ -e setup.sh ]; then
+ . setup.sh
+ fi
+ if [ -e teardown.sh ]; then
+ trap '. teardown.sh' 0
+ fi
+
docker-compose up -d &> $logfile
- if [[ $? -ne 0 ]]; then
- _show_ok 0 "$testname - up" "[ok]" "$(< $logfile)"
- # FIXME: cat log
+ docker_compose_rc=$?
+ if [[ $docker_compose_rc -ne 0 ]]; then
+ _show_ok 0 "$testname - up" "[ok]" "status=$docker_compose_rc"
+ sed -e 's/^/# /' <$logfile
docker-compose down >>$logfile 2>&1 # No status check here
exit 1
fi
_show_ok 1 "$testname - up"
- # FIXME: run tests, e.g. curl
- curls=$TEST_ROOTDIR/$testname.curl
- if [[ -e $curls ]]; then
- while read port expect; do
- actual=$(curl --retry 5 --retry-connrefused -s http://127.0.0.1:$port/)
- curl_rc=$?
- if [ $curl_rc -ne 0 ]; then
- _show_ok 0 "$testname - curl failed with status $curl_rc"
- docker-compose down >>$logfile 2>&1
- exit 1
- fi
- like "$actual" "$expect" "$testname : port $port"
- done < $curls
+ # Run tests. This is likely to be a series of 'test_port' checks
+ # but may also include podman commands to inspect labels, state
+ if [ -e tests.sh ]; then
+ . tests.sh
+ fi
+ # FIXME: if any tests fail, try 'podman logs' on container?
+
+ if [ -n "$COMPOSE_WAIT" ]; then
+ echo -n "Pausing due to \$COMPOSE_WAIT. Press ENTER to continue: "
+ read keepgoing
fi
+ # Done. Clean up.
docker-compose down &> $logfile
- if [[ $? -eq 0 ]]; then
+ rc=$?
+ if [[ $rc -eq 0 ]]; then
_show_ok 1 "$testname - down"
else
- _show_ok 0 "$testname - down" "[ok]" "$(< $logfile)"
+ _show_ok 0 "$testname - down" "[ok]" "rc=$rc"
# FIXME: show error
fi
)
@@ -422,6 +323,9 @@ for t in ${tests_to_run[@]}; do
# FIXME: otherwise we get EBUSY
umount $WORKDIR/root/overlay &>/dev/null
+
+ # FIXME: run 'podman ps'?
+# rm -rf $WORKDIR/${testname}
done
# END entry handler
@@ -432,8 +336,10 @@ done
test_count=$(<$testcounter_file)
failure_count=$(<$failures_file)
-if [ -z "$PODMAN_TESTS_KEEP_WORKDIR" ]; then
- rm -rf $WORKDIR
-fi
+#if [ -z "$PODMAN_TESTS_KEEP_WORKDIR" ]; then
+# rm -rf $WORKDIR
+#fi
+
+echo "1..${test_count}"
exit $failure_count