diff --git a/cmd/versitygw/test.go b/cmd/versitygw/test.go index 541ad2b2..30c1a928 100644 --- a/cmd/versitygw/test.go +++ b/cmd/versitygw/test.go @@ -39,6 +39,7 @@ var ( versioningEnabled bool azureTests bool tlsStatus bool + parallel bool ) func testCommand() *cli.Command { @@ -115,6 +116,12 @@ func initTestCommands() []*cli.Command { Destination: &azureTests, Aliases: []string{"azure"}, }, + &cli.BoolFlag{ + Name: "parallel", + Usage: "executes the tests concurrently", + Destination: ¶llel, + Aliases: []string{"p"}, + }, }, }, { @@ -304,9 +311,9 @@ func initTestCommands() []*cli.Command { }, extractIntTests()...) } -type testFunc func(*integration.S3Conf) +type testFunc func(*integration.TestState) -func getAction(tf testFunc) func(*cli.Context) error { +func getAction(tf testFunc) func(ctx *cli.Context) error { return func(ctx *cli.Context) error { opts := []integration.Option{ integration.WithAccess(awsID), @@ -329,12 +336,14 @@ func getAction(tf testFunc) func(*cli.Context) error { } s := integration.NewS3Conf(opts...) - tf(s) + ts := integration.NewTestState(ctx.Context, s, parallel) + tf(ts) + ts.Wait() fmt.Println() - fmt.Println("RAN:", integration.RunCount, "PASS:", integration.PassCount, "FAIL:", integration.FailCount) - if integration.FailCount > 0 { - return fmt.Errorf("test failed with %v errors", integration.FailCount) + fmt.Println("RAN:", integration.RunCount.Load(), "PASS:", integration.PassCount.Load(), "FAIL:", integration.FailCount.Load()) + if integration.FailCount.Load() > 0 { + return fmt.Errorf("test failed with %v errors", integration.FailCount.Load()) } return nil } diff --git a/runtests.sh b/runtests.sh index 843b30bf..48b08dc0 100755 --- a/runtests.sh +++ b/runtests.sh @@ -16,7 +16,6 @@ ECHO "Generating TLS certificate and key in the cert.pem and key.pem files" openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048 openssl req -new -x509 -key key.pem -out cert.pem -days 365 -subj "/C=US/ST=California/L=San Francisco/O=Versity/OU=Software/CN=versity.com" - ECHO "Running the sdk test over http" # run server in background not versioning-enabled # port: 7070(default) @@ -33,7 +32,7 @@ fi # run tests # full flow tests -if ! ./versitygw test -a user -s pass -e http://127.0.0.1:7070 full-flow; then +if ! ./versitygw test -a user -s pass -e http://127.0.0.1:7070 full-flow --parallel; then echo "full flow tests failed" kill $GW_PID exit 1 @@ -70,7 +69,7 @@ fi # run tests # full flow tests -if ! ./versitygw test --allow-insecure -a user -s pass -e https://127.0.0.1:7071 full-flow; then +if ! ./versitygw test --allow-insecure -a user -s pass -e https://127.0.0.1:7071 full-flow --parallel; then echo "full flow tests failed" kill $GW_HTTPS_PID exit 1 @@ -90,7 +89,6 @@ fi kill $GW_HTTPS_PID - ECHO "Running the sdk test over http against the versioning-enabled gateway" # run server in background versioning-enabled # port: 7072 @@ -108,7 +106,7 @@ fi # run tests # full flow tests -if ! ./versitygw test -a user -s pass -e http://127.0.0.1:7072 full-flow -vs; then +if ! ./versitygw test -a user -s pass -e http://127.0.0.1:7072 full-flow -vs --parallel; then echo "versioning-enabled full-flow tests failed" kill $GW_VS_PID exit 1 @@ -140,7 +138,7 @@ fi # run tests # full flow tests -if ! ./versitygw test --allow-insecure -a user -s pass -e https://127.0.0.1:7073 full-flow -vs; then +if ! ./versitygw test --allow-insecure -a user -s pass -e https://127.0.0.1:7073 full-flow -vs --parallel; then echo "versioning-enabled full-flow tests failed" kill $GW_VS_HTTPS_PID exit 1 @@ -162,4 +160,3 @@ exit 0 # go tool covdata percent -i=/tmp/covdata # go tool covdata textfmt -i=/tmp/covdata -o profile.txt # go tool cover -html=profile.txt - diff --git a/tests/integration/concurrency.go b/tests/integration/concurrency.go new file mode 100644 index 00000000..924ec9d8 --- /dev/null +++ b/tests/integration/concurrency.go @@ -0,0 +1,118 @@ +package integration + +import ( + "context" + "sync" + + "golang.org/x/sync/semaphore" +) + +const ( + // parallelLimit defines the maximum number of concurrent goroutines + // that can execute tests in parallel. + parallelLimit int64 = 100 +) + +// TestState manages the execution of integration tests with optional +// parallelism and synchronization control. +type TestState struct { + mainCh chan IntTest // Channel for queuing test functions to run (used in parallel mode) + syncTests []IntTest // Slice of test functions that must run synchronously after parallel ones + conf *S3Conf // Shared S3 configuration for all tests + sem *semaphore.Weighted // Semaphore limiting the number of concurrent parallel tests + wg *sync.WaitGroup // WaitGroup tracking running test goroutines + ctx context.Context // Context for cancellation and graceful shutdown + parallel bool // Whether tests should run in parallel or sequentially +} + +// NewTestState initializes a new TestState instance. If parallel execution is enabled, +// it starts a background goroutine to process queued tests. +func NewTestState(ctx context.Context, conf *S3Conf, parallel bool) *TestState { + ts := &TestState{ + mainCh: make(chan IntTest, parallelLimit), + conf: conf, + ctx: ctx, + sem: semaphore.NewWeighted(parallelLimit), + wg: &sync.WaitGroup{}, + parallel: parallel, + } + + // Start background test processor (only used in parallel mode) + go ts.process() + + return ts +} + +// Run executes a test function. In parallel mode, it enqueues the function +// for concurrent execution; otherwise, it runs the test immediately. +func (ct *TestState) Run(f IntTest) { + select { + case <-ct.ctx.Done(): + // Stop if context is canceled + return + default: + if ct.parallel { + // Queue test for background processing + ct.mainCh <- f + return + } + + // Run test synchronously + f(ct.conf) + } +} + +// Sync adds a test function to be executed synchronously after all parallel +// tests have completed. It will not execute immediately. +func (ct *TestState) Sync(f IntTest) { + select { + case <-ct.ctx.Done(): + // Stop if context is canceled + return + default: + ct.syncTests = append(ct.syncTests, f) + } +} + +// process continuously reads from the test queue and executes each test +// in a controlled concurrent manner using a semaphore. +func (ct *TestState) process() { + for fn := range ct.mainCh { + select { + case <-ct.ctx.Done(): + // Skip processing if context is canceled + continue + default: + // Acquire semaphore to limit parallelism + if err := ct.sem.Acquire(ct.ctx, 1); err != nil { + continue + } + ct.wg.Add(1) + go func() { + // Run test and release semaphore once done + fn(ct.conf) + ct.sem.Release(1) + ct.wg.Done() + }() + } + } +} + +// Wait blocks until all queued parallel tests complete, then runs all +// synchronous tests. It also ensures proper cleanup of the test channel. +func (ct *TestState) Wait() { + // Wait for all parallel tests to finish + ct.wg.Wait() + close(ct.mainCh) + + // Run all synchronous tests sequentially + for _, fn := range ct.syncTests { + select { + case <-ct.ctx.Done(): + // Stop if context is canceled before completion + return + default: + fn(ct.conf) + } + } +} diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index 49b3d8b3..2871feb2 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -14,1027 +14,1029 @@ package integration -func TestAuthentication(s *S3Conf) { - Authentication_invalid_auth_header(s) - Authentication_unsupported_signature_version(s) - Authentication_missing_components(s) - Authentication_malformed_component(s) - Authentication_missing_credentials(s) - Authentication_missing_signedheaders(s) - Authentication_missing_signature(s) - Authentication_malformed_credential(s) - Authentication_credentials_invalid_terminal(s) - Authentication_credentials_incorrect_service(s) - Authentication_credentials_incorrect_region(s) - Authentication_credentials_invalid_date(s) - Authentication_credentials_future_date(s) - Authentication_credentials_past_date(s) - Authentication_credentials_non_existing_access_key(s) +func TestAuthentication(ts *TestState) { + ts.Run(Authentication_invalid_auth_header) + ts.Run(Authentication_unsupported_signature_version) + ts.Run(Authentication_missing_components) + ts.Run(Authentication_malformed_component) + ts.Run(Authentication_missing_credentials) + ts.Run(Authentication_missing_signedheaders) + ts.Run(Authentication_missing_signature) + ts.Run(Authentication_malformed_credential) + ts.Run(Authentication_credentials_invalid_terminal) + ts.Run(Authentication_credentials_incorrect_service) + ts.Run(Authentication_credentials_incorrect_region) + ts.Run(Authentication_credentials_invalid_date) + ts.Run(Authentication_credentials_future_date) + ts.Run(Authentication_credentials_past_date) + ts.Run(Authentication_credentials_non_existing_access_key) //TODO: handle the case with signed headers - Authentication_missing_date_header(s) - Authentication_invalid_date_header(s) - Authentication_date_mismatch(s) - Authentication_incorrect_payload_hash(s) - Authentication_invalid_sha256_payload_hash(s) - Authentication_md5(s) - Authentication_signature_error_incorrect_secret_key(s) + ts.Run(Authentication_missing_date_header) + ts.Run(Authentication_invalid_date_header) + ts.Run(Authentication_date_mismatch) + ts.Run(Authentication_incorrect_payload_hash) + ts.Run(Authentication_invalid_sha256_payload_hash) + ts.Run(Authentication_md5) + ts.Run(Authentication_signature_error_incorrect_secret_key) } -func TestPresignedAuthentication(s *S3Conf) { - PresignedAuth_security_token_not_supported(s) - PresignedAuth_unsupported_algorithm(s) - PresignedAuth_ECDSA_not_supported(s) - PresignedAuth_missing_signature_query_param(s) - PresignedAuth_missing_credentials_query_param(s) - PresignedAuth_malformed_creds_invalid_parts(s) - PresignedAuth_creds_invalid_terminal(s) - PresignedAuth_creds_incorrect_service(s) - PresignedAuth_creds_incorrect_region(s) - PresignedAuth_creds_invalid_date(s) - PresignedAuth_missing_date_query(s) - PresignedAuth_dates_mismatch(s) - PresignedAuth_non_existing_access_key_id(s) - PresignedAuth_missing_signed_headers_query_param(s) - PresignedAuth_missing_expiration_query_param(s) - PresignedAuth_invalid_expiration_query_param(s) - PresignedAuth_negative_expiration_query_param(s) - PresignedAuth_exceeding_expiration_query_param(s) - PresignedAuth_expired_request(s) - PresignedAuth_incorrect_secret_key(s) - PresignedAuth_PutObject_success(s) - PresignedAuth_Put_GetObject_with_data(s) - if !s.azureTests { - PresignedAuth_Put_GetObject_with_UTF8_chars(s) +func TestPresignedAuthentication(ts *TestState) { + ts.Run(PresignedAuth_security_token_not_supported) + ts.Run(PresignedAuth_unsupported_algorithm) + ts.Run(PresignedAuth_ECDSA_not_supported) + ts.Run(PresignedAuth_missing_signature_query_param) + ts.Run(PresignedAuth_missing_credentials_query_param) + ts.Run(PresignedAuth_malformed_creds_invalid_parts) + ts.Run(PresignedAuth_creds_invalid_terminal) + ts.Run(PresignedAuth_creds_incorrect_service) + ts.Run(PresignedAuth_creds_incorrect_region) + ts.Run(PresignedAuth_creds_invalid_date) + ts.Run(PresignedAuth_missing_date_query) + ts.Run(PresignedAuth_dates_mismatch) + ts.Run(PresignedAuth_non_existing_access_key_id) + ts.Run(PresignedAuth_missing_signed_headers_query_param) + ts.Run(PresignedAuth_missing_expiration_query_param) + ts.Run(PresignedAuth_invalid_expiration_query_param) + ts.Run(PresignedAuth_negative_expiration_query_param) + ts.Run(PresignedAuth_exceeding_expiration_query_param) + ts.Run(PresignedAuth_expired_request) + ts.Run(PresignedAuth_incorrect_secret_key) + ts.Run(PresignedAuth_PutObject_success) + ts.Run(PresignedAuth_Put_GetObject_with_data) + if !ts.conf.azureTests { + ts.Run(PresignedAuth_Put_GetObject_with_UTF8_chars) } - PresignedAuth_UploadPart(s) + ts.Run(PresignedAuth_UploadPart) } -func TestCreateBucket(s *S3Conf) { - CreateBucket_invalid_bucket_name(s) - CreateBucket_existing_bucket(s) - CreateBucket_owned_by_you(s) - CreateBucket_invalid_ownership(s) - CreateBucket_ownership_with_acl(s) - CreateBucket_as_user(s) - CreateBucket_default_acl(s) - CreateBucket_non_default_acl(s) - CreateDeleteBucket_success(s) - CreateBucket_default_object_lock(s) +func TestCreateBucket(ts *TestState) { + ts.Run(CreateBucket_invalid_bucket_name) + ts.Run(CreateBucket_existing_bucket) + ts.Run(CreateBucket_owned_by_you) + ts.Run(CreateBucket_invalid_ownership) + ts.Run(CreateBucket_ownership_with_acl) + ts.Run(CreateBucket_as_user) + ts.Run(CreateBucket_default_acl) + ts.Run(CreateBucket_non_default_acl) + ts.Run(CreateDeleteBucket_success) + ts.Run(CreateBucket_default_object_lock) } -func TestHeadBucket(s *S3Conf) { - HeadBucket_non_existing_bucket(s) - HeadBucket_success(s) +func TestHeadBucket(ts *TestState) { + ts.Run(HeadBucket_non_existing_bucket) + ts.Run(HeadBucket_success) } -func TestListBuckets(s *S3Conf) { - ListBuckets_as_user(s) - ListBuckets_as_admin(s) - ListBuckets_with_prefix(s) - ListBuckets_invalid_max_buckets(s) - ListBuckets_truncated(s) - ListBuckets_success(s) - ListBuckets_empty_success(s) +func TestListBuckets(ts *TestState) { + ts.Sync(ListBuckets_as_user) + ts.Sync(ListBuckets_as_admin) + ts.Sync(ListBuckets_with_prefix) + ts.Sync(ListBuckets_invalid_max_buckets) + ts.Sync(ListBuckets_truncated) + ts.Sync(ListBuckets_success) + ts.Sync(ListBuckets_empty_success) } -func TestDeleteBucket(s *S3Conf) { - DeleteBucket_non_existing_bucket(s) - DeleteBucket_non_empty_bucket(s) - DeleteBucket_success_status_code(s) +func TestDeleteBucket(ts *TestState) { + ts.Run(DeleteBucket_non_existing_bucket) + ts.Run(DeleteBucket_non_empty_bucket) + ts.Run(DeleteBucket_success_status_code) } -func TestPutBucketOwnershipControls(s *S3Conf) { - PutBucketOwnershipControls_non_existing_bucket(s) - PutBucketOwnershipControls_multiple_rules(s) - PutBucketOwnershipControls_invalid_ownership(s) - PutBucketOwnershipControls_success(s) +func TestPutBucketOwnershipControls(ts *TestState) { + ts.Run(PutBucketOwnershipControls_non_existing_bucket) + ts.Run(PutBucketOwnershipControls_multiple_rules) + ts.Run(PutBucketOwnershipControls_invalid_ownership) + ts.Run(PutBucketOwnershipControls_success) } -func TestGetBucketOwnershipControls(s *S3Conf) { - GetBucketOwnershipControls_non_existing_bucket(s) - GetBucketOwnershipControls_default_ownership(s) - GetBucketOwnershipControls_success(s) +func TestGetBucketOwnershipControls(ts *TestState) { + ts.Run(GetBucketOwnershipControls_non_existing_bucket) + ts.Run(GetBucketOwnershipControls_default_ownership) + ts.Run(GetBucketOwnershipControls_success) } -func TestDeleteBucketOwnershipControls(s *S3Conf) { - DeleteBucketOwnershipControls_non_existing_bucket(s) - DeleteBucketOwnershipControls_success(s) +func TestDeleteBucketOwnershipControls(ts *TestState) { + ts.Run(DeleteBucketOwnershipControls_non_existing_bucket) + ts.Run(DeleteBucketOwnershipControls_success) } -func TestPutBucketTagging(s *S3Conf) { - PutBucketTagging_non_existing_bucket(s) - PutBucketTagging_long_tags(s) - PutBucketTagging_duplicate_keys(s) - PutBucketTagging_tag_count_limit(s) - PutBucketTagging_success(s) - PutBucketTagging_success_status(s) +func TestPutBucketTagging(ts *TestState) { + ts.Run(PutBucketTagging_non_existing_bucket) + ts.Run(PutBucketTagging_long_tags) + ts.Run(PutBucketTagging_duplicate_keys) + ts.Run(PutBucketTagging_tag_count_limit) + ts.Run(PutBucketTagging_success) + ts.Run(PutBucketTagging_success_status) } -func TestGetBucketTagging(s *S3Conf) { - GetBucketTagging_non_existing_bucket(s) - GetBucketTagging_unset_tags(s) - GetBucketTagging_success(s) +func TestGetBucketTagging(ts *TestState) { + ts.Run(GetBucketTagging_non_existing_bucket) + ts.Run(GetBucketTagging_unset_tags) + ts.Run(GetBucketTagging_success) } -func TestDeleteBucketTagging(s *S3Conf) { - DeleteBucketTagging_non_existing_object(s) - DeleteBucketTagging_success_status(s) - DeleteBucketTagging_success(s) +func TestDeleteBucketTagging(ts *TestState) { + ts.Run(DeleteBucketTagging_non_existing_object) + ts.Run(DeleteBucketTagging_success_status) + ts.Run(DeleteBucketTagging_success) } -func TestGetBucketLocation(s *S3Conf) { - GetBucketLocation_success(s) - GetBucketLocation_non_exist(s) - GetBucketLocation_no_access(s) +func TestGetBucketLocation(ts *TestState) { + ts.Run(GetBucketLocation_success) + ts.Run(GetBucketLocation_non_exist) + ts.Run(GetBucketLocation_no_access) } -func TestPutObject(s *S3Conf) { - PutObject_non_existing_bucket(s) - PutObject_special_chars(s) - PutObject_tagging(s) - PutObject_missing_object_lock_retention_config(s) - PutObject_with_object_lock(s) - PutObject_invalid_legal_hold(s) - PutObject_invalid_object_lock_mode(s) - PutObject_conditional_writes(s) +func TestPutObject(ts *TestState) { + ts.Run(PutObject_non_existing_bucket) + ts.Run(PutObject_special_chars) + ts.Run(PutObject_tagging) + ts.Run(PutObject_missing_object_lock_retention_config) + ts.Run(PutObject_with_object_lock) + ts.Run(PutObject_invalid_legal_hold) + ts.Run(PutObject_invalid_object_lock_mode) + ts.Run(PutObject_conditional_writes) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - PutObject_checksum_algorithm_and_header_mismatch(s) - PutObject_multiple_checksum_headers(s) - PutObject_invalid_checksum_header(s) - PutObject_incorrect_checksums(s) - PutObject_default_checksum(s) - PutObject_checksums_success(s) + if !ts.conf.azureTests { + ts.Run(PutObject_checksum_algorithm_and_header_mismatch) + ts.Run(PutObject_multiple_checksum_headers) + ts.Run(PutObject_invalid_checksum_header) + ts.Run(PutObject_incorrect_checksums) + ts.Run(PutObject_default_checksum) + ts.Run(PutObject_checksums_success) // azure applies some encoding mechanisms. - PutObject_false_negative_object_names(s) + ts.Run(PutObject_false_negative_object_names) } - PutObject_success(s) - if !s.versioningEnabled { - PutObject_racey_success(s) + ts.Run(PutObject_success) + if !ts.conf.versioningEnabled { + ts.Run(PutObject_racey_success) } - PutObject_invalid_credentials(s) - PutObject_invalid_object_names(s) + ts.Run(PutObject_invalid_credentials) + ts.Run(PutObject_invalid_object_names) } -func TestHeadObject(s *S3Conf) { - HeadObject_non_existing_object(s) - HeadObject_invalid_part_number(s) - HeadObject_part_number_not_supported(s) - HeadObject_directory_object_noslash(s) - HeadObject_non_existing_dir_object(s) - HeadObject_invalid_parent_dir(s) - HeadObject_with_range(s) - HeadObject_zero_len_with_range(s) - HeadObject_dir_with_range(s) - HeadObject_conditional_reads(s) +func TestHeadObject(ts *TestState) { + ts.Run(HeadObject_non_existing_object) + ts.Run(HeadObject_invalid_part_number) + ts.Run(HeadObject_part_number_not_supported) + ts.Run(HeadObject_directory_object_noslash) + ts.Run(HeadObject_non_existing_dir_object) + ts.Run(HeadObject_invalid_parent_dir) + ts.Run(HeadObject_with_range) + ts.Run(HeadObject_zero_len_with_range) + ts.Run(HeadObject_dir_with_range) + ts.Run(HeadObject_conditional_reads) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - HeadObject_not_enabled_checksum_mode(s) - HeadObject_checksums(s) + if !ts.conf.azureTests { + ts.Run(HeadObject_not_enabled_checksum_mode) + ts.Run(HeadObject_checksums) } - HeadObject_success(s) + ts.Run(HeadObject_success) } -func TestGetObjectAttributes(s *S3Conf) { - GetObjectAttributes_non_existing_bucket(s) - GetObjectAttributes_non_existing_object(s) - GetObjectAttributes_invalid_attrs(s) - GetObjectAttributes_invalid_parent(s) - GetObjectAttributes_invalid_single_attribute(s) - GetObjectAttributes_empty_attrs(s) - GetObjectAttributes_existing_object(s) +func TestGetObjectAttributes(ts *TestState) { + ts.Run(GetObjectAttributes_non_existing_bucket) + ts.Run(GetObjectAttributes_non_existing_object) + ts.Run(GetObjectAttributes_invalid_attrs) + ts.Run(GetObjectAttributes_invalid_parent) + ts.Run(GetObjectAttributes_invalid_single_attribute) + ts.Run(GetObjectAttributes_empty_attrs) + ts.Run(GetObjectAttributes_existing_object) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - GetObjectAttributes_checksums(s) + if !ts.conf.azureTests { + ts.Run(GetObjectAttributes_checksums) } } -func TestGetObject(s *S3Conf) { - GetObject_non_existing_key(s) - GetObject_directory_object_noslash(s) - GetObject_with_range(s) - GetObject_zero_len_with_range(s) - GetObject_dir_with_range(s) - GetObject_invalid_parent(s) - GetObject_large_object(s) - GetObject_conditional_reads(s) +func TestGetObject(ts *TestState) { + ts.Run(GetObject_non_existing_key) + ts.Run(GetObject_directory_object_noslash) + ts.Run(GetObject_with_range) + ts.Run(GetObject_zero_len_with_range) + ts.Run(GetObject_dir_with_range) + ts.Run(GetObject_invalid_parent) + ts.Run(GetObject_large_object) + ts.Run(GetObject_conditional_reads) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - GetObject_checksums(s) + if !ts.conf.azureTests { + ts.Run(GetObject_checksums) } - GetObject_success(s) - GetObject_directory_success(s) - GetObject_by_range_resp_status(s) - GetObject_non_existing_dir_object(s) - GetObject_overrides_success(s) - GetObject_overrides_presign_success(s) - GetObject_overrides_fail_public(s) - GetObject_invalid_part_number(s) - GetObject_part_number_not_supported(s) + ts.Run(GetObject_success) + ts.Run(GetObject_directory_success) + ts.Run(GetObject_by_range_resp_status) + ts.Run(GetObject_non_existing_dir_object) + ts.Run(GetObject_overrides_success) + ts.Run(GetObject_overrides_presign_success) + ts.Run(GetObject_overrides_fail_public) + ts.Run(GetObject_invalid_part_number) + ts.Run(GetObject_part_number_not_supported) } -func TestListObjects(s *S3Conf) { - ListObjects_non_existing_bucket(s) - ListObjects_with_prefix(s) - ListObjects_truncated(s) - ListObjects_paginated(s) - ListObjects_invalid_max_keys(s) - ListObjects_max_keys_0(s) - ListObjects_exceeding_max_keys(s) - ListObjects_delimiter(s) - ListObjects_max_keys_none(s) - ListObjects_marker_not_from_obj_list(s) - ListObjects_list_all_objs(s) - ListObjects_nested_dir_file_objs(s) - ListObjects_check_owner(s) - ListObjects_non_truncated_common_prefixes(s) +func TestListObjects(ts *TestState) { + ts.Run(ListObjects_non_existing_bucket) + ts.Run(ListObjects_with_prefix) + ts.Run(ListObjects_truncated) + ts.Run(ListObjects_paginated) + ts.Run(ListObjects_invalid_max_keys) + ts.Run(ListObjects_max_keys_0) + ts.Run(ListObjects_exceeding_max_keys) + ts.Run(ListObjects_delimiter) + ts.Run(ListObjects_max_keys_none) + ts.Run(ListObjects_marker_not_from_obj_list) + ts.Run(ListObjects_list_all_objs) + ts.Run(ListObjects_nested_dir_file_objs) + ts.Run(ListObjects_check_owner) + ts.Run(ListObjects_non_truncated_common_prefixes) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - ListObjects_with_checksum(s) + if !ts.conf.azureTests { + ts.Run(ListObjects_with_checksum) } } -func TestListObjectsV2(s *S3Conf) { - ListObjectsV2_start_after(s) +func TestListObjectsV2(ts *TestState) { + ts.Run(ListObjectsV2_start_after) // posix continuation token not compatible with azure - if !s.azureTests { - ListObjectsV2_both_start_after_and_continuation_token(s) + if !ts.conf.azureTests { + ts.Run(ListObjectsV2_both_start_after_and_continuation_token) } - ListObjectsV2_start_after_not_in_list(s) - ListObjectsV2_start_after_empty_result(s) - ListObjectsV2_both_delimiter_and_prefix(s) - ListObjectsV2_single_dir_object_with_delim_and_prefix(s) - ListObjectsV2_truncated_common_prefixes(s) - ListObjectsV2_all_objs_max_keys(s) - ListObjectsV2_exceeding_max_keys(s) - ListObjectsV2_list_all_objs(s) - ListObjectsV2_with_owner(s) - ListObjectsV2_non_truncated_common_prefixes(s) + ts.Run(ListObjectsV2_start_after_not_in_list) + ts.Run(ListObjectsV2_start_after_empty_result) + ts.Run(ListObjectsV2_both_delimiter_and_prefix) + ts.Run(ListObjectsV2_single_dir_object_with_delim_and_prefix) + ts.Run(ListObjectsV2_truncated_common_prefixes) + ts.Run(ListObjectsV2_all_objs_max_keys) + ts.Run(ListObjectsV2_exceeding_max_keys) + ts.Run(ListObjectsV2_list_all_objs) + ts.Run(ListObjectsV2_with_owner) + ts.Run(ListObjectsV2_non_truncated_common_prefixes) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - ListObjectsV2_with_checksum(s) + if !ts.conf.azureTests { + ts.Run(ListObjectsV2_with_checksum) } - ListObjectsV2_invalid_parent_prefix(s) + ts.Run(ListObjectsV2_invalid_parent_prefix) } // VD stands for Versioning Disabled -func TestListObjectVersions_VD(s *S3Conf) { - ListObjectVersions_VD_success(s) +func TestListObjectVersions_VD(ts *TestState) { + ts.Run(ListObjectVersions_VD_success) } -func TestDeleteObject(s *S3Conf) { - DeleteObject_non_existing_object(s) - DeleteObject_directory_object_noslash(s) - DeleteObject_non_existing_dir_object(s) - DeleteObject_directory_object(s) - DeleteObject_non_empty_dir_obj(s) - DeleteObject_conditional_writes(s) - DeleteObject_success(s) - DeleteObject_success_status_code(s) +func TestDeleteObject(ts *TestState) { + ts.Run(DeleteObject_non_existing_object) + ts.Run(DeleteObject_directory_object_noslash) + ts.Run(DeleteObject_non_existing_dir_object) + ts.Run(DeleteObject_directory_object) + ts.Run(DeleteObject_non_empty_dir_obj) + ts.Run(DeleteObject_conditional_writes) + ts.Run(DeleteObject_success) + ts.Run(DeleteObject_success_status_code) } -func TestDeleteObjects(s *S3Conf) { - DeleteObjects_empty_input(s) - DeleteObjects_non_existing_objects(s) - DeleteObjects_success(s) +func TestDeleteObjects(ts *TestState) { + ts.Run(DeleteObjects_empty_input) + ts.Run(DeleteObjects_non_existing_objects) + ts.Run(DeleteObjects_success) } -func TestCopyObject(s *S3Conf) { - CopyObject_non_existing_dst_bucket(s) - CopyObject_not_owned_source_bucket(s) - CopyObject_copy_to_itself(s) - CopyObject_copy_to_itself_invalid_directive(s) - CopyObject_should_replace_tagging(s) - CopyObject_should_copy_tagging(s) - CopyObject_invalid_tagging_directive(s) - CopyObject_to_itself_with_new_metadata(s) - CopyObject_copy_source_starting_with_slash(s) - CopyObject_invalid_copy_source(s) - CopyObject_non_existing_dir_object(s) - CopyObject_should_copy_meta_props(s) - CopyObject_should_replace_meta_props(s) - CopyObject_invalid_legal_hold(s) - CopyObject_invalid_object_lock_mode(s) - CopyObject_with_legal_hold(s) - CopyObject_with_retention_lock(s) - CopyObject_conditional_reads(s) +func TestCopyObject(ts *TestState) { + ts.Run(CopyObject_non_existing_dst_bucket) + ts.Run(CopyObject_not_owned_source_bucket) + ts.Run(CopyObject_copy_to_itself) + ts.Run(CopyObject_copy_to_itself_invalid_directive) + ts.Run(CopyObject_should_replace_tagging) + ts.Run(CopyObject_should_copy_tagging) + ts.Run(CopyObject_invalid_tagging_directive) + ts.Run(CopyObject_to_itself_with_new_metadata) + ts.Run(CopyObject_copy_source_starting_with_slash) + ts.Run(CopyObject_invalid_copy_source) + ts.Run(CopyObject_non_existing_dir_object) + ts.Run(CopyObject_should_copy_meta_props) + ts.Run(CopyObject_should_replace_meta_props) + ts.Run(CopyObject_invalid_legal_hold) + ts.Run(CopyObject_invalid_object_lock_mode) + ts.Run(CopyObject_with_legal_hold) + ts.Run(CopyObject_with_retention_lock) + ts.Run(CopyObject_conditional_reads) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - CopyObject_invalid_checksum_algorithm(s) - CopyObject_create_checksum_on_copy(s) - CopyObject_should_copy_the_existing_checksum(s) - CopyObject_should_replace_the_existing_checksum(s) - CopyObject_to_itself_by_replacing_the_checksum(s) + if !ts.conf.azureTests { + ts.Run(CopyObject_invalid_checksum_algorithm) + ts.Run(CopyObject_create_checksum_on_copy) + ts.Run(CopyObject_should_copy_the_existing_checksum) + ts.Run(CopyObject_should_replace_the_existing_checksum) + ts.Run(CopyObject_to_itself_by_replacing_the_checksum) } - CopyObject_success(s) + ts.Run(CopyObject_success) } -func TestPutObjectTagging(s *S3Conf) { - PutObjectTagging_non_existing_object(s) - PutObjectTagging_long_tags(s) - PutObjectTagging_duplicate_keys(s) - PutObjectTagging_tag_count_limit(s) - PutObjectTagging_success(s) +func TestPutObjectTagging(ts *TestState) { + ts.Run(PutObjectTagging_non_existing_object) + ts.Run(PutObjectTagging_long_tags) + ts.Run(PutObjectTagging_duplicate_keys) + ts.Run(PutObjectTagging_tag_count_limit) + ts.Run(PutObjectTagging_success) } -func TestGetObjectTagging(s *S3Conf) { - GetObjectTagging_non_existing_object(s) - GetObjectTagging_unset_tags(s) - GetObjectTagging_invalid_parent(s) - GetObjectTagging_success(s) +func TestGetObjectTagging(ts *TestState) { + ts.Run(GetObjectTagging_non_existing_object) + ts.Run(GetObjectTagging_unset_tags) + ts.Run(GetObjectTagging_invalid_parent) + ts.Run(GetObjectTagging_success) } -func TestDeleteObjectTagging(s *S3Conf) { - DeleteObjectTagging_non_existing_object(s) - DeleteObjectTagging_success_status(s) - DeleteObjectTagging_success(s) +func TestDeleteObjectTagging(ts *TestState) { + ts.Run(DeleteObjectTagging_non_existing_object) + ts.Run(DeleteObjectTagging_success_status) + ts.Run(DeleteObjectTagging_success) } -func TestCreateMultipartUpload(s *S3Conf) { - CreateMultipartUpload_non_existing_bucket(s) - CreateMultipartUpload_with_metadata(s) - CreateMultipartUpload_with_tagging(s) - CreateMultipartUpload_with_object_lock(s) - CreateMultipartUpload_with_object_lock_not_enabled(s) - CreateMultipartUpload_with_object_lock_invalid_retention(s) - CreateMultipartUpload_past_retain_until_date(s) - CreateMultipartUpload_invalid_legal_hold(s) - CreateMultipartUpload_invalid_object_lock_mode(s) +func TestCreateMultipartUpload(ts *TestState) { + ts.Run(CreateMultipartUpload_non_existing_bucket) + ts.Run(CreateMultipartUpload_with_metadata) + ts.Run(CreateMultipartUpload_with_tagging) + ts.Run(CreateMultipartUpload_with_object_lock) + ts.Run(CreateMultipartUpload_with_object_lock_not_enabled) + ts.Run(CreateMultipartUpload_with_object_lock_invalid_retention) + ts.Run(CreateMultipartUpload_past_retain_until_date) + ts.Run(CreateMultipartUpload_invalid_legal_hold) + ts.Run(CreateMultipartUpload_invalid_object_lock_mode) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - CreateMultipartUpload_invalid_checksum_algorithm(s) - CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type(s) - CreateMultipartUpload_invalid_checksum_type(s) - CreateMultipartUpload_valid_algo_type(s) + if !ts.conf.azureTests { + ts.Run(CreateMultipartUpload_invalid_checksum_algorithm) + ts.Run(CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type) + ts.Run(CreateMultipartUpload_invalid_checksum_type) + ts.Run(CreateMultipartUpload_valid_algo_type) } - CreateMultipartUpload_success(s) + ts.Run(CreateMultipartUpload_success) } -func TestUploadPart(s *S3Conf) { - UploadPart_non_existing_bucket(s) - UploadPart_invalid_part_number(s) - UploadPart_non_existing_key(s) - UploadPart_non_existing_mp_upload(s) +func TestUploadPart(ts *TestState) { + ts.Run(UploadPart_non_existing_bucket) + ts.Run(UploadPart_invalid_part_number) + ts.Run(UploadPart_non_existing_key) + ts.Run(UploadPart_non_existing_mp_upload) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - UploadPart_checksum_algorithm_and_header_mismatch(s) - UploadPart_multiple_checksum_headers(s) - UploadPart_invalid_checksum_header(s) - UploadPart_checksum_algorithm_mistmatch_on_initialization(s) - UploadPart_checksum_algorithm_mistmatch_on_initialization_with_value(s) - UploadPart_incorrect_checksums(s) - UploadPart_no_checksum_with_full_object_checksum_type(s) - UploadPart_no_checksum_with_composite_checksum_type(s) - UploadPart_should_calculate_checksum_if_only_algorithm_is_provided(s) - UploadPart_with_checksums_success(s) + if !ts.conf.azureTests { + ts.Run(UploadPart_checksum_algorithm_and_header_mismatch) + ts.Run(UploadPart_multiple_checksum_headers) + ts.Run(UploadPart_invalid_checksum_header) + ts.Run(UploadPart_checksum_algorithm_mistmatch_on_initialization) + ts.Run(UploadPart_checksum_algorithm_mistmatch_on_initialization_with_value) + ts.Run(UploadPart_incorrect_checksums) + ts.Run(UploadPart_no_checksum_with_full_object_checksum_type) + ts.Run(UploadPart_no_checksum_with_composite_checksum_type) + ts.Run(UploadPart_should_calculate_checksum_if_only_algorithm_is_provided) + ts.Run(UploadPart_with_checksums_success) } - UploadPart_success(s) + ts.Run(UploadPart_success) } -func TestUploadPartCopy(s *S3Conf) { - UploadPartCopy_non_existing_bucket(s) - UploadPartCopy_incorrect_uploadId(s) - UploadPartCopy_incorrect_object_key(s) - UploadPartCopy_invalid_part_number(s) - UploadPartCopy_invalid_copy_source(s) - UploadPartCopy_non_existing_source_bucket(s) - UploadPartCopy_non_existing_source_object_key(s) - UploadPartCopy_success(s) - UploadPartCopy_by_range_invalid_ranges(s) - UploadPartCopy_exceeding_copy_source_range(s) - UploadPartCopy_greater_range_than_obj_size(s) - UploadPartCopy_by_range_success(s) +func TestUploadPartCopy(ts *TestState) { + ts.Run(UploadPartCopy_non_existing_bucket) + ts.Run(UploadPartCopy_incorrect_uploadId) + ts.Run(UploadPartCopy_incorrect_object_key) + ts.Run(UploadPartCopy_invalid_part_number) + ts.Run(UploadPartCopy_invalid_copy_source) + ts.Run(UploadPartCopy_non_existing_source_bucket) + ts.Run(UploadPartCopy_non_existing_source_object_key) + ts.Run(UploadPartCopy_success) + ts.Run(UploadPartCopy_by_range_invalid_ranges) + ts.Run(UploadPartCopy_exceeding_copy_source_range) + ts.Run(UploadPartCopy_greater_range_than_obj_size) + ts.Run(UploadPartCopy_by_range_success) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - UploadPartCopy_should_copy_the_checksum(s) - UploadPartCopy_should_not_copy_the_checksum(s) - UploadPartCopy_should_calculate_the_checksum(s) - UploadPartCopy_conditional_reads(s) + if !ts.conf.azureTests { + ts.Run(UploadPartCopy_should_copy_the_checksum) + ts.Run(UploadPartCopy_should_not_copy_the_checksum) + ts.Run(UploadPartCopy_should_calculate_the_checksum) + ts.Run(UploadPartCopy_conditional_reads) } } -func TestListParts(s *S3Conf) { - ListParts_incorrect_uploadId(s) - ListParts_incorrect_object_key(s) - ListParts_invalid_max_parts(s) - ListParts_default_max_parts(s) - ListParts_exceeding_max_parts(s) - ListParts_truncated(s) +func TestListParts(ts *TestState) { + ts.Run(ListParts_incorrect_uploadId) + ts.Run(ListParts_incorrect_object_key) + ts.Run(ListParts_invalid_max_parts) + ts.Run(ListParts_default_max_parts) + ts.Run(ListParts_exceeding_max_parts) + ts.Run(ListParts_truncated) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - ListParts_with_checksums(s) - ListParts_null_checksums(s) + if !ts.conf.azureTests { + ts.Run(ListParts_with_checksums) + ts.Run(ListParts_null_checksums) } - ListParts_success(s) + ts.Run(ListParts_success) } -func TestListMultipartUploads(s *S3Conf) { - ListMultipartUploads_non_existing_bucket(s) - ListMultipartUploads_empty_result(s) - ListMultipartUploads_invalid_max_uploads(s) - ListMultipartUploads_max_uploads(s) - ListMultipartUploads_exceeding_max_uploads(s) - ListMultipartUploads_incorrect_next_key_marker(s) - ListMultipartUploads_ignore_upload_id_marker(s) +func TestListMultipartUploads(ts *TestState) { + ts.Run(ListMultipartUploads_non_existing_bucket) + ts.Run(ListMultipartUploads_empty_result) + ts.Run(ListMultipartUploads_invalid_max_uploads) + ts.Run(ListMultipartUploads_max_uploads) + ts.Run(ListMultipartUploads_exceeding_max_uploads) + ts.Run(ListMultipartUploads_incorrect_next_key_marker) + ts.Run(ListMultipartUploads_ignore_upload_id_marker) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - ListMultipartUploads_with_checksums(s) + if !ts.conf.azureTests { + ts.Run(ListMultipartUploads_with_checksums) } - ListMultipartUploads_success(s) + ts.Run(ListMultipartUploads_success) } -func TestAbortMultipartUpload(s *S3Conf) { - AbortMultipartUpload_non_existing_bucket(s) - AbortMultipartUpload_incorrect_uploadId(s) - AbortMultipartUpload_incorrect_object_key(s) - AbortMultipartUpload_success(s) - AbortMultipartUpload_success_status_code(s) - AbortMultipartUpload_if_match_initiated_time(s) +func TestAbortMultipartUpload(ts *TestState) { + ts.Run(AbortMultipartUpload_non_existing_bucket) + ts.Run(AbortMultipartUpload_incorrect_uploadId) + ts.Run(AbortMultipartUpload_incorrect_object_key) + ts.Run(AbortMultipartUpload_success) + ts.Run(AbortMultipartUpload_success_status_code) + ts.Run(AbortMultipartUpload_if_match_initiated_time) } -func TestCompleteMultipartUpload(s *S3Conf) { - CompletedMultipartUpload_non_existing_bucket(s) - CompleteMultipartUpload_incorrect_part_number(s) - CompleteMultipartUpload_invalid_part_number(s) - CompleteMultipartUpload_invalid_ETag(s) - CompleteMultipartUpload_small_upload_size(s) - CompleteMultipartUpload_empty_parts(s) - CompleteMultipartUpload_incorrect_parts_order(s) - CompleteMultipartUpload_mpu_object_size(s) - CompleteMultipartUpload_conditional_writes(s) +func TestCompleteMultipartUpload(ts *TestState) { + ts.Run(CompletedMultipartUpload_non_existing_bucket) + ts.Run(CompleteMultipartUpload_incorrect_part_number) + ts.Run(CompleteMultipartUpload_invalid_part_number) + ts.Run(CompleteMultipartUpload_invalid_ETag) + ts.Run(CompleteMultipartUpload_small_upload_size) + ts.Run(CompleteMultipartUpload_empty_parts) + ts.Run(CompleteMultipartUpload_incorrect_parts_order) + ts.Run(CompleteMultipartUpload_mpu_object_size) + ts.Run(CompleteMultipartUpload_conditional_writes) //TODO: remove the condition after implementing checksums in azure - if !s.azureTests { - CompleteMultipartUpload_invalid_checksum_type(s) - CompleteMultipartUpload_invalid_checksum_part(s) - CompleteMultipartUpload_multiple_checksum_part(s) - CompleteMultipartUpload_incorrect_checksum_part(s) - CompleteMultipartUpload_different_checksum_part(s) - CompleteMultipartUpload_missing_part_checksum(s) - CompleteMultipartUpload_multiple_final_checksums(s) - CompleteMultipartUpload_invalid_final_checksums(s) - CompleteMultipartUpload_incorrect_final_checksums(s) - CompleteMultipartUpload_should_calculate_the_final_checksum_full_object(s) - CompleteMultipartUpload_should_verify_the_final_checksum(s) - CompleteMultipartUpload_checksum_type_mismatch(s) - CompleteMultipartUpload_should_ignore_the_final_checksum(s) - CompleteMultipartUpload_should_succeed_without_final_checksum_type(s) + if !ts.conf.azureTests { + ts.Run(CompleteMultipartUpload_invalid_checksum_type) + ts.Run(CompleteMultipartUpload_invalid_checksum_part) + ts.Run(CompleteMultipartUpload_multiple_checksum_part) + ts.Run(CompleteMultipartUpload_incorrect_checksum_part) + ts.Run(CompleteMultipartUpload_different_checksum_part) + ts.Run(CompleteMultipartUpload_missing_part_checksum) + ts.Run(CompleteMultipartUpload_multiple_final_checksums) + ts.Run(CompleteMultipartUpload_invalid_final_checksums) + ts.Run(CompleteMultipartUpload_incorrect_final_checksums) + ts.Run(CompleteMultipartUpload_should_calculate_the_final_checksum_full_object) + ts.Run(CompleteMultipartUpload_should_verify_the_final_checksum) + ts.Run(CompleteMultipartUpload_checksum_type_mismatch) + ts.Run(CompleteMultipartUpload_should_ignore_the_final_checksum) + ts.Run(CompleteMultipartUpload_should_succeed_without_final_checksum_type) } - CompleteMultipartUpload_success(s) - if !s.azureTests { - CompleteMultipartUpload_racey_success(s) + ts.Run(CompleteMultipartUpload_success) + if !ts.conf.azureTests { + ts.Run(CompleteMultipartUpload_racey_success) } } -func TestPutBucketAcl(s *S3Conf) { - PutBucketAcl_non_existing_bucket(s) - PutBucketAcl_disabled(s) - PutBucketAcl_none_of_the_options_specified(s) - PutBucketAcl_invalid_acl_canned_and_acp(s) - PutBucketAcl_invalid_acl_canned_and_grants(s) - PutBucketAcl_invalid_acl_acp_and_grants(s) - PutBucketAcl_invalid_owner(s) - PutBucketAcl_invalid_owner_not_in_body(s) - PutBucketAcl_invalid_empty_owner_id_in_body(s) - PutBucketAcl_invalid_permission_in_body(s) - PutBucketAcl_invalid_grantee_type_in_body(s) - PutBucketAcl_empty_grantee_ID_in_body(s) - PutBucketAcl_success_access_denied(s) - PutBucketAcl_success_grants(s) - PutBucketAcl_success_canned_acl(s) - PutBucketAcl_success_acp(s) +func TestPutBucketAcl(ts *TestState) { + ts.Run(PutBucketAcl_non_existing_bucket) + ts.Run(PutBucketAcl_disabled) + ts.Run(PutBucketAcl_none_of_the_options_specified) + ts.Run(PutBucketAcl_invalid_acl_canned_and_acp) + ts.Run(PutBucketAcl_invalid_acl_canned_and_grants) + ts.Run(PutBucketAcl_invalid_acl_acp_and_grants) + ts.Run(PutBucketAcl_invalid_owner) + ts.Run(PutBucketAcl_invalid_owner_not_in_body) + ts.Run(PutBucketAcl_invalid_empty_owner_id_in_body) + ts.Run(PutBucketAcl_invalid_permission_in_body) + ts.Run(PutBucketAcl_invalid_grantee_type_in_body) + ts.Run(PutBucketAcl_empty_grantee_ID_in_body) + ts.Run(PutBucketAcl_success_access_denied) + ts.Run(PutBucketAcl_success_grants) + ts.Run(PutBucketAcl_success_canned_acl) + ts.Run(PutBucketAcl_success_acp) } -func TestGetBucketAcl(s *S3Conf) { - GetBucketAcl_non_existing_bucket(s) - GetBucketAcl_translation_canned_public_read(s) - GetBucketAcl_translation_canned_public_read_write(s) - GetBucketAcl_translation_canned_private(s) - GetBucketAcl_access_denied(s) - GetBucketAcl_success(s) +func TestGetBucketAcl(ts *TestState) { + ts.Run(GetBucketAcl_non_existing_bucket) + ts.Run(GetBucketAcl_translation_canned_public_read) + ts.Run(GetBucketAcl_translation_canned_public_read_write) + ts.Run(GetBucketAcl_translation_canned_private) + ts.Run(GetBucketAcl_access_denied) + ts.Run(GetBucketAcl_success) } -func TestPutBucketPolicy(s *S3Conf) { - PutBucketPolicy_non_existing_bucket(s) - PutBucketPolicy_invalid_json(s) - PutBucketPolicy_statement_not_provided(s) - PutBucketPolicy_empty_statement(s) - PutBucketPolicy_invalid_effect(s) - PutBucketPolicy_invalid_action(s) - PutBucketPolicy_empty_principals_string(s) - PutBucketPolicy_empty_principals_array(s) - PutBucketPolicy_principals_aws_struct_empty_string(s) - PutBucketPolicy_principals_aws_struct_empty_string_slice(s) - PutBucketPolicy_principals_incorrect_wildcard_usage(s) - PutBucketPolicy_non_existing_principals(s) - PutBucketPolicy_empty_resources_string(s) - PutBucketPolicy_empty_resources_array(s) - PutBucketPolicy_invalid_resource_prefix(s) - PutBucketPolicy_invalid_resource_with_starting_slash(s) - PutBucketPolicy_duplicate_resource(s) - PutBucketPolicy_incorrect_bucket_name(s) - PutBucketPolicy_action_resource_mismatch(s) - PutBucketPolicy_explicit_deny(s) - PutBucketPolicy_multi_wildcard_resource(s) - PutBucketPolicy_any_char_match(s) - PutBucketPolicy_success(s) +func TestPutBucketPolicy(ts *TestState) { + ts.Run(PutBucketPolicy_non_existing_bucket) + ts.Run(PutBucketPolicy_invalid_json) + ts.Run(PutBucketPolicy_statement_not_provided) + ts.Run(PutBucketPolicy_empty_statement) + ts.Run(PutBucketPolicy_invalid_effect) + ts.Run(PutBucketPolicy_invalid_action) + ts.Run(PutBucketPolicy_empty_principals_string) + ts.Run(PutBucketPolicy_empty_principals_array) + ts.Run(PutBucketPolicy_principals_aws_struct_empty_string) + ts.Run(PutBucketPolicy_principals_aws_struct_empty_string_slice) + ts.Run(PutBucketPolicy_principals_incorrect_wildcard_usage) + ts.Run(PutBucketPolicy_non_existing_principals) + ts.Run(PutBucketPolicy_empty_resources_string) + ts.Run(PutBucketPolicy_empty_resources_array) + ts.Run(PutBucketPolicy_invalid_resource_prefix) + ts.Run(PutBucketPolicy_invalid_resource_with_starting_slash) + ts.Run(PutBucketPolicy_duplicate_resource) + ts.Run(PutBucketPolicy_incorrect_bucket_name) + ts.Run(PutBucketPolicy_action_resource_mismatch) + ts.Run(PutBucketPolicy_explicit_deny) + ts.Run(PutBucketPolicy_multi_wildcard_resource) + ts.Run(PutBucketPolicy_any_char_match) + ts.Run(PutBucketPolicy_success) } -func TestGetBucketPolicy(s *S3Conf) { - GetBucketPolicy_non_existing_bucket(s) - GetBucketPolicy_not_set(s) - GetBucketPolicy_success(s) +func TestGetBucketPolicy(ts *TestState) { + ts.Run(GetBucketPolicy_non_existing_bucket) + ts.Run(GetBucketPolicy_not_set) + ts.Run(GetBucketPolicy_success) } -func TestGetBucketPolicyStatus(s *S3Conf) { - GetBucketPolicyStatus_non_existing_bucket(s) - GetBucketPolicyStatus_no_such_bucket_policy(s) - GetBucketPolicyStatus_success(s) +func TestGetBucketPolicyStatus(ts *TestState) { + ts.Run(GetBucketPolicyStatus_non_existing_bucket) + ts.Run(GetBucketPolicyStatus_no_such_bucket_policy) + ts.Run(GetBucketPolicyStatus_success) } -func TestDeleteBucketPolicy(s *S3Conf) { - DeleteBucketPolicy_non_existing_bucket(s) - DeleteBucketPolicy_remove_before_setting(s) - DeleteBucketPolicy_success(s) +func TestDeleteBucketPolicy(ts *TestState) { + ts.Run(DeleteBucketPolicy_non_existing_bucket) + ts.Run(DeleteBucketPolicy_remove_before_setting) + ts.Run(DeleteBucketPolicy_success) } -func TestPutBucketCors(s *S3Conf) { - PutBucketCors_non_existing_bucket(s) - PutBucketCors_empty_cors_rules(s) - PutBucketCors_invalid_method(s) - PutBucketCors_invalid_header(s) - PutBucketCors_md5(s) - PutBucketCors_success(s) +func TestPutBucketCors(ts *TestState) { + ts.Run(PutBucketCors_non_existing_bucket) + ts.Run(PutBucketCors_empty_cors_rules) + ts.Run(PutBucketCors_invalid_method) + ts.Run(PutBucketCors_invalid_header) + ts.Run(PutBucketCors_md5) + ts.Run(PutBucketCors_success) } -func TestGetBucketCors(s *S3Conf) { - GetBucketCors_non_existing_bucket(s) - GetBucketCors_no_such_bucket_cors(s) - GetBucketCors_success(s) +func TestGetBucketCors(ts *TestState) { + ts.Run(GetBucketCors_non_existing_bucket) + ts.Run(GetBucketCors_no_such_bucket_cors) + ts.Run(GetBucketCors_success) } -func TestDeleteBucketCors(s *S3Conf) { - DeleteBucketCors_non_existing_bucket(s) - DeleteBucketCors_success(s) +func TestDeleteBucketCors(ts *TestState) { + ts.Run(DeleteBucketCors_non_existing_bucket) + ts.Run(DeleteBucketCors_success) } -func TestPreflightOPTIONSEndpoint(s *S3Conf) { - PreflightOPTIONS_non_existing_bucket(s) - PreflightOPTIONS_missing_origin(s) - PreflightOPTIONS_invalid_request_method(s) - PreflightOPTIONS_invalid_request_headers(s) - PreflightOPTIONS_unset_bucket_cors(s) - PreflightOPTIONS_access_forbidden(s) - PreflightOPTIONS_access_granted(s) +func TestPreflightOPTIONSEndpoint(ts *TestState) { + ts.Run(PreflightOPTIONS_non_existing_bucket) + ts.Run(PreflightOPTIONS_missing_origin) + ts.Run(PreflightOPTIONS_invalid_request_method) + ts.Run(PreflightOPTIONS_invalid_request_headers) + ts.Run(PreflightOPTIONS_unset_bucket_cors) + ts.Run(PreflightOPTIONS_access_forbidden) + ts.Run(PreflightOPTIONS_access_granted) } -func TestCORSMiddleware(s *S3Conf) { - CORSMiddleware_invalid_method(s) - CORSMiddleware_invalid_headers(s) - CORSMiddleware_access_forbidden(s) - CORSMiddleware_access_granted(s) +func TestCORSMiddleware(ts *TestState) { + ts.Run(CORSMiddleware_invalid_method) + ts.Run(CORSMiddleware_invalid_headers) + ts.Run(CORSMiddleware_access_forbidden) + ts.Run(CORSMiddleware_access_granted) } -func TestPutObjectLockConfiguration(s *S3Conf) { - PutObjectLockConfiguration_non_existing_bucket(s) - PutObjectLockConfiguration_empty_config(s) - if !s.versioningEnabled { - PutObjectLockConfiguration_not_enabled_on_bucket_creation(s) +func TestPutObjectLockConfiguration(ts *TestState) { + ts.Run(PutObjectLockConfiguration_non_existing_bucket) + ts.Run(PutObjectLockConfiguration_empty_config) + if !ts.conf.versioningEnabled { + ts.Run(PutObjectLockConfiguration_not_enabled_on_bucket_creation) } - PutObjectLockConfiguration_invalid_status(s) - PutObjectLockConfiguration_invalid_mode(s) - PutObjectLockConfiguration_both_years_and_days(s) - PutObjectLockConfiguration_invalid_years_days(s) - PutObjectLockConfiguration_success(s) + ts.Run(PutObjectLockConfiguration_invalid_status) + ts.Run(PutObjectLockConfiguration_invalid_mode) + ts.Run(PutObjectLockConfiguration_both_years_and_days) + ts.Run(PutObjectLockConfiguration_invalid_years_days) + ts.Run(PutObjectLockConfiguration_success) } -func TestGetObjectLockConfiguration(s *S3Conf) { - GetObjectLockConfiguration_non_existing_bucket(s) - GetObjectLockConfiguration_unset_config(s) - GetObjectLockConfiguration_success(s) +func TestGetObjectLockConfiguration(ts *TestState) { + ts.Run(GetObjectLockConfiguration_non_existing_bucket) + ts.Run(GetObjectLockConfiguration_unset_config) + ts.Run(GetObjectLockConfiguration_success) } -func TestPutObjectRetention(s *S3Conf) { - PutObjectRetention_non_existing_bucket(s) - PutObjectRetention_non_existing_object(s) - PutObjectRetention_unset_bucket_object_lock_config(s) - PutObjectRetention_expired_retain_until_date(s) - PutObjectRetention_invalid_mode(s) - PutObjectRetention_overwrite_compliance_mode(s) - PutObjectRetention_overwrite_compliance_with_compliance(s) - PutObjectRetention_overwrite_governance_with_governance(s) - PutObjectRetention_overwrite_governance_without_bypass_specified(s) - PutObjectRetention_overwrite_governance_with_permission(s) - PutObjectRetention_success(s) +func TestPutObjectRetention(ts *TestState) { + ts.Run(PutObjectRetention_non_existing_bucket) + ts.Run(PutObjectRetention_non_existing_object) + ts.Run(PutObjectRetention_unset_bucket_object_lock_config) + ts.Run(PutObjectRetention_expired_retain_until_date) + ts.Run(PutObjectRetention_invalid_mode) + ts.Run(PutObjectRetention_overwrite_compliance_mode) + ts.Run(PutObjectRetention_overwrite_compliance_with_compliance) + ts.Run(PutObjectRetention_overwrite_governance_with_governance) + ts.Run(PutObjectRetention_overwrite_governance_without_bypass_specified) + ts.Run(PutObjectRetention_overwrite_governance_with_permission) + ts.Run(PutObjectRetention_success) } -func TestGetObjectRetention(s *S3Conf) { - GetObjectRetention_non_existing_bucket(s) - GetObjectRetention_non_existing_object(s) - GetObjectRetention_disabled_lock(s) - GetObjectRetention_unset_config(s) - GetObjectRetention_success(s) +func TestGetObjectRetention(ts *TestState) { + ts.Run(GetObjectRetention_non_existing_bucket) + ts.Run(GetObjectRetention_non_existing_object) + ts.Run(GetObjectRetention_disabled_lock) + ts.Run(GetObjectRetention_unset_config) + ts.Run(GetObjectRetention_success) } -func TestPutObjectLegalHold(s *S3Conf) { - PutObjectLegalHold_non_existing_bucket(s) - PutObjectLegalHold_non_existing_object(s) - PutObjectLegalHold_invalid_body(s) - PutObjectLegalHold_invalid_status(s) - PutObjectLegalHold_unset_bucket_object_lock_config(s) - PutObjectLegalHold_success(s) +func TestPutObjectLegalHold(ts *TestState) { + ts.Run(PutObjectLegalHold_non_existing_bucket) + ts.Run(PutObjectLegalHold_non_existing_object) + ts.Run(PutObjectLegalHold_invalid_body) + ts.Run(PutObjectLegalHold_invalid_status) + ts.Run(PutObjectLegalHold_unset_bucket_object_lock_config) + ts.Run(PutObjectLegalHold_success) } -func TestGetObjectLegalHold(s *S3Conf) { - GetObjectLegalHold_non_existing_bucket(s) - GetObjectLegalHold_non_existing_object(s) - GetObjectLegalHold_disabled_lock(s) - GetObjectLegalHold_unset_config(s) - GetObjectLegalHold_success(s) +func TestGetObjectLegalHold(ts *TestState) { + ts.Run(GetObjectLegalHold_non_existing_bucket) + ts.Run(GetObjectLegalHold_non_existing_object) + ts.Run(GetObjectLegalHold_disabled_lock) + ts.Run(GetObjectLegalHold_unset_config) + ts.Run(GetObjectLegalHold_success) } -func TestNotImplementedActions(s *S3Conf) { +func TestNotImplementedActions(ts *TestState) { // bucket analytics actions - PutBucketAnalyticsConfiguration_not_implemented(s) - GetBucketAnalyticsConfiguration_not_implemented(s) - ListBucketAnalyticsConfiguration_not_implemented(s) - DeleteBucketAnalyticsConfiguration_not_implemented(s) + ts.Run(PutBucketAnalyticsConfiguration_not_implemented) + ts.Run(GetBucketAnalyticsConfiguration_not_implemented) + ts.Run(ListBucketAnalyticsConfiguration_not_implemented) + ts.Run(DeleteBucketAnalyticsConfiguration_not_implemented) // bucket encryption actions - PutBucketEncryption_not_implemented(s) - GetBucketEncryption_not_implemented(s) - DeleteBucketEncryption_not_implemented(s) + ts.Run(PutBucketEncryption_not_implemented) + ts.Run(GetBucketEncryption_not_implemented) + ts.Run(DeleteBucketEncryption_not_implemented) // bucket intelligent tierieng actions - PutBucketIntelligentTieringConfiguration_not_implemented(s) - GetBucketIntelligentTieringConfiguration_not_implemented(s) - ListBucketIntelligentTieringConfiguration_not_implemented(s) - DeleteBucketIntelligentTieringConfiguration_not_implemented(s) + ts.Run(PutBucketIntelligentTieringConfiguration_not_implemented) + ts.Run(GetBucketIntelligentTieringConfiguration_not_implemented) + ts.Run(ListBucketIntelligentTieringConfiguration_not_implemented) + ts.Run(DeleteBucketIntelligentTieringConfiguration_not_implemented) // bucket inventory configuration actions - PutBucketInventoryConfiguration_not_implemented(s) - GetBucketInventoryConfiguration_not_implemented(s) - ListBucketInventoryConfiguration_not_implemented(s) - DeleteBucketInventoryConfiguration_not_implemented(s) + ts.Run(PutBucketInventoryConfiguration_not_implemented) + ts.Run(GetBucketInventoryConfiguration_not_implemented) + ts.Run(ListBucketInventoryConfiguration_not_implemented) + ts.Run(DeleteBucketInventoryConfiguration_not_implemented) // bucket lifecycle configuration actions - PutBucketLifecycleConfiguration_not_implemented(s) - GetBucketLifecycleConfiguration_not_implemented(s) - DeleteBucketLifecycle_not_implemented(s) + ts.Run(PutBucketLifecycleConfiguration_not_implemented) + ts.Run(GetBucketLifecycleConfiguration_not_implemented) + ts.Run(DeleteBucketLifecycle_not_implemented) // bucket logging actions - PutBucketLogging_not_implemented(s) - GetBucketLogging_not_implemented(s) + ts.Run(PutBucketLogging_not_implemented) + ts.Run(GetBucketLogging_not_implemented) // bucket request payment actions - PutBucketRequestPayment_not_implemented(s) - GetBucketRequestPayment_not_implemented(s) + ts.Run(PutBucketRequestPayment_not_implemented) + ts.Run(GetBucketRequestPayment_not_implemented) // bucket metrics configuration actions - PutBucketMetricsConfiguration_not_implemented(s) - GetBucketMetricsConfiguration_not_implemented(s) - ListBucketMetricsConfigurations_not_implemented(s) - DeleteBucketMetricsConfiguration_not_implemented(s) + ts.Run(PutBucketMetricsConfiguration_not_implemented) + ts.Run(GetBucketMetricsConfiguration_not_implemented) + ts.Run(ListBucketMetricsConfigurations_not_implemented) + ts.Run(DeleteBucketMetricsConfiguration_not_implemented) // bucket replication actions - PutBucketReplication_not_implemented(s) - GetBucketReplication_not_implemented(s) - DeleteBucketReplication_not_implemented(s) + ts.Run(PutBucketReplication_not_implemented) + ts.Run(GetBucketReplication_not_implemented) + ts.Run(DeleteBucketReplication_not_implemented) // bucket public access block actions - PutPublicAccessBlock_not_implemented(s) - GetPublicAccessBlock_not_implemented(s) - DeletePublicAccessBlock_not_implemented(s) + ts.Run(PutPublicAccessBlock_not_implemented) + ts.Run(GetPublicAccessBlock_not_implemented) + ts.Run(DeletePublicAccessBlock_not_implemented) // bucket notification actions - PutBucketNotificationConfiguratio_not_implemented(s) - GetBucketNotificationConfiguratio_not_implemented(s) + ts.Run(PutBucketNotificationConfiguratio_not_implemented) + ts.Run(GetBucketNotificationConfiguratio_not_implemented) // bucket acceleration actions - PutBucketAccelerateConfiguration_not_implemented(s) - GetBucketAccelerateConfiguration_not_implemented(s) + ts.Run(PutBucketAccelerateConfiguration_not_implemented) + ts.Run(GetBucketAccelerateConfiguration_not_implemented) // bucket website actions - PutBucketWebsite_not_implemented(s) - GetBucketWebsite_not_implemented(s) - DeleteBucketWebsite_not_implemented(s) + ts.Run(PutBucketWebsite_not_implemented) + ts.Run(GetBucketWebsite_not_implemented) + ts.Run(DeleteBucketWebsite_not_implemented) } -func TestWORMProtection(s *S3Conf) { - WORMProtection_bucket_object_lock_configuration_compliance_mode(s) - WORMProtection_bucket_object_lock_configuration_governance_mode(s) - WORMProtection_bucket_object_lock_governance_bypass_delete(s) - WORMProtection_bucket_object_lock_governance_bypass_delete_multiple(s) - WORMProtection_object_lock_retention_compliance_locked(s) - WORMProtection_object_lock_retention_governance_locked(s) - WORMProtection_object_lock_retention_governance_bypass_overwrite(s) - WORMProtection_object_lock_retention_governance_bypass_delete(s) - WORMProtection_object_lock_retention_governance_bypass_delete_mul(s) - WORMProtection_object_lock_legal_hold_locked(s) - WORMProtection_root_bypass_governance_retention_delete_object(s) +func TestWORMProtection(ts *TestState) { + ts.Run(WORMProtection_bucket_object_lock_configuration_compliance_mode) + ts.Run(WORMProtection_bucket_object_lock_configuration_governance_mode) + ts.Run(WORMProtection_bucket_object_lock_governance_bypass_delete) + ts.Run(WORMProtection_bucket_object_lock_governance_bypass_delete_multiple) + ts.Run(WORMProtection_object_lock_retention_compliance_locked) + ts.Run(WORMProtection_object_lock_retention_governance_locked) + ts.Run(WORMProtection_object_lock_retention_governance_bypass_overwrite) + ts.Run(WORMProtection_object_lock_retention_governance_bypass_delete) + ts.Run(WORMProtection_object_lock_retention_governance_bypass_delete_mul) + ts.Run(WORMProtection_object_lock_legal_hold_locked) + ts.Run(WORMProtection_root_bypass_governance_retention_delete_object) } -func TestFullFlow(s *S3Conf) { - TestAuthentication(s) - TestPresignedAuthentication(s) - TestCreateBucket(s) - TestHeadBucket(s) - TestListBuckets(s) - TestDeleteBucket(s) - TestPutBucketOwnershipControls(s) - TestGetBucketOwnershipControls(s) - TestDeleteBucketOwnershipControls(s) - TestPutBucketTagging(s) - TestGetBucketTagging(s) - TestDeleteBucketTagging(s) - TestGetBucketLocation(s) - TestPutObject(s) - TestHeadObject(s) - TestGetObjectAttributes(s) - TestGetObject(s) - TestListObjects(s) - TestListObjectsV2(s) - if !s.versioningEnabled && !s.azureTests { - TestListObjectVersions_VD(s) +func TestFullFlow(ts *TestState) { + TestAuthentication(ts) + TestPresignedAuthentication(ts) + TestCreateBucket(ts) + TestHeadBucket(ts) + TestListBuckets(ts) + TestDeleteBucket(ts) + TestPutBucketOwnershipControls(ts) + TestGetBucketOwnershipControls(ts) + TestDeleteBucketOwnershipControls(ts) + TestPutBucketTagging(ts) + TestGetBucketTagging(ts) + TestDeleteBucketTagging(ts) + TestGetBucketLocation(ts) + TestPutObject(ts) + TestHeadObject(ts) + TestGetObjectAttributes(ts) + TestGetObject(ts) + TestListObjects(ts) + TestListObjectsV2(ts) + if !ts.conf.versioningEnabled && !ts.conf.azureTests { + TestListObjectVersions_VD(ts) } - TestDeleteObject(s) - TestDeleteObjects(s) - TestCopyObject(s) - TestPutObjectTagging(s) - TestDeleteObjectTagging(s) - TestCreateMultipartUpload(s) - TestUploadPart(s) - if !s.azureTests { - TestUploadPartCopy(s) + TestDeleteObject(ts) + TestDeleteObjects(ts) + TestCopyObject(ts) + TestPutObjectTagging(ts) + TestDeleteObjectTagging(ts) + TestCreateMultipartUpload(ts) + TestUploadPart(ts) + if !ts.conf.azureTests { + TestUploadPartCopy(ts) } - TestListParts(s) - TestListMultipartUploads(s) - TestAbortMultipartUpload(s) - TestCompleteMultipartUpload(s) - TestPutBucketAcl(s) - TestGetBucketAcl(s) - TestPutBucketPolicy(s) - TestGetBucketPolicy(s) - TestDeleteBucketPolicy(s) - TestPutBucketCors(s) - TestGetBucketCors(s) - TestDeleteBucketCors(s) - TestPreflightOPTIONSEndpoint(s) - TestPutObjectLockConfiguration(s) - TestGetObjectLockConfiguration(s) - TestPutObjectRetention(s) - TestGetObjectRetention(s) - TestPutObjectLegalHold(s) - TestGetObjectLegalHold(s) - if !s.versioningEnabled { - TestWORMProtection(s) + TestListParts(ts) + TestListMultipartUploads(ts) + TestAbortMultipartUpload(ts) + TestCompleteMultipartUpload(ts) + TestPutBucketAcl(ts) + TestGetBucketAcl(ts) + TestPutBucketPolicy(ts) + TestGetBucketPolicy(ts) + TestDeleteBucketPolicy(ts) + TestPutBucketCors(ts) + TestGetBucketCors(ts) + TestDeleteBucketCors(ts) + TestPreflightOPTIONSEndpoint(ts) + TestPutObjectLockConfiguration(ts) + TestGetObjectLockConfiguration(ts) + TestPutObjectRetention(ts) + TestGetObjectRetention(ts) + TestPutObjectLegalHold(ts) + TestGetObjectLegalHold(ts) + if !ts.conf.versioningEnabled { + TestWORMProtection(ts) } - TestAccessControl(s) - TestRouter(s) + TestAccessControl(ts) + TestRouter(ts) // FIXME: The tests should pass for azure as well // but this issue should be fixed with https://github.com/versity/versitygw/issues/1336 - if !s.azureTests { - TestPublicBuckets(s) + if !ts.conf.azureTests { + TestPublicBuckets(ts) } - if s.versioningEnabled { - TestVersioning(s) + if ts.conf.versioningEnabled { + TestVersioning(ts) } } -func TestPosix(s *S3Conf) { - PutObject_overwrite_dir_obj(s) - PutObject_overwrite_file_obj(s) - PutObject_overwrite_file_obj_with_nested_obj(s) - PutObject_dir_obj_with_data(s) - PutObject_with_slashes(s) - CreateMultipartUpload_dir_obj(s) - PutObject_name_too_long(s) - HeadObject_name_too_long(s) - DeleteObject_name_too_long(s) - CopyObject_overwrite_same_dir_object(s) - CopyObject_overwrite_same_file_object(s) - DeleteObject_directory_not_empty(s) +func TestPosix(ts *TestState) { + ts.Run(PutObject_overwrite_dir_obj) + ts.Run(PutObject_overwrite_file_obj) + ts.Run(PutObject_overwrite_file_obj_with_nested_obj) + ts.Run(PutObject_dir_obj_with_data) + ts.Run(PutObject_with_slashes) + ts.Run(CreateMultipartUpload_dir_obj) + ts.Run(PutObject_name_too_long) + ts.Run(HeadObject_name_too_long) + ts.Run(DeleteObject_name_too_long) + ts.Run(CopyObject_overwrite_same_dir_object) + ts.Run(CopyObject_overwrite_same_file_object) + ts.Run(DeleteObject_directory_not_empty) // posix specific versioning tests - if !s.versioningEnabled { - TestVersioningDisabled(s) + if !ts.conf.versioningEnabled { + TestVersioningDisabled(ts) } } -func TestScoutfs(s *S3Conf) { - TestAuthentication(s) - TestPresignedAuthentication(s) - TestCreateBucket(s) - TestHeadBucket(s) - TestListBuckets(s) - TestDeleteBucket(s) - TestPutBucketOwnershipControls(s) - TestGetBucketOwnershipControls(s) - TestDeleteBucketOwnershipControls(s) - TestPutBucketTagging(s) - TestGetBucketTagging(s) - TestDeleteBucketTagging(s) - TestGetBucketLocation(s) - TestPutObject(s) - TestHeadObject(s) - TestGetObjectAttributes(s) - TestGetObject(s) - TestListObjects(s) - TestListObjectsV2(s) - TestListObjectVersions_VD(s) - TestDeleteObject(s) - TestDeleteObjects(s) - TestCopyObject(s) - TestPutObjectTagging(s) - TestDeleteObjectTagging(s) - TestUploadPart(s) - TestUploadPartCopy(s) - TestListParts(s) - TestListMultipartUploads(s) - TestAbortMultipartUpload(s) - TestPutBucketAcl(s) - TestGetBucketAcl(s) - TestPutBucketPolicy(s) - TestGetBucketPolicy(s) - TestDeleteBucketPolicy(s) - TestPutObjectLockConfiguration(s) - TestGetObjectLockConfiguration(s) - TestPutObjectRetention(s) - TestGetObjectRetention(s) - TestPutObjectLegalHold(s) - TestGetObjectLegalHold(s) - TestWORMProtection(s) - TestAccessControl(s) +func TestScoutfs(ts *TestState) { + TestAuthentication(ts) + TestPresignedAuthentication(ts) + TestCreateBucket(ts) + TestHeadBucket(ts) + TestListBuckets(ts) + TestDeleteBucket(ts) + TestPutBucketOwnershipControls(ts) + TestGetBucketOwnershipControls(ts) + TestDeleteBucketOwnershipControls(ts) + TestPutBucketTagging(ts) + TestGetBucketTagging(ts) + TestDeleteBucketTagging(ts) + TestGetBucketLocation(ts) + TestPutObject(ts) + TestHeadObject(ts) + TestGetObjectAttributes(ts) + TestGetObject(ts) + TestListObjects(ts) + TestListObjectsV2(ts) + TestListObjectVersions_VD(ts) + TestDeleteObject(ts) + TestDeleteObjects(ts) + TestCopyObject(ts) + TestPutObjectTagging(ts) + TestDeleteObjectTagging(ts) + TestUploadPart(ts) + TestUploadPartCopy(ts) + TestListParts(ts) + TestListMultipartUploads(ts) + TestAbortMultipartUpload(ts) + TestPutBucketAcl(ts) + TestGetBucketAcl(ts) + TestPutBucketPolicy(ts) + TestGetBucketPolicy(ts) + TestDeleteBucketPolicy(ts) + TestPutObjectLockConfiguration(ts) + TestGetObjectLockConfiguration(ts) + TestPutObjectRetention(ts) + TestGetObjectRetention(ts) + TestPutObjectLegalHold(ts) + TestGetObjectLegalHold(ts) + TestWORMProtection(ts) + TestAccessControl(ts) - CreateMultipartUpload_non_existing_bucket(s) - CreateMultipartUpload_with_tagging(s) - CreateMultipartUpload_with_object_lock(s) - CreateMultipartUpload_with_object_lock_not_enabled(s) - CreateMultipartUpload_with_object_lock_invalid_retention(s) - CreateMultipartUpload_past_retain_until_date(s) - CreateMultipartUpload_invalid_legal_hold(s) - CreateMultipartUpload_invalid_object_lock_mode(s) - CreateMultipartUpload_invalid_checksum_algorithm(s) - CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type(s) - CreateMultipartUpload_invalid_checksum_type(s) - CreateMultipartUpload_valid_algo_type(s) - CreateMultipartUpload_success(s) + ts.Run(CreateMultipartUpload_non_existing_bucket) + ts.Run(CreateMultipartUpload_with_tagging) + ts.Run(CreateMultipartUpload_with_object_lock) + ts.Run(CreateMultipartUpload_with_object_lock_not_enabled) + ts.Run(CreateMultipartUpload_with_object_lock_invalid_retention) + ts.Run(CreateMultipartUpload_past_retain_until_date) + ts.Run(CreateMultipartUpload_invalid_legal_hold) + ts.Run(CreateMultipartUpload_invalid_object_lock_mode) + ts.Run(CreateMultipartUpload_invalid_checksum_algorithm) + ts.Run(CreateMultipartUpload_empty_checksum_algorithm_with_checksum_type) + ts.Run(CreateMultipartUpload_invalid_checksum_type) + ts.Run(CreateMultipartUpload_valid_algo_type) + ts.Run(CreateMultipartUpload_success) - CompletedMultipartUpload_non_existing_bucket(s) - CompleteMultipartUpload_incorrect_part_number(s) - CompleteMultipartUpload_invalid_part_number(s) - CompleteMultipartUpload_invalid_ETag(s) - CompleteMultipartUpload_small_upload_size(s) - CompleteMultipartUpload_empty_parts(s) - CompleteMultipartUpload_incorrect_parts_order(s) - CompleteMultipartUpload_mpu_object_size(s) - CompleteMultipartUpload_invalid_checksum_type(s) - CompleteMultipartUpload_invalid_checksum_part(s) - CompleteMultipartUpload_multiple_checksum_part(s) - CompleteMultipartUpload_incorrect_checksum_part(s) - CompleteMultipartUpload_different_checksum_part(s) - CompleteMultipartUpload_missing_part_checksum(s) - CompleteMultipartUpload_multiple_final_checksums(s) - CompleteMultipartUpload_invalid_final_checksums(s) - CompleteMultipartUpload_checksum_type_mismatch(s) - CompleteMultipartUpload_should_ignore_the_final_checksum(s) - CompleteMultipartUpload_success(s) - CompleteMultipartUpload_racey_success(s) + ts.Run(CompletedMultipartUpload_non_existing_bucket) + ts.Run(CompleteMultipartUpload_incorrect_part_number) + ts.Run(CompleteMultipartUpload_invalid_part_number) + ts.Run(CompleteMultipartUpload_invalid_ETag) + ts.Run(CompleteMultipartUpload_small_upload_size) + ts.Run(CompleteMultipartUpload_empty_parts) + ts.Run(CompleteMultipartUpload_incorrect_parts_order) + ts.Run(CompleteMultipartUpload_mpu_object_size) + ts.Run(CompleteMultipartUpload_invalid_checksum_type) + ts.Run(CompleteMultipartUpload_invalid_checksum_part) + ts.Run(CompleteMultipartUpload_multiple_checksum_part) + ts.Run(CompleteMultipartUpload_incorrect_checksum_part) + ts.Run(CompleteMultipartUpload_different_checksum_part) + ts.Run(CompleteMultipartUpload_missing_part_checksum) + ts.Run(CompleteMultipartUpload_multiple_final_checksums) + ts.Run(CompleteMultipartUpload_invalid_final_checksums) + ts.Run(CompleteMultipartUpload_checksum_type_mismatch) + ts.Run(CompleteMultipartUpload_should_ignore_the_final_checksum) + ts.Run(CompleteMultipartUpload_success) + ts.Run(CompleteMultipartUpload_racey_success) // posix/scoutfs specific tests - PutObject_overwrite_dir_obj(s) - PutObject_overwrite_file_obj(s) - PutObject_overwrite_file_obj_with_nested_obj(s) - PutObject_dir_obj_with_data(s) - PutObject_with_slashes(s) - CreateMultipartUpload_dir_obj(s) - PutObject_name_too_long(s) - HeadObject_name_too_long(s) - DeleteObject_name_too_long(s) - CopyObject_overwrite_same_dir_object(s) - CopyObject_overwrite_same_file_object(s) - DeleteObject_directory_not_empty(s) + ts.Run(PutObject_overwrite_dir_obj) + ts.Run(PutObject_overwrite_file_obj) + ts.Run(PutObject_overwrite_file_obj_with_nested_obj) + ts.Run(PutObject_dir_obj_with_data) + ts.Run(PutObject_with_slashes) + ts.Run(CreateMultipartUpload_dir_obj) + ts.Run(PutObject_name_too_long) + ts.Run(HeadObject_name_too_long) + ts.Run(DeleteObject_name_too_long) + ts.Run(CopyObject_overwrite_same_dir_object) + ts.Run(CopyObject_overwrite_same_file_object) + ts.Run(DeleteObject_directory_not_empty) } -func TestIAM(s *S3Conf) { - IAM_user_access_denied(s) - IAM_userplus_access_denied(s) - IAM_userplus_CreateBucket(s) - IAM_admin_ChangeBucketOwner(s) - IAM_ChangeBucketOwner_back_to_root(s) - IAM_ListBuckets(s) +func TestIAM(ts *TestState) { + ts.Run(IAM_user_access_denied) + ts.Run(IAM_userplus_access_denied) + ts.Run(IAM_userplus_CreateBucket) + ts.Run(IAM_admin_ChangeBucketOwner) + ts.Run(IAM_ChangeBucketOwner_back_to_root) + ts.Run(IAM_ListBuckets) } -func TestAccessControl(s *S3Conf) { - AccessControl_default_ACL_user_access_denied(s) - AccessControl_default_ACL_userplus_access_denied(s) - AccessControl_default_ACL_admin_successful_access(s) - AccessControl_bucket_resource_single_action(s) - AccessControl_bucket_resource_all_action(s) - AccessControl_single_object_resource_actions(s) - AccessControl_multi_statement_policy(s) - AccessControl_bucket_ownership_to_user(s) - AccessControl_root_PutBucketAcl(s) - AccessControl_user_PutBucketAcl_with_policy_access(s) - AccessControl_copy_object_with_starting_slash_for_user(s) +func TestAccessControl(ts *TestState) { + ts.Run(AccessControl_default_ACL_user_access_denied) + ts.Run(AccessControl_default_ACL_userplus_access_denied) + ts.Run(AccessControl_default_ACL_admin_successful_access) + ts.Run(AccessControl_bucket_resource_single_action) + ts.Run(AccessControl_bucket_resource_all_action) + ts.Run(AccessControl_single_object_resource_actions) + ts.Run(AccessControl_multi_statement_policy) + ts.Run(AccessControl_bucket_ownership_to_user) + ts.Run(AccessControl_root_PutBucketAcl) + ts.Run(AccessControl_user_PutBucketAcl_with_policy_access) + ts.Run(AccessControl_copy_object_with_starting_slash_for_user) } -func TestPublicBuckets(s *S3Conf) { - PublicBucket_default_private_bucket(s) - PublicBucket_public_bucket_policy(s) - if !s.versioningEnabled { +func TestPublicBuckets(ts *TestState) { + ts.Run(PublicBucket_default_private_bucket) + ts.Run(PublicBucket_public_bucket_policy) + if !ts.conf.versioningEnabled { // This test targets gateway actions when bucket grants // public access to object operations: no specific // bucket versioning operations. As object version cleanup // is hard to perform, run the test only on the versioning-disabled // gateway instance - PublicBucket_public_object_policy(s) + ts.Run(PublicBucket_public_object_policy) } - PublicBucket_public_acl(s) - PublicBucket_signed_streaming_payload(s) - PublicBucket_incorrect_sha256_hash(s) + ts.Run(PublicBucket_public_acl) + ts.Run(PublicBucket_signed_streaming_payload) + ts.Run(PublicBucket_incorrect_sha256_hash) } -func TestVersioning(s *S3Conf) { +func TestVersioning(ts *TestState) { // PutBucketVersioning action - PutBucketVersioning_non_existing_bucket(s) - PutBucketVersioning_invalid_status(s) - PutBucketVersioning_success_enabled(s) - PutBucketVersioning_success_suspended(s) + ts.Run(PutBucketVersioning_non_existing_bucket) + ts.Run(PutBucketVersioning_invalid_status) + ts.Run(PutBucketVersioning_success_enabled) + ts.Run(PutBucketVersioning_success_suspended) // GetBucketVersioning action - GetBucketVersioning_non_existing_bucket(s) - GetBucketVersioning_empty_response(s) - GetBucketVersioning_success(s) + ts.Run(GetBucketVersioning_non_existing_bucket) + ts.Run(GetBucketVersioning_empty_response) + ts.Run(GetBucketVersioning_success) // DeleteBucket action - Versioning_DeleteBucket_not_empty(s) + ts.Run(Versioning_DeleteBucket_not_empty) // PutObject action - Versioning_PutObject_suspended_null_versionId_obj(s) - Versioning_PutObject_null_versionId_obj(s) - Versioning_PutObject_overwrite_null_versionId_obj(s) - Versioning_PutObject_success(s) + ts.Run(Versioning_PutObject_suspended_null_versionId_obj) + ts.Run(Versioning_PutObject_null_versionId_obj) + ts.Run(Versioning_PutObject_overwrite_null_versionId_obj) + ts.Run(Versioning_PutObject_success) // CopyObject action - Versioning_CopyObject_success(s) - Versioning_CopyObject_non_existing_version_id(s) - Versioning_CopyObject_from_an_object_version(s) - Versioning_CopyObject_special_chars(s) + ts.Run(Versioning_CopyObject_success) + ts.Run(Versioning_CopyObject_non_existing_version_id) + ts.Run(Versioning_CopyObject_from_an_object_version) + ts.Run(Versioning_CopyObject_special_chars) // HeadObject action - Versioning_HeadObject_invalid_versionId(s) - Versioning_HeadObject_invalid_parent(s) - Versioning_HeadObject_success(s) - Versioning_HeadObject_without_versionId(s) - Versioning_HeadObject_delete_marker(s) + ts.Run(Versioning_HeadObject_invalid_versionId) + ts.Run(Versioning_HeadObject_invalid_parent) + ts.Run(Versioning_HeadObject_success) + ts.Run(Versioning_HeadObject_without_versionId) + ts.Run(Versioning_HeadObject_delete_marker) // GetObject action - Versioning_GetObject_invalid_versionId(s) - Versioning_GetObject_success(s) - Versioning_GetObject_delete_marker_without_versionId(s) - Versioning_GetObject_delete_marker(s) - Versioning_GetObject_null_versionId_obj(s) + ts.Run(Versioning_GetObject_invalid_versionId) + ts.Run(Versioning_GetObject_success) + ts.Run(Versioning_GetObject_delete_marker_without_versionId) + ts.Run(Versioning_GetObject_delete_marker) + ts.Run(Versioning_GetObject_null_versionId_obj) // GetObjectAttributes action - Versioning_GetObjectAttributes_object_version(s) - Versioning_GetObjectAttributes_delete_marker(s) - // DeleteObject(s) actions - Versioning_DeleteObject_delete_object_version(s) - Versioning_DeleteObject_non_existing_object(s) - Versioning_DeleteObject_delete_a_delete_marker(s) - Versioning_Delete_null_versionId_object(s) - Versioning_DeleteObject_nested_dir_object(s) - Versioning_DeleteObject_suspended(s) - Versioning_DeleteObjects_success(s) - Versioning_DeleteObjects_delete_deleteMarkers(s) + ts.Run(Versioning_GetObjectAttributes_object_version) + ts.Run(Versioning_GetObjectAttributes_delete_marker) + // DeleteObject actions + ts.Run(Versioning_DeleteObject_delete_object_version) + ts.Run(Versioning_DeleteObject_non_existing_object) + ts.Run(Versioning_DeleteObject_delete_a_delete_marker) + ts.Run(Versioning_Delete_null_versionId_object) + ts.Run(Versioning_DeleteObject_nested_dir_object) + ts.Run(Versioning_DeleteObject_suspended) + ts.Run(Versioning_DeleteObjects_success) + ts.Run(Versioning_DeleteObjects_delete_deleteMarkers) // ListObjectVersions - ListObjectVersions_non_existing_bucket(s) - ListObjectVersions_list_single_object_versions(s) - ListObjectVersions_list_multiple_object_versions(s) - ListObjectVersions_multiple_object_versions_truncated(s) - ListObjectVersions_with_delete_markers(s) - ListObjectVersions_containing_null_versionId_obj(s) - ListObjectVersions_single_null_versionId_object(s) - ListObjectVersions_checksum(s) + ts.Run(ListObjectVersions_non_existing_bucket) + ts.Run(ListObjectVersions_list_single_object_versions) + ts.Run(ListObjectVersions_list_multiple_object_versions) + ts.Run(ListObjectVersions_multiple_object_versions_truncated) + ts.Run(ListObjectVersions_with_delete_markers) + ts.Run(ListObjectVersions_containing_null_versionId_obj) + ts.Run(ListObjectVersions_single_null_versionId_object) + ts.Run(ListObjectVersions_checksum) // Multipart upload - Versioning_Multipart_Upload_success(s) - Versioning_Multipart_Upload_overwrite_an_object(s) - Versioning_UploadPartCopy_non_existing_versionId(s) - Versioning_UploadPartCopy_from_an_object_version(s) + ts.Run(Versioning_Multipart_Upload_success) + ts.Run(Versioning_Multipart_Upload_overwrite_an_object) + ts.Run(Versioning_UploadPartCopy_non_existing_versionId) + ts.Run(Versioning_UploadPartCopy_from_an_object_version) // Object lock configuration - Versioning_object_lock_not_enabled_on_bucket_creation(s) - Versioning_Enable_object_lock(s) - Versioning_status_switch_to_suspended_with_object_lock(s) + ts.Run(Versioning_object_lock_not_enabled_on_bucket_creation) + ts.Run(Versioning_Enable_object_lock) + ts.Run(Versioning_status_switch_to_suspended_with_object_lock) // Object-Lock Retention - Versioning_PutObjectRetention_invalid_versionId(s) - Versioning_GetObjectRetention_invalid_versionId(s) - Versioning_Put_GetObjectRetention_success(s) + ts.Run(Versioning_PutObjectRetention_invalid_versionId) + ts.Run(Versioning_GetObjectRetention_invalid_versionId) + ts.Run(Versioning_Put_GetObjectRetention_success) // Object-Lock Legal hold - Versioning_PutObjectLegalHold_invalid_versionId(s) - Versioning_GetObjectLegalHold_invalid_versionId(s) - Versioning_Put_GetObjectLegalHold_success(s) + ts.Run(Versioning_PutObjectLegalHold_invalid_versionId) + ts.Run(Versioning_GetObjectLegalHold_invalid_versionId) + ts.Run(Versioning_Put_GetObjectLegalHold_success) // WORM protection - Versioning_WORM_obj_version_locked_with_legal_hold(s) - Versioning_WORM_obj_version_locked_with_governance_retention(s) - Versioning_WORM_obj_version_locked_with_compliance_retention(s) + ts.Run(Versioning_WORM_obj_version_locked_with_legal_hold) + ts.Run(Versioning_WORM_obj_version_locked_with_governance_retention) + ts.Run(Versioning_WORM_obj_version_locked_with_compliance_retention) // Concurrent requests - //Versioninig_concurrent_upload_object(s) - Versioning_AccessControl_GetObjectVersion(s) - Versioning_AccessControl_HeadObjectVersion(s) + // Versioninig_concurrent_upload_object + ts.Run(Versioning_AccessControl_GetObjectVersion) + ts.Run(Versioning_AccessControl_HeadObjectVersion) } -func TestVersioningDisabled(s *S3Conf) { - VersioningDisabled_GetBucketVersioning_not_configured(s) - VersioningDisabled_PutBucketVersioning_not_configured(s) +func TestVersioningDisabled(ts *TestState) { + ts.Run(VersioningDisabled_GetBucketVersioning_not_configured) + ts.Run(VersioningDisabled_PutBucketVersioning_not_configured) } -func TestRouter(s *S3Conf) { - RouterPutPartNumberWithoutUploadId(s) - RouterPostRoot(s) - RouterPostObjectWithoutQuery(s) +func TestRouter(ts *TestState) { + ts.Run(RouterPutPartNumberWithoutUploadId) + ts.Run(RouterPostRoot) + ts.Run(RouterPostObjectWithoutQuery) } -type IntTests map[string]func(s *S3Conf) error +type IntTest func(s3 *S3Conf) error + +type IntTests map[string]IntTest func GetIntTests() IntTests { return IntTests{ diff --git a/tests/integration/output.go b/tests/integration/output.go index 871feacd..788cd00a 100644 --- a/tests/integration/output.go +++ b/tests/integration/output.go @@ -14,7 +14,10 @@ package integration -import "fmt" +import ( + "fmt" + "sync/atomic" +) var ( colorReset = "\033[0m" @@ -24,22 +27,22 @@ var ( ) var ( - RunCount = 0 - PassCount = 0 - FailCount = 0 + RunCount atomic.Uint32 + PassCount atomic.Uint32 + FailCount atomic.Uint32 ) func runF(format string, a ...interface{}) { - RunCount++ + RunCount.Add(1) fmt.Printf(colorCyan+"RUN "+colorReset+format+"\n", a...) } func failF(format string, a ...interface{}) { - FailCount++ + FailCount.Add(1) fmt.Printf(colorRed+"FAIL "+colorReset+format+"\n", a...) } func passF(format string, a ...interface{}) { - PassCount++ + PassCount.Add(1) fmt.Printf(colorGreen+"PASS "+colorReset+format+"\n", a...) } diff --git a/tests/integration/tests.go b/tests/integration/tests.go index f7a66c0e..3e88d76f 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -461,14 +461,15 @@ func Authentication_date_mismatch(s *S3Conf) error { service: "s3", date: time.Now(), }, func(req *http.Request) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } authHdr := req.Header.Get("Authorization") regExp := regexp.MustCompile("Credential=[^,]+,") - hdr := regExp.ReplaceAllString(authHdr, "Credential=grt1/20250912/us-east-1/s3/aws4_request,") + hdr := regExp.ReplaceAllString(authHdr, fmt.Sprintf("Credential=%s/20250912/us-east-1/s3/aws4_request,", testuser.access)) req.Header.Set("Authorization", hdr) resp, err := s.httpClient.Do(req) @@ -1465,10 +1466,12 @@ func CreateBucket_invalid_bucket_name(s *S3Conf) error { func CreateBucket_as_user(s *S3Conf) error { testName := "CreateBucket_as_user" runF(testName) + + testuser := getUser("user") cfg := *s - cfg.awsID = testuser1.access - cfg.awsSecret = testuser1.secret - err := createUsers(s, []user{testuser1}) + cfg.awsID = testuser.access + cfg.awsSecret = testuser.secret + err := createUsers(s, []user{testuser}) if err != nil { failF("%v: %v", testName, err) return fmt.Errorf("%v: %w", testName, err) @@ -1488,14 +1491,15 @@ func CreateBucket_existing_bucket(s *S3Conf) error { testName := "CreateBucket_existing_bucket" runF(testName) bucket := getBucketName() - if err := createUsers(s, []user{testadmin}); err != nil { + adminUser := getUser("admin") + if err := createUsers(s, []user{adminUser}); err != nil { failF("%v: %v", testName, err) return fmt.Errorf("%v: %w", testName, err) } adminCfg := *s - adminCfg.awsID = testadmin.access - adminCfg.awsSecret = testadmin.secret + adminCfg.awsID = adminUser.access + adminCfg.awsSecret = adminUser.secret err := setup(&adminCfg, bucket) if err != nil { @@ -1613,11 +1617,8 @@ func CreateBucket_non_default_acl(s *S3Conf) error { testName := "CreateBucket_non_default_acl" runF(testName) - err := createUsers(s, []user{ - {"grt1", "grt1secret", "user"}, - {"grt2", "grt2secret", "user"}, - {"grt3", "grt3secret", "user"}, - }) + testuser1, testuser2, testuser3 := getUser("user"), getUser("user"), getUser("user") + err := createUsers(s, []user{testuser1, testuser2, testuser3}) if err != nil { failF("%v: %v", testName, err) return fmt.Errorf("%v: %w", testName, err) @@ -1633,21 +1634,21 @@ func CreateBucket_non_default_acl(s *S3Conf) error { }, { Grantee: &types.Grantee{ - ID: getPtr("grt1"), + ID: &testuser1.access, Type: types.TypeCanonicalUser, }, Permission: types.PermissionFullControl, }, { Grantee: &types.Grantee{ - ID: getPtr("grt2"), + ID: &testuser2.access, Type: types.TypeCanonicalUser, }, Permission: types.PermissionReadAcp, }, { Grantee: &types.Grantee{ - ID: getPtr("grt3"), + ID: &testuser3.access, Type: types.TypeCanonicalUser, }, Permission: types.PermissionWrite, @@ -1660,9 +1661,9 @@ func CreateBucket_non_default_acl(s *S3Conf) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = client.CreateBucket(ctx, &s3.CreateBucketInput{ Bucket: &bucket, - GrantFullControl: getPtr("grt1"), - GrantReadACP: getPtr("grt2"), - GrantWrite: getPtr("grt3"), + GrantFullControl: &testuser1.access, + GrantReadACP: &testuser2.access, + GrantWrite: &testuser3.access, ObjectOwnership: types.ObjectOwnershipBucketOwnerPreferred, }) cancel() @@ -1826,12 +1827,13 @@ func GetBucketLocation_non_exist(s *S3Conf) error { func GetBucketLocation_no_access(s *S3Conf) error { testName := "GetBucketLocation_no_access" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testUser := getUser("user") + err := createUsers(s, []user{testUser}) if err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testUser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) resp, err := userClient.GetBucketLocation(ctx, &s3.GetBucketLocationInput{ @@ -1869,7 +1871,9 @@ func ListBuckets_as_user(s *S3Conf) error { }) } - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + + err := createUsers(s, []user{testuser}) if err != nil { return err } @@ -1879,12 +1883,12 @@ func ListBuckets_as_user(s *S3Conf) error { bckts = append(bckts, *buckets[i].Name) } - err = changeBucketsOwner(s, bckts, testuser1.access) + err = changeBucketsOwner(s, bckts, testuser.access) if err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) out, err := userClient.ListBuckets(ctx, &s3.ListBucketsInput{}) @@ -1893,9 +1897,9 @@ func ListBuckets_as_user(s *S3Conf) error { return err } - if getString(out.Owner.ID) != testuser1.access { + if getString(out.Owner.ID) != testuser.access { return fmt.Errorf("expected buckets owner to be %v, instead got %v", - testuser1.access, getString(out.Owner.ID)) + testuser.access, getString(out.Owner.ID)) } if !compareBuckets(out.Buckets, buckets[:3]) { return fmt.Errorf("expected list buckets result to be %v, instead got %v", @@ -1930,8 +1934,9 @@ func ListBuckets_as_admin(s *S3Conf) error { BucketRegion: &s.awsRegion, }) } + testuser, adminUser := getUser("user"), getUser("admin") - err := createUsers(s, []user{testuser1, testadmin}) + err := createUsers(s, []user{testuser, adminUser}) if err != nil { return err } @@ -1941,12 +1946,12 @@ func ListBuckets_as_admin(s *S3Conf) error { bckts = append(bckts, *buckets[i].Name) } - err = changeBucketsOwner(s, bckts, testuser1.access) + err = changeBucketsOwner(s, bckts, testuser.access) if err != nil { return err } - adminClient := s.getUserClient(testadmin) + adminClient := s.getUserClient(adminUser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) out, err := adminClient.ListBuckets(ctx, &s3.ListBucketsInput{}) @@ -1955,9 +1960,9 @@ func ListBuckets_as_admin(s *S3Conf) error { return err } - if getString(out.Owner.ID) != testadmin.access { + if getString(out.Owner.ID) != adminUser.access { return fmt.Errorf("expected buckets owner to be %v, instead got %v", - testadmin.access, getString(out.Owner.ID)) + adminUser.access, getString(out.Owner.ID)) } if !compareBuckets(out.Buckets, buckets) { return fmt.Errorf("expected list buckets result to be %v, instead got %v", @@ -7352,9 +7357,11 @@ func CopyObject_not_owned_source_bucket(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + testuser := getUser("user") - err = createUsers(s, []user{testuser1}) + userClient := s.getUserClient(testuser) + + err = createUsers(s, []user{testuser}) if err != nil { return err } @@ -7365,7 +7372,7 @@ func CopyObject_not_owned_source_bucket(s *S3Conf) error { return err } - err = changeBucketsOwner(s, []string{bucket}, testuser1.access) + err = changeBucketsOwner(s, []string{bucket}, testuser.access) if err != nil { return err } @@ -13624,16 +13631,16 @@ func PutBucketAcl_invalid_acl_acp_and_grants(s *S3Conf) error { func PutBucketAcl_invalid_owner(s *S3Conf) error { testName := "PutBucketAcl_invalid_owner" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - - if err := createUsers(s, []user{testuser1}); err != nil { + testuser := getUser("user") + if err := createUsers(s, []user{testuser}); err != nil { return err } - if err := changeBucketsOwner(s, []string{bucket}, testuser1.access); err != nil { + if err := changeBucketsOwner(s, []string{bucket}, testuser.access); err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := userClient.PutBucketAcl(ctx, &s3.PutBucketAclInput{ @@ -13642,7 +13649,7 @@ func PutBucketAcl_invalid_owner(s *S3Conf) error { Grants: []types.Grant{ { Grantee: &types.Grantee{ - ID: getPtr(testuser1.access), + ID: getPtr(testuser.access), Type: types.TypeCanonicalUser, }, Permission: types.PermissionRead, @@ -13814,7 +13821,8 @@ func PutBucketAcl_empty_grantee_ID_in_body(s *S3Conf) error { func PutBucketAcl_success_access_denied(s *S3Conf) error { testName := "PutBucketAcl_success_access_denied" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } @@ -13826,7 +13834,7 @@ func PutBucketAcl_success_access_denied(s *S3Conf) error { Grants: []types.Grant{ { Grantee: &types.Grantee{ - ID: getPtr(testuser1.access), + ID: getPtr(testuser.access), Type: types.TypeCanonicalUser, }, Permission: types.PermissionRead, @@ -13842,7 +13850,7 @@ func PutBucketAcl_success_access_denied(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) _, err = putObjects(userClient, []string{"my-obj"}, bucket) if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrAccessDenied)); err != nil { @@ -13856,7 +13864,8 @@ func PutBucketAcl_success_access_denied(s *S3Conf) error { func PutBucketAcl_success_canned_acl(s *S3Conf) error { testName := "PutBucketAcl_success_canned_acl" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } @@ -13871,7 +13880,7 @@ func PutBucketAcl_success_canned_acl(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) _, err = putObjects(userClient, []string{"my-obj"}, bucket) if err != nil { @@ -13885,7 +13894,8 @@ func PutBucketAcl_success_canned_acl(s *S3Conf) error { func PutBucketAcl_success_acp(s *S3Conf) error { testName := "PutBucketAcl_success_acp" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } @@ -13893,14 +13903,14 @@ func PutBucketAcl_success_acp(s *S3Conf) error { ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketAcl(ctx, &s3.PutBucketAclInput{ Bucket: &bucket, - GrantRead: &testuser1.access, + GrantRead: &testuser.access, }) cancel() if err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) _, err = putObjects(userClient, []string{"my-obj"}, bucket) if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrAccessDenied)); err != nil { @@ -13923,7 +13933,8 @@ func PutBucketAcl_success_acp(s *S3Conf) error { func PutBucketAcl_success_grants(s *S3Conf) error { testName := "PutBucketAcl_success_grants" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } @@ -13935,7 +13946,7 @@ func PutBucketAcl_success_grants(s *S3Conf) error { Grants: []types.Grant{ { Grantee: &types.Grantee{ - ID: &testuser1.access, + ID: &testuser.access, Type: types.TypeCanonicalUser, }, Permission: types.PermissionFullControl, @@ -13951,7 +13962,7 @@ func PutBucketAcl_success_grants(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) _, err = putObjects(userClient, []string{"my-obj"}, bucket) if err != nil { @@ -14137,12 +14148,13 @@ func GetBucketAcl_translation_canned_private(s *S3Conf) error { func GetBucketAcl_access_denied(s *S3Conf) error { testName := "GetBucketAcl_access_denied" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = userClient.GetBucketAcl(ctx, &s3.GetBucketAclInput{ @@ -14160,11 +14172,8 @@ func GetBucketAcl_access_denied(s *S3Conf) error { func GetBucketAcl_success(s *S3Conf) error { testName := "GetBucketAcl_success" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{ - {"grt1", "grt1secret", "user"}, - {"grt2", "grt2secret", "user"}, - {"grt3", "grt3secret", "user"}, - }) + testuser1, testuser2, testuser3 := getUser("user"), getUser("user"), getUser("user") + err := createUsers(s, []user{testuser1, testuser2, testuser3}) if err != nil { return err } @@ -14172,21 +14181,21 @@ func GetBucketAcl_success(s *S3Conf) error { grants := []types.Grant{ { Grantee: &types.Grantee{ - ID: getPtr("grt1"), + ID: &testuser1.access, Type: types.TypeCanonicalUser, }, Permission: types.PermissionFullControl, }, { Grantee: &types.Grantee{ - ID: getPtr("grt2"), + ID: &testuser2.access, Type: types.TypeCanonicalUser, }, Permission: types.PermissionReadAcp, }, { Grantee: &types.Grantee{ - ID: getPtr("grt3"), + ID: &testuser3.access, Type: types.TypeCanonicalUser, }, Permission: types.PermissionWrite, @@ -14356,7 +14365,8 @@ func PutBucketPolicy_invalid_effect(s *S3Conf) error { func PutBucketPolicy_invalid_action(s *S3Conf) error { testName := "PutBucketPolicy_invalid_action" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } @@ -14375,7 +14385,7 @@ func PutBucketPolicy_invalid_action(s *S3Conf) error { // wildcard abuse `"s3:*Obj??ect*"`, `"s3:????"`, `"s3:*:"`, `"*GetObject"`, `"???PutObject"`, `"s3:Abort?"`, `"s3:??Abort*"`, } { - doc := genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser1.access), action, fmt.Sprintf(`"arn:aws:s3:::%s"`, bucket)) + doc := genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser.access), action, fmt.Sprintf(`"arn:aws:s3:::%s"`, bucket)) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ @@ -14669,6 +14679,7 @@ func PutBucketPolicy_action_resource_mismatch(s *S3Conf) error { func PutBucketPolicy_explicit_deny(s *S3Conf) error { testName := "PutBucketPolicy_explicit_deny" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + testuser1, testuser2 := getUser("user"), getUser("user") err := createUsers(s, []user{testuser1, testuser2}) if err != nil { return err @@ -14686,7 +14697,7 @@ func PutBucketPolicy_explicit_deny(s *S3Conf) error { ], "Effect": "Allow", "Principal": [ - "grt1" + "%s" ], "Resource": [ "%v", @@ -14699,7 +14710,7 @@ func PutBucketPolicy_explicit_deny(s *S3Conf) error { ], "Effect": "Allow", "Principal": [ - "grt2" + "%s" ], "Resource": [ "%v", @@ -14712,12 +14723,12 @@ func PutBucketPolicy_explicit_deny(s *S3Conf) error { ], "Effect": "Deny", "Principal": [ - "grt2" + "%s" ], "Resource": "%v" } ] - }`, resourcePrefix, resource, resourceWildCard, resource, resourcePrefix) + }`, testuser1.access, resourcePrefix, resource, testuser2.access, resourceWildCard, resource, testuser2.access, resourcePrefix) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ @@ -14748,12 +14759,13 @@ func PutBucketPolicy_explicit_deny(s *S3Conf) error { func PutBucketPolicy_multi_wildcard_resource(s *S3Conf) error { testName := "PutBucketPolicy_multi_wildcard_resource" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - if err := createUsers(s, []user{testuser1}); err != nil { + testuser := getUser("user") + if err := createUsers(s, []user{testuser}); err != nil { return err } resource := fmt.Sprintf(`["arn:aws:s3:::%v/*/*", "arn:aws:s3:::%v"]`, bucket, bucket) - principal := fmt.Sprintf("\"%v\"", testuser1.access) + principal := fmt.Sprintf("\"%v\"", testuser.access) doc := genPolicyDoc("Allow", principal, `"s3:*"`, resource) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) @@ -14766,7 +14778,7 @@ func PutBucketPolicy_multi_wildcard_resource(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) _, err = putObjects(userClient, []string{"foo"}, bucket) if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrAccessDenied)); err != nil { return err @@ -14784,12 +14796,13 @@ func PutBucketPolicy_multi_wildcard_resource(s *S3Conf) error { func PutBucketPolicy_any_char_match(s *S3Conf) error { testName := "PutBucketPolicy_any_char_match" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - if err := createUsers(s, []user{testuser1}); err != nil { + testuser := getUser("user") + if err := createUsers(s, []user{testuser}); err != nil { return err } resource := fmt.Sprintf(`["arn:aws:s3:::%v/m?-obj/*"]`, bucket) - principal := fmt.Sprintf("\"%v\"", testuser1.access) + principal := fmt.Sprintf("\"%v\"", testuser.access) doc := genPolicyDoc("Allow", principal, `"s3:*"`, resource) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) @@ -14802,7 +14815,7 @@ func PutBucketPolicy_any_char_match(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) _, err = putObjects(userClient, []string{"myy-obj/hello", "rand/foo", "my-objj/bar"}, bucket) if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrAccessDenied)); err != nil { return err @@ -14820,6 +14833,7 @@ func PutBucketPolicy_any_char_match(s *S3Conf) error { func PutBucketPolicy_success(s *S3Conf) error { testName := "PutBucketPolicy_success" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + testuser1, testuser2 := getUser("user"), getUser("user") err := createUsers(s, []user{testuser1, testuser2}) if err != nil { return err @@ -14829,11 +14843,11 @@ func PutBucketPolicy_success(s *S3Conf) error { objectResource := fmt.Sprintf(`"arn:aws:s3:::%v/*"`, bucket) for _, doc := range []string{ - genPolicyDoc("Allow", `["grt1", "grt2"]`, `["s3:DeleteBucket", "s3:GetBucketAcl"]`, bucketResource), - genPolicyDoc("Allow", `{"AWS": ["grt1", "grt2"]}`, `["s3:DeleteBucket", "s3:GetBucketAcl"]`, bucketResource), + genPolicyDoc("Allow", fmt.Sprintf(`["%s", "%s"]`, testuser1.access, testuser2.access), `["s3:DeleteBucket", "s3:GetBucketAcl"]`, bucketResource), + genPolicyDoc("Allow", fmt.Sprintf(`{"AWS": ["%s", "%s"]}`, testuser1.access, testuser2.access), `["s3:DeleteBucket", "s3:GetBucketAcl"]`, bucketResource), genPolicyDoc("Deny", `"*"`, `"s3:DeleteBucket"`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)), genPolicyDoc("Deny", `{"AWS": "*"}`, `"s3:DeleteBucket"`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)), - genPolicyDoc("Allow", `"grt1"`, `["s3:PutBucketVersioning", "s3:ListMultipartUploadParts", "s3:ListBucket"]`, fmt.Sprintf(`[%v, %v]`, bucketResource, objectResource)), + genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser1.access), `["s3:PutBucketVersioning", "s3:ListMultipartUploadParts", "s3:ListBucket"]`, fmt.Sprintf(`[%v, %v]`, bucketResource, objectResource)), genPolicyDoc("Allow", `"*"`, `"s3:*"`, fmt.Sprintf(`[%v, %v]`, bucketResource, objectResource)), genPolicyDoc("Allow", `"*"`, `"s3:Get*"`, objectResource), genPolicyDoc("Deny", `"*"`, `"s3:Create*"`, fmt.Sprintf(`[%v, %v]`, bucketResource, objectResource)), @@ -14948,6 +14962,7 @@ func GetBucketPolicyStatus_no_such_bucket_policy(s *S3Conf) error { func GetBucketPolicyStatus_success(s *S3Conf) error { testName := "GetBucketPolicyStatus_success" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + testuser1, testuser2 := getUser("user"), getUser("user") err := createUsers(s, []user{testuser1, testuser2}) if err != nil { return err @@ -14958,11 +14973,11 @@ func GetBucketPolicyStatus_success(s *S3Conf) error { status bool }{ { - policy: genPolicyDoc("Allow", `"grt1"`, `["s3:DeleteBucket", "s3:GetBucketTagging"]`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)), + policy: genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser1.access), `["s3:DeleteBucket", "s3:GetBucketTagging"]`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)), status: false, }, { - policy: genPolicyDoc("Allow", `"grt2"`, `"s3:GetObject"`, fmt.Sprintf(`"arn:aws:s3:::%v/obj"`, bucket)), + policy: genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser2.access), `"s3:GetObject"`, fmt.Sprintf(`"arn:aws:s3:::%v/obj"`, bucket)), status: false, }, { @@ -18114,12 +18129,13 @@ func WORMProtection_root_bypass_governance_retention_delete_object(s *S3Conf) er func AccessControl_default_ACL_user_access_denied(s *S3Conf) error { testName := "AccessControl_default_ACL_user_access_denied" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) _, err = putObjects(userClient, []string{"my-obj"}, bucket) if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrAccessDenied)); err != nil { @@ -18133,12 +18149,13 @@ func AccessControl_default_ACL_user_access_denied(s *S3Conf) error { func AccessControl_default_ACL_userplus_access_denied(s *S3Conf) error { testName := "AccessControl_default_ACL_userplus_access_denied" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuserplus}) + testuser := getUser("userplus") + err := createUsers(s, []user{testuser}) if err != nil { return err } - client := s.getUserClient(testuserplus) + client := s.getUserClient(testuser) _, err = putObjects(client, []string{"my-obj"}, bucket) if err := checkApiErr(err, s3err.GetAPIError(s3err.ErrAccessDenied)); err != nil { @@ -18152,12 +18169,13 @@ func AccessControl_default_ACL_userplus_access_denied(s *S3Conf) error { func AccessControl_default_ACL_admin_successful_access(s *S3Conf) error { testName := "AccessControl_default_ACL_admin_successful_access" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testadmin}) + testuser := getUser("admin") + err := createUsers(s, []user{testuser}) if err != nil { return err } - adminClient := s.getUserClient(testadmin) + adminClient := s.getUserClient(testuser) _, err = putObjects(adminClient, []string{"my-obj"}, bucket) if err != nil { @@ -18171,12 +18189,13 @@ func AccessControl_default_ACL_admin_successful_access(s *S3Conf) error { func AccessControl_bucket_resource_single_action(s *S3Conf) error { testName := "AccessControl_bucket_resource_single_action" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + testuser1, testuser2 := getUser("user"), getUser("user") err := createUsers(s, []user{testuser1, testuser2}) if err != nil { return err } - doc := genPolicyDoc("Allow", `["grt1"]`, `"s3:PutBucketTagging"`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)) + doc := genPolicyDoc("Allow", fmt.Sprintf(`["%s"]`, testuser1.access), `"s3:PutBucketTagging"`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ Bucket: &bucket, @@ -18225,6 +18244,7 @@ func AccessControl_bucket_resource_single_action(s *S3Conf) error { func AccessControl_bucket_resource_all_action(s *S3Conf) error { testName := "AccessControl_bucket_resource_all_action" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + testuser1, testuser2 := getUser("user"), getUser("user") err := createUsers(s, []user{testuser1, testuser2}) if err != nil { return err @@ -18232,7 +18252,7 @@ func AccessControl_bucket_resource_all_action(s *S3Conf) error { bucketResource := fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket) objectResource := fmt.Sprintf(`"arn:aws:s3:::%v/*"`, bucket) - doc := genPolicyDoc("Allow", `["grt1"]`, `"s3:*"`, fmt.Sprintf(`[%v, %v]`, bucketResource, objectResource)) + doc := genPolicyDoc("Allow", fmt.Sprintf(`["%s"]`, testuser1.access), `"s3:*"`, fmt.Sprintf(`[%v, %v]`, bucketResource, objectResource)) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ @@ -18270,12 +18290,14 @@ func AccessControl_single_object_resource_actions(s *S3Conf) error { return err } - err = createUsers(s, []user{testuser1}) + testuser := getUser("user") + + err = createUsers(s, []user{testuser}) if err != nil { return err } - doc := genPolicyDoc("Allow", `["grt1"]`, `"s3:*"`, fmt.Sprintf(`"arn:aws:s3:::%v/%v"`, bucket, obj)) + doc := genPolicyDoc("Allow", fmt.Sprintf(`["%s"]`, testuser.access), `"s3:*"`, fmt.Sprintf(`"arn:aws:s3:::%v/%v"`, bucket, obj)) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ @@ -18287,7 +18309,7 @@ func AccessControl_single_object_resource_actions(s *S3Conf) error { return err } - testuser1Client := s.getUserClient(testuser1) + testuser1Client := s.getUserClient(testuser) ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) _, err = testuser1Client.GetObject(ctx, &s3.GetObjectInput{ @@ -18315,27 +18337,28 @@ func AccessControl_single_object_resource_actions(s *S3Conf) error { func AccessControl_multi_statement_policy(s *S3Conf) error { testName := "AccessControl_multi_statement_policy" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + testuser := getUser("user") + err := createUsers(s, []user{testuser}) + if err != nil { + return err + } + policy := fmt.Sprintf(`{ "Statement": [ { "Effect": "Deny", - "Principal": ["grt1"], + "Principal": ["%s"], "Action": "s3:DeleteBucket", "Resource": "arn:aws:s3:::%s" }, { "Effect": "Allow", - "Principal": "grt1", + "Principal": "%s", "Action": "s3:*", "Resource": ["arn:aws:s3:::%s", "arn:aws:s3:::%s/*"] } ] - }`, bucket, bucket, bucket) - - err := createUsers(s, []user{testuser1}) - if err != nil { - return err - } + }`, testuser.access, bucket, testuser.access, bucket, bucket) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ @@ -18347,7 +18370,7 @@ func AccessControl_multi_statement_policy(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) _, err = userClient.ListObjects(ctx, &s3.ListObjectsInput{ @@ -18374,15 +18397,16 @@ func AccessControl_multi_statement_policy(s *S3Conf) error { func AccessControl_bucket_ownership_to_user(s *S3Conf) error { testName := "AccessControl_bucket_ownership_to_user" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - if err := createUsers(s, []user{testuser1}); err != nil { + testuser := getUser("user") + if err := createUsers(s, []user{testuser}); err != nil { return err } - if err := changeBucketsOwner(s, []string{bucket}, testuser1.access); err != nil { + if err := changeBucketsOwner(s, []string{bucket}, testuser.access); err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := userClient.HeadBucket(ctx, &s3.HeadBucketInput{ @@ -18400,16 +18424,16 @@ func AccessControl_bucket_ownership_to_user(s *S3Conf) error { func AccessControl_root_PutBucketAcl(s *S3Conf) error { testName := "AccessControl_root_PutBucketAcl" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - - if err := createUsers(s, []user{testuser1}); err != nil { + testuser := getUser("user") + if err := createUsers(s, []user{testuser}); err != nil { return err } - if err := changeBucketsOwner(s, []string{bucket}, testuser1.access); err != nil { + if err := changeBucketsOwner(s, []string{bucket}, testuser.access); err != nil { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := userClient.PutBucketAcl(ctx, &s3.PutBucketAclInput{ @@ -18428,11 +18452,12 @@ func AccessControl_root_PutBucketAcl(s *S3Conf) error { func AccessControl_user_PutBucketAcl_with_policy_access(s *S3Conf) error { testName := "AccessControl_user_PutBucketAcl_with_policy_access" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - if err := createUsers(s, []user{testuser1}); err != nil { + testuser := getUser("user") + if err := createUsers(s, []user{testuser}); err != nil { return err } - policy := genPolicyDoc("Allow", fmt.Sprintf(`"%v"`, testuser1.access), `"s3:PutBucketAcl"`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)) + policy := genPolicyDoc("Allow", fmt.Sprintf(`"%v"`, testuser.access), `"s3:PutBucketAcl"`, fmt.Sprintf(`"arn:aws:s3:::%v"`, bucket)) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err := s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ @@ -18444,7 +18469,7 @@ func AccessControl_user_PutBucketAcl_with_policy_access(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) _, err = userClient.PutBucketAcl(ctx, &s3.PutBucketAclInput{ Bucket: &bucket, @@ -18499,7 +18524,12 @@ func AccessControl_copy_object_with_starting_slash_for_user(s *S3Conf) error { return err } - if err := changeBucketsOwner(s, []string{bucket}, testuser1.access); err != nil { + testuser := getUser("user") + err = createUsers(s, []user{testuser}) + if err != nil { + return err + } + if err := changeBucketsOwner(s, []string{bucket}, testuser.access); err != nil { return err } @@ -18508,7 +18538,7 @@ func AccessControl_copy_object_with_starting_slash_for_user(s *S3Conf) error { "key1": "val1", } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = userClient.CopyObject(ctx, &s3.CopyObjectInput{ Bucket: &bucket, @@ -20991,13 +21021,14 @@ func IAM_user_access_denied(s *S3Conf) error { testName := "IAM_user_access_denied" runF(testName) - err := createUsers(s, []user{testuser1}) + testuser := getUser("user") + err := createUsers(s, []user{testuser}) if err != nil { failF("%v: %v", testName, err) return fmt.Errorf("%v: %w", testName, err) } - out, err := execCommand(s.getAdminCommand("-a", testuser1.access, "-s", testuser1.secret, "-er", s.endpoint, "delete-user", "-a", "random_access")...) + out, err := execCommand(s.getAdminCommand("-a", testuser.access, "-s", testuser.secret, "-er", s.endpoint, "delete-user", "-a", "random_access")...) if err == nil { failF("%v: expected cmd error", testName) return fmt.Errorf("%v: expected cmd error", testName) @@ -21018,13 +21049,14 @@ func IAM_userplus_access_denied(s *S3Conf) error { testName := "IAM_userplus_access_denied" runF(testName) - err := createUsers(s, []user{testuserplus}) + testuser := getUser("userplus") + err := createUsers(s, []user{testuser}) if err != nil { failF("%v: %v", testName, err) return fmt.Errorf("%v: %w", testName, err) } - out, err := execCommand(s.getAdminCommand("-a", testuserplus.access, "-s", testuserplus.secret, "-er", s.endpoint, "delete-user", "-a", "random_access")...) + out, err := execCommand(s.getAdminCommand("-a", testuser.access, "-s", testuser.secret, "-er", s.endpoint, "delete-user", "-a", "random_access")...) if err == nil { failF("%v: expected cmd error", testName) return fmt.Errorf("%v: expected cmd error", testName) @@ -21044,14 +21076,15 @@ func IAM_userplus_access_denied(s *S3Conf) error { func IAM_userplus_CreateBucket(s *S3Conf) error { testName := "IAM_userplus_CreateBucket" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testuserplus}) + testuser := getUser("userplus") + err := createUsers(s, []user{testuser}) if err != nil { return err } cfg := *s - cfg.awsID = testuserplus.access - cfg.awsSecret = testuserplus.secret + cfg.awsID = testuser.access + cfg.awsSecret = testuser.secret bckt := getBucketName() err = setup(&cfg, bckt) @@ -21078,12 +21111,13 @@ func IAM_userplus_CreateBucket(s *S3Conf) error { func IAM_admin_ChangeBucketOwner(s *S3Conf) error { testName := "IAM_admin_ChangeBucketOwner" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - err := createUsers(s, []user{testadmin, testuser1}) + testuser, adminuser := getUser("user"), getUser("admin") + err := createUsers(s, []user{adminuser, testuser}) if err != nil { return err } - err = changeBucketsOwner(s, []string{bucket}, testuser1.access) + err = changeBucketsOwner(s, []string{bucket}, testuser.access) if err != nil { return err } @@ -21095,9 +21129,9 @@ func IAM_admin_ChangeBucketOwner(s *S3Conf) error { return err } - if getString(resp.Owner.ID) != testuser1.access { + if getString(resp.Owner.ID) != testuser.access { return fmt.Errorf("expected the bucket owner to be %v, instead got %v", - testuser1.access, getString(resp.Owner.ID)) + testuser.access, getString(resp.Owner.ID)) } return nil @@ -21107,12 +21141,13 @@ func IAM_admin_ChangeBucketOwner(s *S3Conf) error { func IAM_ChangeBucketOwner_back_to_root(s *S3Conf) error { testName := "IAM_ChangeBucketOwner_back_to_root" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { - if err := createUsers(s, []user{testuser1}); err != nil { + testuser := getUser("user") + if err := createUsers(s, []user{testuser}); err != nil { return err } // Change the bucket ownership to a random user - if err := changeBucketsOwner(s, []string{bucket}, testuser1.access); err != nil { + if err := changeBucketsOwner(s, []string{bucket}, testuser.access); err != nil { return err } @@ -24037,12 +24072,13 @@ func Versioning_AccessControl_GetObjectVersion(s *S3Conf) error { return err } - err = createUsers(s, []user{testuser1}) + testuser := getUser("user") + err = createUsers(s, []user{testuser}) if err != nil { return err } - doc := genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser1.access), `"s3:GetObject"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) + doc := genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser.access), `"s3:GetObject"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ Bucket: &bucket, @@ -24053,7 +24089,7 @@ func Versioning_AccessControl_GetObjectVersion(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) // querying with versionId should return access denied ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) @@ -24068,7 +24104,7 @@ func Versioning_AccessControl_GetObjectVersion(s *S3Conf) error { } // grant the user s3:GetObjectVersion - doc = genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser1.access), `"s3:GetObjectVersion"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) + doc = genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser.access), `"s3:GetObjectVersion"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ Bucket: &bucket, @@ -24106,12 +24142,13 @@ func Versioning_AccessControl_HeadObjectVersion(s *S3Conf) error { return err } - err = createUsers(s, []user{testuser1}) + testuser := getUser("user") + err = createUsers(s, []user{testuser}) if err != nil { return err } - doc := genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser1.access), `"s3:GetObject"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) + doc := genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser.access), `"s3:GetObject"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ Bucket: &bucket, @@ -24122,7 +24159,7 @@ func Versioning_AccessControl_HeadObjectVersion(s *S3Conf) error { return err } - userClient := s.getUserClient(testuser1) + userClient := s.getUserClient(testuser) // querying with versionId should return access denied ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) @@ -24137,7 +24174,7 @@ func Versioning_AccessControl_HeadObjectVersion(s *S3Conf) error { } // grant the user s3:GetObjectVersion - doc = genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser1.access), `"s3:GetObjectVersion"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) + doc = genPolicyDoc("Allow", fmt.Sprintf(`"%s"`, testuser.access), `"s3:GetObjectVersion"`, fmt.Sprintf(`"arn:aws:s3:::%s/*"`, bucket)) ctx, cancel = context.WithTimeout(context.Background(), shortTimeout) _, err = s3client.PutBucketPolicy(ctx, &s3.PutBucketPolicyInput{ Bucket: &bucket, diff --git a/tests/integration/utils.go b/tests/integration/utils.go index 49ead60c..02b04c9a 100644 --- a/tests/integration/utils.go +++ b/tests/integration/utils.go @@ -39,6 +39,7 @@ import ( "slices" "sort" "strings" + "sync/atomic" "time" "unicode" @@ -53,7 +54,7 @@ import ( ) var ( - bcktCount = 0 + bcktCount atomic.Uint64 adminErrorPrefix = "XAdmin" ) @@ -63,32 +64,17 @@ type user struct { role string } -var ( - testuser1 user = user{ - access: "grt1", - secret: "grt1secret", - role: "user", - } - testuser2 user = user{ - access: "grt2", - secret: "grt2secret", - role: "user", - } - testuserplus user = user{ - access: "grtplus", - secret: "grt1plussecret", - role: "userplus", - } - testadmin user = user{ - access: "admin", - secret: "adminsecret", - role: "admin", - } -) - func getBucketName() string { - bcktCount++ - return fmt.Sprintf("test-bucket-%v", bcktCount) + bcktCount.Add(1) + return fmt.Sprintf("test-bucket-%v", bcktCount.Load()) +} + +func getUser(role string) user { + return user{ + access: fmt.Sprintf("test-user-%v", genRandString(16)), + secret: fmt.Sprintf("test-secret-%v", genRandString(16)), + role: role, + } } func setup(s *S3Conf, bucket string, opts ...setupOpt) error { @@ -945,10 +931,6 @@ func uploadParts(client *s3.Client, size, partCount int64, bucket, key, uploadId func createUsers(s *S3Conf, users []user) error { for _, usr := range users { - err := deleteUser(s, usr.access) - if err != nil { - return err - } out, err := execCommand(s.getAdminCommand("-a", s.awsID, "-s", s.awsSecret, "-er", s.endpoint, "create-user", "-a", usr.access, "-s", usr.secret, "-r", usr.role)...) if err != nil { return err @@ -960,18 +942,6 @@ func createUsers(s *S3Conf, users []user) error { return nil } -func deleteUser(s *S3Conf, access string) error { - out, err := execCommand(s.getAdminCommand("-a", s.awsID, "-s", s.awsSecret, "-er", s.endpoint, "delete-user", "-a", access)...) - if err != nil { - return err - } - if strings.Contains(string(out), adminErrorPrefix) { - return fmt.Errorf("failed to delete the user account, %s", out) - } - - return nil -} - func changeBucketsOwner(s *S3Conf, buckets []string, owner string) error { for _, bucket := range buckets { out, err := execCommand(s.getAdminCommand("-a", s.awsID, "-s", s.awsSecret, "-er", s.endpoint, "change-bucket-owner", "-b", bucket, "-o", owner)...) @@ -1854,6 +1824,8 @@ func cleanupLockedObjects(client *s3.Client, bucket string, objs []objToDelete) return fmt.Errorf("failed to acquire worker space: %w", err) } + defer sem.Release(1) + eg.Go(func() error { // Remove legal hold if required if obj.removeLegalHold || obj.removeOnlyLeglHold {