Skip to content

Commit

Permalink
COSI-40: add-unit-tests-for-revoke-bucket-access
Browse files Browse the repository at this point in the history
- updated IAM mock with new IAM API methods
- added unit tests for RevokeBucketAccess IAM API methods
- removed the unimplemented test for RevokeBucketAccess
  • Loading branch information
anurag4DSB committed Dec 10, 2024
1 parent 1163bf0 commit 8f1ecce
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 12 deletions.
238 changes: 238 additions & 0 deletions pkg/clients/iam/iam_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,242 @@ var _ = Describe("IAMClient", func() {
Expect(client).To(BeNil())
})
})

Describe("RevokeBucketAccess", func() {
var mockIAM *mock.MockIAMClient

BeforeEach(func() {
mockIAM = &mock.MockIAMClient{}
})

It("should handle non-existent user gracefully", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return nil, &types.NoSuchEntityException{}
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "non-existent-user", "test-bucket")
Expect(err).To(BeNil())
})

It("should return an error if getting user fails", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return nil, fmt.Errorf("simulated GetUser failure")
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "test-user", "test-bucket")
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(ContainSubstring("failed to get IAM user test-user"))
})

It("should skip deletion if inline policy does not exist", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return &iam.GetUserOutput{}, nil
}
mockIAM.DeleteUserPolicyFunc = func(ctx context.Context, input *iam.DeleteUserPolicyInput, opts ...func(*iam.Options)) (*iam.DeleteUserPolicyOutput, error) {
return nil, &types.NoSuchEntityException{}
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "test-user", "test-bucket")
Expect(err).To(BeNil())
})

It("should return an error if deleting inline policy fails", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return &iam.GetUserOutput{}, nil
}
mockIAM.DeleteUserPolicyFunc = func(ctx context.Context, input *iam.DeleteUserPolicyInput, opts ...func(*iam.Options)) (*iam.DeleteUserPolicyOutput, error) {
return nil, fmt.Errorf("simulated DeleteUserPolicy failure")
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "test-user", "test-bucket")
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(ContainSubstring("failed to delete inline policy test-bucket for user test-user"))
})

It("should successfully delete all access keys for the user", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return &iam.GetUserOutput{}, nil
}
mockIAM.ListAccessKeysFunc = func(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error) {
return &iam.ListAccessKeysOutput{
AccessKeyMetadata: []types.AccessKeyMetadata{
{AccessKeyId: aws.String("key-1")},
{AccessKeyId: aws.String("key-2")},
},
}, nil
}
mockIAM.DeleteAccessKeyFunc = func(ctx context.Context, input *iam.DeleteAccessKeyInput, opts ...func(*iam.Options)) (*iam.DeleteAccessKeyOutput, error) {
return &iam.DeleteAccessKeyOutput{}, nil
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "test-user", "test-bucket")
Expect(err).To(BeNil())
})

It("should return an error if deleting access key fails", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return &iam.GetUserOutput{}, nil
}
mockIAM.ListAccessKeysFunc = func(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error) {
return &iam.ListAccessKeysOutput{
AccessKeyMetadata: []types.AccessKeyMetadata{
{AccessKeyId: aws.String("key-1")},
},
}, nil
}
mockIAM.DeleteAccessKeyFunc = func(ctx context.Context, input *iam.DeleteAccessKeyInput, opts ...func(*iam.Options)) (*iam.DeleteAccessKeyOutput, error) {
return nil, fmt.Errorf("simulated DeleteAccessKey failure")
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "test-user", "test-bucket")
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(ContainSubstring("failed to delete access key key-1 for IAM user test-user"))
})

It("should successfully delete the user", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return &iam.GetUserOutput{}, nil
}
mockIAM.ListAccessKeysFunc = func(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error) {
return &iam.ListAccessKeysOutput{}, nil
}
mockIAM.DeleteUserFunc = func(ctx context.Context, input *iam.DeleteUserInput, opts ...func(*iam.Options)) (*iam.DeleteUserOutput, error) {
return &iam.DeleteUserOutput{}, nil
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "test-user", "test-bucket")
Expect(err).To(BeNil())
})

It("should return an error if deleting user fails", func(ctx SpecContext) {
mockIAM.GetUserFunc = func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
return &iam.GetUserOutput{}, nil
}
mockIAM.ListAccessKeysFunc = func(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error) {
return &iam.ListAccessKeysOutput{}, nil
}
mockIAM.DeleteUserFunc = func(ctx context.Context, input *iam.DeleteUserInput, opts ...func(*iam.Options)) (*iam.DeleteUserOutput, error) {
return nil, fmt.Errorf("simulated DeleteUser failure")
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.RevokeBucketAccess(ctx, "test-user", "test-bucket")
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(ContainSubstring("failed to delete IAM user test-user"))
})

