github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/test/apiv2/test-apiv2 (about)

     1  #!/bin/bash
     2  #
     3  # Usage: test-apiv2 [PORT]
     4  #
     5  # DEVELOPER NOTE: you almost certainly don't need to play in here. See README.
     6  #
     7  ME=$(basename $0)
     8  
     9  ###############################################################################
    10  # BEGIN stuff you can but probably shouldn't customize
    11  
    12  PODMAN_TEST_IMAGE_REGISTRY=${PODMAN_TEST_IMAGE_REGISTRY:-"quay.io"}
    13  PODMAN_TEST_IMAGE_USER=${PODMAN_TEST_IMAGE_USER:-"libpod"}
    14  PODMAN_TEST_IMAGE_NAME=${PODMAN_TEST_IMAGE_NAME:-"alpine_labels"}
    15  PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"latest"}
    16  PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG"
    17  
    18  IMAGE=$PODMAN_TEST_IMAGE_FQN
    19  
    20  # END   stuff you can but probably shouldn't customize
    21  ###############################################################################
    22  # BEGIN setup
    23  
    24  TMPDIR=${TMPDIR:-/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  HOST=localhost
    33  PORT=${PODMAN_SERVICE_PORT:-8081}
    34  
    35  # Keep track of test count and failures in files, not variables, because
    36  # variables don't carry back up from subshells.
    37  testcounter_file=$WORKDIR/.testcounter
    38  failures_file=$WORKDIR/.failures
    39  
    40  echo 0 >$testcounter_file
    41  echo 0 >$failures_file
    42  
    43  # Where the tests live
    44  TESTS_DIR=$(realpath $(dirname $0))
    45  
    46  # Path to podman binary
    47  PODMAN_BIN=${PODMAN:-${TESTS_DIR}/../../bin/podman}
    48  
    49  # END   setup
    50  ###############################################################################
    51  # BEGIN infrastructure code - the helper functions used in tests themselves
    52  
    53  #########
    54  #  die  #  Exit error with a message to stderr
    55  #########
    56  function die() {
    57      echo "$ME: $*" >&2
    58      exit 1
    59  }
    60  
    61  ########
    62  #  is  #  Simple comparison
    63  ########
    64  function is() {
    65      local actual=$1
    66      local expect=$2
    67      local testname=$3
    68  
    69      if [ "$actual" = "$expect" ]; then
    70          # On success, include expected value; this helps readers understand
    71          _show_ok 1 "$testname=$expect"
    72          return
    73      fi
    74      _show_ok 0 "$testname" "$expect" "$actual"
    75  }
    76  
    77  ##########
    78  #  like  #  Compare, but allowing patterns
    79  ##########
    80  function like() {
    81      local actual=$1
    82      local expect=$2
    83      local testname=$3
    84  
    85      if expr "$actual" : "$expect" &>/dev/null; then
    86          # On success, include expected value; this helps readers understand
    87          _show_ok 1 "$testname~$expect"
    88          return
    89      fi
    90      _show_ok 0 "$testname" "~ $expect" "$actual"
    91  }
    92  
    93  ##############
    94  #  _show_ok  #  Helper for is() and like(): displays 'ok' or 'not ok'
    95  ##############
    96  function _show_ok() {
    97      local ok=$1
    98      local testname=$2
    99  
   100      # If output is a tty, colorize pass/fail
   101      local red=
   102      local green=
   103      local reset=
   104      local bold=
   105      if [ -t 1 ]; then
   106          red='\e[31m'
   107          green='\e[32m'
   108          reset='\e[0m'
   109          bold='\e[1m'
   110      fi
   111  
   112      _bump $testcounter_file
   113      count=$(<$testcounter_file)
   114      if [ $ok -eq 1 ]; then
   115          echo -e "${green}ok $count ${TEST_CONTEXT} $testname${reset}"
   116          echo    "ok $count ${TEST_CONTEXT} $testname" >>$LOG
   117          return
   118      fi
   119  
   120      # Failed
   121      local expect=$3
   122      local actual=$4
   123      echo -e "${red}not ok $count ${TEST_CONTEXT} $testname${reset}"
   124      echo -e "${red}#  expected: $expect${reset}"
   125      echo -e "${red}#    actual: ${bold}$actual${reset}"
   126  
   127      echo    "not ok $count ${TEST_CONTEXT} $testname" >>$LOG
   128      echo    "  expected: $expect"
   129  
   130      _bump $failures_file
   131  }
   132  
   133  ###########
   134  #  _bump  #  Increment a counter in a file
   135  ###########
   136  function _bump() {
   137      local file=$1
   138  
   139      count=$(<$file)
   140      echo $(( $count + 1 )) >| $file
   141  }
   142  
   143  #############
   144  #  jsonify  #  convert 'foo=bar,x=y' to json {"foo":"bar","x":"y"}
   145  #############
   146  function jsonify() {
   147      # split by comma
   148      local -a settings_in
   149      read -ra settings_in <<<"$1"
   150  
   151      # convert each to double-quoted form
   152      local -a settings_out
   153      for i in ${settings_in[*]}; do
   154          settings_out+=$(sed -e 's/\(.*\)=\(.*\)/"\1":"\2"/' <<<$i)
   155      done
   156  
   157      # ...and wrap inside braces.
   158      # FIXME: handle commas
   159      echo "{${settings_out[*]}}"
   160  }
   161  
   162  #######
   163  #  t  #  Main test helper
   164  #######
   165  function t() {
   166      local method=$1; shift
   167      local path=$1; shift
   168      local curl_args
   169  
   170      local testname="$method $path"
   171      # POST requests require an extra params arg
   172      if [[ $method = "POST" ]]; then
   173          curl_args="-d $(jsonify $1)"
   174          testname="$testname [$1]"
   175          shift
   176      fi
   177  
   178      # entrypoint path can include a descriptive comment; strip it off
   179      path=${path%% *}
   180  
   181      # curl -X HEAD but without --head seems to wait for output anyway
   182      if [[ $method == "HEAD" ]]; then
   183          curl_args="--head"
   184      fi
   185      local expected_code=$1; shift
   186  
   187      # If given path begins with /, use it as-is; otherwise prepend /version/
   188      local url=http://$HOST:$PORT
   189      if expr "$path" : "/" >/dev/null; then
   190          url="$url$path"
   191      else
   192          url="$url/v1.40/$path"
   193      fi
   194  
   195      # Log every action we do
   196      echo "-------------------------------------------------------------" >>$LOG
   197      echo "\$ $testname"                                                  >>$LOG
   198      rm -f $WORKDIR/curl.*
   199      curl -s -X $method ${curl_args}                   \
   200           -H 'Content-type: application/json'          \
   201           --dump-header $WORKDIR/curl.headers.out       \
   202           -o $WORKDIR/curl.result.out "$url"
   203  
   204      if [[ $? -eq 7 ]]; then
   205          echo "FATAL: curl failure on $url - cannot continue" >&2
   206          exit 1
   207      fi
   208  
   209      cat $WORKDIR/curl.headers.out >>$LOG 2>/dev/null || true
   210      output=$(< $WORKDIR/curl.result.out)
   211  
   212      # Log results. If JSON, filter through jq for readability
   213      if egrep -qi '^Content-Type: application/json' $WORKDIR/curl.headers.out; then
   214          jq . <<<"$output" >>$LOG
   215      else
   216          echo "$output" >>$LOG
   217      fi
   218  
   219      # Test return code
   220      actual_code=$(head -n1 $WORKDIR/curl.headers.out | awk '/^HTTP/ { print $2}')
   221      is "$actual_code" "$expected_code" "$testname : status"
   222  
   223  
   224      # Special case: 204/304, by definition, MUST NOT return content (rfc2616)
   225      if [[ $expected_code = 204 || $expected_code = 304 ]]; then
   226          if [ -n "$*" ]; then
   227              die "Internal error: ${expected_code} status returns no output; fix your test."
   228          fi
   229          if [ -n "$output" ]; then
   230              _show_ok 0 "$testname: ${expected_code} status returns no output" "''" "$output"
   231          fi
   232          return
   233      fi
   234  
   235      for i; do
   236          case "$i" in
   237              # Exact match on json field
   238              *=*)
   239                  json_field=$(expr "$i" : "\([^=]*\)=")
   240                  expect=$(expr "$i" : '[^=]*=\(.*\)')
   241                  actual=$(jq -r "$json_field" <<<"$output")
   242                  is "$actual" "$expect" "$testname : $json_field"
   243                  ;;
   244              # regex match on json field
   245              *~*)
   246                  json_field=$(expr "$i" : "\([^~]*\)~")
   247                  expect=$(expr "$i" : '[^~]*~\(.*\)')
   248                  actual=$(jq -r "$json_field" <<<"$output")
   249                  like "$actual" "$expect" "$testname : $json_field"
   250                  ;;
   251              # Direct string comparison
   252              *)
   253                  is "$output" "$i" "$testname : output"
   254                  ;;
   255          esac
   256      done
   257  }
   258  
   259  ###################
   260  #  start_service  #  Run the socket listener
   261  ###################
   262  service_pid=
   263  function start_service() {
   264      # If there's a listener on the port, nothing for us to do
   265      { exec 3<> /dev/tcp/$HOST/$PORT; } &>/dev/null && return
   266  
   267      test -x $PODMAN_BIN || die "Not found: $PODMAN_BIN"
   268  
   269      if [ "$HOST" != "localhost" ]; then
   270          die "Cannot start service on non-localhost ($HOST)"
   271      fi
   272  
   273      $PODMAN_BIN --root $WORKDIR system service --timeout 15 tcp:127.0.0.1:$PORT \
   274          &> $WORKDIR/server.log &
   275      service_pid=$!
   276  
   277      # Wait
   278      local _timeout=5
   279      while [ $_timeout -gt 0 ]; do
   280          { exec 3<> /dev/tcp/$HOST/$PORT; } &>/dev/null && return
   281          sleep 1
   282          _timeout=$(( $_timeout - 1 ))
   283      done
   284      die "Timed out waiting for service"
   285  }
   286  
   287  ############
   288  #  podman  #  Needed by some test scripts to invoke the actual podman binary
   289  ############
   290  function podman() {
   291      echo "\$ $PODMAN_BIN $*"           >>$WORKDIR/output.log
   292      $PODMAN_BIN --root $WORKDIR "$@"   >>$WORKDIR/output.log 2>&1
   293  }
   294  
   295  ####################
   296  #  root, rootless  #  Is server rootless?
   297  ####################
   298  ROOTLESS=
   299  function root() {
   300      ! rootless
   301  }
   302  
   303  function rootless() {
   304      if [[ -z $ROOTLESS ]]; then
   305          ROOTLESS=$(curl -s http://$HOST:$PORT/v1.40/info | jq .Rootless)
   306      fi
   307      test "$ROOTLESS" = "true"
   308  }
   309  
   310  # True if cgroups v2 are enabled
   311  function have_cgroupsv2() {
   312      cgroup_type=$(stat -f -c %T /sys/fs/cgroup)
   313      test "$cgroup_type" = "cgroup2fs"
   314  }
   315  
   316  # END   infrastructure code
   317  ###############################################################################
   318  # BEGIN sanity checks
   319  
   320  for tool in curl jq podman; do
   321      type $tool &>/dev/null || die "$ME: Required tool '$tool' not found"
   322  done
   323  
   324  # END   sanity checks
   325  ###############################################################################
   326  # BEGIN entry handler (subtest invoker)
   327  
   328  # Identify the tests to run. If called with args, use those as globs.
   329  tests_to_run=()
   330  if [ -n "$*" ]; then
   331      shopt -s nullglob
   332      for i; do
   333          match=(${TESTS_DIR}/*${i}*.at)
   334          if [ ${#match} -eq 0 ]; then
   335              die "No match for $TESTS_DIR/*$i*.at"
   336          fi
   337          tests_to_run+=("${match[@]}")
   338      done
   339      shopt -u nullglob
   340  else
   341      tests_to_run=($TESTS_DIR/*.at)
   342  fi
   343  
   344  start_service
   345  
   346  for i in ${tests_to_run[@]}; do
   347      TEST_CONTEXT="[$(basename $i .at)]"
   348      source $i
   349  done
   350  
   351  # END   entry handler
   352  ###############################################################################
   353  
   354  # Clean up
   355  
   356  if [ -n "$service_pid" ]; then
   357      kill $service_pid
   358      wait $service_pid
   359  fi
   360  
   361  test_count=$(<$testcounter_file)
   362  failure_count=$(<$failures_file)
   363  
   364  if [ -z "$PODMAN_TESTS_KEEP_WORKDIR" ]; then
   365      rm -rf $WORKDIR
   366  fi
   367  
   368  echo "1..${test_count}"
   369  
   370  exit $failure_count