github.com/containers/podman/v5@v5.1.0-rc1/test/system/helpers.t (about)

     1  #!/usr/bin/env bash
     2  #
     3  # regression tests for helpers.bash
     4  #
     5  # Some of those helper functions are fragile, and we don't want to break
     6  # anything if we have to mess with them.
     7  #
     8  
     9  source "$(dirname $0)"/helpers.bash
    10  source "$(dirname $0)"/helpers.network.bash
    11  
    12  die() {
    13      echo "$(basename $0): $*" >&2
    14      exit 1
    15  }
    16  
    17  # Iterator and return code; updated in check_result()
    18  testnum=0
    19  rc=0
    20  
    21  # Possibly used by the code we're testing
    22  PODMAN_TMPDIR=$(mktemp -d --tmpdir=${TMPDIR:-/tmp} podman_helper_tests.XXXXXX)
    23  trap 'rm -rf $PODMAN_TMPDIR' 0
    24  
    25  ###############################################################################
    26  # BEGIN test the parse_table helper
    27  
    28  function check_result {
    29      testnum=$(expr $testnum + 1)
    30      if [ "$1" = "$2" ]; then
    31          # Multi-level echo flattens newlines, makes success messages readable
    32          echo $(echo "ok $testnum $3 = $1")
    33      else
    34          echo "not ok $testnum $3"
    35          echo "#  expected: $2"
    36          echo "#    actual: $1"
    37          rc=1
    38      fi
    39  }
    40  
    41  # IMPORTANT NOTE: you have to do
    42  #      this: while ... done < <(parse_table)
    43  #   and not: parse_table | while read ...
    44  #
    45  # ...because piping to 'while' makes it a subshell, hence testnum and rc
    46  # will not be updated.
    47  #
    48  while read x y z; do
    49      check_result "$x" "a" "parse_table simple: column 1"
    50      check_result "$y" "b" "parse_table simple: column 2"
    51      check_result "$z" "c" "parse_table simple: column 3"
    52  done < <(parse_table "a | b | c")
    53  
    54  # More complicated example, with spaces
    55  while read x y z; do
    56      check_result "$x" "a b"   "parse_table with spaces: column 1"
    57      check_result "$y" "c d"   "parse_table with spaces: column 2"
    58      check_result "$z" "e f g" "parse_table with spaces: column 3"
    59  done < <(parse_table "a b | c d | e f g")
    60  
    61  # Multi-row, with spaces and with blank lines
    62  table="
    63  a     | b   | c d e
    64  d e f | g h | i j
    65  "
    66  declare -A expect=(
    67      [0,0]="a"
    68      [0,1]="b"
    69      [0,2]="c d e"
    70      [1,0]="d e f"
    71      [1,1]="g h"
    72      [1,2]="i j"
    73  )
    74  row=0
    75  while read x y z;do
    76      check_result "$x" "${expect[$row,0]}" "parse_table multi_row[$row,0]"
    77      check_result "$y" "${expect[$row,1]}" "parse_table multi_row[$row,1]"
    78      check_result "$z" "${expect[$row,2]}" "parse_table multi_row[$row,2]"
    79      row=$(expr $row + 1)
    80  done < <(parse_table "$table")
    81  
    82  # Backslash handling. The first element should have none, the second some
    83  while read x y;do
    84      check_result "$x" '[0-9]{2}'    "backslash test - no backslashes"
    85      check_result "$y" '[0-9]\{3\}'  "backslash test - one backslash each"
    86  done < <(parse_table "[0-9]{2}  | [0-9]\\\{3\\\}")
    87  
    88  # Empty strings. I wish we could convert those to real empty strings.
    89  while read x y z; do
    90      check_result "$x" "''" "empty string - left-hand"
    91      check_result "$y" "''" "empty string - middle"
    92      check_result "$z" "''" "empty string - right"
    93  done < <(parse_table "  |  |")
    94  
    95  # Quotes
    96  while read x y z;do
    97      check_result "$x" "a 'b c'"     "single quotes"
    98      check_result "$y" "d \"e f\" g" "double quotes"
    99      check_result "$z" "h"           "no quotes"
   100  
   101      # FIXME FIXME FIXME: this is the only way I can find to get bash-like
   102      # splitting of tokens. It really should be done inside parse_table
   103      # but I can't find any way of doing so. If you can find a way, please
   104      # update this test and any BATS tests that rely on quoting.
   105      eval set "$x"
   106      check_result "$1" "a"     "single quotes - token split - 1"
   107      check_result "$2" "b c"   "single quotes - token split - 2"
   108      check_result "$3" ""      "single quotes - token split - 3"
   109  
   110      eval set "$y"
   111      check_result "$1" "d"     "double quotes - token split - 1"
   112      check_result "$2" "e f"   "double quotes - token split - 2"
   113      check_result "$3" "g"     "double quotes - token split - 3"
   114  done < <(parse_table "a 'b c' | d \"e f\" g | h")
   115  
   116  # Split on '|' only when bracketed by spaces or at beginning/end of line
   117  while read x y z;do
   118      check_result "$x" "|x"    "pipe in strings - pipe at start"
   119      check_result "$y" "y|y1"  "pipe in strings - pipe in middle"
   120      check_result "$z" "z|"    "pipe in strings - pipe at end"
   121  done < <(parse_table "|x | y|y1 | z|")
   122  
   123  # END   test the parse_table helper
   124  ###############################################################################
   125  # BEGIN dprint
   126  
   127  function dprint_test_1() {
   128      dprint "$*"
   129  }
   130  
   131  # parse_table works, might as well use it
   132  #
   133  #  <value of PODMAN_TEST_DEBUG> | <blank for no msg, - for msg> | <desc>
   134  #
   135  table="
   136                             |   | debug unset
   137  dprint_test                | - | substring match
   138  dprint_test_1              | - | exact match
   139  dprint_test_10             |   | caller name mismatch
   140  xxx yyy zzz                |   | multiple callers, no match
   141  dprint_test_1 xxx yyy zzz  | - | multiple callers, match at start
   142  xxx dprint_test_1 yyy zzz  | - | multiple callers, match in middle
   143  xxx yyy zzz dprint_test_1  | - | multiple callers, match at end
   144  "
   145  while read var expect name; do
   146      random_string=$(random_string 20)
   147      PODMAN_TEST_DEBUG="$var" result=$(dprint_test_1 "$random_string" 3>&1)
   148      expect_full=""
   149      if [ -n "$expect" -a "$expect" != "''" ]; then
   150          expect_full="# dprint_test_1() : $random_string"
   151      fi
   152      check_result "$result" "$expect_full" "DEBUG='$var' - $name"
   153  done < <(parse_table "$table")
   154  
   155  # END   dprint
   156  ###############################################################################
   157  # BEGIN remove_same_dev_warning
   158  
   159  # Test-helper function: runs remove_same_dev_warning, compares resulting
   160  # value of $lines and $output to expected values given on command line
   161  function check_same_dev() {
   162      local testname="$1"; shift
   163      local -a expect_lines=("$@")
   164      local nl="
   165  "
   166  
   167      remove_same_dev_warning
   168  
   169      # After processing, check the expected number of lines
   170      check_result "${#lines[@]}" "${#@}" "$testname: expected # of lines"
   171  
   172      # ...and each expected line
   173      local expect_output=""
   174      local i=0
   175      while [ $i -lt ${#expect_lines[@]} ]; do
   176          check_result "${lines[$i]}" "${expect_lines[$i]}" "$testname: line $i"
   177          expect_output+="${expect_lines[$i]}$nl"
   178          i=$(( i + 1 ))
   179      done
   180  
   181      # ...and the possibly-multi-line $output
   182      check_result "$output" "${expect_output%%$nl}"  "$testname: output"
   183  }
   184  
   185  # Simplest case: nothing removed.
   186  declare -a lines=("a b c" "d" "e f")
   187  check_same_dev "abc" "a b c" "d" "e f"
   188  
   189  # Confirm that the warning message is removed from the beginning
   190  declare -a lines=(
   191      "WARNING: The same type, major and minor should not be used for multiple devices."
   192      "a"
   193      "b"
   194      "c"
   195  )
   196  check_same_dev "warning is removed" a b c
   197  
   198  # ...and from the middle (we do not expect to see this)
   199  declare -a lines=(
   200      "WARNING: The same type, major and minor should not be used for multiple devices."
   201      "a"
   202      "b"
   203      "WARNING: The same type, major and minor should not be used for multiple devices."
   204      "c"
   205  )
   206  check_same_dev "multiple warnings removed" a b c
   207  
   208  # Corner case: two lines of output, only one of which we care about
   209  declare -a lines=(
   210      "WARNING: The same type, major and minor should not be used for multiple devices."
   211      "this is the only line we care about"
   212  )
   213  check_same_dev "one-line output" "this is the only line we care about"
   214  
   215  # Corner case: one line of output, but we expect zero.
   216  declare -a lines=(
   217      "WARNING: The same type, major and minor should not be used for multiple devices."
   218  )
   219  check_same_dev "zero-line output"
   220  
   221  # END   remove_same_dev_warning
   222  ###############################################################################
   223  # BEGIN random_free_port
   224  
   225  # Assumes that 16700 is open
   226  found=$(random_free_port 16700-16700)
   227  
   228  check_result "$found" "16700" "random_free_port"
   229  
   230  # END   random_free_port
   231  ###############################################################################
   232  # BEGIN ipv6_to_procfs
   233  
   234  # Table of IPv6 short forms and their procfs equivalents. For readability,
   235  # spaces separate each 16-bit word. Spaces are removed when testing.
   236  table="
   237  2b06::1     | 2B06 0000 0000 0000 0000 0000 0000 0001
   238  ::1         | 0000 0000 0000 0000 0000 0000 0000 0001
   239  0::1        | 0000 0000 0000 0000 0000 0000 0000 0001
   240  "
   241  
   242  while read shortform expect; do
   243      actual=$(ipv6_to_procfs $shortform)
   244      check_result "$actual" "${expect// }" "ipv6_to_procfs $shortform"
   245  done < <(parse_table "$table")
   246  
   247  # END   ipv6_to_procfs
   248  ###############################################################################
   249  # BEGIN subnet_in_use  ...  because that's complicated
   250  
   251  # Override ip command
   252  function ip() {
   253      echo "default foo"
   254      echo "192.168.0.0/16"
   255      echo "172.17.2.3/30"
   256      echo "172.128.0.0/9"
   257  }
   258  
   259  # x.y.z | result (1 = in use, 0 = not in use - opposite of exit code)
   260  table="
   261  172 |   0 |   0  | 0
   262  172 |   0 | 255  | 0
   263  172 |   1 |   1  | 0
   264  172 |   1 |   2  | 0
   265  172 |   1 |   3  | 0
   266  172 |  17 |   1  | 0
   267  172 |  17 |   2  | 1
   268  172 |  17 |   3  | 0
   269  172 | 127 |   0  | 0
   270  172 | 128 |   0  | 1
   271  172 | 255 |   2  | 1
   272  192 | 168 |   1  | 1
   273  "
   274  
   275  while read n1 n2 n3 expect; do
   276      subnet_in_use $n1 $n2 $n3
   277      actual=$?
   278      check_result "$((1 - $actual))" "$expect" "subnet_in_use $n1.$n2.$n3"
   279  done < <(parse_table "$table")
   280  
   281  unset -f ip
   282  
   283  # END   subnet_in_use
   284  ###############################################################################
   285  # BEGIN check_assert
   286  #
   287  # This is way, way more complicated than it should be. The purpose is
   288  # to generate readable error messages should any of the tests ever fail.
   289  #
   290  
   291  # Args: the last one is "" (expect to pass) or non-"" (expect that as msg).
   292  # All other args are what we feed to assert()
   293  function check_assert() {
   294      local argv=("$@")
   295      testnum=$(expr $testnum + 1)
   296  
   297      # Final arg: "" to expect pass, anything else is expected error message
   298      local expect="${argv[-1]}"
   299      unset 'argv[-1]'
   300  
   301      # Descriptive test name. If multiline, use sed to make the rest '[...]'
   302      local testname="assert ${argv[*]}"
   303      testname="$(sed -z -e 's/[\r\n].\+/ [...]/' <<<"$testname")"
   304  
   305      # HERE WE GO. This is the actual test.
   306      actual=$(assert "${argv[@]}" 2>&1)
   307      status=$?
   308  
   309      # Now compare actual to expect.
   310      if [[ -z "$expect" ]]; then
   311          # expect: pass
   312          if [[ $status -eq 0 ]]; then
   313              # got: pass
   314              echo "ok $testnum $testname"
   315          else
   316              # got: fail
   317              echo "not ok $testnum $testname"
   318              echo "# expected success; got:"
   319              local -a actual_split
   320              IFS=$'\n' read -rd '' -a actual_split <<<"$actual" || true
   321              if [[ "${actual_split[0]}" =~ 'vvvvv' ]]; then
   322                  unset 'actual_split[0]'
   323                  unset 'actual_split[1]'
   324                  unset 'actual_split[-1]'
   325                  actual_split=("${actual_split[@]}")
   326              fi
   327              for line in "${actual_split[@]}"; do
   328                  echo "#     $line"
   329              done
   330              rc=1
   331          fi
   332      else
   333          # expect: fail
   334          if [[ $status -eq 0 ]]; then
   335              # got: pass
   336              echo "not ok $testnum $testname"
   337              echo "# expected it to fail, but it passed"
   338              rc=1
   339          else
   340              # Expected failure, got failure. But is it the desired failure?
   341  
   342              # Split what we got into lines, and remove the top/bottom borders
   343              local -a actual_split
   344              IFS=$'\n' read -rd '' -a actual_split <<<"$actual" || true
   345              if [[ "${actual_split[0]}" =~ 'vvvvv' ]]; then
   346                  unset 'actual_split[0]'
   347                  unset 'actual_split[1]'
   348                  unset 'actual_split[-1]'
   349                  actual_split=("${actual_split[@]}")
   350              fi
   351  
   352              # Split the expect string into lines, and remove first if empty
   353              local -a expect_split
   354              IFS=$'\n' read -rd '' -a expect_split <<<"$expect" || true
   355              if [[ -z "${expect_split[0]}" ]]; then
   356                  unset 'expect_split[0]'
   357                  expect_split=("${expect_split[@]}")
   358              fi
   359  
   360              if [[ "${actual_split[*]}" = "${expect_split[*]}" ]]; then
   361                  # Yay.
   362                  echo "ok $testnum $testname"
   363              else
   364                  # Nope. Mismatch between actual and expected output
   365                  echo "not ok $testnum $testname"
   366                  rc=1
   367  
   368                  # Ugh, this is complicated. Try to produce a useful err msg.
   369                  local n_e=${#expect_split[*]}
   370                  local n_a=${#actual_split[*]}
   371                  local n_max=${n_e}
   372                  if [[ $n_max -lt $n_a ]]; then
   373                      n_max=${n_a}
   374                  fi
   375                  printf "#    %-35s | actual\n" "expect"
   376                  printf "#    ----------------------------------- | ------\n"
   377                  for i in $(seq 0 $((${n_max}-1))); do
   378                      local e="${expect_split[$i]}"
   379                      local a="${actual_split[$i]}"
   380                      local same=' '
   381                      local eq='='
   382                      if [[ "$e" != "$a" ]]; then
   383                          same='!'
   384                          eq='|'
   385                      fi
   386                      printf "#  %s %-35s %s %s\n" "$same" "$e" "$eq" "$a"
   387                  done
   388              fi
   389          fi
   390      fi
   391  }
   392  
   393  # Positive tests
   394  check_assert "a"    =  "a"     ""
   395  check_assert "abc"  =~ "a"     ""
   396  check_assert "abc"  =~ "b"     ""
   397  check_assert "abc"  =~ "c"     ""
   398  check_assert "abc"  =~ "a.*c"  ""
   399  check_assert "a"   !=  "b"     ""
   400  
   401  # Simple Failure tests
   402  check_assert "a" = "b" "
   403  #| expected: = b
   404  #|   actual:   a"
   405  
   406  # This is the one that triggered #17509
   407  expect="abcd efg
   408  hijk lmnop"
   409  actual="abcd efg
   410  
   411  hijk lmnop"
   412  check_assert "$actual" = "$expect" "
   413  #| expected: = abcd efg
   414  #|         >   hijk lmnop
   415  #|   actual:   abcd efg
   416  #|         >   ''
   417  #|         >   hijk lmnop"
   418  
   419  # Undesired carriage returns
   420  cr=$'\r'
   421  expect="this is line 1
   422  this is line 2"
   423  actual="this is line 1$cr
   424  this is line 2$cr"
   425  check_assert "$actual" = "$expect" "
   426  #| expected: = this is line 1
   427  #|         >   this is line 2
   428  #|   actual:   \$'this is line 1\r'
   429  #|         >   \$'this is line 2\r'"
   430  
   431  # Anchored expressions; the 2nd and 3rd are 15 and 17 characters, not 16
   432  check_assert "0123456789abcdef"  =~ "^[0-9a-f]{16}\$" ""
   433  check_assert "0123456789abcde"   =~ "^[0-9a-f]{16}\$" "
   434  #| expected: =~ \^\[0-9a-f\]\{16\}\\$
   435  #|   actual:    0123456789abcde"
   436  check_assert "0123456789abcdeff"  =~ "^[0-9a-f]{16}\$" "
   437  #| expected: =~ \^\[0-9a-f\]\{16\}\\$
   438  #|   actual:    0123456789abcdeff"
   439  
   440  # END   check_assert
   441  ###############################################################################
   442  
   443  exit $rc