From a4dc837f54548495046ed781224cc33a5a039e6b Mon Sep 17 00:00:00 2001 From: niksis02 Date: Tue, 7 Oct 2025 23:21:08 +0400 Subject: [PATCH] feat: concurrent execution of integration tests This change introduces concurrent execution for integration tests. It adds a mechanism to run tests either synchronously or in parallel, controlled by a new flag. By default, tests continue to run in synchronous mode to maintain predictable behavior during local development. In GitHub Actions, the tests are now executed in parallel mode to significantly reduce overall runtime. The implementation uses a semaphore-based concurrency control to limit the number of parallel test executions and ensures graceful shutdown through context cancellation. This approach improves test performance while keeping the system stable and backward compatible. --- cmd/versitygw/test.go | 21 +- runtests.sh | 11 +- tests/integration/concurrency.go | 118 +++ tests/integration/group-tests.go | 1636 +++++++++++++++--------------- tests/integration/output.go | 17 +- tests/integration/tests.go | 297 +++--- tests/integration/utils.go | 56 +- 7 files changed, 1147 insertions(+), 1009 deletions(-) create mode 100644 tests/integration/concurrency.go 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 {