diff options
Diffstat (limited to 'test/compose/test-compose')
-rwxr-xr-x | test/compose/test-compose | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/test/compose/test-compose b/test/compose/test-compose new file mode 100755 index 000000000..9558fbf58 --- /dev/null +++ b/test/compose/test-compose @@ -0,0 +1,345 @@ +#!/usr/bin/env bash +# +# Usage: test-compose [testname] +# +ME=$(basename $0) + +############################################################################### +# BEGIN stuff you can but probably shouldn't customize + +# Directory where this script and all subtests live +TEST_ROOTDIR=$(realpath $(dirname $0)) + +# Podman executable +PODMAN_BIN=$(realpath $TEST_ROOTDIR/../../bin)/podman + +# 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 + +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 +LOGBASE=${TMPDIR}/$ME.log +LOG=${LOGBASE}.$(date +'%Y%m%dT%H%M%S') +ln -sf $LOG $LOGBASE + +# Keep track of test count and failures in files, not variables, because +# variables don't carry back up from subshells. +testcounter_file=$WORKDIR/.testcounter +failures_file=$WORKDIR/.failures + +echo 0 >$testcounter_file +echo 0 >$failures_file + +# END setup +############################################################################### +# BEGIN infrastructure code - the helper functions used in tests themselves + +######### +# die # Exit error with a message to stderr +######### +function die() { + echo "$ME: $*" >&2 + exit 1 +} + +######## +# is # Simple comparison +######## +function is() { + local actual=$1 + local expect=$2 + local testname=$3 + + if [[ $actual = $expect ]]; then + # On success, include expected value; this helps readers understand + _show_ok 1 "$testname=$expect" + return + fi + _show_ok 0 "$testname" "$expect" "$actual" +} + +########## +# like # Compare, but allowing patterns +########## +function like() { + local actual=$1 + local expect=$2 + local testname=$3 + + # "is" (equality) is a subset of "like", but one that expr fails on if + # the expected result has shell-special characters like '['. Treat it + # as a special case. + + if [[ "$actual" = "$expect" ]]; then + _show_ok 1 "$testname=$expect" + return + fi + + if expr "$actual" : ".*$expect" &>/dev/null; then + # On success, include expected value; this helps readers understand + _show_ok 1 "$testname ('$actual') ~ $expect" + return + fi + _show_ok 0 "$testname" "~ $expect" "$actual" +} + +############## +# _show_ok # Helper for is() and like(): displays 'ok' or 'not ok' +############## +function _show_ok() { + local ok=$1 + local testname=$2 + + # If output is a tty, colorize pass/fail + local red= + local green= + local reset= + local bold= + if [ -t 1 ]; then + red='\e[31m' + green='\e[32m' + reset='\e[0m' + bold='\e[1m' + fi + + _bump $testcounter_file + count=$(<$testcounter_file) + + # "skip" is a special case of "ok". Assume that our caller has included + # the magical '# skip - reason" comment string. + if [[ $ok == "skip" ]]; then + # colon-plus: replace green with yellow, but only if green is non-null + green="${green:+\e[33m}" + ok=1 + fi + if [ $ok -eq 1 ]; then + echo -e "${green}ok $count $testname${reset}" + echo "ok $count $testname" >>$LOG + return + fi + + # Failed + local expect=$3 + local actual=$4 + printf "${red}not ok $count $testname${reset}\n" + printf "${red}# expected: %s${reset}\n" "$expect" + printf "${red}# actual: ${bold}%s${reset}\n" "$actual" + + echo "not ok $count $testname" >>$LOG + echo " expected: $expect" >>$LOG + + _bump $failures_file +} + +########### +# _bump # Increment a counter in a file +########### +function _bump() { + local file=$1 + + count=$(<$file) + echo $(( $count + 1 )) >| $file +} + +############### +# 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 + + 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 +################### +service_pid= +function start_service() { + test -x $PODMAN_BIN || die "Not found: $PODMAN_BIN" + + # 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 \ + --root $WORKDIR/root \ + --runroot $WORKDIR/runroot \ + --cgroup-manager=systemd \ + --cni-config-dir $WORKDIR/cni \ + system service \ + --time 0 unix:/$DOCKER_SOCK \ + &> $WORKDIR/server.log & + service_pid=$! + + # Wait (FIXME: how do we test the socket?) + local _timeout=5 + while [ $_timeout -gt 0 ]; do + # FIXME: should we actually try a read or write? + test -S $DOCKER_SOCK && return + sleep 1 + _timeout=$(( $_timeout - 1 )) + done + cat $WORKDIR/server.log + die "Timed out waiting for service" +} + +############ +# podman # Needed by some test scripts to invoke the actual podman binary +############ +function podman() { + 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 +############################################################################### +# BEGIN sanity checks + +for tool in curl docker-compose; do + type $tool &>/dev/null || die "$ME: Required tool '$tool' not found" +done + +# END sanity checks +############################################################################### +# BEGIN entry handler (subtest invoker) + +# 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}*/docker-compose.yml) + if [ ${#match} -eq 0 ]; then + die "No match for $TEST_ROOTDIR/*$i*.curl" + fi + tests_to_run+=("${match[@]}") + done + shopt -u nullglob +else + tests_to_run=(${TEST_ROOTDIR}/*/docker-compose.yml) +fi + +# 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 + testdir="$(dirname $t)" + testname="$(basename $testdir)" + + 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 $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 + 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" + + # 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 + rc=$? + if [[ $rc -eq 0 ]]; then + _show_ok 1 "$testname - down" + else + _show_ok 0 "$testname - down" "[ok]" "rc=$rc" + # FIXME: show error + fi + ) + + kill $service_pid + wait $service_pid + + # FIXME: otherwise we get EBUSY + umount $WORKDIR/root/overlay &>/dev/null + + # FIXME: run 'podman ps'? +# rm -rf $WORKDIR/${testname} +done + +# END entry handler +############################################################################### + +# Clean up + +test_count=$(<$testcounter_file) +failure_count=$(<$failures_file) + +#if [ -z "$PODMAN_TESTS_KEEP_WORKDIR" ]; then +# rm -rf $WORKDIR +#fi + +echo "1..${test_count}" + +exit $failure_count |