diff --git a/tests/rest_scripts/delete_objects.sh b/tests/rest_scripts/delete_objects.sh new file mode 100755 index 0000000..5355038 --- /dev/null +++ b/tests/rest_scripts/delete_objects.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +# Copyright 2024 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/rest_scripts/rest.sh + +# Fields + +# shellcheck disable=SC2153,SC2154 +payload="$PAYLOAD" +# shellcheck disable=SC2153,SC2154 +bucket_name="$BUCKET_NAME" +has_content_md5="${HAS_CONTENT_MD5:="true"}" + +current_date_time=$(date -u +"%Y%m%dT%H%M%SZ") +payload_hash="$(echo -n "$payload" | sha256sum | awk '{print $1}')" +if [ "$has_content_md5" == "true" ]; then + content_md5=$(echo -n "$payload" | openssl dgst -binary -md5 | openssl base64) +fi + +canonical_request="POST +/$bucket_name +delete= +" +if [ "$has_content_md5" == "true" ]; then + canonical_request+="content-md5:$content_md5 +" +fi +canonical_request+="host:$host +x-amz-content-sha256:$payload_hash +x-amz-date:$current_date_time + +" +if [ "$has_content_md5" == "true" ]; then + canonical_request+="content-md5;" +fi +canonical_request+="host;x-amz-content-sha256;x-amz-date +$payload_hash" + +create_canonical_hash_sts_and_signature + +curl_command+=(curl -ks -w "\"%{http_code}\"" -X POST "$AWS_ENDPOINT_URL/$bucket_name?delete") +signed_headers="" +if [ "$has_content_md5" == "true" ]; then + signed_headers+="content-md5;" +fi +signed_headers+="host;x-amz-content-sha256;x-amz-date" +curl_command+=(-H "\"Authorization: AWS4-HMAC-SHA256 Credential=$aws_access_key_id/$year_month_day/$aws_region/s3/aws4_request,SignedHeaders=$signed_headers,Signature=$signature\"") +curl_command+=(-H "\"Content-Type: application/xml\"") +if [ "$has_content_md5" == "true" ]; then + curl_command+=(-H "\"content-md5: $content_md5\"") +fi +curl_command+=(-H "\"x-amz-content-sha256: $payload_hash\"" +-H "\"x-amz-date: $current_date_time\"") +curl_command+=(-o "$OUTPUT_FILE") +curl_command+=(-d "\"${payload//\"/\\\"}\"") +# shellcheck disable=SC2154 +eval "${curl_command[*]}" 2>&1 diff --git a/tests/test_rest.sh b/tests/test_rest.sh index c66f1d2..7a3c576 100755 --- a/tests/test_rest.sh +++ b/tests/test_rest.sh @@ -33,6 +33,7 @@ source ./tests/logger.sh source ./tests/setup.sh source ./tests/util/util_acl.sh source ./tests/util/util_attributes.sh +source ./tests/util/util_delete_object.sh source ./tests/util/util_head_object.sh source ./tests/util/util_legal_hold.sh source ./tests/util/util_list_buckets.sh @@ -545,3 +546,53 @@ export RUN_USERS=true run get_etag_attribute_rest "$BUCKET_ONE_NAME" "$test_file" "$expected_etag" assert_success } + +@test "REST - POST call on root endpoint" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1036" + fi + run delete_object_empty_bucket_check_error + assert_success +} + +@test "REST - delete objects - no content-md5 header" { + if [ "$DIRECT" != "true" ]; then + skip "https://github.com/versity/versitygw/issues/1040" + fi + run setup_bucket "s3api" "$BUCKET_ONE_NAME" + assert_success + + run delete_objects_no_content_md5_header "$BUCKET_ONE_NAME" + assert_success +} + +@test "REST - delete objects command" { + run setup_bucket "s3api" "$BUCKET_ONE_NAME" + assert_success + + test_file_one="test_file" + test_file_two="test_file_two" + run create_test_files "$test_file_one" "$test_file_two" + assert_success + + run put_object "s3api" "$TEST_FILE_FOLDER/$test_file_one" "$BUCKET_ONE_NAME" "$test_file_one" + assert_success + + run put_object "s3api" "$TEST_FILE_FOLDER/$test_file_two" "$BUCKET_ONE_NAME" "$test_file_two" + assert_success + + run verify_object_exists "$BUCKET_ONE_NAME" "$test_file_one" + assert_success + + run verify_object_exists "$BUCKET_ONE_NAME" "$test_file_two" + assert_success + + run delete_objects_verify_success "$BUCKET_ONE_NAME" "$test_file_one" "$test_file_two" + assert_success + + run verify_object_not_found "$BUCKET_ONE_NAME" "$test_file_one" + assert_success + + run verify_object_not_found "$BUCKET_ONE_NAME" "$test_file_two" + assert_success +} \ No newline at end of file diff --git a/tests/util/util_delete_object.sh b/tests/util/util_delete_object.sh index 2948eb5..2a9c34c 100644 --- a/tests/util/util_delete_object.sh +++ b/tests/util/util_delete_object.sh @@ -15,4 +15,82 @@ block_delete_object_without_permission() { return 1 fi return 0 -} \ No newline at end of file +} + +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 + if ! check_xml_element <(echo "$error") "MethodNotAllowed" "Code"; then + log 2 "Code mismatch" + return 1 + fi + if ! check_xml_element <(echo "$error") "POST" "Method"; then + log 2 "Method mismatch" + return 1 + fi + if ! check_xml_element <(echo "$error") "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_head_object.sh b/tests/util/util_head_object.sh index 82e6dcf..9bbf415 100644 --- a/tests/util/util_head_object.sh +++ b/tests/util/util_head_object.sh @@ -87,4 +87,36 @@ get_etag_rest() { log 5 "head object data: $(cat "$TEST_FILE_FOLDER/head_object.txt")" etag_value=$(grep "E[Tt]ag:" "$TEST_FILE_FOLDER/head_object.txt" | sed -n 's/E[Tt]ag: "\([^"]*\)"/\1/p' | tr -d '\r') echo "$etag_value" -} \ No newline at end of file +} + +verify_object_not_found() { + if [ $# -ne 2 ]; then + log 2 "'verify_object_not_found' requires bucket name, object key" + return 1 + fi + if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/result.txt" COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="$1" OBJECT_KEY="$2" ./tests/rest_scripts/head_object.sh); then + log 2 "error getting result: $result" + return 1 + fi + if [ "$result" != "404" ]; then + log 2 "expected '404', was '$result' ($(cat "$TEST_FILE_FOLDER/result.txt"))" + return 1 + fi + return 0 +} + +verify_object_exists() { + if [ $# -ne 2 ]; then + log 2 "'verify_object_not_found' requires bucket name, object key" + return 1 + fi + if ! result=$(OUTPUT_FILE="$TEST_FILE_FOLDER/result.txt" COMMAND_LOG="$COMMAND_LOG" BUCKET_NAME="$1" OBJECT_KEY="$2" ./tests/rest_scripts/head_object.sh); then + log 2 "error getting result: $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 +}