It("should successfully delete an inline policy", func(ctx SpecContext) {
mockIAM.DeleteUserPolicyFunc = func(ctx context.Context, input *iam.DeleteUserPolicyInput, opts ...func(*iam.Options)) (*iam.DeleteUserPolicyOutput, error) {
Expect(*input.PolicyName).To(Equal("test-bucket"))
Expect(*input.UserName).To(Equal("test-user"))
return &iam.DeleteUserPolicyOutput{}, nil
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.DeleteInlinePolicy(ctx, "test-user", "test-bucket")
Expect(err).To(BeNil())
})

It("should skip deletion if inline policy does not exist", func(ctx SpecContext) {
mockIAM.DeleteUserPolicyFunc = func(ctx context.Context, input *iam.DeleteUserPolicyInput, opts ...func(*iam.Options)) (*iam.DeleteUserPolicyOutput, error) {
return nil, &types.NoSuchEntityException{}
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.DeleteInlinePolicy(ctx, "test-user", "test-bucket")
Expect(err).To(BeNil())
})

It("should successfully delete all access keys", func(ctx SpecContext) {
mockIAM.ListAccessKeysFunc = func(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error) {
return &iam.ListAccessKeysOutput{
AccessKeyMetadata: []types.AccessKeyMetadata{
{AccessKeyId: aws.String("key-1")},
{AccessKeyId: aws.String("key-2")},
},
}, nil
}
mockIAM.DeleteAccessKeyFunc = func(ctx context.Context, input *iam.DeleteAccessKeyInput, opts ...func(*iam.Options)) (*iam.DeleteAccessKeyOutput, error) {
return &iam.DeleteAccessKeyOutput{}, nil
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.DeleteAllAccessKeys(ctx, "test-user")
Expect(err).To(BeNil())
})

It("should return an error if deleting any access key fails", func(ctx SpecContext) {
mockIAM.ListAccessKeysFunc = func(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error) {
return &iam.ListAccessKeysOutput{
AccessKeyMetadata: []types.AccessKeyMetadata{
{AccessKeyId: aws.String("key-1")},
},
}, nil
}
mockIAM.DeleteAccessKeyFunc = func(ctx context.Context, input *iam.DeleteAccessKeyInput, opts ...func(*iam.Options)) (*iam.DeleteAccessKeyOutput, error) {
return nil, fmt.Errorf("simulated DeleteAccessKey failure")
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.DeleteAllAccessKeys(ctx, "test-user")
Expect(err).NotTo(BeNil())
Expect(err.Error()).To(ContainSubstring("simulated DeleteAccessKey failure"))
})
It("should successfully delete a user", func(ctx SpecContext) {
mockIAM.DeleteUserFunc = func(ctx context.Context, input *iam.DeleteUserInput, opts ...func(*iam.Options)) (*iam.DeleteUserOutput, error) {
Expect(*input.UserName).To(Equal("test-user"))
return &iam.DeleteUserOutput{}, nil
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.DeleteUser(ctx, "test-user")
Expect(err).To(BeNil())
})

It("should skip deletion if user does not exist", func(ctx SpecContext) {
mockIAM.DeleteUserFunc = func(ctx context.Context, input *iam.DeleteUserInput, opts ...func(*iam.Options)) (*iam.DeleteUserOutput, error) {
return nil, &types.NoSuchEntityException{}
}

client, _ := iamclient.InitIAMClient(params)
client.IAMService = mockIAM

err := client.DeleteUser(ctx, "test-user")
Expect(err).To(BeNil())
})

})
})
9 changes: 0 additions & 9 deletions pkg/driver/provisioner_server_impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,6 @@ var _ = Describe("ProvisionerServer Unimplemented Methods", Ordered, func() {
Expect(status.Code(err)).To(Equal(codes.Unimplemented))
Expect(err.Error()).To(ContainSubstring("DriverCreateBucket: not implemented"))
})

It("DriverRevokeBucketAccess should return Unimplemented error", func(ctx SpecContext) {
request := &cosiapi.DriverRevokeBucketAccessRequest{AccountId: accountID}
resp, err := provisioner.DriverRevokeBucketAccess(ctx, request)
Expect(resp).To(BeNil())
Expect(err).To(HaveOccurred())
Expect(status.Code(err)).To(Equal(codes.Unimplemented))
Expect(err.Error()).To(ContainSubstring("DriverCreateBucket: not implemented"))
})
})

