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