From 038ae5e1eaae5071990158357765d95c96540dd1 Mon Sep 17 00:00:00 2001 From: Luke McCrone Date: Mon, 2 Mar 2026 19:33:58 -0300 Subject: [PATCH] test: update functions, transfer/remove some utils files --- tests/commands/complete_multipart_upload.sh | 4 +- tests/commands/delete_object.sh | 1 + .../complete_multipart_upload_rest.sh | 59 +++++++ .../delete_object/delete_object_s3api.sh | 31 ++++ .../delete_objects/delete_objects_rest.sh | 109 ++++++++++++ .../get_object_attributes_rest.sh | 2 - tests/drivers/list_parts/list_parts_rest.sh | 131 ++++++++++++++ tests/env.sh | 6 + tests/test_rest_bucket.sh | 1 - tests/test_rest_delete_object.sh | 2 +- tests/test_rest_multipart.sh | 1 - tests/test_s3api_policy_object.sh | 2 +- tests/util/util_delete_object.sh | 97 ---------- tests/util/util_list_parts.sh | 165 ------------------ 14 files changed, 342 insertions(+), 269 deletions(-) create mode 100644 tests/drivers/delete_object/delete_object_s3api.sh create mode 100644 tests/drivers/delete_objects/delete_objects_rest.sh create mode 100644 tests/drivers/list_parts/list_parts_rest.sh delete mode 100644 tests/util/util_delete_object.sh delete mode 100644 tests/util/util_list_parts.sh diff --git a/tests/commands/complete_multipart_upload.sh b/tests/commands/complete_multipart_upload.sh index 62f90415..8958e154 100644 --- a/tests/commands/complete_multipart_upload.sh +++ b/tests/commands/complete_multipart_upload.sh @@ -14,6 +14,8 @@ # specific language governing permissions and limitations # under the License. +source ./tests/drivers/list_parts/list_parts_rest.sh + complete_multipart_upload() { if [[ $# -ne 4 ]]; then log 2 "'complete multipart upload' command requires bucket, key, upload ID, parts list" @@ -100,4 +102,4 @@ complete_multipart_upload_rest_invalid_checksum() { log 2 "expected '400', was $result: $(cat "$TEST_FILE_FOLDER/result.txt")" return 1 fi -} \ No newline at end of file +} diff --git a/tests/commands/delete_object.sh b/tests/commands/delete_object.sh index ce4551ab..ffc3c761 100644 --- a/tests/commands/delete_object.sh +++ b/tests/commands/delete_object.sh @@ -139,6 +139,7 @@ delete_object_with_user() { fi if [ $exit_code -ne 0 ]; then log 2 "error deleting object: $delete_object_error" + echo "$delete_object_error" >&2 return 1 fi return 0 diff --git a/tests/drivers/complete_multipart_upload/complete_multipart_upload_rest.sh b/tests/drivers/complete_multipart_upload/complete_multipart_upload_rest.sh index 5ca91773..23d2fe8e 100644 --- a/tests/drivers/complete_multipart_upload/complete_multipart_upload_rest.sh +++ b/tests/drivers/complete_multipart_upload/complete_multipart_upload_rest.sh @@ -179,3 +179,62 @@ complete_multipart_upload_invalid_object_size_string() { fi return 0 } + +perform_multipart_upload_rest() { + if ! check_param_count_v2 "bucket, key, four parts" 6 $#; then + return 1 + fi + if ! upload_id=$(create_multipart_upload_rest "$1" "$2" "" "parse_upload_id" 2>&1); then + log 2 "error creating multipart upload: $upload_id" + return 1 + fi + if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 1 "$3" 2>&1); then + log 2 "error uploading part 1" + return 1 + fi + parts_payload="$etag1" + if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 2 "$4" 2>&1); then + log 2 "error uploading part 2: $etag" + return 1 + fi + parts_payload+="$etag2" + if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 3 "$5" 2>&1); then + log 2 "error uploading part 3: $etag" + return 1 + fi + parts_payload+="$etag3" + if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 4 "$6" 2>&1); then + log 2 "error uploading part 4: $etag" + return 1 + fi + parts_payload+="$etag4" + if ! complete_multipart_upload_rest "$1" "$2" "$upload_id" "$parts_payload"; then + log 2 "error completing multipart upload" + return 1 + fi + return 0 +} + +upload_check_parts() { + if ! check_param_count_v2 "bucket, key, list of 4 parts" 6 $#; then + return 1 + fi + if ! upload_id=$(create_multipart_upload_rest "$1" "$2" "" "parse_upload_id" 2>&1); then + log 2 "error creating upload: $upload_id" + return 1 + fi + if ! check_part_list_rest "$1" "$2" "$upload_id" 0; then + log 2 "error checking part list before part upload" + return 1 + fi + if ! parts_payload=$(upload_each_part_and_check "$1" "$2" "$upload_id" "${@:3}" 2>&1); then + log 2 "error uploading and checking parts: $parts_payload" + return 1 + fi + log 5 "PARTS PAYLOAD: $parts_payload" + if ! complete_multipart_upload_rest "$1" "$2" "$upload_id" "$parts_payload"; then + log 2 "error completing multipart upload" + return 1 + fi + return 0 +} diff --git a/tests/drivers/delete_object/delete_object_s3api.sh b/tests/drivers/delete_object/delete_object_s3api.sh new file mode 100644 index 00000000..36f80e4f --- /dev/null +++ b/tests/drivers/delete_object/delete_object_s3api.sh @@ -0,0 +1,31 @@ +#!/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. + +block_delete_object_without_permission() { + if ! check_param_count_v2 "bucket, file, username, password" 4 $#; then + return 1 + fi + if delete_object_error=$(delete_object_with_user "s3api" "$1" "$2" "$3" "$4" 2>&1); then + log 2 "able to delete object despite lack of permissions" + return 1 + fi + # shellcheck disable=SC2154 + if [[ "$delete_object_error" != *"AccessDenied"* ]]; then + log 2 "invalid delete object error: $delete_object_error" + return 1 + fi + return 0 +} diff --git a/tests/drivers/delete_objects/delete_objects_rest.sh b/tests/drivers/delete_objects/delete_objects_rest.sh new file mode 100644 index 00000000..2e55fc22 --- /dev/null +++ b/tests/drivers/delete_objects/delete_objects_rest.sh @@ -0,0 +1,109 @@ +#!/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. + +delete_object_empty_bucket_check_error() { + if ! file_name=$(get_file_name 2>&1); then + log 2 "error getting file name: $file_name" + return 1 + fi + if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/$file_name" COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="" ./tests/rest_scripts/delete_objects.sh); then + log 2 "error deleting objects: $result" + return 1 + fi + log 5 "result: $(cat "$TEST_FILE_FOLDER/$file_name")" + if ! error=$(xmllint --xpath "Error" "$TEST_FILE_FOLDER/$file_name" 2>&1); then + log 2 "error getting XML error data: $error" + return 1 + fi + if ! error_file_name=$(get_file_name 2>&1); then + log 2 "error getting error file name: $file_name" + return 1 + fi + echo -n "$error" > "$TEST_FILE_FOLDER/$error_file_name" + if ! check_xml_element "$TEST_FILE_FOLDER/$error_file_name" "MethodNotAllowed" "Code"; then + log 2 "Code mismatch" + return 1 + fi + if ! check_xml_element "$TEST_FILE_FOLDER/$error_file_name" "POST" "Method"; then + log 2 "Method mismatch" + return 1 + fi + if ! check_xml_element "$TEST_FILE_FOLDER/$error_file_name" "SERVICE" "ResourceType"; then + log 2 "ResourceType mismatch" + return 1 + fi + return 0 +} + +delete_objects_no_content_md5_header() { + if ! check_param_count_v2 "bucket name" 1 $#; then + return 1 + fi + data=" + + dontcare + + + dontcareeither + + " + + if ! file_name=$(get_file_name 2>&1); then + log 2 "error getting file name: $file_name" + return 1 + fi + if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/$file_name" COMMAND_LOG="$COMMAND_LOG" PAYLOAD="$data" BUCKET_NAME="$1" HAS_CONTENT_MD5="false" ./tests/rest_scripts/delete_objects.sh); then + log 2 "error deleting objects: $result" + return 1 + fi + if [ "$result" != "400" ]; then + log 2 "expected response code '400', actual '$result' ($(cat "$TEST_FILE_FOLDER/$file_name")" + return 1 + fi + if ! check_xml_element "$TEST_FILE_FOLDER/$file_name" "InvalidRequest" "Error" "Code"; then + log 2 "error checking error element" + return 1 + fi + return 0 +} + +delete_objects_verify_success() { + if ! check_param_count_v2 "bucket name, two object names" 3 $#; then + return 1 + fi + data=" + + $2 + + + $3 + +" + + if ! file_name=$(get_file_name 2>&1); then + log 2 "error getting file name: $file_name" + return 1 + fi + if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/$file_name" COMMAND_LOG="$COMMAND_LOG" PAYLOAD="$data" BUCKET_NAME="$1" ./tests/rest_scripts/delete_objects.sh); then + log 2 "error deleting objects: $result" + return 1 + fi + if [ "$result" != "200" ]; then + log 2 "expected '200', was '$result ($(cat "$TEST_FILE_FOLDER/$file_name"))" + return 1 + fi + return 0 +} diff --git a/tests/drivers/get_object_attributes/get_object_attributes_rest.sh b/tests/drivers/get_object_attributes/get_object_attributes_rest.sh index c597b029..6b2f1d2c 100644 --- a/tests/drivers/get_object_attributes/get_object_attributes_rest.sh +++ b/tests/drivers/get_object_attributes/get_object_attributes_rest.sh @@ -14,8 +14,6 @@ # specific language governing permissions and limitations # under the License. -source ./tests/util/util_list_parts.sh - upload_and_check_attributes() { if ! check_param_count_v2 "bucket, test file, file size" 3 $#; then return 1 diff --git a/tests/drivers/list_parts/list_parts_rest.sh b/tests/drivers/list_parts/list_parts_rest.sh new file mode 100644 index 00000000..918ed8c0 --- /dev/null +++ b/tests/drivers/list_parts/list_parts_rest.sh @@ -0,0 +1,131 @@ +#!/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_part_list_rest_etags() { + if ! check_param_count_gt "data file name, etags" 2 $#; then + return 1 + fi + if ! etags_raw=$(xmllint --xpath '//*[local-name()="ETag"]/text()' "$1" 2>&1); then + log 2 "error retrieving etags: $etags" + return 1 + fi + etags=$(echo "$etags_raw" | tr '\n' ' ') + read -ra etags_array <<< "$etags" + + idx=0 + shift + if [ $# -ne ${#etags_array[@]} ]; then + log 2 "expected tag size of '$#', actual ${#etags_array[@]}" + return 1 + fi + while [ $# -gt 0 ]; do + if [ "$1" != "${etags_array[$idx]}" ]; then + log 2 "etag mismatch (expected '$1', actual ${etags_array[$idx]})" + return 1 + fi + ((idx++)) + shift + done + return 0 +} + +check_part_list_rest() { + if ! check_param_count_gt "bucket, key name, upload ID, expected etag count, expected etags" 4 $#; then + return 1 + fi + if ! file_name=$(get_file_name 2>&1); then + log 2 "error getting file name: $file_name" + return 1 + fi + if ! result=$(COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="$1" OBJECT_KEY="$2" UPLOAD_ID="$3" OUTPUT_FILE="$TEST_FILE_FOLDER/$file_name" ./tests/rest_scripts/list_parts.sh); then + log 2 "error listing multipart upload parts: $result" + return 1 + fi + if [ "$result" != "200" ]; then + log 2 "list-parts returned response code: $result, reply: $(cat "$TEST_FILE_FOLDER/$file_name")" + return 1 + fi + log 5 "parts list: $(cat "$TEST_FILE_FOLDER/$file_name")" + if ! parts_upload_id=$(xmllint --xpath '//*[local-name()="UploadId"]/text()' "$TEST_FILE_FOLDER/$file_name" 2>&1); then + log 2 "error retrieving UploadId: $parts_upload_id" + return 1 + fi + if [ "$parts_upload_id" != "$3" ]; then + log 2 "expected '$3', UploadId value is '$parts_upload_id'" + return 1 + fi + if ! part_count=$(xmllint --xpath 'count(//*[local-name()="Part"])' "$TEST_FILE_FOLDER/$file_name" 2>&1); then + log 2 "error retrieving part count: $part_count" + return 1 + fi + if [ "$part_count" != "$4" ]; then + log 2 "expected $4, 'Part' count is '$part_count'" + return 1 + fi + if [ "$4" == 0 ]; then + return 0 + fi + if ! check_part_list_rest_etags "$TEST_FILE_FOLDER/$file_name" "${@:5}"; then + log 2 "error checking etags" + return 1 + fi + return 0 +} + +upload_each_part_and_check() { + if ! check_param_count_gt "bucket, key, upload ID, parts" 5 $#; then + return 1 + fi + + local part_count=$(($#-3)) + local parts_payload="" + local etags=() + + for ((idx=1; idx<=part_count; idx++)); do + local payload_section="" + part_number=$((idx+3)) + + if ! etag_and_payload_section=$(upload_check_part "$1" "$2" "$3" "$idx" "${!part_number}" "${etags[@]}" 2>&1); then + log 2 "error uploading and checking part '$idx': $etag_and_payload_section" + return 1 + fi + + IFS=$'\n' read -r -d '' etag payload_section < <(printf '%s\0' "$etag_and_payload_section") + parts_payload+="$payload_section" + etags+=("$etag") + done + echo "$parts_payload" + return 0 +} + +upload_check_part() { + if ! check_param_count_gt "bucket, key, upload ID, part number, part, etags (if any)" 5 $#; then + return 1 + fi + if ! etag=$(upload_part_rest "$1" "$2" "$3" "$4" "$5" 2>&1); then + log 2 "error uploading part '$4': $etag" + return 1 + fi + local payload_part="$etag$4" + # shellcheck disable=SC2068 + if ! check_part_list_rest "$1" "$2" "$3" "$4" "${@:6}" "$etag"; then + log 2 "error checking part list after upload $4" + return 1 + fi + echo "$etag" + echo "$payload_part" + return 0 +} diff --git a/tests/env.sh b/tests/env.sh index af4c3824..58571abf 100644 --- a/tests/env.sh +++ b/tests/env.sh @@ -16,6 +16,12 @@ source ./tests/versity.sh +if [ -n "$BASH_VERSION" ] && [ "${BASH_VERSINFO[0]}" -lt 4 ]; then + echo "ERROR: This test suite requires bash 4.0 or later. Current: $BASH_VERSION" >&2 + echo "On macOS: brew install bash && add to PATH" >&2 + exit 1 +fi + base_setup() { check_env_vars if [ "$RUN_VERSITYGW" == "true" ] && [ "$UNIT_TEST" != "true" ]; then diff --git a/tests/test_rest_bucket.sh b/tests/test_rest_bucket.sh index b2765b5c..dba4630a 100755 --- a/tests/test_rest_bucket.sh +++ b/tests/test_rest_bucket.sh @@ -29,7 +29,6 @@ source ./tests/drivers/put_bucket_ownership_controls/put_bucket_ownership_contro source ./tests/drivers/put_bucket_tagging/put_bucket_tagging_rest.sh source ./tests/logger.sh source ./tests/setup.sh -source ./tests/util/util_delete_object.sh source ./tests/util/util_list_buckets.sh source ./tests/util/util_lock_config.sh source ./tests/util/util_public_access_block.sh diff --git a/tests/test_rest_delete_object.sh b/tests/test_rest_delete_object.sh index b7336000..0d8a18c8 100755 --- a/tests/test_rest_delete_object.sh +++ b/tests/test_rest_delete_object.sh @@ -18,7 +18,7 @@ load ./bats-support/load load ./bats-assert/load source ./tests/drivers/create_bucket/create_bucket_rest.sh -source ./tests/util/util_delete_object.sh +source ./tests/drivers/delete_objects/delete_objects_rest.sh source ./tests/setup.sh @test "test_rest_delete_object" { diff --git a/tests/test_rest_multipart.sh b/tests/test_rest_multipart.sh index f149721e..57f818cf 100755 --- a/tests/test_rest_multipart.sh +++ b/tests/test_rest_multipart.sh @@ -25,7 +25,6 @@ source ./tests/drivers/complete_multipart_upload/complete_multipart_upload_rest. source ./tests/drivers/list_buckets/list_buckets_rest.sh source ./tests/drivers/upload_part/upload_part_rest.sh source ./tests/util/util_file.sh -source ./tests/util/util_list_parts.sh test_file="test_file" diff --git a/tests/test_s3api_policy_object.sh b/tests/test_s3api_policy_object.sh index 1eb80963..793eea95 100644 --- a/tests/test_s3api_policy_object.sh +++ b/tests/test_s3api_policy_object.sh @@ -14,8 +14,8 @@ # specific language governing permissions and limitations # under the License. +source ./tests/drivers/delete_object/delete_object_s3api.sh source ./tests/drivers/put_bucket_policy/put_bucket_policy.sh -source ./tests/util/util_delete_object.sh test_s3api_policy_allow_deny() { policy_file="policy_file" diff --git a/tests/util/util_delete_object.sh b/tests/util/util_delete_object.sh deleted file mode 100644 index d05de529..00000000 --- a/tests/util/util_delete_object.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash - -block_delete_object_without_permission() { - if [ $# -ne 4 ]; then - log 2 "'attempt_delete_object_without_permission' requires bucket, file, username, password" - return 1 - fi - if delete_object_with_user "s3api" "$1" "$2" "$3" "$4"; then - log 2 "able to delete object despite lack of permissions" - return 1 - fi - # shellcheck disable=SC2154 - if [[ "$delete_object_error" != *"AccessDenied"* ]]; then - log 2 "invalid delete object error: $delete_object_error" - return 1 - fi - return 0 -} - -delete_object_empty_bucket_check_error() { - if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/result.txt" COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="" ./tests/rest_scripts/delete_objects.sh); then - log 2 "error deleting objects: $result" - return 1 - fi - log 5 "result: $(cat "$TEST_FILE_FOLDER/result.txt")" - if ! error=$(xmllint --xpath "Error" "$TEST_FILE_FOLDER/result.txt" 2>&1); then - log 2 "error getting XML error data: $error" - return 1 - fi - echo -n "$error" > "$TEST_FILE_FOLDER/error.txt" - if ! check_xml_element "$TEST_FILE_FOLDER/error.txt" "MethodNotAllowed" "Code"; then - log 2 "Code mismatch" - return 1 - fi - if ! check_xml_element "$TEST_FILE_FOLDER/error.txt" "POST" "Method"; then - log 2 "Method mismatch" - return 1 - fi - if ! check_xml_element "$TEST_FILE_FOLDER/error.txt" "SERVICE" "ResourceType"; then - log 2 "ResourceType mismatch" - return 1 - fi - return 0 -} - -delete_objects_no_content_md5_header() { - if [ $# -ne 1 ]; then - log 2 "delete_objects_no_content_md5_header requires bucket name" - return 1 - fi - data=" - - dontcare - - - dontcareeither - - " - - if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/result.txt" COMMAND_LOG="$COMMAND_LOG" PAYLOAD="$data" BUCKET_NAME="$1" HAS_CONTENT_MD5="false" ./tests/rest_scripts/delete_objects.sh); then - log 2 "error deleting objects: $result" - return 1 - fi - if [ "$result" != "400" ]; then - log 2 "expected response code '400', actual '$result' ($(cat "$TEST_FILE_FOLDER/result.txt")" - return 1 - fi - if ! check_xml_element "$TEST_FILE_FOLDER/result.txt" "InvalidRequest" "Error" "Code"; then - log 2 "error checking error element" - return 1 - fi -} - -delete_objects_verify_success() { - if [ $# -ne 3 ]; then - log 2 "'delete_objects_verify_success' requires bucket name, two objects" - return 1 - fi - data=" - - $2 - - - $3 - -" - - if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/result.txt" COMMAND_LOG="$COMMAND_LOG" PAYLOAD="$data" BUCKET_NAME="$1" ./tests/rest_scripts/delete_objects.sh); then - log 2 "error deleting objects: $result" - return 1 - fi - if [ "$result" != "200" ]; then - log 2 "expected '200', was '$result ($(cat "$TEST_FILE_FOLDER/result.txt"))" - return 1 - fi - return 0 -} diff --git a/tests/util/util_list_parts.sh b/tests/util/util_list_parts.sh deleted file mode 100644 index 397e0c09..00000000 --- a/tests/util/util_list_parts.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env bash - -check_part_list_rest_etags() { - if ! etags=$(xmllint --xpath '//*[local-name()="ETag"]/text()' "$TEST_FILE_FOLDER/parts.txt" | tr '\n' ' ' 2>&1); then - log 2 "error retrieving etags: $etags" - return 1 - fi - read -ra etags_array <<< "$etags" - idx=0 - if [ $# -ne ${#etags_array[@]} ]; then - log 2 "expected tag size of '$#', actual ${#etags_array[@]}" - return 1 - fi - while [ $# -gt 0 ]; do - if [ "$1" != "${etags_array[$idx]}" ]; then - log 2 "etag mismatch (expected '$1', actual ${etags_array[$idx]})" - return 1 - fi - ((idx++)) - shift - done - return 0 -} - -check_part_list_rest() { - if [ $# -lt 4 ]; then - log 2 "'check_part_list_rest' requires bucket, file name, upload ID, expected count, etags" - return 1 - fi - if ! result=$(COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="$1" OBJECT_KEY="$2" UPLOAD_ID="$3" OUTPUT_FILE="$TEST_FILE_FOLDER/parts.txt" ./tests/rest_scripts/list_parts.sh); then - log 2 "error listing multipart upload parts: $result" - return 1 - fi - if [ "$result" != "200" ]; then - log 2 "list-parts returned response code: $result, reply: $(cat "$TEST_FILE_FOLDER/parts.txt")" - return 1 - fi - log 5 "parts list: $(cat "$TEST_FILE_FOLDER/parts.txt")" - if ! parts_upload_id=$(xmllint --xpath '//*[local-name()="UploadId"]/text()' "$TEST_FILE_FOLDER/parts.txt" 2>&1); then - log 2 "error retrieving UploadId: $parts_upload_id" - return 1 - fi - if [ "$parts_upload_id" != "$3" ]; then - log 2 "expected '$3', UploadId value is '$parts_upload_id'" - return 1 - fi - if ! part_count=$(xmllint --xpath 'count(//*[local-name()="Part"])' "$TEST_FILE_FOLDER/parts.txt" 2>&1); then - log 2 "error retrieving part count: $part_count" - return 1 - fi - if [ "$part_count" != "$4" ]; then - log 2 "expected $4, 'Part' count is '$part_count'" - return 1 - fi - if [ "$4" == 0 ]; then - return 0 - fi - if ! check_part_list_rest_etags "${@:5}"; then - log 2 "error checking etags" - return 1 - fi - return 0 -} - -perform_multipart_upload_rest() { - if [ $# -ne 6 ]; then - log 2 "'upload_check_parts' requires bucket, key, part list (4 parts)" - return 1 - fi - if ! create_multipart_upload_rest "$1" "$2" "" "parse_upload_id"; then - log 2 "error creating multipart upload" - return 1 - fi - # shellcheck disable=SC2154 - if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 1 "$3" 2>&1); then - log 2 "error uploading part 1" - return 1 - fi - # shellcheck disable=SC2154 - parts_payload="$etag1" - if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 2 "$4" 2>&1); then - log 2 "error uploading part 2: $etag" - return 1 - fi - parts_payload+="$etag2" - if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 3 "$5" 2>&1); then - log 2 "error uploading part 3: $etag" - return 1 - fi - parts_payload+="$etag3" - if ! etag=$(upload_part_rest "$1" "$2" "$upload_id" 4 "$6" 2>&1); then - log 2 "error uploading part 4: $etag" - return 1 - fi - parts_payload+="$etag4" - if ! complete_multipart_upload_rest "$1" "$2" "$upload_id" "$parts_payload"; then - log 2 "error completing multipart upload" - return 1 - fi - return 0 -} - -upload_check_parts() { - if [ $# -ne 6 ]; then - log 2 "'upload_check_parts' requires bucket, key, part list" - return 1 - fi - if ! create_multipart_upload_rest "$1" "$2" "" "parse_upload_id"; then - log 2 "error creating upload" - return 1 - fi - # shellcheck disable=SC2154 - if ! check_part_list_rest "$1" "$2" "$upload_id" 0; then - log 2 "error checking part list before part upload" - return 1 - fi - sleep 5 - parts_payload="" - if ! upload_check_part "$1" "$2" "$upload_id" 1 "$3"; then - log 2 "error uploading and checking first part" - return 1 - fi - if ! list_multipart_uploads_rest "$1"; then - log 2 "error listing uploads" - return 1 - fi - etag_one=$etag - if ! upload_check_part "$1" "$2" "$upload_id" 2 "$4" "$etag_one"; then - log 2 "error uploading and checking second part" - return 1 - fi - etag_two=$etag - if ! upload_check_part "$1" "$2" "$upload_id" 3 "$5" "$etag_one" "$etag_two"; then - log 2 "error uploading and checking third part" - return 1 - fi - etag_three=$etag - if ! upload_check_part "$1" "$2" "$upload_id" 4 "$6" "$etag_one" "$etag_two" "$etag_three"; then - log 2 "error uploading and checking fourth part" - return 1 - fi - log 5 "PARTS PAYLOAD: $parts_payload" - if ! complete_multipart_upload_rest "$1" "$2" "$upload_id" "$parts_payload"; then - log 2 "error completing multipart upload" - return 1 - fi - return 0 -} - -upload_check_part() { - if [ $# -lt 5 ]; then - log 2 "'upload_check_part' requires bucket, key, upload ID, part number, part, etags" - return 1 - fi - if ! etag=$(upload_part_rest "$1" "$2" "$3" "$4" "$5" 2>&1); then - log 2 "error uploading part $4: $etag" - return 1 - fi - parts_payload+="$etag$4" - # shellcheck disable=SC2068 - if ! check_part_list_rest "$1" "$2" "$3" "$4" "${@:6}" "$etag"; then - log 2 "error checking part list after upload $4" - return 1 - fi -}