var _ = Describe("FetchSecretInformation", Ordered, func() {
Expand Down
60 changes: 57 additions & 3 deletions pkg/mock/mock_iam.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ import (
// MockIAMClient simulates the behavior of an IAM client for testing purposes.
// It embeds iamclient.IAMClient to ensure compatibility with the interface or struct.
type MockIAMClient struct {
CreateUserFunc func(ctx context.Context, input *iam.CreateUserInput, opts ...func(*iam.Options)) (*iam.CreateUserOutput, error)
PutUserPolicyFunc func(ctx context.Context, input *iam.PutUserPolicyInput, opts ...func(*iam.Options)) (*iam.PutUserPolicyOutput, error)
CreateAccessKeyFunc func(ctx context.Context, input *iam.CreateAccessKeyInput, opts ...func(*iam.Options)) (*iam.CreateAccessKeyOutput, error)
CreateUserFunc func(ctx context.Context, input *iam.CreateUserInput, opts ...func(*iam.Options)) (*iam.CreateUserOutput, error)
PutUserPolicyFunc func(ctx context.Context, input *iam.PutUserPolicyInput, opts ...func(*iam.Options)) (*iam.PutUserPolicyOutput, error)
CreateAccessKeyFunc func(ctx context.Context, input *iam.CreateAccessKeyInput, opts ...func(*iam.Options)) (*iam.CreateAccessKeyOutput, error)
GetUserFunc func(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error)
DeleteUserPolicyFunc func(ctx context.Context, input *iam.DeleteUserPolicyInput, opts ...func(*iam.Options)) (*iam.DeleteUserPolicyOutput, error)
ListAccessKeysFunc func(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error)
DeleteAccessKeyFunc func(ctx context.Context, input *iam.DeleteAccessKeyInput, opts ...func(*iam.Options)) (*iam.DeleteAccessKeyOutput, error)
DeleteUserFunc func(ctx context.Context, input *iam.DeleteUserInput, opts ...func(*iam.Options)) (*iam.DeleteUserOutput, error)
}

// CreateUser creates a mock IAM user with default behavior or custom logic.
Expand Down Expand Up @@ -49,3 +54,52 @@ func (m *MockIAMClient) CreateAccessKey(ctx context.Context, input *iam.CreateAc
},
}, nil
}

// GetUser retrieves a mock IAM user.
func (m *MockIAMClient) GetUser(ctx context.Context, input *iam.GetUserInput, opts ...func(*iam.Options)) (*iam.GetUserOutput, error) {
if m.GetUserFunc != nil {
return m.GetUserFunc(ctx, input, opts...)
}
return &iam.GetUserOutput{
User: &types.User{
UserName: input.UserName,
UserId: aws.String("mock-user-id"),
},
}, nil
}

// DeleteUserPolicy deletes a mock inline policy for the user.
func (m *MockIAMClient) DeleteUserPolicy(ctx context.Context, input *iam.DeleteUserPolicyInput, opts ...func(*iam.Options)) (*iam.DeleteUserPolicyOutput, error) {
if m.DeleteUserPolicyFunc != nil {
return m.DeleteUserPolicyFunc(ctx, input, opts...)
}
return &iam.DeleteUserPolicyOutput{}, nil
}

// ListAccessKeys retrieves mock access keys for the user.
func (m *MockIAMClient) ListAccessKeys(ctx context.Context, input *iam.ListAccessKeysInput, opts ...func(*iam.Options)) (*iam.ListAccessKeysOutput, error) {
if m.ListAccessKeysFunc != nil {
return m.ListAccessKeysFunc(ctx, input, opts...)
}
return &iam.ListAccessKeysOutput{
AccessKeyMetadata: []types.AccessKeyMetadata{
{AccessKeyId: aws.String("mock-access-key-id")},
},
}, nil
}

// DeleteAccessKey deletes a mock access key for the user.
func (m *MockIAMClient) DeleteAccessKey(ctx context.Context, input *iam.DeleteAccessKeyInput, opts ...func(*iam.Options)) (*iam.DeleteAccessKeyOutput, error) {
if m.DeleteAccessKeyFunc != nil {
return m.DeleteAccessKeyFunc(ctx, input, opts...)
}
return &iam.DeleteAccessKeyOutput{}, nil
}

// DeleteUser deletes a mock IAM user.
func (m *MockIAMClient) DeleteUser(ctx context.Context, input *iam.DeleteUserInput, opts ...func(*iam.Options)) (*iam.DeleteUserOutput, error) {
if m.DeleteUserFunc != nil {
return m.DeleteUserFunc(ctx, input, opts...)
}
return &iam.DeleteUserOutput{}, nil
}

0 comments on commit 8f1ecce

Please sign in to comment.