|
@ -237,327 +237,6 @@ EOF |
|
|
echo -e "${GREEN}✅ Distributed environment configuration ready${NC}" |
|
|
echo -e "${GREEN}✅ Distributed environment configuration ready${NC}" |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
# Function to create distributed test functions |
|
|
|
|
|
create_distributed_tests() { |
|
|
|
|
|
echo -e "${BLUE}🧪 Creating distributed test functions...${NC}" |
|
|
|
|
|
|
|
|
|
|
|
# Create distributed test file if it doesn't exist |
|
|
|
|
|
if [ ! -f "$TEST_DIR/s3_iam_distributed_test.go" ]; then |
|
|
|
|
|
cat > "$TEST_DIR/s3_iam_distributed_test.go" << 'EOF' |
|
|
|
|
|
package iam |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
|
"context" |
|
|
|
|
|
"fmt" |
|
|
|
|
|
"os" |
|
|
|
|
|
"sync" |
|
|
|
|
|
"testing" |
|
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert" |
|
|
|
|
|
"github.com/stretchr/testify/require" |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// TestS3IAMDistributedTests tests IAM functionality across multiple S3 gateway instances |
|
|
|
|
|
func TestS3IAMDistributedTests(t *testing.T) { |
|
|
|
|
|
// Skip if not in distributed test mode |
|
|
|
|
|
if os.Getenv("ENABLE_DISTRIBUTED_TESTS") != "true" { |
|
|
|
|
|
t.Skip("Distributed tests not enabled. Set ENABLE_DISTRIBUTED_TESTS=true") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
framework := NewS3IAMTestFramework(t) |
|
|
|
|
|
defer framework.Cleanup() |
|
|
|
|
|
|
|
|
|
|
|
t.Run("distributed_session_consistency", func(t *testing.T) { |
|
|
|
|
|
// Test that sessions created on one instance are visible on others |
|
|
|
|
|
// This requires filer-based session storage |
|
|
|
|
|
|
|
|
|
|
|
// Create session token |
|
|
|
|
|
sessionToken, err := framework.generateSTSSessionToken("test-user", "TestAdminRole", time.Hour) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
// Create S3 clients that would connect to different gateway instances |
|
|
|
|
|
// In a real distributed setup, these would point to different S3 gateway ports |
|
|
|
|
|
client1, err := framework.CreateS3ClientWithJWT("test-user", "TestAdminRole") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
client2, err := framework.CreateS3ClientWithJWT("test-user", "TestAdminRole") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
// Both clients should be able to perform operations |
|
|
|
|
|
bucketName := "test-distributed-session" |
|
|
|
|
|
|
|
|
|
|
|
err = framework.CreateBucket(client1, bucketName) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
// Client2 should see the bucket created by client1 |
|
|
|
|
|
buckets, err := framework.ListBuckets(client2) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
found := false |
|
|
|
|
|
for _, bucket := range buckets { |
|
|
|
|
|
if bucket == bucketName { |
|
|
|
|
|
found = true |
|
|
|
|
|
break |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
assert.True(t, found, "Bucket should be visible across distributed instances") |
|
|
|
|
|
|
|
|
|
|
|
// Cleanup |
|
|
|
|
|
err = framework.DeleteBucket(client1, bucketName) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
t.Run("distributed_role_consistency", func(t *testing.T) { |
|
|
|
|
|
// Test that role definitions are consistent across instances |
|
|
|
|
|
// This requires filer-based role storage |
|
|
|
|
|
|
|
|
|
|
|
// Create clients with different roles |
|
|
|
|
|
adminClient, err := framework.CreateS3ClientWithJWT("admin-user", "TestAdminRole") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
readOnlyClient, err := framework.CreateS3ClientWithJWT("readonly-user", "TestReadOnlyRole") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
bucketName := "test-distributed-roles" |
|
|
|
|
|
objectKey := "test-object.txt" |
|
|
|
|
|
|
|
|
|
|
|
// Admin should be able to create bucket |
|
|
|
|
|
err = framework.CreateBucket(adminClient, bucketName) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
// Admin should be able to put object |
|
|
|
|
|
err = framework.PutObject(adminClient, bucketName, objectKey, "test content") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
// Read-only user should be able to get object |
|
|
|
|
|
content, err := framework.GetObject(readOnlyClient, bucketName, objectKey) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
assert.Equal(t, "test content", content) |
|
|
|
|
|
|
|
|
|
|
|
// Read-only user should NOT be able to put object |
|
|
|
|
|
err = framework.PutObject(readOnlyClient, bucketName, "forbidden-object.txt", "forbidden content") |
|
|
|
|
|
require.Error(t, err, "Read-only user should not be able to put objects") |
|
|
|
|
|
|
|
|
|
|
|
// Cleanup |
|
|
|
|
|
err = framework.DeleteObject(adminClient, bucketName, objectKey) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
err = framework.DeleteBucket(adminClient, bucketName) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
t.Run("distributed_concurrent_operations", func(t *testing.T) { |
|
|
|
|
|
// Test concurrent operations across distributed instances |
|
|
|
|
|
const numGoroutines = 10 |
|
|
|
|
|
const numOperationsPerGoroutine = 5 |
|
|
|
|
|
|
|
|
|
|
|
var wg sync.WaitGroup |
|
|
|
|
|
errors := make(chan error, numGoroutines*numOperationsPerGoroutine) |
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < numGoroutines; i++ { |
|
|
|
|
|
wg.Add(1) |
|
|
|
|
|
go func(goroutineID int) { |
|
|
|
|
|
defer wg.Done() |
|
|
|
|
|
|
|
|
|
|
|
client, err := framework.CreateS3ClientWithJWT(fmt.Sprintf("user-%d", goroutineID), "TestAdminRole") |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
errors <- err |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for j := 0; j < numOperationsPerGoroutine; j++ { |
|
|
|
|
|
bucketName := fmt.Sprintf("test-concurrent-%d-%d", goroutineID, j) |
|
|
|
|
|
|
|
|
|
|
|
// Create bucket |
|
|
|
|
|
if err := framework.CreateBucket(client, bucketName); err != nil { |
|
|
|
|
|
errors <- err |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Put object |
|
|
|
|
|
objectKey := "test-object.txt" |
|
|
|
|
|
if err := framework.PutObject(client, bucketName, objectKey, fmt.Sprintf("content-%d-%d", goroutineID, j)); err != nil { |
|
|
|
|
|
errors <- err |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Get object |
|
|
|
|
|
if _, err := framework.GetObject(client, bucketName, objectKey); err != nil { |
|
|
|
|
|
errors <- err |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Delete object |
|
|
|
|
|
if err := framework.DeleteObject(client, bucketName, objectKey); err != nil { |
|
|
|
|
|
errors <- err |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Delete bucket |
|
|
|
|
|
if err := framework.DeleteBucket(client, bucketName); err != nil { |
|
|
|
|
|
errors <- err |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}(i) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
wg.Wait() |
|
|
|
|
|
close(errors) |
|
|
|
|
|
|
|
|
|
|
|
// Check for errors |
|
|
|
|
|
var errorList []error |
|
|
|
|
|
for err := range errors { |
|
|
|
|
|
errorList = append(errorList, err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if len(errorList) > 0 { |
|
|
|
|
|
t.Errorf("Concurrent operations failed with %d errors. First error: %v", len(errorList), errorList[0]) |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TestS3IAMPerformanceTests tests IAM performance characteristics |
|
|
|
|
|
func TestS3IAMPerformanceTests(t *testing.T) { |
|
|
|
|
|
// Skip if not in performance test mode |
|
|
|
|
|
if os.Getenv("ENABLE_PERFORMANCE_TESTS") != "true" { |
|
|
|
|
|
t.Skip("Performance tests not enabled. Set ENABLE_PERFORMANCE_TESTS=true") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
framework := NewS3IAMTestFramework(t) |
|
|
|
|
|
defer framework.Cleanup() |
|
|
|
|
|
|
|
|
|
|
|
t.Run("authentication_performance", func(t *testing.T) { |
|
|
|
|
|
// Test authentication performance |
|
|
|
|
|
const numRequests = 100 |
|
|
|
|
|
|
|
|
|
|
|
client, err := framework.CreateS3ClientWithJWT("perf-user", "TestAdminRole") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
bucketName := "test-auth-performance" |
|
|
|
|
|
err = framework.CreateBucket(client, bucketName) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
defer framework.DeleteBucket(client, bucketName) |
|
|
|
|
|
|
|
|
|
|
|
start := time.Now() |
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < numRequests; i++ { |
|
|
|
|
|
_, err := framework.ListBuckets(client) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
duration := time.Since(start) |
|
|
|
|
|
avgLatency := duration / numRequests |
|
|
|
|
|
|
|
|
|
|
|
t.Logf("Authentication performance: %d requests in %v (avg: %v per request)", |
|
|
|
|
|
numRequests, duration, avgLatency) |
|
|
|
|
|
|
|
|
|
|
|
// Performance assertion - should be under 100ms per request on average |
|
|
|
|
|
assert.Less(t, avgLatency, 100*time.Millisecond, |
|
|
|
|
|
"Average authentication latency should be under 100ms") |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
t.Run("authorization_performance", func(t *testing.T) { |
|
|
|
|
|
// Test authorization performance with different policy complexities |
|
|
|
|
|
const numRequests = 50 |
|
|
|
|
|
|
|
|
|
|
|
client, err := framework.CreateS3ClientWithJWT("perf-user", "TestAdminRole") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
bucketName := "test-authz-performance" |
|
|
|
|
|
err = framework.CreateBucket(client, bucketName) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
defer framework.DeleteBucket(client, bucketName) |
|
|
|
|
|
|
|
|
|
|
|
start := time.Now() |
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < numRequests; i++ { |
|
|
|
|
|
objectKey := fmt.Sprintf("perf-object-%d.txt", i) |
|
|
|
|
|
err := framework.PutObject(client, bucketName, objectKey, "performance test content") |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
_, err = framework.GetObject(client, bucketName, objectKey) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
|
|
|
|
|
|
err = framework.DeleteObject(client, bucketName, objectKey) |
|
|
|
|
|
require.NoError(t, err) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
duration := time.Since(start) |
|
|
|
|
|
avgLatency := duration / (numRequests * 3) // 3 operations per iteration |
|
|
|
|
|
|
|
|
|
|
|
t.Logf("Authorization performance: %d operations in %v (avg: %v per operation)", |
|
|
|
|
|
numRequests*3, duration, avgLatency) |
|
|
|
|
|
|
|
|
|
|
|
// Performance assertion - should be under 50ms per operation on average |
|
|
|
|
|
assert.Less(t, avgLatency, 50*time.Millisecond, |
|
|
|
|
|
"Average authorization latency should be under 50ms") |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// BenchmarkS3IAMAuthentication benchmarks JWT authentication |
|
|
|
|
|
func BenchmarkS3IAMAuthentication(b *testing.B) { |
|
|
|
|
|
if os.Getenv("ENABLE_PERFORMANCE_TESTS") != "true" { |
|
|
|
|
|
b.Skip("Performance tests not enabled. Set ENABLE_PERFORMANCE_TESTS=true") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
framework := NewS3IAMTestFramework(&testing.T{}) |
|
|
|
|
|
defer framework.Cleanup() |
|
|
|
|
|
|
|
|
|
|
|
client, err := framework.CreateS3ClientWithJWT("bench-user", "TestAdminRole") |
|
|
|
|
|
require.NoError(b, err) |
|
|
|
|
|
|
|
|
|
|
|
bucketName := "test-bench-auth" |
|
|
|
|
|
err = framework.CreateBucket(client, bucketName) |
|
|
|
|
|
require.NoError(b, err) |
|
|
|
|
|
defer framework.DeleteBucket(client, bucketName) |
|
|
|
|
|
|
|
|
|
|
|
b.ResetTimer() |
|
|
|
|
|
b.RunParallel(func(pb *testing.PB) { |
|
|
|
|
|
for pb.Next() { |
|
|
|
|
|
_, err := framework.ListBuckets(client) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
b.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// BenchmarkS3IAMAuthorization benchmarks policy evaluation |
|
|
|
|
|
func BenchmarkS3IAMAuthorization(b *testing.B) { |
|
|
|
|
|
if os.Getenv("ENABLE_PERFORMANCE_TESTS") != "true" { |
|
|
|
|
|
b.Skip("Performance tests not enabled. Set ENABLE_PERFORMANCE_TESTS=true") |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
framework := NewS3IAMTestFramework(&testing.T{}) |
|
|
|
|
|
defer framework.Cleanup() |
|
|
|
|
|
|
|
|
|
|
|
client, err := framework.CreateS3ClientWithJWT("bench-user", "TestAdminRole") |
|
|
|
|
|
require.NoError(b, err) |
|
|
|
|
|
|
|
|
|
|
|
bucketName := "test-bench-authz" |
|
|
|
|
|
err = framework.CreateBucket(client, bucketName) |
|
|
|
|
|
require.NoError(b, err) |
|
|
|
|
|
defer framework.DeleteBucket(client, bucketName) |
|
|
|
|
|
|
|
|
|
|
|
b.ResetTimer() |
|
|
|
|
|
b.RunParallel(func(pb *testing.PB) { |
|
|
|
|
|
i := 0 |
|
|
|
|
|
for pb.Next() { |
|
|
|
|
|
objectKey := fmt.Sprintf("bench-object-%d.txt", i) |
|
|
|
|
|
err := framework.PutObject(client, bucketName, objectKey, "benchmark content") |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
b.Error(err) |
|
|
|
|
|
} |
|
|
|
|
|
i++ |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
EOF |
|
|
|
|
|
echo -e "${GREEN}✅ Distributed test functions created${NC}" |
|
|
|
|
|
fi |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
# Function to create performance test runner |
|
|
# Function to create performance test runner |
|
|
create_performance_test_runner() { |
|
|
create_performance_test_runner() { |
|
|
echo -e "${BLUE}🏁 Creating performance test runner...${NC}" |
|
|
echo -e "${BLUE}🏁 Creating performance test runner...${NC}" |
|
@ -892,7 +571,6 @@ main() { |
|
|
setup_distributed_environment |
|
|
setup_distributed_environment |
|
|
|
|
|
|
|
|
# Create test functions |
|
|
# Create test functions |
|
|
create_distributed_tests |
|
|
|
|
|
|
|
|
|
|
|
# Create test runners |
|
|
# Create test runners |
|
|
create_performance_test_runner |
|
|
create_performance_test_runner |
|
|