feat(testing): add loopback plugin support for overriding the error state with SBC State
This commit is contained in:
1 parent
9bc5e492f6
commit
130010a2ca
3 files changed
+136
-11
No files matched your search
@@ -47,12 +47,13 @@ const (
|
||||
|
||||
// PluginMockError is used to mock an error when interacting with an external object store.
|
||||
type PluginMockError struct {
|
||||
BucketName string
|
||||
BucketPrefix string
|
||||
ObjectKey string
|
||||
ErrMsg string
|
||||
ErrCode codes.Code
|
||||
ErrMethod Method
|
||||
BucketName string
|
||||
BucketPrefix string
|
||||
ObjectKey string
|
||||
ErrMsg string
|
||||
ErrCode codes.Code
|
||||
ErrMethod Method
|
||||
StorageBucketCredentialState *plgpb.StorageBucketCredentialState
|
||||
}
|
||||
|
||||
// match compares the given values from the parameters to the values provided in the mocked error.
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
@@ -225,8 +226,12 @@ func (l *LoopbackStorage) validatePermissions(ctx context.Context, req *plgpb.Va
|
||||
if _, ok := l.buckets[BucketName(req.GetBucket().GetBucketName())]; !ok {
|
||||
return nil, status.Errorf(codes.NotFound, "%s: bucket not found", op)
|
||||
}
|
||||
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), "", ValidatePermissions) {
|
||||
if err.StorageBucketCredentialState != nil {
|
||||
return nil, createErrorWithBucketCredentialState(err.ErrCode, fmt.Sprintf("%s: %s", op, err.ErrMsg), err.StorageBucketCredentialState)
|
||||
}
|
||||
return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
@@ -260,6 +265,9 @@ func (l *LoopbackStorage) headObject(ctx context.Context, req *plgpb.HeadObjectR
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), req.GetKey(), HeadObject) {
|
||||
if err.StorageBucketCredentialState != nil {
|
||||
return nil, createErrorWithBucketCredentialState(err.ErrCode, fmt.Sprintf("%s: %s", op, err.ErrMsg), err.StorageBucketCredentialState)
|
||||
}
|
||||
return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
@@ -300,6 +308,9 @@ func (l *LoopbackStorage) getObject(req *plgpb.GetObjectRequest, stream plgpb.St
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), req.GetKey(), GetObject) {
|
||||
if err.StorageBucketCredentialState != nil {
|
||||
return createErrorWithBucketCredentialState(err.ErrCode, fmt.Sprintf("%s: %s", op, err.ErrMsg), err.StorageBucketCredentialState)
|
||||
}
|
||||
return status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
@@ -368,6 +379,9 @@ func (l *LoopbackStorage) putObject(ctx context.Context, req *plgpb.PutObjectReq
|
||||
// return an expected mock error if one was provided
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), req.GetKey(), PutObject) {
|
||||
if err.StorageBucketCredentialState != nil {
|
||||
return nil, createErrorWithBucketCredentialState(err.ErrCode, fmt.Sprintf("%s: %s", op, err.ErrMsg), err.StorageBucketCredentialState)
|
||||
}
|
||||
return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
@@ -526,3 +540,12 @@ func MockObject(data []Chunk) *storagePluginStorageInfo {
|
||||
func copyBytes(in []byte) []byte {
|
||||
return append([]byte{}, in...)
|
||||
}
|
||||
|
||||
func createErrorWithBucketCredentialState(errCode codes.Code, msg string, sbcState *plgpb.StorageBucketCredentialState) error {
|
||||
st := status.New(errCode, msg)
|
||||
stWithDetails, stErr := st.WithDetails(sbcState)
|
||||
if stErr == nil {
|
||||
st = stWithDetails
|
||||
}
|
||||
return st.Err()
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func TestLoopbackOnCreateStorageBucket(t *testing.T) {
|
||||
@@ -376,14 +377,37 @@ func TestLoopbackValidatePermissions(t *testing.T) {
|
||||
|
||||
plg, err := NewLoopbackPlugin(
|
||||
WithMockBuckets(map[BucketName]Bucket{
|
||||
"aws_s3_mock": {},
|
||||
"aws_s3_err": {},
|
||||
"aws_s3_mock": {},
|
||||
"aws_s3_err": {},
|
||||
"aws_s3_err_with_sbc_state": {},
|
||||
}),
|
||||
WithMockError(PluginMockError{
|
||||
BucketName: "aws_s3_err",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
}),
|
||||
WithMockError(PluginMockError{
|
||||
BucketName: "aws_s3_err_with_sbc_state",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
StorageBucketCredentialState: &plgpb.StorageBucketCredentialState{
|
||||
State: &plgpb.Permissions{
|
||||
Write: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_ERROR,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
ErrorDetails: "invalid credentials",
|
||||
},
|
||||
Read: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_OK,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
},
|
||||
Delete: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_OK,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
)
|
||||
assert.NoError(err)
|
||||
|
||||
@@ -396,9 +420,10 @@ func TestLoopbackValidatePermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
request *plgpb.ValidatePermissionsRequest
|
||||
expectedErr codes.Code
|
||||
name string
|
||||
request *plgpb.ValidatePermissionsRequest
|
||||
expectedErr codes.Code
|
||||
expectedSBCState *plgpb.StorageBucketCredentialState
|
||||
}{
|
||||
{
|
||||
name: "missing request",
|
||||
@@ -475,6 +500,38 @@ func TestLoopbackValidatePermissions(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mocked error with SBC state",
|
||||
request: &plgpb.ValidatePermissionsRequest{
|
||||
Bucket: &storagebuckets.StorageBucket{
|
||||
BucketName: "aws_s3_err_with_sbc_state",
|
||||
Secrets: secrets,
|
||||
Attributes: &structpb.Struct{
|
||||
Fields: map[string]*structpb.Value{
|
||||
"endpoint": structpb.NewStringValue("0.0.0.0"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedErr: codes.PermissionDenied,
|
||||
expectedSBCState: &plgpb.StorageBucketCredentialState{
|
||||
State: &plgpb.Permissions{
|
||||
Write: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_ERROR,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
ErrorDetails: "invalid credentials",
|
||||
},
|
||||
Read: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_OK,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
},
|
||||
Delete: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_OK,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -485,6 +542,19 @@ func TestLoopbackValidatePermissions(t *testing.T) {
|
||||
s, ok := status.FromError(err)
|
||||
require.True(ok, "invalid error type")
|
||||
assert.Equal(tt.expectedErr, s.Code())
|
||||
|
||||
if tt.expectedSBCState != nil {
|
||||
sbcState := parseStorageBucketCredentialStateFromError(err)
|
||||
require.NotNil(sbcState)
|
||||
assert.Equal(tt.expectedSBCState.State.Write.GetState(), sbcState.State.Write.GetState())
|
||||
assert.Equal(tt.expectedSBCState.State.Write.GetErrorDetails(), sbcState.State.Write.GetErrorDetails())
|
||||
|
||||
assert.Equal(tt.expectedSBCState.State.Read.GetState(), sbcState.State.Read.GetState())
|
||||
assert.Equal(tt.expectedSBCState.State.Read.GetErrorDetails(), sbcState.State.Read.GetErrorDetails())
|
||||
|
||||
assert.Equal(tt.expectedSBCState.State.Delete.GetState(), sbcState.State.Delete.GetState())
|
||||
assert.Equal(tt.expectedSBCState.State.Delete.GetErrorDetails(), sbcState.State.Delete.GetErrorDetails())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1504,3 +1574,34 @@ func TestLoopbackStoragePlugin(t *testing.T) {
|
||||
require.NotEmpty(objectData)
|
||||
assert.EqualValues(objectData, getObjectData)
|
||||
}
|
||||
|
||||
func parseStorageBucketCredentialStateFromError(err error) *plgpb.StorageBucketCredentialState {
|
||||
sbcState := &plgpb.StorageBucketCredentialState{
|
||||
State: &plgpb.Permissions{
|
||||
Write: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_UNKNOWN,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
},
|
||||
Read: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_UNKNOWN,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
},
|
||||
Delete: &plgpb.Permission{
|
||||
State: plgpb.StateType_STATE_TYPE_UNKNOWN,
|
||||
CheckedAt: timestamppb.Now(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// attempt to retrieve the StorageBucketCredentialState detail from the error.
|
||||
if st, ok := status.FromError(err); ok {
|
||||
for _, detail := range st.Details() {
|
||||
if statusDetail, ok := detail.(*plgpb.StorageBucketCredentialState); ok {
|
||||
sbcState = statusDetail
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sbcState
|
||||
}
|
||||
Reference in new issue
Block a user