diff --git a/scripts/s3-tests/README.md b/scripts/s3-tests/README.md index b4f4c496e..5a4e25719 100644 --- a/scripts/s3-tests/README.md +++ b/scripts/s3-tests/README.md @@ -144,9 +144,11 @@ DEPLOY_MODE=existing S3_HOST=192.168.1.100 S3_PORT=9000 ./scripts/s3-tests/run.s - `MAXFAIL`: Stop after N failures (default: `1`) - `XDIST`: Enable parallel execution with N workers (default: `0`, disabled) - `MARKEXPR`: pytest marker expression for filtering tests - - Default: `not lifecycle and not versioning and not s3website and not bucket_logging and not encryption` - - Excludes features not yet supported by RustFS to reduce test execution time - - Can be customized to test specific features or remove exclusions + - Default: no marker filtering; file-based test lists control the selected tests + - Can be customized to test specific marker groups +- `TESTEXPR`: optional pytest `-k` expression for custom runs + - Default: exact pytest node ids loaded from `implemented_tests.txt` + - Setting `TESTEXPR` overrides the implemented test list ### Configuration Files @@ -182,9 +184,6 @@ DATA_ROOT=/tmp ./scripts/s3-tests/run.sh # Run specific test markers (e.g., test multipart uploads only) MARKEXPR="multipart" ./scripts/s3-tests/run.sh - -# Remove feature exclusions (test all features, including unsupported ones) -MARKEXPR="" ./scripts/s3-tests/run.sh ``` ### Binary File Mode diff --git a/scripts/s3-tests/excluded_tests.txt b/scripts/s3-tests/excluded_tests.txt index eb4bbbd39..a5ac96e19 100644 --- a/scripts/s3-tests/excluded_tests.txt +++ b/scripts/s3-tests/excluded_tests.txt @@ -122,18 +122,13 @@ test_bucket_policy_get_obj_existing_tag test_bucket_policy_get_obj_tagging_existing_tag test_bucket_policy_put_obj_copy_source test_bucket_policy_put_obj_copy_source_meta -test_bucket_policy_put_obj_kms_noenc test_bucket_policy_put_obj_request_obj_tag -test_bucket_policy_put_obj_s3_incorrect_algo_sse_s3 -test_bucket_policy_put_obj_s3_noenc 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_overwrite_acl test_copy_object_ifmatch_failed -test_copy_object_ifmatch_good -test_copy_object_ifnonematch_failed test_copy_object_ifnonematch_good test_cors_presigned_get_object_tenant_v2 test_cors_presigned_get_object_v2 @@ -164,27 +159,11 @@ test_delete_objects_if_match_size test_delete_objects_version_if_match test_delete_objects_version_if_match_last_modified_time test_delete_objects_version_if_match_size -test_delete_tags_obj_public -test_encrypted_transfer_13b -test_encrypted_transfer_1MB -test_encrypted_transfer_1b -test_encrypted_transfer_1kb -test_encryption_sse_c_deny_algo_with_bucket_policy -test_encryption_sse_c_enforced_with_bucket_policy test_encryption_sse_c_multipart_invalid_chunks_1 test_encryption_sse_c_multipart_invalid_chunks_2 test_encryption_sse_c_multipart_upload -test_encryption_sse_c_post_object_authenticated_request test_encryption_sse_c_unaligned_multipart_upload -test_expected_bucket_owner test_get_multipart_checksum_object_attributes -test_get_multipart_object_attributes -test_get_obj_tagging -test_get_object_attributes -test_get_paginated_multipart_object_attributes -test_get_single_multipart_object_attributes -test_get_sse_c_encrypted_object_attributes -test_get_tags_acl_public test_head_bucket_usage test_lifecycle_cloud_multiple_transition test_lifecycle_cloud_transition @@ -193,7 +172,8 @@ test_lifecycle_deletemarker_expiration test_lifecycle_deletemarker_expiration_with_days_tag test_lifecycle_expiration test_lifecycle_expiration_date -test_lifecycle_expiration_header_and_tags_head +test_lifecycle_expiration_days0 +test_lifecycle_expiration_header_put test_lifecycle_expiration_header_head test_lifecycle_expiration_header_tags_head test_lifecycle_expiration_newer_noncurrent @@ -215,18 +195,10 @@ test_list_buckets_anonymous test_list_buckets_paginated test_list_multipart_upload test_list_multipart_upload_owner -test_multipart_checksum_sha256 -test_multipart_copy_multiple_sizes -test_multipart_copy_versioned test_multipart_get_part -test_multipart_put_current_object_if_match -test_multipart_put_current_object_if_none_match -test_multipart_put_object_if_match test_multipart_single_get_part test_multipart_sse_c_get_part test_multipart_upload -test_multipart_upload_contents -test_multipart_upload_resend_part test_multipart_upload_small test_multipart_use_cksum_helper_crc32 test_multipart_use_cksum_helper_crc32c @@ -235,10 +207,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_copy_canned_acl test_object_header_acl_grants -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_put_authenticated_expired @@ -263,54 +232,16 @@ test_put_bucket_logging_tenant_s test_put_bucket_ownership_bucket_owner_enforced test_put_bucket_ownership_bucket_owner_preferred test_put_bucket_ownership_object_writer -test_put_current_object_if_match -test_put_current_object_if_none_match -test_put_delete_tags -test_put_max_tags -test_put_modify_tags -test_put_obj_with_tags test_put_object_current_if_match -test_put_object_if_match -test_put_tags_acl_public -test_ranged_big_request_response_code -test_ranged_request_response_code -test_ranged_request_return_trailing_bytes_response_code -test_ranged_request_skip_leading_bytes_response_code test_read_through test_restore_noncur_obj test_restore_object_permanent test_restore_object_temporary -test_sse_kms_default_post_object_authenticated_request -test_sse_kms_default_upload_1b -test_sse_kms_default_upload_1kb -test_sse_kms_default_upload_1mb -test_sse_kms_default_upload_8mb -test_sse_kms_method_head -test_sse_kms_multipart_invalid_chunks_1 -test_sse_kms_multipart_invalid_chunks_2 test_sse_kms_multipart_upload test_sse_kms_post_object_authenticated_request -test_sse_kms_present -test_sse_kms_transfer_13b -test_sse_kms_transfer_1MB -test_sse_kms_transfer_1b -test_sse_kms_transfer_1kb -test_sse_s3_default_method_head test_sse_s3_default_multipart_upload -test_sse_s3_default_post_object_authenticated_request -test_sse_s3_default_upload_1b -test_sse_s3_default_upload_1kb -test_sse_s3_default_upload_1mb -test_sse_s3_default_upload_8mb -test_sse_s3_encrypted_upload_1b -test_sse_s3_encrypted_upload_1kb -test_sse_s3_encrypted_upload_1mb -test_sse_s3_encrypted_upload_8mb test_versioned_object_acl_no_version_specified -test_versioning_copy_obj_version test_versioning_multi_object_delete_with_marker_create -test_versioning_obj_create_overwrite_multipart -test_versioning_obj_suspended_copy test_versioning_stack_delete_merkers # Intentionally unsupported by design: ACL-related tests diff --git a/scripts/s3-tests/implemented_tests.txt b/scripts/s3-tests/implemented_tests.txt index ec6f19e67..a9ddbe1ed 100644 --- a/scripts/s3-tests/implemented_tests.txt +++ b/scripts/s3-tests/implemented_tests.txt @@ -19,8 +19,6 @@ # - Conditional GET: If-Match, If-None-Match, If-Modified-Since # # - SSE-C: Server-side encryption with customer-provided keys -# - Object ownership: Bucket ownership controls -# # - SSE-KMS: KMS-related edge cases # - Bucket Policy: Multipart upload authorization, SSE condition keys, grant header conditions # - Versioning: Concurrent multi-object delete @@ -157,7 +155,6 @@ test_ranged_request_empty_object test_ranged_request_invalid_range test_set_multipart_tagging test_upload_part_copy_percent_encoded_key -test_api_error_from_storage_error_mappings test_get_object_torrent # Object attributes @@ -219,9 +216,6 @@ test_bucket_policy_allow_notprincipal test_bucket_policy_put_obj_kms_s3 test_bucket_policy_put_obj_s3_kms -# Object ownership -test_create_bucket_no_ownership_controls - # Bucket encryption test_put_bucket_encryption_kms test_put_bucket_encryption_s3 @@ -229,11 +223,8 @@ test_get_bucket_encryption_kms test_get_bucket_encryption_s3 test_delete_bucket_encryption_kms test_delete_bucket_encryption_s3 -test_lifecycle_expiration_days0 - # Lifecycle tests test_lifecycle_delete -test_lifecycle_expiration_header_put test_lifecycle_get test_lifecycle_get_no_id test_lifecycle_id_too_long @@ -310,7 +301,6 @@ 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 @@ -443,3 +433,78 @@ test_object_delete_key_bucket_gone # Multipart copy range validation test_multipart_copy_invalid_range + +# Reclassified standard tests +test_bucket_policy_put_obj_kms_noenc +test_bucket_policy_put_obj_s3_incorrect_algo_sse_s3 +test_bucket_policy_put_obj_s3_noenc +test_copy_object_ifmatch_good +test_copy_object_ifnonematch_failed +test_delete_tags_obj_public +test_encrypted_transfer_13b +test_encrypted_transfer_1MB +test_encrypted_transfer_1b +test_encrypted_transfer_1kb +test_encryption_sse_c_deny_algo_with_bucket_policy +test_encryption_sse_c_enforced_with_bucket_policy +test_encryption_sse_c_post_object_authenticated_request +test_expected_bucket_owner +test_get_multipart_object_attributes +test_get_obj_tagging +test_get_object_attributes +test_get_paginated_multipart_object_attributes +test_get_single_multipart_object_attributes +test_get_sse_c_encrypted_object_attributes +test_get_tags_acl_public +test_lifecycle_expiration_header_and_tags_head +test_multipart_checksum_sha256 +test_multipart_copy_multiple_sizes +test_multipart_copy_versioned +test_multipart_put_current_object_if_match +test_multipart_put_current_object_if_none_match +test_multipart_put_object_if_match +test_multipart_upload_contents +test_multipart_upload_resend_part +test_object_copy_canned_acl +test_object_raw_get_x_amz_expires_not_expired +test_object_raw_get_x_amz_expires_not_expired_tenant +test_put_current_object_if_match +test_put_current_object_if_none_match +test_put_delete_tags +test_put_max_tags +test_put_modify_tags +test_put_obj_with_tags +test_put_object_if_match +test_put_tags_acl_public +test_ranged_big_request_response_code +test_ranged_request_response_code +test_ranged_request_return_trailing_bytes_response_code +test_ranged_request_skip_leading_bytes_response_code +test_sse_kms_default_post_object_authenticated_request +test_sse_kms_default_upload_1b +test_sse_kms_default_upload_1kb +test_sse_kms_default_upload_1mb +test_sse_kms_default_upload_8mb +test_sse_kms_method_head +test_sse_kms_multipart_invalid_chunks_1 +test_sse_kms_multipart_invalid_chunks_2 +test_sse_kms_present +test_sse_kms_transfer_13b +test_sse_kms_transfer_1MB +test_sse_kms_transfer_1b +test_sse_kms_transfer_1kb +test_sse_s3_default_method_head +test_sse_s3_default_post_object_authenticated_request +test_sse_s3_default_upload_1b +test_sse_s3_default_upload_1kb +test_sse_s3_default_upload_1mb +test_sse_s3_default_upload_8mb +test_sse_s3_encrypted_upload_1b +test_sse_s3_encrypted_upload_1kb +test_sse_s3_encrypted_upload_1mb +test_sse_s3_encrypted_upload_8mb +test_versioning_copy_obj_version +test_versioning_obj_create_overwrite_multipart +test_versioning_obj_suspended_copy +test_rm_bucket_logging +test_versioned_concurrent_object_create_concurrent_remove diff --git a/scripts/s3-tests/non_standard_tests.txt b/scripts/s3-tests/non_standard_tests.txt index a04f5e36a..2f49e4870 100644 --- a/scripts/s3-tests/non_standard_tests.txt +++ b/scripts/s3-tests/non_standard_tests.txt @@ -10,7 +10,6 @@ # - X-RGW-* headers: Ceph proprietary headers # - allowUnordered: Ceph-specific query parameter # - 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 @@ -129,18 +128,13 @@ test_bucket_policy_get_obj_existing_tag test_bucket_policy_get_obj_tagging_existing_tag test_bucket_policy_put_obj_copy_source test_bucket_policy_put_obj_copy_source_meta -test_bucket_policy_put_obj_kms_noenc test_bucket_policy_put_obj_request_obj_tag -test_bucket_policy_put_obj_s3_incorrect_algo_sse_s3 -test_bucket_policy_put_obj_s3_noenc 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_overwrite_acl test_copy_object_ifmatch_failed -test_copy_object_ifmatch_good -test_copy_object_ifnonematch_failed test_copy_object_ifnonematch_good test_cors_presigned_get_object_tenant_v2 test_cors_presigned_get_object_v2 @@ -171,27 +165,11 @@ test_delete_objects_if_match_size test_delete_objects_version_if_match test_delete_objects_version_if_match_last_modified_time test_delete_objects_version_if_match_size -test_delete_tags_obj_public -test_encrypted_transfer_13b -test_encrypted_transfer_1MB -test_encrypted_transfer_1b -test_encrypted_transfer_1kb -test_encryption_sse_c_deny_algo_with_bucket_policy -test_encryption_sse_c_enforced_with_bucket_policy test_encryption_sse_c_multipart_invalid_chunks_1 test_encryption_sse_c_multipart_invalid_chunks_2 test_encryption_sse_c_multipart_upload -test_encryption_sse_c_post_object_authenticated_request test_encryption_sse_c_unaligned_multipart_upload -test_expected_bucket_owner test_get_multipart_checksum_object_attributes -test_get_multipart_object_attributes -test_get_obj_tagging -test_get_object_attributes -test_get_paginated_multipart_object_attributes -test_get_single_multipart_object_attributes -test_get_sse_c_encrypted_object_attributes -test_get_tags_acl_public test_head_bucket_usage test_lifecycle_cloud_multiple_transition test_lifecycle_cloud_transition @@ -200,7 +178,8 @@ test_lifecycle_deletemarker_expiration test_lifecycle_deletemarker_expiration_with_days_tag test_lifecycle_expiration test_lifecycle_expiration_date -test_lifecycle_expiration_header_and_tags_head +test_lifecycle_expiration_days0 +test_lifecycle_expiration_header_put test_lifecycle_expiration_header_head test_lifecycle_expiration_header_tags_head test_lifecycle_expiration_newer_noncurrent @@ -222,18 +201,10 @@ test_list_buckets_anonymous test_list_buckets_paginated test_list_multipart_upload test_list_multipart_upload_owner -test_multipart_checksum_sha256 -test_multipart_copy_multiple_sizes -test_multipart_copy_versioned test_multipart_get_part -test_multipart_put_current_object_if_match -test_multipart_put_current_object_if_none_match -test_multipart_put_object_if_match test_multipart_single_get_part test_multipart_sse_c_get_part test_multipart_upload -test_multipart_upload_contents -test_multipart_upload_resend_part test_multipart_upload_small test_multipart_use_cksum_helper_crc32 test_multipart_use_cksum_helper_crc32c @@ -242,42 +213,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_copy_canned_acl test_object_header_acl_grants -test_object_lock_changing_mode_from_compliance -test_object_lock_changing_mode_from_governance_with_bypass -test_object_lock_changing_mode_from_governance_without_bypass -test_object_lock_delete_multipart_object_with_legal_hold_on -test_object_lock_delete_multipart_object_with_retention -test_object_lock_delete_object_with_legal_hold_off -test_object_lock_delete_object_with_legal_hold_on -test_object_lock_delete_object_with_retention -test_object_lock_delete_object_with_retention_and_marker -test_object_lock_get_legal_hold -test_object_lock_get_obj_lock -test_object_lock_get_obj_metadata -test_object_lock_get_obj_retention -test_object_lock_get_obj_retention_iso8601 -test_object_lock_multi_delete_object_with_retention -test_object_lock_put_legal_hold -test_object_lock_put_legal_hold_invalid_status -test_object_lock_put_obj_lock -test_object_lock_put_obj_lock_invalid_days -test_object_lock_put_obj_lock_invalid_mode -test_object_lock_put_obj_lock_invalid_status -test_object_lock_put_obj_lock_invalid_years -test_object_lock_put_obj_lock_with_days_and_years -test_object_lock_put_obj_retention -test_object_lock_put_obj_retention_increase_period -test_object_lock_put_obj_retention_invalid_mode -test_object_lock_put_obj_retention_override_default_retention -test_object_lock_put_obj_retention_shorten_period -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_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_put_authenticated_expired @@ -302,52 +238,14 @@ test_put_bucket_logging_tenant_s test_put_bucket_ownership_bucket_owner_enforced test_put_bucket_ownership_bucket_owner_preferred test_put_bucket_ownership_object_writer -test_put_current_object_if_match -test_put_current_object_if_none_match -test_put_delete_tags -test_put_max_tags -test_put_modify_tags -test_put_obj_with_tags test_put_object_current_if_match -test_put_object_if_match -test_put_tags_acl_public -test_ranged_big_request_response_code -test_ranged_request_response_code -test_ranged_request_return_trailing_bytes_response_code -test_ranged_request_skip_leading_bytes_response_code test_read_through test_restore_noncur_obj test_restore_object_permanent test_restore_object_temporary -test_sse_kms_default_post_object_authenticated_request -test_sse_kms_default_upload_1b -test_sse_kms_default_upload_1kb -test_sse_kms_default_upload_1mb -test_sse_kms_default_upload_8mb -test_sse_kms_method_head -test_sse_kms_multipart_invalid_chunks_1 -test_sse_kms_multipart_invalid_chunks_2 test_sse_kms_multipart_upload test_sse_kms_post_object_authenticated_request -test_sse_kms_present -test_sse_kms_transfer_13b -test_sse_kms_transfer_1MB -test_sse_kms_transfer_1b -test_sse_kms_transfer_1kb -test_sse_s3_default_method_head test_sse_s3_default_multipart_upload -test_sse_s3_default_post_object_authenticated_request -test_sse_s3_default_upload_1b -test_sse_s3_default_upload_1kb -test_sse_s3_default_upload_1mb -test_sse_s3_default_upload_8mb -test_sse_s3_encrypted_upload_1b -test_sse_s3_encrypted_upload_1kb -test_sse_s3_encrypted_upload_1mb -test_sse_s3_encrypted_upload_8mb test_versioned_object_acl_no_version_specified -test_versioning_copy_obj_version test_versioning_multi_object_delete_with_marker_create -test_versioning_obj_create_overwrite_multipart -test_versioning_obj_suspended_copy test_versioning_stack_delete_merkers diff --git a/scripts/s3-tests/run.sh b/scripts/s3-tests/run.sh index ced0ecbb6..5090b6dba 100755 --- a/scripts/s3-tests/run.sh +++ b/scripts/s3-tests/run.sh @@ -78,17 +78,20 @@ TEST_LISTS_DIR="${SCRIPT_DIR}" IMPLEMENTED_TESTS_FILE="${TEST_LISTS_DIR}/implemented_tests.txt" UNIMPLEMENTED_TESTS_FILE="${TEST_LISTS_DIR}/unimplemented_tests.txt" EXCLUDED_TESTS_FILE="${TEST_LISTS_DIR}/excluded_tests.txt" -LEGACY_NON_STANDARD_TESTS_FILE="${TEST_LISTS_DIR}/non_standard_tests.txt" +S3_TEST_FILE="s3tests/functional/test_s3.py" # ============================================================================= -# build_testexpr_from_file: Read test names from file and build pytest -k expr +# load_testnodes_from_file: Read test names and build exact pytest node ids # ============================================================================= -# Reads test names from a file (one per line, ignoring comments and empty lines) -# and builds a pytest -k expression to include only those tests. +# Pytest -k matches substrings, so similar test names can accidentally include or +# exclude each other. The default file-based path uses exact node ids instead. # ============================================================================= -build_testexpr_from_file() { +TEST_NODE_ARGS=() +USE_FILE_TEST_NODES=false + +load_testnodes_from_file() { local file="$1" - local expr="" + local line="" if [[ ! -f "${file}" ]]; then log_error "Test list file not found: ${file}" @@ -102,36 +105,27 @@ build_testexpr_from_file() { line=$(echo "$line" | xargs) [[ -z "$line" ]] && continue - if [[ -n "${expr}" ]]; then - expr+=" or " - fi - expr+="${line}" + TEST_NODE_ARGS+=("${S3_TEST_FILE}::${line}") done < "${file}" - - echo "${expr}" } # ============================================================================= -# MARKEXPR: pytest marker expression (safety net for marker-based filtering) +# MARKEXPR: pytest marker expression # ============================================================================= -# Even though we use file-based test selection, we keep marker exclusions -# as a safety net to ensure excluded tests do not slip through. +# File-based test selection is authoritative. Keep the default marker expression +# non-restrictive so implemented tests that carry upstream compatibility markers +# are still run when they are listed in implemented_tests.txt. # ============================================================================= if [[ -z "${MARKEXPR:-}" ]]; then - # Minimal marker exclusions as safety net (file-based filtering is primary) - MARKEXPR="not fails_on_aws and not fails_on_rgw and not fails_on_dbstore" + # Valid pytest -m expression that does not match any real marker. + MARKEXPR="not rustfs_never_marker" fi # ============================================================================= -# TESTEXPR: pytest -k expression to select specific tests +# TESTEXPR: optional pytest -k expression to select specific tests # ============================================================================= -# By default, builds an inclusion expression from implemented_tests.txt, -# combined with an exclusion expression from excluded_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. +# By default, loads exact pytest node ids from implemented_tests.txt. +# Set TESTEXPR to override this with a custom pytest -k expression. # # The file-based approach provides: # 1. Clear visibility of which tests are run @@ -141,41 +135,14 @@ fi if [[ -z "${TESTEXPR:-}" ]]; then if [[ -f "${IMPLEMENTED_TESTS_FILE}" ]]; then log_info "Loading test list from: ${IMPLEMENTED_TESTS_FILE}" - INCLUDE_EXPR=$(build_testexpr_from_file "${IMPLEMENTED_TESTS_FILE}") - if [[ -z "${INCLUDE_EXPR}" ]]; then + load_testnodes_from_file "${IMPLEMENTED_TESTS_FILE}" + TEST_COUNT="${#TEST_NODE_ARGS[@]}" + if [[ "${TEST_COUNT}" -eq 0 ]]; then log_error "No tests found in ${IMPLEMENTED_TESTS_FILE}" exit 1 fi - 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 excluded and unimplemented lists - # to guard against pytest -k substring matching false positives - EXCLUDE_EXPR="" - EXCLUDE_FILES=("${EXCLUDED_TESTS_FILE}" "${UNIMPLEMENTED_TESTS_FILE}") - if [[ ! -f "${EXCLUDED_TESTS_FILE}" && -f "${LEGACY_NON_STANDARD_TESTS_FILE}" ]]; then - log_warn "excluded_tests.txt not found, fallback to legacy non_standard_tests.txt" - EXCLUDE_FILES=("${LEGACY_NON_STANDARD_TESTS_FILE}" "${UNIMPLEMENTED_TESTS_FILE}") - fi - - for exclude_file in "${EXCLUDE_FILES[@]}"; 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 excluded + unimplemented lists" - else - TESTEXPR="${INCLUDE_EXPR}" - fi + USE_FILE_TEST_NODES=true + log_info "Loaded ${TEST_COUNT} exact test nodes from implemented_tests.txt" else log_warn "Test list file not found: ${IMPLEMENTED_TESTS_FILE}" log_warn "Falling back to exclusion-based filtering" @@ -249,8 +216,8 @@ Environment Variables: S3_ALT_SECRET_KEY - Alt user secret key (default: rustfsalt) MAXFAIL - Stop after N failures (default: 1) XDIST - Enable parallel execution with N workers (default: 0) - MARKEXPR - pytest marker expression (default: safety net exclusions) - TESTEXPR - pytest -k expression (default: from implemented_tests.txt) + MARKEXPR - pytest marker expression (default: no marker filtering) + TESTEXPR - pytest -k expression (overrides implemented_tests.txt node list) S3TESTS_CONF_TEMPLATE - Path to s3tests config template (default: .github/s3tests/s3tests.conf) S3TESTS_CONF - Path to generated s3tests config (default: s3tests.conf) DATA_ROOT - Root directory for test data storage (default: target) @@ -841,6 +808,13 @@ fi # Resolve config path (absolute path for tox) CONF_OUTPUT_PATH="${PROJECT_ROOT}/${S3TESTS_CONF}" +PYTEST_SELECTION_ARGS=() +if [[ "${USE_FILE_TEST_NODES}" == "true" ]]; then + PYTEST_SELECTION_ARGS=("${TEST_NODE_ARGS[@]}") +else + PYTEST_SELECTION_ARGS=("${S3_TEST_FILE}" -k "${TESTEXPR}") +fi + # Run tests from s3tests/functional S3TEST_CONF="${CONF_OUTPUT_PATH}" \ tox -- \ @@ -848,9 +822,8 @@ S3TEST_CONF="${CONF_OUTPUT_PATH}" \ --maxfail="${MAXFAIL}" \ --junitxml="${ARTIFACTS_DIR}/junit.xml" \ ${XDIST_ARGS} \ - s3tests/functional/test_s3.py \ + "${PYTEST_SELECTION_ARGS[@]}" \ -m "${MARKEXPR}" \ - -k "${TESTEXPR}" \ 2>&1 | tee "${ARTIFACTS_DIR}/pytest.log" TEST_EXIT_CODE=${PIPESTATUS[0]} diff --git a/scripts/s3-tests/unimplemented_tests.txt b/scripts/s3-tests/unimplemented_tests.txt index d67dcf3be..9a60b5e9e 100644 --- a/scripts/s3-tests/unimplemented_tests.txt +++ b/scripts/s3-tests/unimplemented_tests.txt @@ -11,6 +11,7 @@ # Failed tests test_bucket_create_delete_bucket_ownership +test_create_bucket_no_ownership_controls test_bucket_logging_owner test_object_copy_not_owned_bucket test_bucket_policy_multipart @@ -19,7 +20,6 @@ test_put_bucket_logging test_put_bucket_logging_errors test_put_bucket_logging_permissions test_put_bucket_logging_policy_wildcard -test_rm_bucket_logging # Skipped tests (require IAM account or multiple storage classes) test_bucket_policy_deny_self_denied_policy @@ -31,5 +31,4 @@ test_lifecycle_transition_encrypted # Tests with known issues (need further investigation) test_bucket_policy_different_tenant test_bucket_policy_tenanted_bucket -# Flaky in CI: version count assertion (expects 5, gets 1) - timing/concurrency -test_versioned_concurrent_object_create_concurrent_remove +test_object_copy_to_itself_with_metadata