github.com/AbhinandanKurakure/podman/v3@v3.4.10/test/compose/test-compose (about) 1 #!/usr/bin/env bash 2 # 3 # Usage: test-compose [testname] 4 # 5 ME=$(basename $0) 6 7 ############################################################################### 8 # BEGIN stuff you can but probably shouldn't customize 9 10 # Directory where this script and all subtests live 11 TEST_ROOTDIR=$(realpath $(dirname $0)) 12 13 # Podman executable 14 PODMAN_BIN=$(realpath $TEST_ROOTDIR/../../bin)/podman 15 16 # Local path to docker socket with unix prefix 17 # The path will be changed for rootless users 18 DOCKER_SOCK=/var/run/docker.sock 19 20 # END stuff you can but probably shouldn't customize 21 ############################################################################### 22 # BEGIN setup 23 24 export TMPDIR=${TMPDIR:-/var/tmp} 25 WORKDIR=$(mktemp --tmpdir -d $ME.tmp.XXXXXX) 26 27 # Log of all HTTP requests and responses; always make '.log' point to latest 28 LOGBASE=${TMPDIR}/$ME.log 29 LOG=${LOGBASE}.$(date +'%Y%m%dT%H%M%S') 30 ln -sf $LOG $LOGBASE 31 32 # Keep track of test count and failures in files, not variables, because 33 # variables don't carry back up from subshells. 34 testcounter_file=$WORKDIR/.testcounter 35 failures_file=$WORKDIR/.failures 36 37 echo 0 >$testcounter_file 38 echo 0 >$failures_file 39 40 # END setup 41 ############################################################################### 42 # BEGIN infrastructure code - the helper functions used in tests themselves 43 44 ################# 45 # is_rootless # Check if we run as normal user 46 ################# 47 function is_rootless() { 48 [ "$(id -u)" -ne 0 ] 49 } 50 51 ######### 52 # die # Exit error with a message to stderr 53 ######### 54 function die() { 55 echo "$ME: $*" >&2 56 exit 1 57 } 58 59 ######## 60 # is # Simple comparison 61 ######## 62 function is() { 63 local actual=$1 64 local expect=$2 65 local testname=$3 66 67 if [[ $actual = $expect ]]; then 68 # On success, include expected value; this helps readers understand 69 _show_ok 1 "$testname=$expect" 70 return 71 fi 72 _show_ok 0 "$testname" "$expect" "$actual" 73 } 74 75 ########## 76 # like # Compare, but allowing patterns 77 ########## 78 function like() { 79 local actual=$1 80 local expect=$2 81 local testname=$3 82 83 # "is" (equality) is a subset of "like", but one that expr fails on if 84 # the expected result has shell-special characters like '['. Treat it 85 # as a special case. 86 87 if [[ "$actual" = "$expect" ]]; then 88 _show_ok 1 "$testname=$expect" 89 return 90 fi 91 92 if expr "$actual" : ".*$expect" &>/dev/null; then 93 # On success, include expected value; this helps readers understand 94 _show_ok 1 "$testname ('$actual') ~ $expect" 95 return 96 fi 97 _show_ok 0 "$testname" "~ $expect" "$actual" 98 } 99 100 ############## 101 # _show_ok # Helper for is() and like(): displays 'ok' or 'not ok' 102 ############## 103 function _show_ok() { 104 local ok=$1 105 local testname=$2 106 107 # If output is a tty, colorize pass/fail 108 local red= 109 local green= 110 local reset= 111 local bold= 112 if [ -t 1 ]; then 113 red='\e[31m' 114 green='\e[32m' 115 reset='\e[0m' 116 bold='\e[1m' 117 fi 118 119 _bump $testcounter_file 120 count=$(<$testcounter_file) 121 122 # "skip" is a special case of "ok". Assume that our caller has included 123 # the magical '# skip - reason" comment string. 124 if [[ $ok == "skip" ]]; then 125 # colon-plus: replace green with yellow, but only if green is non-null 126 green="${green:+\e[33m}" 127 ok=1 128 fi 129 if [ $ok -eq 1 ]; then 130 echo -e "${green}ok $count $testname${reset}" 131 echo "ok $count $testname" >>$LOG 132 return 133 fi 134 135 # Failed 136 local expect=$3 137 local actual=$4 138 printf "${red}not ok $count $testname${reset}\n" 139 # Not all errors include actual/expect 140 if [[ -n "$expect" || -n "$actual" ]]; then 141 printf "${red}# expected: %s${reset}\n" "$expect" 142 printf "${red}# actual: ${bold}%s${reset}\n" "$actual" 143 fi 144 145 echo "not ok $count $testname" >>$LOG 146 echo " expected: $expect" >>$LOG 147 148 _bump $failures_file 149 } 150 151 ########### 152 # _bump # Increment a counter in a file 153 ########### 154 function _bump() { 155 local file=$1 156 157 count=$(<$file) 158 echo $(( $count + 1 )) >| $file 159 } 160 161 ############### 162 # test_port # Run curl against a port, check results against expectation 163 ############### 164 function test_port() { 165 local port="$1" # e.g. 5000 166 local op="$2" # '=' or '~' 167 local expect="$3" # what to expect from curl output 168 169 # -s -S means "silent, but show errors" 170 local actual 171 actual=$(curl --retry 3 --retry-all-errors -s -S http://127.0.0.1:$port/) 172 local curl_rc=$? 173 174 if [ $curl_rc -ne 0 ]; then 175 _show_ok 0 "$testname - curl (port $port) failed with status $curl_rc" 176 echo "# podman ps -a:" 177 $PODMAN_BIN --storage-driver=vfs --root $WORKDIR/root --runroot $WORKDIR/runroot ps -a 178 if type -p ss; then 179 echo "# ss -tulpn:" 180 ss -tulpn 181 echo "# podman unshare --rootless-cni ss -tulpn:" 182 $PODMAN_BIN --storage-driver=vfs --root $WORKDIR/root --runroot $WORKDIR/runroot unshare --rootless-cni ss -tulpn 183 fi 184 echo "# cat $WORKDIR/server.log:" 185 cat $WORKDIR/server.log 186 echo "# cat $logfile:" 187 cat $logfile 188 return 189 fi 190 191 case "$op" in 192 '=') is "$actual" "$expect" "$testname : port $port" ;; 193 '~') like "$actual" "$expect" "$testname : port $port" ;; 194 *) die "Invalid operator '$op'" ;; 195 esac 196 } 197 198 199 ################### 200 # start_service # Run the socket listener 201 ################### 202 service_pid= 203 function start_service() { 204 test -x $PODMAN_BIN || die "Not found: $PODMAN_BIN" 205 206 # FIXME: use ${testname} subdir but we can't: 50-char limit in runroot 207 if ! is_rootless; then 208 rm -rf $WORKDIR/{root,runroot,cni} 209 else 210 $PODMAN_BIN unshare rm -rf $WORKDIR/{root,runroot,cni} 211 fi 212 rm -f $DOCKER_SOCK 213 mkdir --mode 0755 $WORKDIR/{root,runroot,cni} 214 chcon --reference=/var/lib/containers $WORKDIR/root 215 cp /etc/cni/net.d/*podman*conflist $WORKDIR/cni/ 216 217 $PODMAN_BIN \ 218 --log-level debug \ 219 --storage-driver=vfs \ 220 --root $WORKDIR/root \ 221 --runroot $WORKDIR/runroot \ 222 --cgroup-manager=systemd \ 223 --cni-config-dir $WORKDIR/cni \ 224 system service \ 225 --time 0 unix://$DOCKER_SOCK \ 226 &> $WORKDIR/server.log & 227 service_pid=$! 228 229 # Wait (FIXME: how do we test the socket?) 230 local _timeout=5 231 while [ $_timeout -gt 0 ]; do 232 # FIXME: should we actually try a read or write? 233 test -S $DOCKER_SOCK && return 234 sleep 1 235 _timeout=$(( $_timeout - 1 )) 236 done 237 cat $WORKDIR/server.log 238 die "Timed out waiting for service" 239 } 240 241 ############ 242 # podman # Needed by some test scripts to invoke the actual podman binary 243 ############ 244 function podman() { 245 echo "\$ podman $*" >>$WORKDIR/output.log 246 output=$($PODMAN_BIN \ 247 --storage-driver=vfs \ 248 --root $WORKDIR/root \ 249 --runroot $WORKDIR/runroot \ 250 "$@") 251 echo -n "$output" >>$WORKDIR/output.log 252 } 253 254 ################### 255 # random_string # Returns a pseudorandom human-readable string 256 ################### 257 function random_string() { 258 # Numeric argument, if present, is desired length of string 259 local length=${1:-10} 260 261 head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length 262 } 263 264 # END infrastructure code 265 ############################################################################### 266 # BEGIN sanity checks 267 268 for tool in curl docker-compose; do 269 type $tool &>/dev/null || die "$ME: Required tool '$tool' not found" 270 done 271 272 # END sanity checks 273 ############################################################################### 274 # BEGIN entry handler (subtest invoker) 275 276 # When rootless use a socket path accessible by the rootless user 277 if is_rootless; then 278 DOCKER_SOCK="$WORKDIR/docker.sock" 279 DOCKER_HOST="unix://$DOCKER_SOCK" 280 # export DOCKER_HOST docker-compose will use it 281 export DOCKER_HOST 282 fi 283 284 # Identify the tests to run. If called with args, use those as globs. 285 tests_to_run=() 286 if [ -n "$*" ]; then 287 shopt -s nullglob 288 for i; do 289 match=(${TEST_ROOTDIR}/*${i}*/docker-compose.yml) 290 if [ ${#match} -eq 0 ]; then 291 die "No match for $TEST_ROOTDIR/*$i*.curl" 292 fi 293 tests_to_run+=("${match[@]}") 294 done 295 shopt -u nullglob 296 else 297 tests_to_run=(${TEST_ROOTDIR}/*/docker-compose.yml) 298 fi 299 300 # Too hard to precompute the number of tests; just spit it out at the end. 301 n_tests=0 302 303 # We aren't really TAP 13; this helps logformatter recognize our output as BATS 304 echo "TAP version 13" 305 306 for t in ${tests_to_run[@]}; do 307 testdir="$(dirname $t)" 308 testname="$(basename $testdir)" 309 310 if [ -e $test_dir/SKIP ]; then 311 local reason="$(<$test_dir/SKIP)" 312 if [ -n "$reason" ]; then 313 reason=" - $reason" 314 fi 315 _show_ok skip "$testname # skip$reason" 316 continue 317 fi 318 319 start_service 320 321 logfile=$WORKDIR/$testname.log 322 ( 323 cd $testdir || die "Cannot cd $testdir" 324 325 # setup file may be used for creating temporary directories/files. 326 # We source it so that envariables defined in it will get back to us. 327 if [ -e setup.sh ]; then 328 . setup.sh 329 fi 330 if [ -e teardown.sh ]; then 331 trap '. teardown.sh' 0 332 fi 333 334 docker-compose up -d &> $logfile 335 docker_compose_rc=$? 336 if [[ $docker_compose_rc -ne 0 ]]; then 337 _show_ok 0 "$testname - up" "[ok]" "status=$docker_compose_rc" 338 sed -e 's/^/# /' <$logfile 339 docker-compose down >>$logfile 2>&1 # No status check here 340 exit 1 341 fi 342 _show_ok 1 "$testname - up" 343 344 # Run tests. This is likely to be a series of 'test_port' checks 345 # but may also include podman commands to inspect labels, state 346 if [ -e tests.sh ]; then 347 . tests.sh 348 fi 349 # FIXME: if any tests fail, try 'podman logs' on container? 350 351 if [ -n "$COMPOSE_WAIT" ]; then 352 echo -n "Pausing due to \$COMPOSE_WAIT. Press ENTER to continue: " 353 read keepgoing 354 fi 355 356 # Done. Clean up. 357 docker-compose down &>> $logfile 358 rc=$? 359 if [[ $rc -eq 0 ]]; then 360 _show_ok 1 "$testname - down" 361 else 362 _show_ok 0 "$testname - down" "[ok]" "rc=$rc" 363 # FIXME: show error 364 fi 365 ) 366 367 kill $service_pid 368 wait $service_pid 369 370 # FIXME: otherwise we get EBUSY 371 if ! is_rootless; then 372 umount $WORKDIR/root/overlay &>/dev/null 373 else 374 $PODMAN_BIN unshare umount $WORKDIR/root/overlay &>/dev/null 375 fi 376 377 # FIXME: run 'podman ps'? 378 # rm -rf $WORKDIR/${testname} 379 done 380 381 # END entry handler 382 ############################################################################### 383 384 # Clean up 385 386 test_count=$(<$testcounter_file) 387 failure_count=$(<$failures_file) 388 389 if [ -z "$PODMAN_TESTS_KEEP_WORKDIR" ]; then 390 if ! is_rootless; then 391 rm -rf $WORKDIR 392 else 393 $PODMAN_BIN unshare rm -rf $WORKDIR 394 fi 395 fi 396 397 echo "1..${test_count}" 398 399 exit $failure_count