github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/functional-tests.sh (about)

     1  #!/bin/bash
     2  #
     3  # Copyright (c) 2015-2023 MinIO, Inc.
     4  #
     5  # This file is part of MinIO Object Storage stack
     6  #
     7  # This program is free software: you can redistribute it and/or modify
     8  # it under the terms of the GNU Affero General Public License as published by
     9  # the Free Software Foundation, either version 3 of the License, or
    10  # (at your option) any later version.
    11  #
    12  # This program is distributed in the hope that it will be useful
    13  # but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  # GNU Affero General Public License for more details.
    16  #
    17  # You should have received a copy of the GNU Affero General Public License
    18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19  #
    20  
    21  ################################################################################
    22  #
    23  # This script is usable by mc functional tests, mint tests and MinIO verification
    24  # tests.
    25  #
    26  # * As mc functional tests, just run this script.  It uses mc executable binary
    27  #   in current working directory or in the path.  The tests uses play.min.io
    28  #   as MinIO server.
    29  #
    30  # * For other, call this script with environment variables MINT_MODE,
    31  #   MINT_DATA_DIR, SERVER_ENDPOINT, ACCESS_KEY, SECRET_KEY and ENABLE_HTTPS. It
    32  #   uses mc executable binary in current working directory and uses given MinIO
    33  #   server to run tests. MINT_MODE is set by mint to specify what category of
    34  #   tests to run.
    35  #
    36  ################################################################################
    37  
    38  # Force bytewise sorting for CLI tools
    39  LANG=C
    40  
    41  if [ -n "$MINT_MODE" ]; then
    42      if [ -z "${MINT_DATA_DIR+x}" ]; then
    43  	echo "MINT_DATA_DIR not defined"
    44  	exit 1
    45      fi
    46      if [ -z "${SERVER_ENDPOINT+x}" ]; then
    47  	echo "SERVER_ENDPOINT not defined"
    48  	exit 1
    49      fi
    50      if [ -z "${ACCESS_KEY+x}" ]; then
    51  	echo "ACCESS_KEY not defined"
    52  	exit 1
    53      fi
    54      if [ -z "${SECRET_KEY+x}" ]; then
    55  	echo "SECRET_KEY not defined"
    56  	exit 1
    57      fi
    58  fi
    59  
    60  if [ -z "${SERVER_ENDPOINT+x}" ]; then
    61      SERVER_ENDPOINT="play.min.io"
    62      ACCESS_KEY="Q3AM3UQ867SPQQA43P2F"
    63      SECRET_KEY="zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
    64      ENABLE_HTTPS=1
    65  fi
    66  
    67  # If you want to run the complete site cleaning test, set this variable to true 
    68  COMPLETE_RB_TEST=true
    69  
    70  WORK_DIR="$PWD"
    71  DATA_DIR="$MINT_DATA_DIR"
    72  if [ -z "$MINT_MODE" ]; then
    73      WORK_DIR="$PWD/.run-$RANDOM"
    74      DATA_DIR="$WORK_DIR/data"
    75  fi
    76  
    77  FILE_0_B="$DATA_DIR/datafile-0-b"
    78  FILE_1_MB="$DATA_DIR/datafile-1-MB"
    79  FILE_65_MB="$DATA_DIR/datafile-65-MB"
    80  declare FILE_0_B_MD5SUM
    81  declare FILE_1_MB_MD5SUM
    82  declare FILE_65_MB_MD5SUM
    83  
    84  ENDPOINT="https://$SERVER_ENDPOINT"
    85  if [ "$ENABLE_HTTPS" != "1" ]; then
    86      ENDPOINT="http://$SERVER_ENDPOINT"
    87  fi
    88  
    89  SERVER_ALIAS="myminio"
    90  SERVER_ALIAS_TLS="myminio-ssl"
    91  
    92  BUCKET_NAME="mc-test-bucket-$RANDOM"
    93  WATCH_OUT_FILE="$WORK_DIR/watch.out-$RANDOM"
    94  
    95  MC_CONFIG_DIR="/tmp/.mc-$RANDOM"
    96  MC="$PWD/mc"
    97  declare -a MC_CMD
    98  
    99  function get_md5sum()
   100  {
   101      filename="$1"
   102      out=$(md5sum "$filename" 2>/dev/null)
   103      rv=$?
   104      if [ "$rv" -eq 0 ]; then
   105  	echo $(awk '{ print $1 }' <<< "$out")
   106      fi
   107  
   108      return "$rv"
   109  }
   110  
   111  function get_time()
   112  {
   113      date +%s%N
   114  }
   115  
   116  function get_duration()
   117  {
   118      start_time=$1
   119      end_time=$(get_time)
   120  
   121      echo $(( (end_time - start_time) / 1000000 ))
   122  }
   123  
   124  function log_success()
   125  {
   126      if [ -n "$MINT_MODE" ]; then
   127  	printf '{"name": "mc", "duration": "%d", "function": "%s", "status": "PASS"}\n' "$(get_duration "$1")" "$2"
   128      fi
   129  }
   130  
   131  function show()
   132  {
   133      if [ -z "$MINT_MODE" ]; then
   134  	func_name="$1"
   135  	echo "Running $func_name()"
   136      fi
   137  }
   138  
   139  function show_on_success()
   140  {
   141      rv="$1"
   142      shift
   143  
   144      if [ "$rv" -eq 0 ]; then
   145  	echo "$@"
   146      fi
   147  
   148      return "$rv"
   149  }
   150  
   151  function show_on_failure()
   152  {
   153      rv="$1"
   154      shift
   155  
   156      if [ "$rv" -ne 0 ]; then
   157  	echo "$@"
   158      fi
   159  
   160      return "$rv"
   161  }
   162  
   163  function assert()
   164  {
   165      expected_rv="$1"
   166      shift
   167      start_time="$1"
   168      shift
   169      func_name="$1"
   170      shift
   171  
   172      err=$("$@")
   173      rv=$?
   174      if [ "$rv" -ne "$expected_rv" ]; then
   175  	if [ -n "$MINT_MODE" ]; then
   176  	    err=$(printf "$err" | python -c 'import sys,json; print(json.dumps(sys.stdin.read()))')
   177  	    ## err is already JSON string, no need to double quote
   178  	    printf '{"name": "mc", "duration": "%d", "function": "%s", "status": "FAIL", "error": %s}\n' "$(get_duration "$start_time")" "$func_name" "$err"
   179  	else
   180  	    echo "mc: $func_name: $err"
   181  	fi
   182  
   183  	if [ "$rv" -eq 0 ]; then
   184  	    exit 1
   185  	fi
   186  
   187  	exit "$rv"
   188      fi
   189  
   190      return 0
   191  }
   192  
   193  function assert_success() {
   194      assert 0 "$@"
   195  }
   196  
   197  function assert_failure() {
   198      assert 1 "$@"
   199  }
   200  
   201  function mc_cmd()
   202  {
   203      cmd=( "${MC_CMD[@]}" "$@" )
   204      err_file="$WORK_DIR/cmd.out.$RANDOM"
   205  
   206      "${cmd[@]}" >"$err_file" 2>&1
   207      rv=$?
   208      if [ "$rv" -ne 0 ]; then
   209  	printf '%q ' "${cmd[@]}"
   210  	echo " >>> "
   211  	cat "$err_file"
   212      fi
   213  
   214      rm -f "$err_file"
   215      return "$rv"
   216  }
   217  
   218  function check_md5sum()
   219  {
   220      expected_checksum="$1"
   221      shift
   222      filename="$@"
   223  
   224      checksum="$(get_md5sum "$filename")"
   225      rv=$?
   226      if [ "$rv" -ne 0 ]; then
   227  	echo "unable to get md5sum for $filename"
   228  	return "$rv"
   229      fi
   230  
   231      if [ "$checksum" != "$expected_checksum" ]; then
   232  	echo "$filename: md5sum mismatch"
   233  	return 1
   234      fi
   235  
   236      return 0
   237  }
   238  
   239  function test_make_bucket()
   240  {
   241      show "${FUNCNAME[0]}"
   242  
   243      start_time=$(get_time)
   244      bucket_name="mc-test-bucket-$RANDOM"
   245      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   246      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket_name}"
   247  
   248      log_success "$start_time" "${FUNCNAME[0]}"
   249  }
   250  
   251  function test_make_bucket_error() {
   252      show "${FUNCNAME[0]}"
   253  
   254      start_time=$(get_time)
   255      bucket_name="MC-test%bucket%$RANDOM"
   256      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   257  
   258      log_success "$start_time" "${FUNCNAME[0]}"
   259  }
   260  
   261  function test_rb()
   262  {
   263      show "${FUNCNAME[0]}"
   264  
   265      start_time=$(get_time)
   266      bucket1="mc-test-bucket-$RANDOM-1"
   267      bucket2="mc-test-bucket-$RANDOM-2"
   268      object_name="mc-test-object-$RANDOM"
   269  
   270      # Tets rb when the bucket is empty
   271      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
   272      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket1}"
   273  
   274      # Test rb with --force flag when the bucket is not empty
   275      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
   276      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket1}/${object_name}"
   277      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd rb "${SERVER_ALIAS}/${bucket1}"
   278      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket1}"
   279  
   280      # Test rb with --force and --dangerous to remove a site content
   281      if [ "${COMPLETE_RB_TEST}" == "true" ]; then
   282          assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket1}"
   283          assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket2}"
   284          assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket1}/${object_name}"
   285          assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket2}/${object_name}"
   286          assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/"
   287          assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force --dangerous "${SERVER_ALIAS}"
   288      fi
   289      
   290      log_success "$start_time" "${FUNCNAME[0]}"
   291  }
   292  
   293  function setup()
   294  {
   295      start_time=$(get_time)
   296      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${BUCKET_NAME}"
   297  }
   298  
   299  function teardown()
   300  {
   301      start_time=$(get_time)
   302      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${BUCKET_NAME}"
   303  }
   304  
   305  # Test mc ls on a S3 prefix where a lower similar prefix exists as well e.g. dir-foo/ and dir/
   306  function test_list_dir()
   307  {
   308      show "${FUNCNAME[0]}"
   309  
   310      start_time=$(get_time)
   311      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/dir-foo/object1"
   312      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/dir/object2"
   313      diff -bB <(echo "object2")  <("${MC_CMD[@]}" --json ls "${SERVER_ALIAS}/${BUCKET_NAME}/dir" |  jq -r '.key')  >/dev/null 2>&1
   314      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unexpected listing dir"
   315  
   316      # Cleanup
   317      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/dir-foo/${object_name}"
   318      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/dir/${object_name}"
   319  
   320      log_success "$start_time" "${FUNCNAME[0]}"
   321  }
   322  
   323  function test_od_object() {
   324      show "${FUNCNAME[0]}"
   325  
   326      start_time=$(get_time)
   327      object_name="mc-test-object-$RANDOM"
   328      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd od if="${FILE_1_MB}" of="${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   329      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd od of="${FILE_1_MB}" if="${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   330  
   331      log_success "$start_time" "${FUNCNAME[0]}"
   332  }
   333  
   334  function test_put_object()
   335  {
   336      show "${FUNCNAME[0]}"
   337  
   338      start_time=$(get_time)
   339      object_name="mc-test-object-$RANDOM"
   340      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   341      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   342  
   343      log_success "$start_time" "${FUNCNAME[0]}"
   344  }
   345  
   346  function test_put_object_error()
   347  {
   348      show "${FUNCNAME[0]}"
   349      start_time=$(get_time)
   350  
   351      object_long_name=$(printf "mc-test-object-%01100d" 1)
   352      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_long_name}"
   353  
   354      log_success "$start_time" "${FUNCNAME[0]}"
   355  }
   356  
   357  function test_put_object_multipart()
   358  {
   359      show "${FUNCNAME[0]}"
   360  
   361      start_time=$(get_time)
   362      object_name="mc-test-object-$RANDOM"
   363      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_65_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   364      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   365  
   366      log_success "$start_time" "${FUNCNAME[0]}"
   367  }
   368  
   369  function test_put_object_0byte()
   370  {
   371      show "${FUNCNAME[0]}"
   372  
   373      start_time=$(get_time)
   374      object_name="mc-test-object-$RANDOM"
   375      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_0_B}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   376      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
   377      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_0_B_MD5SUM" "${object_name}.downloaded"
   378      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   379  
   380      log_success "$start_time" "${FUNCNAME[0]}"
   381  }
   382  
   383  ## Test mc cp command with storage-class flag set
   384  function test_put_object_with_storage_class()
   385  {
   386      show "${FUNCNAME[0]}"
   387  
   388      start_time=$(get_time)
   389      object_name="mc-test-object-$RANDOM"
   390      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --storage-class REDUCED_REDUNDANCY "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   391      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   392  
   393      log_success "$start_time" "${FUNCNAME[0]}"
   394  }
   395  
   396  ## Test mc cp command with storage-class flag set to incorrect value
   397  function test_put_object_with_storage_class_error()
   398  {
   399      show "${FUNCNAME[0]}"
   400  
   401      start_time=$(get_time)
   402      object_name="mc-test-object-$RANDOM"
   403      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp --storage-class REDUCED "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   404  
   405      log_success "$start_time" "${FUNCNAME[0]}"
   406  }
   407  
   408  ## Test mc cp command with valid metadata string
   409  function test_put_object_with_metadata()
   410  {
   411      show "${FUNCNAME[0]}"
   412  
   413      start_time=$(get_time)
   414      object_name="mc-test-object-$RANDOM"
   415      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --attr key1=val1\;key2=val2 "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   416      diff -bB <(echo "val1")  <("${MC_CMD[@]}"   --json stat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"  |  jq -r '.metadata."X-Amz-Meta-Key1"')  >/dev/null 2>&1
   417      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to put object with metadata"
   418      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   419      log_success "$start_time" "${FUNCNAME[0]}"
   420  
   421  }
   422  
   423  function test_get_object()
   424  {
   425      show "${FUNCNAME[0]}"
   426  
   427      start_time=$(get_time)
   428      object_name="mc-test-object-$RANDOM"
   429      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   430      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
   431      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   432      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   433  
   434      log_success "$start_time" "${FUNCNAME[0]}"
   435  }
   436  
   437  function test_get_object_multipart()
   438  {
   439      show "${FUNCNAME[0]}"
   440  
   441      start_time=$(get_time)
   442      object_name="mc-test-object-$RANDOM"
   443      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_65_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   444      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
   445      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_65_MB_MD5SUM" "${object_name}.downloaded"
   446      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   447  
   448      log_success "$start_time" "${FUNCNAME[0]}"
   449  }
   450  
   451  function test_presigned_post_policy_error()
   452  {
   453      show "${FUNCNAME[0]}"
   454  
   455      start_time=$(get_time)
   456      object_name="mc-test-object-$RANDOM"
   457  
   458      out=$("${MC_CMD[@]}" --json share upload "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}")
   459      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to get presigned post policy and put object url"
   460  
   461      # Support IPv6 address, IPv6 is specifed as [host]:9000 form, we should
   462      # replace '['']' with their escaped values as '\[' '\]'.
   463      #
   464      # Without escaping '['']', 'sed' command interprets them as expressions
   465      # which fails our requirement of replacing $endpoint/$bucket URLs in the
   466      # subsequent operations.
   467      endpoint=$(echo "$ENDPOINT" | sed 's|[][]|\\&|g')
   468  
   469      # Extract share field of json output, and append object name to the URL
   470      upload=$(echo "$out" | jq -r .share | sed "s|<FILE>|$FILE_1_MB|g" | sed "s|curl|curl -sSg|g" | sed "s|${endpoint}/${BUCKET_NAME}/|${endpoint}/${BUCKET_NAME}/${object_name}|g")
   471  
   472      # In case of virtual host style URL path, the previous replace would have failed.
   473      # One of the following two commands will append the object name in that scenario.
   474      upload=$(echo "$upload" | sed "s|http://${BUCKET_NAME}.${SERVER_ENDPOINT}/|http://${BUCKET_NAME}.${SERVER_ENDPOINT}/${object_name}|g")
   475      upload=$(echo "$upload" | sed "s|https://${BUCKET_NAME}.${SERVER_ENDPOINT}/|https://${BUCKET_NAME}.${SERVER_ENDPOINT}/${object_name}|g")
   476  
   477      ret=$($upload 2>&1 | grep -oP '(?<=Code>)[^<]+')
   478      # Check if the command execution failed.
   479      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unknown failure in upload of $FILE_1_MB using presigned post policy"
   480      if [ -z "$ret" ]; then
   481  
   482      # Check if the upload succeeded. We expect it to fail.
   483      assert_failure "$start_time" "${FUNCNAME[0]}" show_on_success 0 "upload of $FILE_1_MB using presigned post policy should have failed"
   484      fi
   485  
   486      if [ "$ret" != "MethodNotAllowed" ]; then
   487      assert_failure "$start_time" "${FUNCNAME[0]}" show_on_success 0 "upload of $FILE_1_MB using presigned post policy should have failed with MethodNotAllowed error, instead failed with $ret error"
   488      fi
   489      log_success "$start_time" "${FUNCNAME[0]}"
   490  }
   491  
   492  function test_presigned_put_object()
   493  {
   494      show "${FUNCNAME[0]}"
   495  
   496      start_time=$(get_time)
   497      object_name="mc-test-object-$RANDOM"
   498  
   499      out=$("${MC_CMD[@]}" --json share upload "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}")
   500      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to get presigned put object url"
   501      upload=$(echo "$out" | jq -r .share | sed "s|<FILE>|$FILE_1_MB|g" | sed "s|curl|curl -sSg|g")
   502      $upload >/dev/null 2>&1
   503      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to upload $FILE_1_MB presigned put object url"
   504  
   505      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
   506      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   507      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   508  
   509      log_success "$start_time" "${FUNCNAME[0]}"
   510  }
   511  
   512  function test_presigned_get_object()
   513  {
   514      show "${FUNCNAME[0]}"
   515  
   516      start_time=$(get_time)
   517      object_name="mc-test-object-$RANDOM"
   518      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   519  
   520      out=$("${MC_CMD[@]}" --json share download "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}")
   521      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to get presigned get object url"
   522      download_url=$(echo "$out" | jq -r .share)
   523      curl -sSg --output "${object_name}.downloaded" -X GET "$download_url"
   524      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download $download_url"
   525  
   526      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   527      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   528  
   529      log_success "$start_time" "${FUNCNAME[0]}"
   530  }
   531  
   532  function test_cat_object()
   533  {
   534      show "${FUNCNAME[0]}"
   535  
   536      start_time=$(get_time)
   537      object_name="mc-test-object-$RANDOM"
   538      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   539      "${MC_CMD[@]}" cat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" > "${object_name}.downloaded"
   540      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
   541      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   542      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   543  
   544      log_success "$start_time" "${FUNCNAME[0]}"
   545  }
   546  
   547  function test_cat_stdin()
   548  {
   549      show "${FUNCNAME[0]}"
   550  
   551      start_time=$(get_time)
   552      object_name="mc-test-object-$RANDOM"
   553      bucket_name="mc-test-bucket-$RANDOM"
   554      "${MC_CMD[@]}" mb "${SERVER_ALIAS}/${bucket_name}"
   555      echo "testcontent" | "${MC_CMD[@]}" pipe "${SERVER_ALIAS}/${bucket_name}/${object_name}"
   556      "${MC_CMD[@]}" cat "${SERVER_ALIAS}/${bucket_name}/${object_name}" > stdout.output
   557      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to redirect stdin to stdout using 'mc cat'"
   558      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "42ed9fb3563d8e9c7bb522be443033f4" stdout.output
   559      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm stdout.output
   560  
   561      log_success "$start_time" "${FUNCNAME[0]}"
   562  }
   563  
   564  
   565  function test_mirror_list_objects()
   566  {
   567      show "${FUNCNAME[0]}"
   568  
   569      start_time=$(get_time)
   570      bucket_name="mc-test-bucket-$RANDOM"
   571      object_name="mc-test-object-$RANDOM"
   572      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   573      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
   574  
   575      diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json ls "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key) >/dev/null 2>&1
   576      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
   577  
   578      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
   579  
   580      log_success "$start_time" "${FUNCNAME[0]}"
   581  }
   582  
   583  ## Tests mc mirror command with --storage-class flag set
   584  function test_mirror_list_objects_storage_class()
   585  {
   586      show "${FUNCNAME[0]}"
   587  
   588      start_time=$(get_time)
   589      bucket_name="mc-test-bucket-$RANDOM"
   590      object_name="mc-test-object-$RANDOM"
   591      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   592      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror --storage-class REDUCED_REDUNDANCY "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
   593  
   594      diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json ls "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key) >/dev/null 2>&1
   595      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
   596  
   597      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
   598  
   599      log_success "$start_time" "${FUNCNAME[0]}"
   600  }
   601  
   602  ## Tests find command with --older-than set to 1day, should be empty.
   603  function test_find_empty() {
   604      show "${FUNCNAME[0]}"
   605  
   606      start_time=$(get_time)
   607      bucket_name="mc-test-bucket-$RANDOM"
   608      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   609      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
   610  
   611      # find --older-than 1 day should be empty, so we compare with empty string.
   612      diff -bB <(echo "") <("${MC_CMD[@]}" find "${SERVER_ALIAS}/${bucket_name}" --json --older-than 1d | jq -r .key | sed "s/${SERVER_ALIAS}\/${bucket_name}\///g") >/dev/null 2>&1
   613      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
   614  
   615      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
   616  
   617      log_success "$start_time" "${FUNCNAME[0]}"
   618  }
   619  
   620  ## Tests find command, should list.
   621  function test_find() {
   622      show "${FUNCNAME[0]}"
   623  
   624      start_time=$(get_time)
   625      bucket_name="mc-test-bucket-$RANDOM"
   626      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   627      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
   628  
   629      diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json find "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key | sed "s/${SERVER_ALIAS}\/${bucket_name}\///g") >/dev/null 2>&1
   630      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
   631  
   632      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
   633  
   634      log_success "$start_time" "${FUNCNAME[0]}"
   635  }
   636  
   637  function test_watch_object()
   638  {
   639      show "${FUNCNAME[0]}"
   640  
   641      start_time=$(get_time)
   642      bucket_name="mc-test-bucket-$RANDOM"
   643      object_name="mc-test-object-$RANDOM"
   644      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   645  
   646      # start a process to watch on bucket
   647      "${MC_CMD[@]}" --json watch "${SERVER_ALIAS}/${bucket_name}" > "$WATCH_OUT_FILE" &
   648      watch_cmd_pid=$!
   649      sleep 1
   650  
   651      ( assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${bucket_name}/${object_name}" )
   652      rv=$?
   653      if [ "$rv" -ne 0 ]; then
   654  	kill "$watch_cmd_pid"
   655  	exit "$rv"
   656      fi
   657  
   658      sleep 1
   659      if ! jq -r .events.type "$WATCH_OUT_FILE" | grep -qi ObjectCreated; then
   660  	kill "$watch_cmd_pid"
   661  	assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure 1 "ObjectCreated event not found"
   662      fi
   663  
   664      ( assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${bucket_name}/${object_name}" )
   665      rv=$?
   666      if [ "$rv" -ne 0 ]; then
   667  	kill "$watch_cmd_pid"
   668  	exit "$rv"
   669      fi
   670  
   671      sleep 1
   672      if ! jq -r .events.type "$WATCH_OUT_FILE" | grep -qi ObjectRemoved; then
   673  	kill "$watch_cmd_pid"
   674  	assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure 1 "ObjectRemoved event not found"
   675      fi
   676  
   677      kill "$watch_cmd_pid"
   678  
   679      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
   680  
   681      log_success "$start_time" "${FUNCNAME[0]}"
   682  }
   683  
   684  
   685  function test_config_host_add()
   686  {
   687      show "${FUNCNAME[0]}"
   688      start_time=$(get_time)
   689  
   690      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias set "${SERVER_ALIAS}1" "$ENDPOINT" "$ACCESS_KEY" "$SECRET_KEY"
   691      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias list "${SERVER_ALIAS}1"
   692  
   693      log_success "$start_time" "${FUNCNAME[0]}"
   694  }
   695  
   696  function test_config_host_add_error()
   697  {
   698      show "${FUNCNAME[0]}"
   699      start_time=$(get_time)
   700  
   701      out=$("${MC_CMD[@]}" --json alias set "${SERVER_ALIAS}1" "$ENDPOINT" "$ACCESS_KEY" "invalid-secret")
   702      assert_failure "$start_time" "${FUNCNAME[0]}" show_on_success $? "adding host should fail"
   703      got_code=$(echo "$out" | jq -r .error.cause.error.Code)
   704      if [ "${got_code}" != "SignatureDoesNotMatch" ]; then
   705  	assert_failure "$start_time" "${FUNCNAME[0]}" show_on_failure 1 "incorrect error code ${got_code} returned by server"
   706      fi
   707  
   708      log_success "$start_time" "${FUNCNAME[0]}"
   709  }
   710  
   711  function test_put_object_with_sse()
   712  {
   713      show "${FUNCNAME[0]}"
   714      start_time=$(get_time)
   715      object_name="mc-test-object-$RANDOM"
   716      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
   717      # put encrypted object; then delete with correct secret key
   718      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   719      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   720      log_success "$start_time" "${FUNCNAME[0]}"
   721  }
   722  
   723  function test_put_object_with_encoded_sse()
   724  {
   725      show "${FUNCNAME[0]}"
   726      start_time=$(get_time)
   727      object_name="mc-test-object-$RANDOM"
   728      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=MzJieXRlc2xvbmdzZWNyZWFiY2RlZmcJZ2l2ZW5uMjE="
   729      # put encrypted object; then delete with correct secret key
   730      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   731      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   732      log_success "$start_time" "${FUNCNAME[0]}"
   733  }
   734  
   735  function test_put_object_with_sse_error()
   736  {
   737      show "${FUNCNAME[0]}"
   738      start_time=$(get_time)
   739      object_name="mc-test-object-$RANDOM"
   740      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven"
   741      # put object with invalid encryption key; should fail
   742      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   743      log_success "$start_time" "${FUNCNAME[0]}"
   744  }
   745  
   746  function test_cat_object_with_sse()
   747  {
   748      show "${FUNCNAME[0]}"
   749      start_time=$(get_time)
   750      object_name="mc-test-object-$RANDOM"
   751      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
   752      # put encrypted object; then cat object correct secret key
   753      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp  --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   754      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cat --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   755      log_success "$start_time" "${FUNCNAME[0]}"
   756  }
   757  
   758  function test_cat_object_with_sse_error()
   759  {
   760      show "${FUNCNAME[0]}"
   761      start_time=$(get_time)
   762      object_name="mc-test-object-$RANDOM"
   763      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
   764      # put encrypted object; then cat object with no secret key
   765      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp  --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   766      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cat  "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   767      log_success "$start_time" "${FUNCNAME[0]}"
   768  }
   769  
   770  # Test "mc cp -r" command of a directory with and without a leading slash
   771  function test_copy_directory()
   772  {
   773      show "${FUNCNAME[0]}"
   774  
   775      random_dir="dir-$RANDOM-$RANDOM"
   776      tmpdir="$(mktemp -d)"
   777  
   778      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-name"
   779      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to upload an object"
   780  
   781      # Copy a directory with a trailing slash
   782      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp -r "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/" "${tmpdir}/"
   783      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to copy a directory with a trailing slash"
   784      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${tmpdir}/object-name"
   785      assert_success "$start_time" "${FUNCNAME[0]}" rm "${tmpdir}/object-name"
   786  
   787      # Copy a directory without a trailing slash
   788      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp -r "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}" "${tmpdir}/"
   789      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to copy a directory without a trailing slash"
   790      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${tmpdir}/${random_dir}/object-name"
   791  
   792      # Cleanup
   793      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm -r --force "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/"
   794      assert_success "$start_time" "${FUNCNAME[0]}" rm -r "${tmpdir}"
   795  
   796      log_success "$start_time" "${FUNCNAME[0]}"
   797  }
   798  
   799  # Test "mc cp -a" command to see if it preserves file system attributes
   800  function test_copy_object_preserve_filesystem_attr()
   801  {
   802      show "${FUNCNAME[0]}"
   803      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp -a "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   804      diff -bB <("${MC_CMD[@]}"   --json stat "${FILE_1_MB}"  |  jq -r '.metadata."X-Amz-Meta-Mc-Attrs"')  >/dev/null 2>&1 <("${MC_CMD[@]}"   --json stat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"  |  jq -r '.metadata."X-Amz-Meta-Mc-Attrs"')  >/dev/null 2>&1
   805      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to put object with file system attribute"
   806      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   807      log_success "$start_time" "${FUNCNAME[0]}"
   808  }
   809  
   810  # Test "mc mv" command
   811  function test_mv_object()
   812  {
   813      show "${FUNCNAME[0]}"
   814  
   815      random_dir="dir-$RANDOM-$RANDOM"
   816      tmpdir="$(mktemp -d)"
   817  
   818      # Test mv command locally
   819      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "${FILE_1_MB}" "${tmpdir}/file.tmp"
   820      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mv "${tmpdir}/file.tmp" "${tmpdir}/file"
   821      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd stat "${tmpdir}/file.tmp"
   822      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${tmpdir}/file"
   823  
   824      # Test mv command from filesystem to S3
   825      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mv "${tmpdir}/file" "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-1"
   826      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd stat "${tmpdir}/file"
   827      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd stat "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-1"
   828  
   829     # Test mv command from S3 to S3
   830      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mv "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-1" "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-2"
   831      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd stat "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-1"
   832      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd stat "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-2"
   833  
   834      # Test mv command from S3 to filesystem
   835      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mv "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-2" "${tmpdir}/file"
   836      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd stat "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/object-2"
   837      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd stat "${tmpdir}/file"
   838  
   839      # Cleanup
   840      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm -r --force "${SERVER_ALIAS}/${BUCKET_NAME}/${random_dir}/"
   841      assert_success "$start_time" "${FUNCNAME[0]}" rm -r "${tmpdir}"
   842  
   843      log_success "$start_time" "${FUNCNAME[0]}"
   844  }
   845  
   846  
   847  function test_copy_object_with_sse_rewrite()
   848  {
   849      # test server side copy and remove operation - target is unencrypted while source is encrypted
   850      show "${FUNCNAME[0]}"
   851      start_time=$(get_time)
   852      prefix="prefix"
   853      object_name="mc-test-object-$RANDOM"
   854  
   855      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}=32byteslongsecretkeymustbegiven1"
   856      # create encrypted object on server
   857      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
   858      # now do a server side copy and store it unencrypted.
   859      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   860      # cat the unencrypted destination object. should return data without any error
   861      "${MC_CMD[@]}" cat "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" >"${object_name}.downloaded"
   862      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
   863      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   864      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded"
   865      # mc rm on with multi-object delete, deletes encrypted object without encryption key.
   866      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
   867      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   868  
   869      log_success "$start_time" "${FUNCNAME[0]}"
   870  }
   871  
   872  function test_copy_object_with_sse_dest()
   873  {
   874      # test server side copy and remove operation - target is encrypted with different key
   875      show "${FUNCNAME[0]}"
   876      start_time=$(get_time)
   877      prefix="prefix"
   878      object_name="mc-test-object-$RANDOM"
   879  
   880      cli_flag1="${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}=32byteslongsecretkeymustbegiven1"
   881      cli_flag2="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven2"
   882  
   883      # create encrypted object on server
   884      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
   885      # now do a server side copy and store it eith different encryption key.
   886      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1},${cli_flag2}"  "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   887      # cat the destination object with the new key. should return data without any error
   888      "${MC_CMD[@]}" cat --encrypt-key "${cli_flag2}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" > "${object_name}.downloaded"
   889      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
   890      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   891      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded"
   892      # mc rm on src object with first encryption key should pass
   893      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag1}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
   894      # mc rm on encrypted destination object with second encryption key should pass
   895      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm  --encrypt-key "${cli_flag2}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   896  
   897      log_success "$start_time" "${FUNCNAME[0]}"
   898  }
   899  
   900  function test_sse_key_rotation()
   901  {
   902      # test server side copy and remove operation - target is encrypted with different key
   903      show "${FUNCNAME[0]}"
   904      start_time=$(get_time)
   905      prefix="prefix"
   906      object_name="mc-test-object-$RANDOM"
   907      old_key="32byteslongsecretkeymustbegiven1"
   908      new_key="32byteslongsecretkeymustbegiven2"
   909      cli_flag1="${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}=${old_key}"
   910      cli_flag2="${SERVER_ALIAS_TLS}/${BUCKET_NAME}=${new_key}"
   911  
   912      # create encrypted object on server
   913      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}"
   914      # now do a server side copy on same object and do a key rotation
   915      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag1},${cli_flag2}"  "${SERVER_ALIAS}/${BUCKET_NAME}/${prefix}/${object_name}" "${SERVER_ALIAS_TLS}/${BUCKET_NAME}/${object_name}"
   916      # cat the object with the new key. should return data without any error
   917      "${MC_CMD[@]}" cat --encrypt-key "${cli_flag2}" "${SERVER_ALIAS_TLS}/${BUCKET_NAME}/${object_name}" > "${object_name}.downloaded"
   918      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "unable to download object using 'mc cat'"
   919      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   920      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${object_name}.downloaded"
   921      # mc rm on encrypted object with succeed anyways, without encrypted keys.
   922      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS_TLS}/${BUCKET_NAME}/${object_name}"
   923  
   924      log_success "$start_time" "${FUNCNAME[0]}"
   925  }
   926  
   927  function test_mirror_with_sse()
   928  {
   929      # test if mirror operation works with encrypted objects
   930      show "${FUNCNAME[0]}"
   931  
   932      start_time=$(get_time)
   933      bucket_name="mc-test-bucket-$RANDOM"
   934      cli_flag="${SERVER_ALIAS}/${bucket_name}=32byteslongsecretkeymustbegiven1"
   935  
   936      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mb "${SERVER_ALIAS}/${bucket_name}"
   937      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd mirror --encrypt-key "${cli_flag}" "$DATA_DIR" "${SERVER_ALIAS}/${bucket_name}"
   938      diff -bB <(ls "$DATA_DIR") <("${MC_CMD[@]}" --json ls "${SERVER_ALIAS}/${bucket_name}/" | jq -r .key) >/dev/null 2>&1
   939      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure $? "mirror and list differs"
   940      # Remove the test bucket with its contents
   941      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rb --force "${SERVER_ALIAS}/${bucket_name}"
   942  
   943      log_success "$start_time" "${FUNCNAME[0]}"
   944  }
   945  
   946  function test_rm_object_with_sse()
   947  {
   948      show "${FUNCNAME[0]}"
   949  
   950      # test whether remove fails for encrypted object if secret key not provided.
   951      start_time=$(get_time)
   952      object_name="mc-test-object-$RANDOM"
   953      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
   954  
   955      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   956      # rm will not fail even if the encryption keys are not provided, since mc rm uses multi-object delete.
   957      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   958  
   959      log_success "$start_time" "${FUNCNAME[0]}"
   960  }
   961  
   962  function test_get_object_with_sse()
   963  {
   964      show "${FUNCNAME[0]}"
   965  
   966      start_time=$(get_time)
   967      object_name="mc-test-object-$RANDOM"
   968      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
   969  
   970      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_1_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   971      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}" "${object_name}.downloaded"
   972      assert_success "$start_time" "${FUNCNAME[0]}" check_md5sum "$FILE_1_MB_MD5SUM" "${object_name}.downloaded"
   973      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${object_name}.downloaded" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   974  
   975      log_success "$start_time" "${FUNCNAME[0]}"
   976  }
   977  
   978  function test_put_object_multipart_sse()
   979  {
   980      show "${FUNCNAME[0]}"
   981  
   982      start_time=$(get_time)
   983      object_name="mc-test-object-$RANDOM"
   984      cli_flag="${SERVER_ALIAS}/${BUCKET_NAME}=32byteslongsecretkeymustbegiven1"
   985  
   986      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp --encrypt-key "${cli_flag}" "${FILE_65_MB}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   987      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm --encrypt-key "${cli_flag}" "${SERVER_ALIAS}/${BUCKET_NAME}/${object_name}"
   988  
   989      log_success "$start_time" "${FUNCNAME[0]}"
   990  }
   991  
   992  function test_admin_users()
   993  {
   994      show "${FUNCNAME[0]}"
   995  
   996      start_time=$(get_time)
   997  
   998      # create a user
   999      username=foo
  1000      password=foobar12345
  1001      test_alias="aliasx"
  1002  
  1003      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user add "$SERVER_ALIAS" "$username" "$password"
  1004  
  1005      # check that user appears in the user list
  1006      "${MC_CMD[@]}" --json admin user list "${SERVER_ALIAS}" | jq -r '.accessKey' | grep --quiet "^${username}$"
  1007      rv=$?
  1008      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure ${rv} "user ${username} did NOT appear in the list of users returned by server"
  1009  
  1010      # setup temporary alias to make requests as the created user.
  1011      scheme="https"
  1012      if [ "$ENABLE_HTTPS" != "1" ]; then
  1013  	  scheme="http"
  1014      fi
  1015      object1_name="mc-test-object-$RANDOM"
  1016      object2_name="mc-test-object-$RANDOM"
  1017  
  1018      # Adding an alias for the $test_alias
  1019      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias set $test_alias "${scheme}://${SERVER_ENDPOINT}" ${username} ${password} 
  1020  
  1021      # check that alias appears in the alias list
  1022      "${MC_CMD[@]}" --json alias list | jq -r '.alias' | grep --quiet "^${test_alias}$"
  1023      rv=$?
  1024      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure ${rv} "alias ${test_alias} did NOT appear in the list of aliases returned by server"
  1025  
  1026      # check that the user can write objects with readwrite policy
  1027      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin policy attach "$SERVER_ALIAS" readwrite --user="${username}"
  1028  
  1029      # Validate that the correct policy has been added to the user
  1030      "${MC_CMD[@]}" --json admin user list "${SERVER_ALIAS}" | jq -r '.policyName' | grep --quiet "^readwrite$"
  1031      rv=$?
  1032      assert_success "$start_time" "${FUNCNAME[0]}" show_on_failure ${rv} "user ${username} did NOT have the readwrite policy attached"
  1033  
  1034      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "$FILE_1_MB" "${test_alias}/${BUCKET_NAME}/${object1_name}"
  1035  
  1036      # check that the user cannot write objects with readonly policy
  1037      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin policy detach "$SERVER_ALIAS" readwrite --user="${username}"
  1038      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin policy attach "$SERVER_ALIAS" readonly --user="${username}"
  1039      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cp "$FILE_1_MB" "${test_alias}/${BUCKET_NAME}/${object2_name}"
  1040  
  1041      # check that the user can read with readonly policy
  1042      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cat "${test_alias}/${BUCKET_NAME}/${object1_name}"
  1043  
  1044      # check that user can delete with readwrite policy
  1045      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin policy attach "$SERVER_ALIAS" readwrite --user="${username}"
  1046      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd rm "${test_alias}/${BUCKET_NAME}/${object1_name}"
  1047  
  1048      # check that user cannot perform admin actions with readwrite policy
  1049      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd admin info $test_alias
  1050  
  1051      # create object1_name for subsequent tests.
  1052      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cp "$FILE_1_MB" "${test_alias}/${BUCKET_NAME}/${object1_name}"
  1053  
  1054      # check that user can be disabled
  1055      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user disable "$SERVER_ALIAS" "$username"
  1056  
  1057      # check that disabled cannot perform any action
  1058      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cat "${test_alias}/${BUCKET_NAME}/${object1_name}"
  1059  
  1060      # check that user can be enabled and can then perform an allowed action
  1061      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user enable "$SERVER_ALIAS" "$username"
  1062      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd cat "${test_alias}/${BUCKET_NAME}/${object1_name}"
  1063  
  1064      # check that user can be removed, and then is no longer available
  1065      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd admin user remove "$SERVER_ALIAS" "$username"
  1066      assert_failure "$start_time" "${FUNCNAME[0]}" mc_cmd cat "${test_alias}/${BUCKET_NAME}/${object1_name}"
  1067  
  1068      log_success "$start_time" "${FUNCNAME[0]}"
  1069  }
  1070  
  1071  function run_test()
  1072  {
  1073      test_make_bucket
  1074      test_make_bucket_error
  1075      test_rb
  1076  
  1077      setup
  1078      test_list_dir
  1079      test_put_object
  1080      test_put_object_error
  1081      test_put_object_0byte
  1082      test_put_object_with_storage_class
  1083      test_put_object_with_storage_class_error
  1084      test_put_object_with_metadata
  1085      test_put_object_multipart
  1086      test_get_object
  1087      test_get_object_multipart
  1088      test_od_object
  1089      test_mv_object
  1090      test_presigned_post_policy_error
  1091      test_presigned_put_object
  1092      test_presigned_get_object
  1093      test_cat_object
  1094      test_cat_stdin
  1095      test_copy_directory
  1096      test_mirror_list_objects
  1097      test_mirror_list_objects_storage_class
  1098      test_copy_object_preserve_filesystem_attr
  1099      test_find
  1100      test_find_empty
  1101      if [ -z "$MINT_MODE" ]; then
  1102  	test_watch_object
  1103      fi
  1104  
  1105      if [ "$ENABLE_HTTPS" == "1" ]; then
  1106  	test_put_object_with_sse
  1107  	test_put_object_with_encoded_sse
  1108  	test_put_object_with_sse_error
  1109  	test_put_object_multipart_sse
  1110  	test_get_object_with_sse
  1111  	test_cat_object_with_sse
  1112  	test_cat_object_with_sse_error
  1113  	test_copy_object_with_sse_rewrite
  1114  	test_copy_object_with_sse_dest
  1115  	test_sse_key_rotation
  1116  	test_mirror_with_sse
  1117  	test_rm_object_with_sse
  1118      fi
  1119  
  1120      test_config_host_add
  1121      test_config_host_add_error
  1122      test_admin_users
  1123  
  1124      teardown
  1125  }
  1126  
  1127  function __init__()
  1128  {
  1129      set -e
  1130      if [ -n "$DEBUG" ]; then
  1131  	set -x
  1132      fi
  1133  
  1134      # For Mint, setup is already done.  For others, setup the environment
  1135      if [ -z "$MINT_MODE" ]; then
  1136  	mkdir -p "$WORK_DIR"
  1137  	mkdir -p "$DATA_DIR"
  1138  
  1139  	# If mc executable binary is not available in current directory, use it in the path.
  1140  	if [ ! -x "$MC" ]; then
  1141  	    if ! MC=$(which mc 2>/dev/null); then
  1142  		echo "'mc' executable binary not found in current directory and in path"
  1143  		exit 1
  1144  	    fi
  1145  	fi
  1146      fi
  1147  
  1148      if [ ! -x "$MC" ]; then
  1149  	echo "$MC executable binary not found"
  1150  	exit 1
  1151      fi
  1152  
  1153      mkdir -p "$MC_CONFIG_DIR"
  1154      MC_CMD=( "${MC}" --config-dir "$MC_CONFIG_DIR" --quiet --no-color )
  1155  
  1156      if [ ! -e "$FILE_0_B" ]; then
  1157  	touch "$FILE_0_B"
  1158      fi
  1159  
  1160      if [ ! -e "$FILE_1_MB" ]; then
  1161  	base64 -i /dev/urandom | head -c 1048576 >"$FILE_1_MB"
  1162      fi
  1163  
  1164      if [ ! -e "$FILE_65_MB" ]; then
  1165  	base64 -i /dev/urandom | head -c 68157440 >"$FILE_65_MB"
  1166      fi
  1167  
  1168      set -E
  1169      set -o pipefail
  1170  
  1171      FILE_0_B_MD5SUM="$(get_md5sum "$FILE_0_B")"
  1172      if [ $? -ne 0 ]; then
  1173  	echo "unable to get md5sum of $FILE_0_B"
  1174  	exit 1
  1175      fi
  1176  
  1177      FILE_1_MB_MD5SUM="$(get_md5sum "$FILE_1_MB")"
  1178      if [ $? -ne 0 ]; then
  1179  	echo "unable to get md5sum of $FILE_1_MB"
  1180  	exit 1
  1181      fi
  1182  
  1183      FILE_65_MB_MD5SUM="$(get_md5sum "$FILE_65_MB")"
  1184      if [ $? -ne 0 ]; then
  1185  	echo "unable to get md5sum of $FILE_65_MB"
  1186  	exit 1
  1187      fi
  1188      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias set "${SERVER_ALIAS}" "$ENDPOINT" "$ACCESS_KEY" "$SECRET_KEY"
  1189      assert_success "$start_time" "${FUNCNAME[0]}" mc_cmd alias set "${SERVER_ALIAS_TLS}" "$ENDPOINT" "$ACCESS_KEY" "$SECRET_KEY"
  1190  
  1191      set +e
  1192  }
  1193  
  1194  function validate_dependencies() {
  1195  	jqVersion=$(jq --version)
  1196  	if [[ $jqVersion == *"jq"* ]]; then
  1197  		echo "Dependency validation complete"
  1198  	else
  1199  		echo "jq is missing, please install: 'sudo apt install jq'"
  1200  		exit 1
  1201  	fi
  1202  }
  1203  
  1204  function main()
  1205  {
  1206      validate_dependencies
  1207  
  1208      ( run_test )
  1209      rv=$?
  1210  
  1211      rm -fr "$MC_CONFIG_DIR" "$WATCH_OUT_FILE"
  1212      if [ -z "$MINT_MODE" ]; then
  1213  	rm -fr "$WORK_DIR" "$DATA_DIR"
  1214      fi
  1215  
  1216      exit "$rv"
  1217  }
  1218  
  1219  __init__ "$@"
  1220  main "$@"