diff options
| author | chrislu <chris.lu@gmail.com> | 2025-12-14 16:08:56 -0800 |
|---|---|---|
| committer | chrislu <chris.lu@gmail.com> | 2025-12-14 16:08:56 -0800 |
| commit | f734b2d4bf154b372d382283a8ef09fe1c808154 (patch) | |
| tree | 85d2e06d14257051a3e57da1d6ee773a401113fe /weed/iam/helpers_test.go | |
| parent | f41925b60bd066048217a6de23185a6e6cfb75a7 (diff) | |
| download | seaweedfs-f734b2d4bf154b372d382283a8ef09fe1c808154.tar.xz seaweedfs-f734b2d4bf154b372d382283a8ef09fe1c808154.zip | |
Refactor: Extract common IAM logic into shared weed/iam package (#7747)
This resolves GitHub issue #7747 by extracting duplicated IAM code into
a shared package that both the embedded S3 IAM and standalone IAM use.
New shared package (weed/iam/):
- constants.go: Common constants (charsets, action strings, error messages)
- helpers.go: Shared helper functions (Hash, GenerateRandomString,
GenerateAccessKeyId, GenerateSecretAccessKey, StringSlicesEqual,
MapToStatementAction, MapToIdentitiesAction, MaskAccessKey)
- responses.go: Common IAM response structs (CommonResponse, ListUsersResponse,
CreateUserResponse, etc.)
- helpers_test.go: Unit tests for shared helpers
Updated files:
- weed/s3api/s3api_embedded_iam.go: Use type aliases and function wrappers
to the shared package, removing ~200 lines of duplicated code
- weed/iamapi/iamapi_management_handlers.go: Use shared package for constants
and helper functions, removing ~100 lines of duplicated code
- weed/iamapi/iamapi_response.go: Re-export types from shared package for
backwards compatibility
Benefits:
- Single source of truth for IAM constants and helpers
- Easier maintenance - changes only need to be made in one place
- Reduced risk of inconsistencies between embedded and standalone IAM
- Better test coverage through shared test suite
Diffstat (limited to 'weed/iam/helpers_test.go')
| -rw-r--r-- | weed/iam/helpers_test.go | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/weed/iam/helpers_test.go b/weed/iam/helpers_test.go new file mode 100644 index 000000000..c9913d28a --- /dev/null +++ b/weed/iam/helpers_test.go @@ -0,0 +1,135 @@ +package iam + +import ( + "testing" + + "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants" + "github.com/stretchr/testify/assert" +) + +func TestHash(t *testing.T) { + input := "test" + result := Hash(&input) + assert.NotEmpty(t, result) + assert.Len(t, result, 40) // SHA1 hex is 40 chars + + // Same input should produce same hash + result2 := Hash(&input) + assert.Equal(t, result, result2) + + // Different input should produce different hash + different := "different" + result3 := Hash(&different) + assert.NotEqual(t, result, result3) +} + +func TestGenerateRandomString(t *testing.T) { + // Valid generation + result, err := GenerateRandomString(10, CharsetUpper) + assert.NoError(t, err) + assert.Len(t, result, 10) + + // Different calls should produce different results (with high probability) + result2, err := GenerateRandomString(10, CharsetUpper) + assert.NoError(t, err) + assert.NotEqual(t, result, result2) + + // Invalid length + _, err = GenerateRandomString(0, CharsetUpper) + assert.Error(t, err) + + _, err = GenerateRandomString(-1, CharsetUpper) + assert.Error(t, err) + + // Empty charset + _, err = GenerateRandomString(10, "") + assert.Error(t, err) +} + +func TestGenerateAccessKeyId(t *testing.T) { + keyId, err := GenerateAccessKeyId() + assert.NoError(t, err) + assert.Len(t, keyId, AccessKeyIdLength) +} + +func TestGenerateSecretAccessKey(t *testing.T) { + secretKey, err := GenerateSecretAccessKey() + assert.NoError(t, err) + assert.Len(t, secretKey, SecretAccessKeyLength) +} + +func TestStringSlicesEqual(t *testing.T) { + tests := []struct { + a []string + b []string + expected bool + }{ + {[]string{"a", "b", "c"}, []string{"a", "b", "c"}, true}, + {[]string{"c", "b", "a"}, []string{"a", "b", "c"}, true}, // Order independent + {[]string{"a", "b"}, []string{"a", "b", "c"}, false}, + {[]string{}, []string{}, true}, + {nil, nil, true}, + {[]string{"a"}, []string{"b"}, false}, + } + + for _, test := range tests { + result := StringSlicesEqual(test.a, test.b) + assert.Equal(t, test.expected, result) + } +} + +func TestMapToStatementAction(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {StatementActionAdmin, s3_constants.ACTION_ADMIN}, + {StatementActionWrite, s3_constants.ACTION_WRITE}, + {StatementActionRead, s3_constants.ACTION_READ}, + {StatementActionList, s3_constants.ACTION_LIST}, + {StatementActionDelete, s3_constants.ACTION_DELETE_BUCKET}, + {"unknown", ""}, + } + + for _, test := range tests { + result := MapToStatementAction(test.input) + assert.Equal(t, test.expected, result) + } +} + +func TestMapToIdentitiesAction(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {s3_constants.ACTION_ADMIN, StatementActionAdmin}, + {s3_constants.ACTION_WRITE, StatementActionWrite}, + {s3_constants.ACTION_READ, StatementActionRead}, + {s3_constants.ACTION_LIST, StatementActionList}, + {s3_constants.ACTION_DELETE_BUCKET, StatementActionDelete}, + {"unknown", ""}, + } + + for _, test := range tests { + result := MapToIdentitiesAction(test.input) + assert.Equal(t, test.expected, result) + } +} + +func TestMaskAccessKey(t *testing.T) { + tests := []struct { + input string + expected string + }{ + {"AKIAIOSFODNN7EXAMPLE", "AKIA***"}, + {"AKIA", "AKIA"}, + {"AKI", "AKI"}, + {"", ""}, + } + + for _, test := range tests { + result := MaskAccessKey(test.input) + assert.Equal(t, test.expected, result) + } +} + |
