diff --git a/scripts/s3-tests/implemented_tests.txt b/scripts/s3-tests/implemented_tests.txt index a7e8af6c8..25567a480 100644 --- a/scripts/s3-tests/implemented_tests.txt +++ b/scripts/s3-tests/implemented_tests.txt @@ -23,8 +23,14 @@ # - SSE-KMS: KMS-related edge cases # - Bucket Policy: Multipart upload authorization, SSE condition keys # - Versioning: Concurrent multi-object delete +# - ACL: Bucket and Object ACL +# - Object Copy: Same/cross bucket, metadata, versioning +# - POST Object: HTML form upload +# - Raw requests: Authenticated and anonymous +# - Conditional writes: If-Match/If-None-Match for PUT/Copy +# - Atomic read/write: Concurrent read/write consistency # -# Total: 231 tests +# Total: 376 tests test_basic_key_count test_bucket_create_naming_bad_short_one @@ -281,3 +287,172 @@ test_versioning_obj_suspend_versions # Tenant and presigned tests test_object_presigned_put_object_with_acl_tenant + +# ACL tests (bucket and object) +test_access_bucket_private_object_private +test_access_bucket_private_object_publicread +test_access_bucket_private_object_publicreadwrite +test_access_bucket_private_objectv2_private +test_access_bucket_private_objectv2_publicread +test_access_bucket_private_objectv2_publicreadwrite +test_access_bucket_publicread_object_private +test_access_bucket_publicread_object_publicread +test_access_bucket_publicread_object_publicreadwrite +test_access_bucket_publicreadwrite_object_private +test_access_bucket_publicreadwrite_object_publicread +test_access_bucket_publicreadwrite_object_publicreadwrite +test_bucket_acl_canned +test_bucket_acl_canned_authenticatedread +test_bucket_acl_canned_during_create +test_bucket_acl_canned_private_to_private +test_bucket_acl_canned_publicreadwrite +test_bucket_acl_default +test_bucket_acl_grant_email +test_bucket_acl_grant_email_not_exist +test_bucket_acl_grant_nonexist_user +test_bucket_acl_grant_userid_fullcontrol +test_bucket_acl_grant_userid_read +test_bucket_acl_grant_userid_readacp +test_bucket_acl_grant_userid_write +test_bucket_acl_grant_userid_writeacp +test_bucket_acl_revoke_all +test_bucket_concurrent_set_canned_acl +test_object_acl +test_object_acl_canned +test_object_acl_canned_authenticatedread +test_object_acl_canned_bucketownerfullcontrol +test_object_acl_canned_bucketownerread +test_object_acl_canned_during_create +test_object_acl_canned_publicreadwrite +test_object_acl_default +test_object_acl_full_control_verify_attributes +test_object_acl_full_control_verify_owner +test_object_acl_read +test_object_acl_readacp +test_object_acl_write +test_object_acl_writeacp +test_object_anon_put +test_object_anon_put_write_access +test_put_bucket_acl_grant_group_read + +# Bucket creation and naming +test_bucket_create_exists +test_bucket_create_naming_bad_ip +test_bucket_create_naming_dns_long +test_bucket_create_special_key_names +test_bucket_recreate_not_overriding + +# ListObjects / ListObjectsV2 additional tests +test_bucket_list_delimiter_not_skip_special +test_bucket_list_delimiter_prefix +test_bucket_list_delimiter_prefix_underscore +test_bucket_list_many +test_bucket_list_maxkeys_one +test_bucket_list_objects_anonymous +test_bucket_list_objects_anonymous_fail +test_bucket_list_unordered +test_bucket_listv2_both_continuationtoken_startafter +test_bucket_listv2_delimiter_prefix +test_bucket_listv2_delimiter_prefix_underscore +test_bucket_listv2_many +test_bucket_listv2_maxkeys_one +test_bucket_listv2_objects_anonymous +test_bucket_listv2_objects_anonymous_fail +test_bucket_listv2_unordered + +# Object copy tests +test_object_copy_16m +test_object_copy_diff_bucket +test_object_copy_not_owned_bucket +test_object_copy_replacing_metadata +test_object_copy_retaining_metadata +test_object_copy_same_bucket +test_object_copy_to_itself +test_object_copy_to_itself_with_metadata +test_object_copy_verify_contenttype +test_object_copy_versioned_bucket +test_object_copy_versioned_url_encoding +test_object_copy_versioning_multipart_upload +test_object_copy_zero_size + +# Object content encoding +test_object_content_encoding_aws_chunked + +# Raw request tests +test_object_raw_authenticated +test_object_raw_authenticated_bucket_acl +test_object_raw_authenticated_bucket_gone +test_object_raw_authenticated_object_acl +test_object_raw_authenticated_object_gone +test_object_raw_get +test_object_raw_get_bucket_acl +test_object_raw_get_bucket_gone +test_object_raw_get_object_acl +test_object_raw_get_object_gone +test_object_raw_get_x_amz_expires_out_range_zero +test_object_raw_response_headers + +# POST Object tests +test_post_object_anonymous_request +test_post_object_authenticated_no_content_type +test_post_object_authenticated_request +test_post_object_authenticated_request_bad_access_key +test_post_object_case_insensitive_condition_fields +test_post_object_condition_is_case_sensitive +test_post_object_empty_conditions +test_post_object_escaped_field_values +test_post_object_expired_policy +test_post_object_expires_is_case_sensitive +test_post_object_ignored_header +test_post_object_invalid_access_key +test_post_object_invalid_content_length_argument +test_post_object_invalid_signature +test_post_object_missing_conditions_list +test_post_object_missing_content_length_argument +test_post_object_missing_expires_condition +test_post_object_missing_signature +test_post_object_no_key_specified +test_post_object_set_invalid_success_code +test_post_object_set_success_code +test_post_object_upload_larger_than_chunk +test_post_object_upload_size_below_minimum +test_post_object_upload_size_limit_exceeded +test_post_object_upload_size_rgw_chunk_size_bug +test_post_object_user_specified_header + +# Conditional GET additional tests +test_get_object_ifmatch_failed +test_get_object_ifmodifiedsince_failed +test_get_object_ifnonematch_failed +test_get_object_ifnonematch_good +test_get_object_ifunmodifiedsince_good + +# Conditional writes (If-Match/If-None-Match for PUT/COPY) +test_put_object_ifmatch_failed +test_put_object_ifmatch_good +test_put_object_ifmatch_nonexisted_failed +test_put_object_ifmatch_overwrite_existed_good +test_put_object_ifnonmatch_failed +test_put_object_ifnonmatch_good +test_put_object_ifnonmatch_nonexisted_good +test_put_object_ifnonmatch_overwrite_existed_failed + +# Multipart copy tests +test_multipart_copy_improper_range +test_multipart_copy_small +test_multipart_copy_special_names + +# Authentication tests +test_list_buckets_invalid_auth + +# Atomic read/write tests +test_atomic_read_1mb +test_atomic_read_4mb +test_atomic_read_8mb +test_atomic_write_1mb +test_atomic_write_4mb +test_atomic_write_8mb +test_atomic_dual_write_1mb +test_atomic_dual_write_4mb +test_atomic_dual_write_8mb +test_atomic_multipart_upload_write diff --git a/scripts/s3-tests/non_standard_tests.txt b/scripts/s3-tests/non_standard_tests.txt index c4b01aea2..c2c9ba1a5 100644 --- a/scripts/s3-tests/non_standard_tests.txt +++ b/scripts/s3-tests/non_standard_tests.txt @@ -8,75 +8,27 @@ # - fails_on_aws marker: Ceph-specific features # - X-RGW-* headers: Ceph proprietary headers # - allowUnordered: Ceph-specific query parameter -# - ACL tests: RustFS uses IAM policy-based access control # - CORS tests: Not implemented -# - POST Object: HTML form upload not implemented +# - Bucket Logging: Ceph-specific logging extensions +# - Object Lock: Ceph-specific lock behavior differences +# - Lifecycle: Ceph-specific lifecycle expiration behavior +# - SSE-KMS: Ceph-specific KMS extensions # - Error format differences: Minor response format variations -# -# Total: non-standard tests listed below test_100_continue test_100_continue_error_retry test_abort_multipart_upload_not_found -test_access_bucket_private_object_private -test_access_bucket_private_object_publicread -test_access_bucket_private_object_publicreadwrite -test_access_bucket_private_objectv2_private -test_access_bucket_private_objectv2_publicread -test_access_bucket_private_objectv2_publicreadwrite -test_access_bucket_publicread_object_private -test_access_bucket_publicread_object_publicread -test_access_bucket_publicread_object_publicreadwrite -test_access_bucket_publicreadwrite_object_private -test_access_bucket_publicreadwrite_object_publicread -test_access_bucket_publicreadwrite_object_publicreadwrite test_account_usage test_atomic_conditional_write_1mb test_atomic_dual_conditional_write_1mb test_atomic_write_bucket_gone test_block_public_restrict_public_buckets -test_bucket_acl_canned -test_bucket_acl_canned_authenticatedread -test_bucket_acl_canned_during_create -test_bucket_acl_canned_private_to_private -test_bucket_acl_canned_publicreadwrite -test_bucket_acl_default -test_bucket_acl_grant_email -test_bucket_acl_grant_email_not_exist -test_bucket_acl_grant_nonexist_user -test_bucket_acl_grant_userid_fullcontrol -test_bucket_acl_grant_userid_read -test_bucket_acl_grant_userid_readacp -test_bucket_acl_grant_userid_write -test_bucket_acl_grant_userid_writeacp -test_bucket_acl_revoke_all -test_bucket_concurrent_set_canned_acl -test_bucket_create_exists test_bucket_create_exists_nonowner -test_bucket_create_naming_bad_ip -test_bucket_create_naming_dns_long -test_bucket_create_special_key_names test_bucket_get_location test_bucket_head_extended test_bucket_header_acl_grants -test_bucket_list_delimiter_not_skip_special -test_bucket_list_delimiter_prefix -test_bucket_list_delimiter_prefix_underscore -test_bucket_list_many -test_bucket_list_maxkeys_one -test_bucket_list_objects_anonymous -test_bucket_list_objects_anonymous_fail test_bucket_list_return_data test_bucket_list_return_data_versioning -test_bucket_list_unordered -test_bucket_listv2_both_continuationtoken_startafter -test_bucket_listv2_delimiter_prefix -test_bucket_listv2_delimiter_prefix_underscore -test_bucket_listv2_many -test_bucket_listv2_maxkeys_one -test_bucket_listv2_objects_anonymous -test_bucket_listv2_objects_anonymous_fail -test_bucket_listv2_unordered test_bucket_logging_bucket_acl_required test_bucket_logging_bucket_auth_type test_bucket_logging_cleanup_bucket_concurrent_deletion_j @@ -189,7 +141,6 @@ test_bucket_policy_put_obj_tagging_existing_tag test_bucket_policy_set_condition_operator_end_with_IfExists test_bucket_policy_upload_part_copy test_bucket_recreate_new_acl -test_bucket_recreate_not_overriding test_bucket_recreate_overwrite_acl test_copy_object_ifmatch_failed test_copy_object_ifmatch_good @@ -250,11 +201,6 @@ test_get_multipart_checksum_object_attributes test_get_multipart_object_attributes test_get_obj_tagging test_get_object_attributes -test_get_object_ifmatch_failed -test_get_object_ifmodifiedsince_failed -test_get_object_ifnonematch_failed -test_get_object_ifnonematch_good -test_get_object_ifunmodifiedsince_good test_get_paginated_multipart_object_attributes test_get_single_multipart_object_attributes test_get_sse_c_encrypted_object_attributes @@ -286,16 +232,12 @@ test_lifecycle_transition test_lifecycle_transition_single_rule_multi_trans test_lifecyclev2_expiration test_list_buckets_anonymous -test_list_buckets_invalid_auth test_list_buckets_paginated test_list_multipart_upload test_list_multipart_upload_owner test_multipart_checksum_sha256 -test_multipart_copy_improper_range test_multipart_copy_invalid_range test_multipart_copy_multiple_sizes -test_multipart_copy_small -test_multipart_copy_special_names test_multipart_copy_versioned test_multipart_get_part test_multipart_put_current_object_if_match @@ -314,37 +256,7 @@ test_multipart_use_cksum_helper_sha1 test_multipart_use_cksum_helper_sha256 test_non_multipart_get_part test_non_multipart_sse_c_get_part -test_object_acl -test_object_acl_canned -test_object_acl_canned_authenticatedread -test_object_acl_canned_bucketownerfullcontrol -test_object_acl_canned_bucketownerread -test_object_acl_canned_during_create -test_object_acl_canned_publicreadwrite -test_object_acl_default -test_object_acl_full_control_verify_attributes -test_object_acl_full_control_verify_owner -test_object_acl_read -test_object_acl_readacp -test_object_acl_write -test_object_acl_writeacp -test_object_anon_put -test_object_anon_put_write_access -test_object_content_encoding_aws_chunked -test_object_copy_16m test_object_copy_canned_acl -test_object_copy_diff_bucket -test_object_copy_not_owned_bucket -test_object_copy_replacing_metadata -test_object_copy_retaining_metadata -test_object_copy_same_bucket -test_object_copy_to_itself -test_object_copy_to_itself_with_metadata -test_object_copy_verify_contenttype -test_object_copy_versioned_bucket -test_object_copy_versioned_url_encoding -test_object_copy_versioning_multipart_upload -test_object_copy_zero_size test_object_delete_key_bucket_gone test_object_header_acl_grants test_object_lock_changing_mode_from_compliance @@ -379,63 +291,24 @@ test_object_lock_put_obj_retention_shorten_period_bypass test_object_lock_put_obj_retention_versionid test_object_lock_suspend_versioning test_object_lock_uploading_obj -test_object_raw_authenticated -test_object_raw_authenticated_bucket_acl -test_object_raw_authenticated_bucket_gone -test_object_raw_authenticated_object_acl -test_object_raw_authenticated_object_gone -test_object_raw_get -test_object_raw_get_bucket_acl -test_object_raw_get_bucket_gone -test_object_raw_get_object_acl -test_object_raw_get_object_gone test_object_raw_get_x_amz_expires_not_expired test_object_raw_get_x_amz_expires_not_expired_tenant test_object_raw_get_x_amz_expires_out_max_range test_object_raw_get_x_amz_expires_out_positive_range -test_object_raw_get_x_amz_expires_out_range_zero test_object_raw_put_authenticated_expired -test_object_raw_response_headers test_object_read_unreadable test_object_requestid_matches_header_on_error test_object_set_get_unicode_metadata test_object_write_with_chunked_transfer_encoding -test_post_object_anonymous_request -test_post_object_authenticated_no_content_type -test_post_object_authenticated_request -test_post_object_authenticated_request_bad_access_key -test_post_object_case_insensitive_condition_fields -test_post_object_condition_is_case_sensitive -test_post_object_empty_conditions -test_post_object_escaped_field_values -test_post_object_expired_policy -test_post_object_expires_is_case_sensitive -test_post_object_ignored_header -test_post_object_invalid_access_key -test_post_object_invalid_content_length_argument test_post_object_invalid_date_format test_post_object_invalid_request_field_value -test_post_object_invalid_signature -test_post_object_missing_conditions_list -test_post_object_missing_content_length_argument -test_post_object_missing_expires_condition test_post_object_missing_policy_condition -test_post_object_missing_signature -test_post_object_no_key_specified test_post_object_request_missing_policy_specified_field -test_post_object_set_invalid_success_code test_post_object_set_key_from_filename -test_post_object_set_success_code test_post_object_success_redirect_action test_post_object_tags_anonymous_request test_post_object_tags_authenticated_request -test_post_object_upload_larger_than_chunk -test_post_object_upload_size_below_minimum -test_post_object_upload_size_limit_exceeded -test_post_object_upload_size_rgw_chunk_size_bug -test_post_object_user_specified_header test_post_object_wrong_bucket -test_put_bucket_acl_grant_group_read test_put_bucket_logging_account_j test_put_bucket_logging_account_s test_put_bucket_logging_extensions @@ -453,14 +326,6 @@ test_put_modify_tags test_put_obj_with_tags test_put_object_current_if_match test_put_object_if_match -test_put_object_ifmatch_failed -test_put_object_ifmatch_good -test_put_object_ifmatch_nonexisted_failed -test_put_object_ifmatch_overwrite_existed_good -test_put_object_ifnonmatch_failed -test_put_object_ifnonmatch_good -test_put_object_ifnonmatch_nonexisted_good -test_put_object_ifnonmatch_overwrite_existed_failed test_put_tags_acl_public test_ranged_big_request_response_code test_ranged_request_response_code diff --git a/scripts/s3-tests/run.sh b/scripts/s3-tests/run.sh index 8bf9c304c..2769c7bed 100755 --- a/scripts/s3-tests/run.sh +++ b/scripts/s3-tests/run.sh @@ -120,8 +120,13 @@ fi # ============================================================================= # TESTEXPR: pytest -k expression to select specific tests # ============================================================================= -# By default, builds an inclusion expression from implemented_tests.txt. -# Use TESTEXPR env var to override with custom selection. +# By default, builds an inclusion expression from implemented_tests.txt, +# combined with an exclusion expression from non_standard_tests.txt and +# unimplemented_tests.txt to prevent substring-matching collisions. +# +# For example, "test_object_raw_get" in the include list would also match +# "test_object_raw_get_x_amz_expires_not_expired" via pytest -k substring +# matching. The exclusion guard ensures only intended tests run. # # The file-based approach provides: # 1. Clear visibility of which tests are run @@ -131,18 +136,38 @@ fi if [[ -z "${TESTEXPR:-}" ]]; then if [[ -f "${IMPLEMENTED_TESTS_FILE}" ]]; then log_info "Loading test list from: ${IMPLEMENTED_TESTS_FILE}" - TESTEXPR=$(build_testexpr_from_file "${IMPLEMENTED_TESTS_FILE}") - if [[ -z "${TESTEXPR}" ]]; then + INCLUDE_EXPR=$(build_testexpr_from_file "${IMPLEMENTED_TESTS_FILE}") + if [[ -z "${INCLUDE_EXPR}" ]]; then log_error "No tests found in ${IMPLEMENTED_TESTS_FILE}" exit 1 fi - # Count tests for logging TEST_COUNT=$(grep -v '^#' "${IMPLEMENTED_TESTS_FILE}" | grep -v '^[[:space:]]*$' | wc -l | xargs) log_info "Loaded ${TEST_COUNT} tests from implemented_tests.txt" + + # Build exclusion expression from non-standard and unimplemented lists + # to guard against pytest -k substring matching false positives + EXCLUDE_EXPR="" + for exclude_file in "${NON_STANDARD_TESTS_FILE}" "${UNIMPLEMENTED_TESTS_FILE}"; do + if [[ -f "${exclude_file}" ]]; then + FILE_EXPR=$(build_testexpr_from_file "${exclude_file}") + if [[ -n "${FILE_EXPR}" ]]; then + if [[ -n "${EXCLUDE_EXPR}" ]]; then + EXCLUDE_EXPR+=" or " + fi + EXCLUDE_EXPR+="${FILE_EXPR}" + fi + fi + done + + if [[ -n "${EXCLUDE_EXPR}" ]]; then + TESTEXPR="(${INCLUDE_EXPR}) and not (${EXCLUDE_EXPR})" + log_info "Added exclusion guard from non_standard + unimplemented lists" + else + TESTEXPR="${INCLUDE_EXPR}" + fi else log_warn "Test list file not found: ${IMPLEMENTED_TESTS_FILE}" log_warn "Falling back to exclusion-based filtering" - # Fallback to exclusion-based filtering if file doesn't exist EXCLUDED_TESTS=( "test_post_object" "test_bucket_list_objects_anonymous" diff --git a/scripts/s3-tests/unimplemented_tests.txt b/scripts/s3-tests/unimplemented_tests.txt index 6c4f78b9a..ac69fa9d0 100644 --- a/scripts/s3-tests/unimplemented_tests.txt +++ b/scripts/s3-tests/unimplemented_tests.txt @@ -8,10 +8,9 @@ # - Bucket Logging: Access logging # - Object Lock: Enable after create # - Checksum: Full checksum validation -# - Conditional writes: If-Match/If-None-Match for writes # - Bucket Ownership Controls -# Failed tests (11) +# Failed tests test_bucket_create_delete_bucket_ownership test_bucket_logging_owner test_object_checksum_crc64nvme @@ -31,18 +30,6 @@ test_lifecycle_plain_null_version_current_transition test_lifecycle_set_noncurrent_transition test_lifecycle_transition_encrypted -# Checksum and atomic write tests (require x-amz-checksum-* support) -test_atomic_dual_write_1mb -test_atomic_dual_write_4mb -test_atomic_dual_write_8mb -test_atomic_multipart_upload_write -test_atomic_read_1mb -test_atomic_read_4mb -test_atomic_read_8mb -test_atomic_write_1mb -test_atomic_write_4mb -test_atomic_write_8mb - # Tests with known issues (need further investigation) test_bucket_policy_different_tenant test_bucket_policy_put_obj_grant