Merge pull request #2157 from versity/test/list_multipart_uploads

test: ListMultipartUpload query tests
This commit is contained in:
Ben McClelland
2026-05-28 16:02:30 -07:00
committed by GitHub
18 changed files with 760 additions and 161 deletions
+12 -8
View File
@@ -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
}
+23 -9
View File
@@ -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
}
+5 -2
View File
@@ -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
@@ -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() {
+91
View File
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
+15 -8
View File
@@ -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
+17 -12
View File
@@ -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"
+1 -1
View File
@@ -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"
@@ -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")
+20 -14
View File
@@ -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:
+5
View File
@@ -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
+231
View File
@@ -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
}
+52 -6
View File
@@ -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"
}
+13 -6
View File
@@ -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
+28 -18
View File
@@ -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
}