From 179fdc0352cb94dcca5b3cd1dab58333bdb169f5 Mon Sep 17 00:00:00 2001 From: Luke McCrone Date: Mon, 11 May 2026 16:08:43 -0300 Subject: [PATCH] test: ListMultipartUpload query tests, related cleanup --- tests/commands/create_multipart_upload.sh | 20 +- tests/commands/list_multipart_uploads.sh | 32 ++- tests/commands/list_objects.sh | 7 +- .../create_bucket/create_bucket_rest.sh | 7 +- tests/drivers/list.sh | 91 +++++++ .../list_multipart_uploads_rest.sh | 189 ++++++++++++++ .../list_multipart_uploads_s3api.sh | 48 ++++ .../drivers/list_objects/list_objects_rest.sh | 76 +----- tests/drivers/rest.sh | 23 +- tests/drivers/xml.sh | 29 ++- tests/rest_scripts/abort_multipart_upload.sh | 2 +- tests/rest_scripts/create_multipart_upload.sh | 4 +- tests/tags/tags.yaml | 34 +-- tests/test_rest_head_object.sh | 5 + tests/test_rest_list_multipart_uploads.sh | 231 ++++++++++++++++++ tests/test_s3api_multipart.sh | 58 ++++- tests/util/util_multipart_abort.sh | 19 +- .../util/util_multipart_before_completion.sh | 46 ++-- 18 files changed, 760 insertions(+), 161 deletions(-) create mode 100644 tests/drivers/list.sh create mode 100644 tests/drivers/list_multipart_uploads/list_multipart_uploads_rest.sh create mode 100644 tests/drivers/list_multipart_uploads/list_multipart_uploads_s3api.sh create mode 100755 tests/test_rest_list_multipart_uploads.sh diff --git a/tests/commands/create_multipart_upload.sh b/tests/commands/create_multipart_upload.sh index 70d56fb0..7ceecec3 100644 --- a/tests/commands/create_multipart_upload.sh +++ b/tests/commands/create_multipart_upload.sh @@ -18,11 +18,12 @@ create_multipart_upload_rest() { if ! check_param_count_v2 "bucket name, key, additional params, callback" 4 $#; then return 1 fi - env_vars="BUCKET_NAME=$1 OBJECT_KEY=$2 $3" - if ! send_rest_command_expect_success_callback "$env_vars" "./tests/rest_scripts/create_multipart_upload.sh" "200" "$4"; then - log 2 "error sending REST command and checking error" + local response env_vars="BUCKET_NAME=$1 OBJECT_KEY=$2 $3" + if ! response=$(send_rest_command_expect_success_callback "$env_vars" "./tests/rest_scripts/create_multipart_upload.sh" "200" "$4" 2>&1); then + log 2 "error sending REST command and checking error: $response" return 1 fi + echo "$response" return 0 } @@ -44,17 +45,20 @@ create_multipart_upload_s3api() { if ! check_param_count_v2 "bucket, key" 2 $#; then return 1 fi + local response multipart_data upload_id - if ! multipart_data=$(send_command aws --no-verify-ssl s3api create-multipart-upload --bucket "$1" --key "$2" 2>&1); then - log 2 "Error creating multipart upload: $multipart_data" + if ! response=$(send_command aws --no-verify-ssl s3api create-multipart-upload --bucket "$1" --key "$2" 2>&1); then + log 2 "Error creating multipart upload: $response" return 1 fi + multipart_data="$response" - if ! upload_id=$(echo "$multipart_data" | grep -v "InsecureRequestWarning" | jq -r '.UploadId' 2>&1); then - log 2 "error parsing upload ID: $upload_id" + if ! response=$(echo "$multipart_data" | grep -v "InsecureRequestWarning" | jq -r '.UploadId' 2>&1); then + log 2 "error parsing upload ID: $response" return 1 fi - upload_id="${upload_id//\"/}" + upload_id="${response//\"/}" + echo "$upload_id" return 0 } diff --git a/tests/commands/list_multipart_uploads.sh b/tests/commands/list_multipart_uploads.sh index 37eb9da5..16c920c6 100644 --- a/tests/commands/list_multipart_uploads.sh +++ b/tests/commands/list_multipart_uploads.sh @@ -15,29 +15,42 @@ # under the License. list_multipart_uploads() { - if [[ $# -ne 1 ]]; then - log 2 "'list multipart uploads' command requires bucket name" + if ! check_param_count_gt "bucket name, parameters (optional)" 1 $#; then return 1 fi - if ! uploads=$(send_command aws --no-verify-ssl s3api list-multipart-uploads --bucket "$1" 2>&1); then - log 2 "error listing uploads: $uploads" + local response + + if ! response=$(send_command aws --no-verify-ssl s3api list-multipart-uploads --bucket "$1" "${@:2}" 2>&1); then + log 2 "error listing uploads: $response" return 1 fi + echo "$response" + return 0 } list_multipart_uploads_rest() { if ! check_param_count "list_multipart_upload_rest" "bucket" 1 $#; then return 1 fi - if ! result=$(COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="$1" OUTPUT_FILE="$TEST_FILE_FOLDER/uploads.txt" ./tests/rest_scripts/list_multipart_uploads.sh 2>&1); then - log 2 "error listing multipart uploads: $result" + local response response_file uploads + + if ! response=$(get_file_name 2>&1); then + log 2 "error getting file name: $response" return 1 fi - uploads=$(cat "$TEST_FILE_FOLDER/uploads.txt") - if [ "$result" != "200" ]; then - log 2 "expected '200', was '$result' ($uploads)" + response_file="$response" + + if ! response=$(COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="$1" OUTPUT_FILE="$TEST_FILE_FOLDER/$response_file" ./tests/rest_scripts/list_multipart_uploads.sh 2>&1); then + log 2 "error listing multipart uploads: $response" return 1 fi + uploads=$(cat "$TEST_FILE_FOLDER/$response_file") + + if [ "$response" != "200" ]; then + log 2 "expected '200', was '$response' (data: $uploads)" + return 1 + fi + echo "$uploads" return 0 } @@ -52,4 +65,5 @@ list_multipart_uploads_with_user() { list_multipart_uploads_error=$uploads return 1 fi + return 0 } \ No newline at end of file diff --git a/tests/commands/list_objects.sh b/tests/commands/list_objects.sh index bfeec7ed..4743cbd4 100644 --- a/tests/commands/list_objects.sh +++ b/tests/commands/list_objects.sh @@ -63,13 +63,16 @@ list_objects_s3api() { if ! check_param_count "list_objects_s3api" "bucket" 1 $#; then return 1 fi - if ! output=$(send_command aws --no-verify-ssl s3api list-objects --bucket "$1" 2>&1); then + local response object_list modified_output contents keys + + if ! response=$(send_command aws --no-verify-ssl s3api list-objects --bucket "$1" 2>&1); then log 2 "error listing objects: $output" return 1 fi + object_list="$response" log 5 "list_objects_s3api: raw data returned: $output" - modified_output=$(echo "$output" | grep -v "InsecureRequestWarning") + modified_output=$(echo "$object_list" | grep -v "InsecureRequestWarning") log 5 "modified output: $modified_output" if echo "$modified_output" | jq -e 'has("Contents")' >/dev/null; then diff --git a/tests/drivers/create_bucket/create_bucket_rest.sh b/tests/drivers/create_bucket/create_bucket_rest.sh index 717cc4a6..9455534f 100644 --- a/tests/drivers/create_bucket/create_bucket_rest.sh +++ b/tests/drivers/create_bucket/create_bucket_rest.sh @@ -125,13 +125,16 @@ get_bucket_prefix() { if ! check_param_count_v2 "bucket prefix or name" 1 $#; then return 1 fi + local prefix + if [ "$RECREATE_BUCKETS" == "true" ]; then - # remove date/time suffix - prefix="$(echo "$1" | awk '{print substr($0, 1, length($0)-15)}')" + # remove buckets with suffix + prefix="$1-" else prefix="$1" fi echo "$prefix" + return 0 } setup_bucket_v2() { diff --git a/tests/drivers/list.sh b/tests/drivers/list.sh new file mode 100644 index 00000000..b017a295 --- /dev/null +++ b/tests/drivers/list.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash + +# Copyright 2026 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +check_prefixes_delimiters_and_keys() { + if ! check_param_count_gt "data file, enclosing element, individual element, prefix, delimiter, common prefixes, --, keys" 6 $#; then + return 1 + fi + local response xml_data checking_prefixes="true" prefix_count=0 key_count=0 + + if ! response=$(check_validity_and_or_parse_xml_data "$1" 2>&1); then + log 2 "error parsing xml data: $response" + return 1 + fi + xml_data="$response" + + log 5 "XML data: $xml_data" + for param in "${@:6}"; do + if [ "$param" == "--" ]; then + checking_prefixes=false + continue + fi + if ! check_a_common_prefix_or_key "$xml_data" "$param" "$checking_prefixes" "$2" "$3"; then + log 2 "error checking if common prefix or key '$param' exists" + return 1 + fi + if [ "$checking_prefixes" == "true" ]; then + ((prefix_count++)) + else + ((key_count++)) + fi + done + if ! check_prefixes_delimiter_and_counts "$xml_data" "$4" "$5" "$prefix_count" "$key_count" "$2" "$3"; then + log 2 "error checking prefix" + return 1 + fi + return 0 +} + +check_a_common_prefix_or_key() { + if ! check_param_count_v2 "data file, parameter, prefix or not, base element, unit element" 5 $#; then + return 1 + fi + if [ "$3" == "true" ]; then + if ! check_if_element_exists "$1" "$2" "$4" "CommonPrefixes" "Prefix"; then + log 2 "error checking if CommonPrefix '$2' exists" + return 1 + fi + else + if ! check_if_element_exists "$1" "$2" "$4" "$5" "Key"; then + log 2 "error checking if Key '$2' exists" + return 1 + fi + fi + return 0 +} + +check_prefixes_delimiter_and_counts() { + if ! check_param_count_v2 "data, prefix, delimiter, prefix count, key count, base element, unit element" 7 $#; then + return 1 + fi + if ! check_xml_element "$1" "$2" "$6" "Prefix"; then + log 2 "error checking prefix" + return 1 + fi + if ! check_xml_element "$1" "$3" "$6" "Delimiter"; then + log 2 "error checking delimiter" + return 1 + fi + if ! check_element_count "$1" "$4" "$6" "CommonPrefixes" "Prefix"; then + log 2 "Prefix count mismatch" + return 1 + fi + if ! check_element_count "$1" "$5" "$6" "$7" "Key"; then + log 2 "Key count mismatch" + return 1 + fi + return 0 +} diff --git a/tests/drivers/list_multipart_uploads/list_multipart_uploads_rest.sh b/tests/drivers/list_multipart_uploads/list_multipart_uploads_rest.sh new file mode 100644 index 00000000..6495a2e8 --- /dev/null +++ b/tests/drivers/list_multipart_uploads/list_multipart_uploads_rest.sh @@ -0,0 +1,189 @@ +#!/usr/bin/env bash + +# Copyright 2026 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License.# + +source ./tests/drivers/list.sh + +check_multipart_upload_user_data() { + if ! check_param_count_v2 "data file, expected upload ID, owner ID, initiator ID" 4 $#; then + return 1 + fi + local response upload_data + + if ! response=$(get_element_with_matching_inner_value "$1" "$2" "ListMultipartUploadsResult" "Upload" "--" "UploadId" 2>&1); then + log 2 "error getting info with upload ID: $response" + return 1 + fi + upload_data="$response" + + if ! check_xml_element_inside_string "$upload_data" "$3" "Owner" "ID"; then + log 2 "error checking Owner ID" + return 1 + fi + if ! check_xml_element_inside_string "$upload_data" "$4" "Initiator" "ID"; then + log 2 "error checking Initiator ID" + return 1 + fi + return 0 +} + +list_multipart_uploads_check_user_data() { + if ! check_param_count_v2 "bucket, uploadID, owner ID, initiator ID" 4 $#; then + return 1 + fi + local response + + if ! response=$(send_rest_go_command_callback "200" "check_multipart_upload_user_data" "-bucketName" "$1" "-query" "uploads" \ + "--" "$2" "$3" "$4" 2>&1); then + log 2 "error listing multipart upload and checking owner data: $response" + return 1 + fi + return 0 +} + +check_multipart_upload_next_key_upload_id() { + if ! check_param_count_v2 "data file, expected next key, next upload ID" 3 $#; then + return 1 + fi + if ! check_xml_element "$1" "$2" "ListMultipartUploadsResult" "NextKeyMarker"; then + log 2 "error checking NextKeyMarker" + return 1 + fi + if ! check_xml_element "$1" "$3" "ListMultipartUploadsResult" "NextUploadIdMarker"; then + log 2 "error checking NextUploadIdMarker" + return 1 + fi + return 0 +} + +list_multipart_uploads_check_next_values() { + if ! check_param_count_v2 "bucket, expected next key, expected upload ID" 3 $#; then + return 1 + fi + local response + + if ! response=$(send_rest_go_command_callback "200" "check_multipart_upload_next_key_upload_id" "-bucketName" "$1" "-query" "uploads" \ + "--" "$2" "$3" 2>&1); then + log 2 "error listing multipart upload and checking expected NextKeyMarker and NextUploadIdMarker: $response" + return 1 + fi + return 0 +} + +get_next_values() { + if ! check_param_count_v2 "data file" 1 $#; then + return 1 + fi + local response next_key_marker next_upload_id_marker + + if ! response=$(get_element_text "$1" "NextKeyMarker" 2>&1); then + log 2 "error checking NextKeyMarker: $response" + return 1 + fi + next_key_marker="$response" + + if ! response=$(get_element_text "$1" "NextUploadIdMarker" 2>&1); then + log 2 "error checking NextUploadIdMarker: $response" + return 1 + fi + next_upload_id_marker="$response" + + echo "$next_key_marker" + echo "$next_upload_id_marker" + return 0 +} + +list_multipart_uploads_get_check_next_values() { + if ! check_param_count_ge_le "bucket, expected key, expected upload ID, next key (optional), next upload ID (optional)" 3 5 $#; then + return 1 + fi + local query_val="max-uploads=1&uploads" response + if [ "$4" != "" ]; then + query_val+="&key-marker=$4" + fi + if [ "$5" != "" ]; then + query_val+="&upload-id-marker=$5" + fi + if ! response=$(send_rest_go_command_callback "200" "get_next_values" "-bucketName" "$1" "-query" "$query_val" 2>&1); then + log 2 "error sending multipart upload and checking key and upload ID vals" + return 1 + fi + return 0 +} + +check_for_no_upload_id() { + if ! check_param_count_v2 "data file, unexpected upload ID, first upload ID" 3 $#; then + return 1 + fi + check_if_element_exists "$1" "$2" "UploadIdMarker" + if [ "$?" -ne 1 ]; then + log 2 "error checking for element, or '$2' actually exists in 'UploadIdMarker' (data: $(cat "$1"))" + return 1 + fi + if ! check_xml_element "$1" "$3" "Upload" "UploadId"; then + log 2 "error checking upload ID" + return 1 + fi + return 0 +} + +list_multipart_uploads_check_no_upload_id_in_response() { + if ! check_param_count_v2 "bucket, upload ID query, second upload ID" 3 $#; then + return 1 + fi + local response + + if ! response=$(send_rest_go_command_callback "200" "check_for_no_upload_id" "-bucketName" "$1" "-query" "uploads&max-uploads=1&upload-id-marker=$2" "--" "$2" "$3" 2>&1); then + log 2 "error sending multipart upload and checking for no upload ID marker in response" + return 1 + fi + return 0 +} + +check_encoding() { + if ! check_param_count_v2 "data file, expected encoding" 2 $#; then + return 1 + fi + log 5 "data: $(cat "$1")" + if ! check_xml_element "$1" "$2" "ListMultipartUploadsResult" "Upload" "Key"; then + log 2 "error checking encoded key" + return 1 + fi + return 0 +} + +list_multipart_uploads_check_encoding() { + if ! check_param_count_v2 "bucket, encoding type query add-on, expected encoding" 3 $#; then + return 1 + fi + local response + + if ! response=$(send_rest_go_command_callback "200" "check_encoding" "-query" "uploads${2}" "-bucketName" "$1" "--" "$3" 2>&1); then + log 2 "error listing uploads and checking encoding: $response" + return 1 + fi + return 0 +} + +list_uploads_with_prefix_and_delimiter_check_results() { + if ! check_param_count_gt "bucket name, prefix, delimiter, expected common prefixes, --, expected keys" 6 $#; then + return 1 + fi + if ! send_rest_go_command_callback "200" "check_prefixes_delimiters_and_keys" "-bucketName" "$1" "-query" "uploads&delimiter=$3&prefix=$2" "--" "ListMultipartUploadsResult" "Upload" "${@:2}"; then + log 2 "error sending command to list objects or receiving prefix and delimiter response" + return 1 + fi + return 0 +} diff --git a/tests/drivers/list_multipart_uploads/list_multipart_uploads_s3api.sh b/tests/drivers/list_multipart_uploads/list_multipart_uploads_s3api.sh new file mode 100644 index 00000000..c8ffa996 --- /dev/null +++ b/tests/drivers/list_multipart_uploads/list_multipart_uploads_s3api.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bats + +# Copyright 2026 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +list_multipart_uploads_check_key_id_get_next_token() { + if ! check_param_count_gt "bucket, expected key, expected upload ID, starting token (optional)" 3 $#; then + return 1 + fi + local starting_token_param=() response upload_json upload upload_id key next_token + if [ "$4" != "" ]; then + starting_token_param=("--starting-token" "$4") + fi + if ! response=$(list_multipart_uploads "$1" "--max-items" "1" "${starting_token_param[@]}" 2>&1); then + log 2 "error listing multipart uploads: $response" + return 1 + fi + + upload_json=$(echo "$response" | grep -v "InsecureRequestWarning") + log 5 "JSON: $upload_json" + upload="$(echo "$upload_json" | jq -r '.Uploads[0]')" + upload_id="$(echo "$upload" | jq -r '.UploadId')" + key="$(echo "$upload" | jq -r '.Key')" + + if [ "$key" != "$2" ]; then + log 2 "expected key of '$2', was '$key'" + return 1 + fi + if [ "$upload_id" != "$3" ]; then + log 2 "expected upload ID of '$3', was '$upload_id'" + return 1 + fi + + next_token="$(echo "$upload_json" | jq -r '.NextToken')" + echo "$next_token" + return 0 +} \ No newline at end of file diff --git a/tests/drivers/list_objects/list_objects_rest.sh b/tests/drivers/list_objects/list_objects_rest.sh index b7ce43a0..c1449dc3 100644 --- a/tests/drivers/list_objects/list_objects_rest.sh +++ b/tests/drivers/list_objects/list_objects_rest.sh @@ -14,6 +14,8 @@ # specific language governing permissions and limitations # under the License. +source ./tests/drivers/list.sh + list_check_single_object() { if ! check_param_count_gt "bucket, key, env params (optional)" 2 $#; then return 1 @@ -85,83 +87,11 @@ list_check_objects_rest_v2() { fi } -check_single_common_prefix_or_key() { - if ! check_param_count_v2 "data file, parameter, prefix or not" 3 $#; then - return 1 - fi - if [ "$3" == "true" ]; then - if ! check_if_element_exists "$1" "$2" "ListBucketResult" "CommonPrefixes" "Prefix"; then - log 2 "error checking if CommonPrefix '$2' exists" - return 1 - fi - else - if ! check_if_element_exists "$1" "$2" "ListBucketResult" "Contents" "Key"; then - log 2 "error checking if Key '$2' exists" - return 1 - fi - fi - return 0 -} - -check_common_prefixes_and_keys() { - if ! check_param_count_gt "data file, prefix, delimiter, common prefixes, --, keys" 4 $#; then - return 1 - fi - if ! xml_data=$(check_validity_and_or_parse_xml_data "$1" 2>&1); then - log 2 "error parsing xml data: $xml_data" - return 1 - fi - local checking_prefixes="true" prefix_count=0 key_count=0 - for param in "${@:4}"; do - if [ "$param" == "--" ]; then - checking_prefixes=false - continue - fi - if ! check_single_common_prefix_or_key "$xml_data" "$param" "$checking_prefixes"; then - log 2 "error checking if common prefix or key '$param' exists" - return 1 - fi - if [ "$checking_prefixes" == "true" ]; then - ((prefix_count++)) - else - ((key_count++)) - fi - done - if ! check_prefix_delimiter_and_counts "$xml_data" "$2" "$3" "$prefix_count" "$key_count"; then - log 2 "error checking prefix" - return 1 - fi - return 0 -} - -check_prefix_delimiter_and_counts() { - if ! check_param_count_v2 "data, prefix, delimiter, prefix count, key count" 5 $#; then - return 1 - fi - if ! check_xml_element "$1" "$2" "ListBucketResult" "Prefix"; then - log 2 "error checking prefix" - return 1 - fi - if ! check_xml_element "$1" "$3" "ListBucketResult" "Delimiter"; then - log 2 "error checking delimiter" - return 1 - fi - if ! check_element_count "$1" "$4" "ListBucketResult" "CommonPrefixes" "Prefix"; then - log 2 "Prefix count mismatch" - return 1 - fi - if ! check_element_count "$1" "$5" "ListBucketResult" "Contents" "Key"; then - log 2 "Prefix count mismatch" - return 1 - fi - return 0 -} - list_objects_with_prefix_and_delimiter_check_results() { if ! check_param_count_gt "bucket name, ListObjects version, prefix, delimiter, expected common prefixes, --, expected keys" 6 $#; then return 1 fi - if ! send_rest_go_command_callback "200" "check_common_prefixes_and_keys" "-bucketName" "$1" "-query" "list-type=$2&delimiter=$4&prefix=$3" "--" "${@:3}"; then + if ! send_rest_go_command_callback "200" "check_prefixes_delimiters_and_keys" "-bucketName" "$1" "-query" "list-type=$2&delimiter=$4&prefix=$3" "--" "ListBucketResult" "Contents" "${@:3}"; then log 2 "error sending command to list objects or receiving response" return 1 fi diff --git a/tests/drivers/rest.sh b/tests/drivers/rest.sh index 271a5a73..5e461b34 100644 --- a/tests/drivers/rest.sh +++ b/tests/drivers/rest.sh @@ -154,22 +154,29 @@ send_rest_command_expect_success_callback() { if ! check_param_count_v2 "env vars, script, response code, callback fn" 4 $#; then return 1 fi - if ! output_file_name=$(get_file_name 2>&1); then + local response output_file_name output_file env_array=() http_response response_code callback_response + + if ! response=$(get_file_name 2>&1); then log 2 "error generating output file name: $output_file_name" return 1 fi + output_file_name="$response" + output_file="$TEST_FILE_FOLDER/$output_file_name" local env_array=("env" "COMMAND_LOG=$COMMAND_LOG" "OUTPUT_FILE=$output_file") if [ "$1" != "" ]; then IFS=' ' read -r -a env_vars <<< "$1" env_array+=("${env_vars[@]}") fi + log 5 "command: ${env_array[*]} $2" # shellcheck disable=SC2068 - if ! result=$(${env_array[@]} "$2" 2>&1); then + if ! response=$(${env_array[@]} "$2" 2>&1); then log 2 "error sending command: $result" return 1 fi - response_code="$(echo "$result" | tail -n 1)" + http_response="$response" + + response_code="$(echo "$http_response" | tail -n 1)" if [ "$response_code" != "$3" ]; then log 2 "expected '$3', was '$response_code' ($(cat "$output_file"))" return 1 @@ -178,11 +185,11 @@ send_rest_command_expect_success_callback() { cat "$output_file" return 0 fi - if ! callback_result=$("$4" "$output_file" 2>&1); then - log 2 "callback error: $callback_result" + if ! callback_response=$("$4" "$output_file" 2>&1); then + log 2 "callback error: $callback_response" return 1 fi - echo "$callback_result" + echo "$callback_response" return 0 } @@ -270,8 +277,8 @@ send_rest_go_command_expect_error_callback() { log 2 "error checking expected header error" return 1 fi - if [ "$4" != "" ] && ! "$4" "$TEST_FILE_FOLDER/$file_name" "${callback_params[@]}"; then - log 2 "callback error" + if [ "$4" != "" ] && ! response=$("$4" "$response_file" "${callback_params[@]}" 2>&1); then + log 2 "callback error: $response" return 1 fi return 0 diff --git a/tests/drivers/xml.sh b/tests/drivers/xml.sh index dae02411..e7b2380b 100644 --- a/tests/drivers/xml.sh +++ b/tests/drivers/xml.sh @@ -236,24 +236,29 @@ check_xml_error_contains_with_single_error_field() { check_if_element_exists() { if ! check_param_count_gt "data file, element, XML tree" 3 $#; then - return 1 - fi - if ! xpath=$(build_xpath_string_for_element "${@:3}" 2>&1); then - log 2 "error building XPath search string: $xpath" - return 1 + return 2 fi + local response xpath data_file search_string - if ! data_file=$(check_validity_and_or_parse_xml_data "$1" 2>&1); then - log 2 "error checking XML data: $data_file" - return 1 + if ! response=$(build_xpath_string_for_element "${@:3}" 2>&1); then + log 2 "error building XPath search string: $xpath" + return 2 fi + xpath="$response" + + if ! response=$(check_validity_and_or_parse_xml_data "$1" 2>&1); then + log 2 "error checking XML data: $data_file" + return 2 + fi + data_file="$response" + local search_string="boolean(${xpath}[text()='$2'])" log 5 "search string: $search_string" - if ! result=$(xmllint --xpath "$search_string" "$data_file" 2>&1); then - log 2 "error getting result: $result" - return 1 + if ! response=$(xmllint --xpath "$search_string" "$data_file" 2>&1); then + log 2 "error getting result: $response" + return 2 fi - if [ "$result" == "true" ]; then + if [ "$response" == "true" ]; then return 0 fi log 5 "element '$2' not found" diff --git a/tests/rest_scripts/abort_multipart_upload.sh b/tests/rest_scripts/abort_multipart_upload.sh index bf9924bc..21c173e9 100755 --- a/tests/rest_scripts/abort_multipart_upload.sh +++ b/tests/rest_scripts/abort_multipart_upload.sh @@ -21,7 +21,7 @@ source ./tests/rest_scripts/rest.sh # shellcheck disable=SC2153 bucket_name="$BUCKET_NAME" # shellcheck disable=SC2153 -key="$OBJECT_KEY" +key="$(echo -n "$OBJECT_KEY" | jq -sRr 'split("/") | map(@uri) | join("/")')" # shellcheck disable=SC2153,SC2034 upload_id="$UPLOAD_ID" diff --git a/tests/rest_scripts/create_multipart_upload.sh b/tests/rest_scripts/create_multipart_upload.sh index 68346794..040a1599 100755 --- a/tests/rest_scripts/create_multipart_upload.sh +++ b/tests/rest_scripts/create_multipart_upload.sh @@ -21,7 +21,7 @@ source ./tests/rest_scripts/rest.sh # shellcheck disable=SC2153 bucket_name="$BUCKET_NAME" # shellcheck disable=SC2153 -key="$OBJECT_KEY" +key="$(echo -n "$OBJECT_KEY" | jq -sRr 'split("/") | map(@uri) | join("/")')" # shellcheck disable=SC2153 checksum_type="$CHECKSUM_TYPE" # shellcheck disable=SC2153 @@ -42,7 +42,7 @@ build_canonical_request "${cr_data[@]}" # shellcheck disable=SC2119 create_canonical_hash_sts_and_signature -curl_command+=(curl -ks -w "\"%{http_code}\"" -X POST "$AWS_ENDPOINT_URL/$bucket_name/$key?uploads=" +curl_command+=(curl -ks -w "\"%{http_code}\"" -X POST "\"$AWS_ENDPOINT_URL/$bucket_name/$key?uploads=\"" -H "\"Authorization: AWS4-HMAC-SHA256 Credential=$aws_access_key_id/$year_month_day/$aws_region/s3/aws4_request,SignedHeaders=$param_list,Signature=$signature\"") curl_command+=("${header_fields[@]}") curl_command+=(-o "$OUTPUT_FILE") diff --git a/tests/tags/tags.yaml b/tests/tags/tags.yaml index 43c285d8..7e2232e2 100644 --- a/tests/tags/tags.yaml +++ b/tests/tags/tags.yaml @@ -256,10 +256,26 @@ tags: desc: "ListBuckets bucket-region query" cors: desc: "Bucket CORS subresource (?cors)" + partNumber: + desc: "Multipart part number query" continuation-token: desc: "ListBuckets/ListObjects continuation token query" + response-cache-control: + desc: "Override Cache-Control response header" + response-content-disposition: + desc: "Override Content-Disposition response header" + response-content-encoding: + desc: "Override Content-Encoding response header" + response-content-language: + desc: "Override Content-Language response header" + response-content-type: + desc: "Override Content-Type response header" + response-expires: + desc: "Override Expires response header" delimiter: desc: "ListObjects delimiter query" + key-marker: + desc: "ListMultipartUploads key-marker query" legal-hold: desc: "Object legal-hold subresource (?legal-hold=)" encoding-type: @@ -282,8 +298,10 @@ tags: desc: "Bucket policyStatus subresource (?policyStatus=)" policy: desc: "Bucket policy subresource (?policy=)" - partNumber: - desc: "partNumber query for multiparts and gets" + next-key-marker: + desc: "ListMultipartUploads NextKeyMarker response value" + next-upload-id-marker: + desc: "ListMultipartUploads NextUploadIdMarker response value" uploadId: desc: "Multipart uploadId query" prefix: @@ -292,18 +310,6 @@ tags: desc: "Bucket/object tagging subresource (?tagging=)" start-after: desc: "ListObjectsV2 start-after query" - response-cache-control: - desc: "override cache-control header response" - response-content-disposition: - desc: "override content-disposition header response" - response-content-encoding: - desc: "override content-encoding header response" - response-content-language: - desc: "override content-language header response" - response-content-type: - desc: "override content-type header response" - response-expires: - desc: "override expires header response" retention: desc: "Object retention subresource (?retention=)" attributes: diff --git a/tests/test_rest_head_object.sh b/tests/test_rest_head_object.sh index 83362938..24c12605 100755 --- a/tests/test_rest_head_object.sh +++ b/tests/test_rest_head_object.sh @@ -47,6 +47,7 @@ source ./tests/drivers/string.sh assert_success } +# tags: curl,HeadObject,partNumber,invalid-query @test "REST - HeadObject - letter partNumber" { run setup_bucket_and_add_file_v3 "$BUCKET_ONE_NAME" assert_success @@ -56,6 +57,7 @@ source ./tests/drivers/string.sh assert_success } +# tags: curl,HeadObject,partNumber,invalid-query @test "REST - HeadObject - invalid partNumber" { run setup_bucket_and_add_file_v3 "$BUCKET_ONE_NAME" assert_success @@ -65,6 +67,7 @@ source ./tests/drivers/string.sh assert_success } +# tags: curl,HeadObject,partNumber,multipart @test "REST - HeadObject - valid partNumbers" { file_mb=8 run setup_bucket_and_large_file_v3 "$BUCKET_ONE_NAME" "$file_mb" @@ -97,6 +100,7 @@ source ./tests/drivers/string.sh assert_success } +# tags: curl,HeadObject,invalid-query @test "REST - HeadObject - invalid request header type" { if [ "$DIRECT" != "true" ]; then skip "https://github.com/versity/versitygw/issues/2075" @@ -110,6 +114,7 @@ source ./tests/drivers/string.sh assert_success } +# tags: curl,HeadObject,response-cache-control,response-content-disposition,response-content-encoding,response-content-language,response-content-type,response-expires @test "REST - HeadObject - response queries" { run setup_bucket_and_add_file_v3 "$BUCKET_ONE_NAME" assert_success diff --git a/tests/test_rest_list_multipart_uploads.sh b/tests/test_rest_list_multipart_uploads.sh new file mode 100755 index 00000000..6038dad1 --- /dev/null +++ b/tests/test_rest_list_multipart_uploads.sh @@ -0,0 +1,231 @@ +#!/usr/bin/env bats + +# Copyright 2026 Versity Software +# This file is licensed under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +load ./bats-support/load +load ./bats-assert/load + +source ./tests/drivers/create_bucket/create_bucket_rest.sh +source ./tests/drivers/list_multipart_uploads/list_multipart_uploads_rest.sh +source ./tests/drivers/file.sh +source ./tests/setup.sh + +# tags: curl,ListMultipartUploads,multipart +@test "REST - ListMultipartUploads - Initiator and Owner data shown" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/2142" + fi + run setup_bucket_and_file_v3 "$BUCKET_ONE_NAME" + assert_success + read -r bucket_name test_file <<< "$output" + + run create_multipart_upload_rest "$bucket_name" "$test_file" "" "parse_upload_id" + assert_success + upload_id=$output + + local owner_id initiator_id + if [ "$DIRECT" == "true" ]; then + owner_id="$AWS_CANONICAL_ID" + initiator_id="arn:aws:iam::$DIRECT_AWS_USER_ID:user/$DIRECT_S3_ROOT_ACCOUNT_NAME" + else + owner_id="$AWS_ACCESS_KEY_ID" + initiator_id="$AWS_ACCESS_KEY_ID" + fi + + run list_multipart_uploads_check_user_data "$bucket_name" "$upload_id" "$owner_id" "$initiator_id" + assert_success +} + +# tags: curl,ListMultipartUploads,multipart,uploadId,next-key-marker,next-upload-id-marker +@test "REST - ListMultipartUploads - NextKeyMarker and NextUploadIdMarker set to last item" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/2144" + fi + run setup_bucket_and_files_v3 "$BUCKET_ONE_NAME" 2 + assert_success + read -r bucket_name test_file_one test_file_two <<< "$output" + + local upload_id_one upload_id_two + run create_multipart_upload_rest "$bucket_name" "$test_file_one" "" "parse_upload_id" + assert_success + upload_id_one=$output + + run create_multipart_upload_rest "$bucket_name" "$test_file_two" "" "parse_upload_id" + assert_success + upload_id_two=$output + + local last_key last_upload_id + if [[ "$test_file_one" < "$test_file_two" ]]; then + last_key="$test_file_two" + last_upload_id="$upload_id_two" + else + last_key="$test_file_one" + last_upload_id="$upload_id_one" + fi + + run list_multipart_uploads_check_next_values "$bucket_name" "$last_key" "$last_upload_id" + assert_success +} + +# tags: curl,ListMultipartUploads,multipart,uploadId,key-marker +@test "REST - ListMultipartUploads - uploadId and key combo work" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/2149" + fi + run setup_bucket_and_files_v3 "$BUCKET_ONE_NAME" 2 + assert_success + read -r bucket_name test_file_one test_file_two <<< "$output" + + local upload_id_one upload_id_two + run create_multipart_upload_rest "$bucket_name" "$test_file_one" "" "parse_upload_id" + assert_success + upload_id_one=$output + + run create_multipart_upload_rest "$bucket_name" "$test_file_two" "" "parse_upload_id" + assert_success + upload_id_two=$output + + local first_key first_upload_id second_key second_upload_id + if [[ "$test_file_one" < "$test_file_two" ]]; then + first_key="$test_file_one" + first_upload_id="$upload_id_one" + second_key="$test_file_two" + second_upload_id="$upload_id_two" + else + first_key="$test_file_two" + first_upload_id="$upload_id_two" + second_key="$test_file_one" + second_upload_id="$upload_id_one" + fi + + run list_multipart_uploads_get_check_next_values "$bucket_name" "$second_key" "$second_upload_id" "$first_key" "$first_upload_id" + assert_success +} + +# tags: curl,ListMultipartUploads,multipart,uploadId +@test "REST - ListMultipartUploads - uploadId without key should be ignored" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/2150" + fi + run setup_bucket_and_file_v3 "$BUCKET_ONE_NAME" + assert_success + read -r bucket_name test_file <<< "$output" + + run create_multipart_upload_rest "$bucket_name" "$test_file" "" "parse_upload_id" + assert_success + upload_id_one=$output + + run create_multipart_upload_rest "$bucket_name" "$test_file" "" "parse_upload_id" + assert_success + upload_id_two=$output + + local first_upload_id second_upload_id + if [[ "$upload_id_one" < "$upload_id_two" ]]; then + first_upload_id="$upload_id_one" + second_upload_id="$upload_id_two" + else + first_upload_id="$upload_id_two" + second_upload_id="$upload_id_one" + fi + + run list_multipart_uploads_check_no_upload_id_in_response "$bucket_name" "$second_upload_id" "$first_upload_id" + assert_success +} + +# tags: curl,ListMultipartUploads,multipart,prefix,delimiter +@test "REST - ListMultipartUploads - prefix and delimiter" { + file_names=("a-b-1.txt" "a-b-2.txt" "a-b/c-1.txt" "a-b/c-2.txt" "a-b/d.txt" "a/c.txt") + local prefix="a-" + run create_test_files_and_folders "${file_names[@]}" + assert_success + + run setup_bucket_v3 "$BUCKET_ONE_NAME" + assert_success + bucket_name="$output" + + for file_name in "${file_names[@]}"; do + run create_multipart_upload_rest "$bucket_name" "$file_name" "" "" + assert_success + done + + run list_multipart_uploads_rest "$bucket_name" + assert_success + log 5 "uploads: $output" + + run list_uploads_with_prefix_and_delimiter_check_results "$bucket_name" "$prefix" "/" "a-b/" "--" "a-b-1.txt" "a-b-2.txt" + assert_success +} + +# tags: curl,ListMultipartUploads,multipart,encoding-type +@test "REST - ListMultipartUploads - encoding type" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/2156" + fi + run setup_bucket_v3 "$BUCKET_ONE_NAME" + assert_success + bucket_name="$output" + + run create_test_files_with_prefix " " + assert_success + base_file_name="$output" + file_name="${base_file_name}(test)+" + log 5 "file name: '$file_name'" + + run send_rest_go_command_callback "200" "parse_upload_id" "-method" "POST" "-query" "uploads" "-bucketName" "$bucket_name" "-objectKey" "$file_name" + assert_success + upload_id=$output + + run list_multipart_uploads_check_encoding "$bucket_name" "&encoding-type=url" "${base_file_name/ /+}%28test%29%2B" + assert_success + + run list_multipart_uploads_check_encoding "$bucket_name" "" "$file_name" + assert_success +} + +# tags: curl,ListMultipartUploads,multipart,encoding-type,invalid-query +@test "REST - ListMultipartUploads - invalid encoding type" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/2156" + fi + run setup_bucket_and_file_v3 "$BUCKET_ONE_NAME" + assert_success + read -r bucket_name test_file <<< "$output" + + run create_multipart_upload_rest "$bucket_name" "$test_file" "" "parse_upload_id" + assert_success + upload_id_one=$output + + local invalid_encoding="abc" + run send_rest_go_command_expect_error_with_arg_name_value "400" "InvalidArgument" "Invalid Encoding Method specified" \ + "encoding-type" "$invalid_encoding" "-bucketName" "$bucket_name" "-query" "uploads&encoding-type=$invalid_encoding" + assert_success +} + +# tags: curl,ListMultipartUploads,multipart,uploadId,invalid-query +@test "REST - ListMultipartUploads - uploads/uploadId combo" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/2155" + fi + run setup_bucket_and_file_v3 "$BUCKET_ONE_NAME" + assert_success + read -r bucket_name test_file <<< "$output" + + run create_multipart_upload_rest "$bucket_name" "$test_file" "" "parse_upload_id" + assert_success + upload_id_one=$output + + run send_rest_go_command_expect_error "400" "InvalidArgument" "Conflicting query string parameters" "-query" "uploads&uploadId=$upload_id_one" "-bucketName" "$bucket_name" + assert_success +} diff --git a/tests/test_s3api_multipart.sh b/tests/test_s3api_multipart.sh index 2dcd61ee..288d7f77 100755 --- a/tests/test_s3api_multipart.sh +++ b/tests/test_s3api_multipart.sh @@ -27,6 +27,7 @@ source ./tests/drivers/head_object/head_object_s3api.sh source ./tests/drivers/create_bucket/create_bucket_rest.sh source ./tests/drivers/get_object_legal_hold/get_object_legal_hold.sh source ./tests/drivers/get_object_tagging/get_object_tagging.sh +source ./tests/drivers/list_multipart_uploads/list_multipart_uploads_s3api.sh source ./tests/drivers/put_bucket_ownership_controls/put_bucket_ownership_controls_rest.sh source ./tests/util/util_multipart.sh source ./tests/util/util_multipart_abort.sh @@ -160,16 +161,61 @@ export RUN_USERS=true # test listing of active uploads # tags: s3api, multipart, ListMultipartUploads @test "test-multipart-upload-list-uploads" { - if [[ $RECREATE_BUCKETS == false ]]; then - run abort_all_multipart_uploads "$BUCKET_ONE_NAME" + run setup_bucket_and_files_v3 "$BUCKET_ONE_NAME" 2 + assert_success + read -r bucket_name bucket_file_one bucket_file_two <<< "$output" + + run create_list_check_multipart_uploads "$bucket_name" "$bucket_file_one" "$bucket_file_two" + assert_success +} + +@test "s3api - ListMultipartUploads with upload ID" { + run get_bucket_prefix "$BUCKET_ONE_NAME" + assert_success + prefix="$output" + + run bucket_cleanup_if_bucket_exists_v2 "$prefix" + assert_success + + run get_bucket_name "$BUCKET_ONE_NAME" + assert_success + bucket_name="$output" + + if [ "$RECREATE_BUCKETS" == "true" ]; then + run create_bucket "s3api" "$bucket_name" assert_success fi - local bucket_file_one="bucket-file-one" - local bucket_file_two="bucket-file-two" - run setup_bucket_and_files "$BUCKET_ONE_NAME" "$bucket_file_one" "$bucket_file_two" + run create_test_files_with_prefix "file" 2 assert_success + read -r file_one file_two <<< "$output" - run create_list_check_multipart_uploads "$BUCKET_ONE_NAME" "$bucket_file_one" "$bucket_file_two" + run create_multipart_upload_s3api "$bucket_name" "$file_one" assert_success + upload_id_one="$output" + + run create_multipart_upload_s3api "$bucket_name" "$file_two" + assert_success + upload_id_two="$output" + + local first_key first_upload_id second_key second_upload_id + if [[ "$file_one" < "$file_two" ]]; then + first_key="$file_one" + first_upload_id="$upload_id_one" + second_key="$file_two" + second_upload_id="$upload_id_two" + else + first_key="$file_two" + first_upload_id="$upload_id_two" + second_key="$file_one" + second_upload_id="$upload_id_one" + fi + + run list_multipart_uploads_check_key_id_get_next_token "$bucket_name" "$first_key" "$first_upload_id" + assert_success + first_token="$output" + + run list_multipart_uploads_check_key_id_get_next_token "$bucket_name" "$second_key" "$second_upload_id" "$first_token" + assert_success + assert_output "null" } diff --git a/tests/util/util_multipart_abort.sh b/tests/util/util_multipart_abort.sh index 525e3dc6..7ab97612 100644 --- a/tests/util/util_multipart_abort.sh +++ b/tests/util/util_multipart_abort.sh @@ -114,20 +114,27 @@ abort_all_multipart_uploads_rest() { if ! check_param_count "abort_all_multipart_uploads_rest" "bucket" 1 $#; then return 1 fi - if ! list_multipart_uploads_rest "$1"; then - log 2 "error listing multipart uploads" + local response uploads upload_data key upload_id + + if ! response=$(list_multipart_uploads_rest "$1" 2>&1); then + log 2 "error listing multipart uploads: $response" return 1 fi + uploads="$response" + # shellcheck disable=SC2154 log 5 "UPLOADS: $uploads" - if ! upload_data=$(xmllint --xpath '//*[local-name()="Upload"]' "$TEST_FILE_FOLDER/uploads.txt" 2>&1); then - if [[ "$upload_data" == *"XPath set is empty"* ]]; then + if ! response=$(echo -n "$uploads" | xmllint --xpath '//*[local-name()="Upload"]' - 2>&1); then + if [[ "$response" == *"XPath set is empty"* ]]; then return 0 fi - log 2 "error retrieving upload data: $upload_data" + log 2 "error retrieving upload data: $response" return 1 fi - for upload in $upload_data; do + mapfile -t upload_data <<< "$response" + + for upload in "${upload_data[@]}"; do + log 5 "upload: $upload" if ! key=$(echo -n "$upload" | xmllint --xpath '//*[local-name()="Key"]/text()' - 2>&1); then log 2 "error retrieving key: $key" return 1 diff --git a/tests/util/util_multipart_before_completion.sh b/tests/util/util_multipart_before_completion.sh index d4a08e6d..9ce01ed5 100644 --- a/tests/util/util_multipart_before_completion.sh +++ b/tests/util/util_multipart_before_completion.sh @@ -161,14 +161,17 @@ start_multipart_upload_and_list_parts() { } create_list_check_multipart_uploads() { - if [ $# -ne 3 ]; then - log 2 "list multipart uploads command requires bucket and two keys" + if ! check_param_count_v2 "bucket, two keys" 3 $#; then return 1 fi - if ! create_and_list_multipart_uploads "$1" "$2" "$3"; then + local response uploads raw_uploads key_one key_two second_match + + if ! response=$(create_and_list_multipart_uploads "$1" "$2" "$3" 2>&1); then log 2 "error creating and listing multipart uploads" return 1 fi + uploads="$response" + # shellcheck disable=SC2154 log 5 "Uploads: $uploads" raw_uploads=$(echo "$uploads" | grep -v "InsecureRequestWarning") @@ -180,12 +183,18 @@ create_list_check_multipart_uploads() { log 2 "error getting key two: $key_two" return 1 fi + if [[ "$2" != "$key_one" ]]; then - log 2 "Key mismatch ($2, $key_one)" - return 1 + if [ "$2" != "$key_two" ]; then + log 2 "Key mismatch ('$2' doesn't match '$key_one' or '$key_two')" + return 1 + fi + second_match="$key_one" + else + second_match="$key_two" fi - if [[ "$3" != "$key_two" ]]; then - log 2 "Key mismatch ($3, $key_two)" + if [[ "$3" != "$second_match" ]]; then + log 2 "Key mismatch (expected '$3', actual '$second_match')" return 1 fi return 0 @@ -195,25 +204,26 @@ create_list_check_multipart_uploads() { # params: bucket, key one, key two # export current two uploads on success, return 1 for error create_and_list_multipart_uploads() { - if [ $# -ne 3 ]; then - log 2 "list multipart uploads command requires bucket and two keys" + if ! check_param_count_v2 "bucket, two keys" 3 $#; then + return 1 + fi + local response + + if ! response=$(create_multipart_upload_rest "$1" "$2" "" "" 2>&1); then + log 2 "error creating multipart upload one: $response" return 1 fi - if ! create_multipart_upload_rest "$1" "$2" "" ""; then - log 2 "error creating multpart upload" + if ! response=$(create_multipart_upload_rest "$1" "$3" "" "" 2>&1); then + log 2 "error creating multipart upload two: $response" return 1 fi - if ! create_multipart_upload_rest "$1" "$3" "" ""; then - log 2 "error creating multpart upload two" - return 1 - fi - - if ! list_multipart_uploads "$1"; then - log 2 "error listing uploads" + if ! response=$(list_multipart_uploads "$1" 2>&1); then + log 2 "error listing uploads: $response" return 1 fi + echo "$response" return 0 }