test(storage): improve loopback mock err & update storage container closed err msg
This commit is contained in:
1 parent
cfe0dc08d9
commit
95c3b2d56a
4 files changed
+148
-45
No files matched your search
@@ -8,25 +8,77 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// Method is used to determine if an error should be returned to a specific storage plugin method.
|
||||
type Method uint8
|
||||
|
||||
const (
|
||||
// Any will return an error for any of the method defined in the storage plugin.
|
||||
Any Method = iota
|
||||
|
||||
// Will return an error for the OnCreateStorageBucket method
|
||||
OnCreateStorageBucket
|
||||
|
||||
// Will return an error for the OnUpdateStorageBucket method
|
||||
OnUpdateStorageBucket
|
||||
|
||||
// Will return an error for the OnDeleteStorageBucket method
|
||||
OnDeleteStorageBucket
|
||||
|
||||
// Will return an error for the ValidatePermissions method
|
||||
ValidatePermissions
|
||||
|
||||
// Will return an error for the HeadObject method
|
||||
HeadObject
|
||||
|
||||
// Will return an error for the GetObject method
|
||||
GetObject
|
||||
|
||||
// Will return an error for the PutObject method
|
||||
PutObject
|
||||
)
|
||||
|
||||
// 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
|
||||
BucketName string
|
||||
BucketPrefix string
|
||||
ObjectKey string
|
||||
ErrMsg string
|
||||
ErrCode codes.Code
|
||||
ErrMethod Method
|
||||
}
|
||||
|
||||
func (e PluginMockError) match(bucket *storagebuckets.StorageBucket, key string) bool {
|
||||
if key != "" && e.objectKey != key {
|
||||
// match compares the given values from the parameters to the values provided in the mocked error.
|
||||
// The bucket and key parameter values should be provided from the plugin request. The method
|
||||
// value should be based on the plugin method that is calling this function.
|
||||
//
|
||||
// When match returns false, the mocked error should not be used for the plugin response.
|
||||
// When match returns true, the mocked error should be used for the plugin response.
|
||||
func (e PluginMockError) match(bucket *storagebuckets.StorageBucket, key string, method Method) bool {
|
||||
// if the mocked error object key does not match the request's object key, return false.
|
||||
// the object key comparison is ignored when the given key is empty because the following
|
||||
// plugin methods do not provide key values: onCreateStorageBucket, onUpdateStorageBucket,
|
||||
// onDeleteStorageBucket
|
||||
if key != "" && e.ObjectKey != key {
|
||||
return false
|
||||
}
|
||||
if e.bucketName != bucket.BucketName {
|
||||
// if the mocked error bucket name does not match the request's bucket name, return false.
|
||||
if e.BucketName != bucket.BucketName {
|
||||
return false
|
||||
}
|
||||
if bucket.BucketPrefix != "" && e.bucketPrefix != bucket.BucketPrefix {
|
||||
// if the request has a bucket prefix and it does not match the mocked error bucket prefix, return false.
|
||||
if bucket.BucketPrefix != "" && e.BucketPrefix != bucket.BucketPrefix {
|
||||
return false
|
||||
}
|
||||
// if the mocked error method is set to Any, return true. This means that the mocked error response
|
||||
// will be utilized by all the plugin methods.
|
||||
if e.ErrMethod == Any {
|
||||
return true
|
||||
}
|
||||
// if the mocked error method does match the given method, return false.
|
||||
if e.ErrMethod != method {
|
||||
return false
|
||||
}
|
||||
// all checks comparison checks passed, return true.
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -130,8 +131,8 @@ func (l *LoopbackStorage) onCreateStorageBucket(ctx context.Context, req *plgpb.
|
||||
return nil, status.Errorf(codes.NotFound, "%s: bucket not found", op)
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), "") {
|
||||
return nil, status.Errorf(err.errCode, err.errMsg)
|
||||
if err.match(req.GetBucket(), "", OnCreateStorageBucket) {
|
||||
return nil, status.Errorf(err.ErrCode, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
return &plgpb.OnCreateStorageBucketResponse{
|
||||
@@ -158,8 +159,8 @@ func (l *LoopbackStorage) onUpdateStorageBucket(ctx context.Context, req *plgpb.
|
||||
return nil, status.Errorf(codes.NotFound, "%s: bucket not found", op)
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetNewBucket(), "") {
|
||||
return nil, status.Errorf(err.errCode, "%s: %s", op, err.errMsg)
|
||||
if err.match(req.GetNewBucket(), "", OnUpdateStorageBucket) {
|
||||
return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
var sec *storagebuckets.StorageBucketPersisted
|
||||
@@ -206,8 +207,8 @@ func (l *LoopbackStorage) validatePermissions(ctx context.Context, req *plgpb.Va
|
||||
return nil, status.Errorf(codes.NotFound, "%s: bucket not found", op)
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), "") {
|
||||
return nil, status.Errorf(err.errCode, "%s: %s", op, err.errMsg)
|
||||
if err.match(req.GetBucket(), "", ValidatePermissions) {
|
||||
return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
return &plgpb.ValidatePermissionsResponse{}, nil
|
||||
@@ -239,8 +240,8 @@ func (l *LoopbackStorage) headObject(ctx context.Context, req *plgpb.HeadObjectR
|
||||
return nil, status.Errorf(codes.NotFound, "%s: object %s not found", op, objectPath)
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), req.GetKey()) {
|
||||
return nil, status.Errorf(err.errCode, "%s: %s", op, err.errMsg)
|
||||
if err.match(req.GetBucket(), req.GetKey(), HeadObject) {
|
||||
return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
var contentLength int64
|
||||
@@ -279,8 +280,8 @@ func (l *LoopbackStorage) getObject(req *plgpb.GetObjectRequest, stream plgpb.St
|
||||
return status.Errorf(codes.NotFound, "%s: object %s not found", op, objectPath)
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), req.GetKey()) {
|
||||
return status.Errorf(err.errCode, "%s: %s", op, err.errMsg)
|
||||
if err.match(req.GetBucket(), req.GetKey(), GetObject) {
|
||||
return status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
@@ -334,8 +335,8 @@ func (l *LoopbackStorage) putObject(ctx context.Context, req *plgpb.PutObjectReq
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%s: bucket not found", op)
|
||||
}
|
||||
for _, err := range l.errs {
|
||||
if err.match(req.GetBucket(), req.GetKey()) {
|
||||
return nil, status.Errorf(err.errCode, "%s: %s", op, err.errMsg)
|
||||
if err.match(req.GetBucket(), req.GetKey(), PutObject) {
|
||||
return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,8 +355,11 @@ func (l *LoopbackStorage) putObject(ctx context.Context, req *plgpb.PutObjectReq
|
||||
for _, p := range parts[:len(parts)-1] {
|
||||
// Directories should have trailing `/` in the key
|
||||
tempPath = fmt.Sprintf("%v%v/", tempPath, p)
|
||||
emptyContent := int64(0)
|
||||
bucket[ObjectName(tempPath)] = &storagePluginStorageInfo{
|
||||
lastModified: &lastModified,
|
||||
lastModified: &lastModified,
|
||||
contentLength: &emptyContent,
|
||||
DataChunks: []Chunk{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +373,7 @@ func (l *LoopbackStorage) putObject(ctx context.Context, req *plgpb.PutObjectReq
|
||||
}
|
||||
|
||||
// Now insert the object
|
||||
objectPath := ObjectName(req.GetBucket().GetBucketPrefix() + req.GetKey())
|
||||
objectPath := ObjectName(path.Join(req.GetBucket().GetBucketPrefix(), req.GetKey()))
|
||||
bucket[objectPath] = &storagePluginStorageInfo{
|
||||
DataChunks: objectChunks,
|
||||
contentLength: &contentLength,
|
||||
@@ -386,6 +390,53 @@ func (l *LoopbackStorage) putObject(ctx context.Context, req *plgpb.PutObjectReq
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CloneBucket returns a clone of the bucket.
|
||||
// returns nil when the bucket is not found.
|
||||
func (l *LoopbackStorage) CloneBucket(name string) Bucket {
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
if _, ok := l.buckets[BucketName(name)]; !ok {
|
||||
return nil
|
||||
}
|
||||
bucket := Bucket{}
|
||||
for objName, obj := range l.buckets[BucketName(name)] {
|
||||
if obj != nil {
|
||||
bucket[objName] = copyStorageInfo(obj)
|
||||
}
|
||||
}
|
||||
return bucket
|
||||
}
|
||||
|
||||
// CloneStorageInfo returns a clone of the object stored in memory.
|
||||
// Returns nil when the bucket or object is not found.
|
||||
func (l *LoopbackStorage) CloneStorageInfo(bucketName, objectName string) *storagePluginStorageInfo {
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
bucket, ok := l.buckets[BucketName(bucketName)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
obj, ok := bucket[ObjectName(objectName)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return copyStorageInfo(obj)
|
||||
}
|
||||
|
||||
func copyStorageInfo(obj *storagePluginStorageInfo) *storagePluginStorageInfo {
|
||||
chunks := make([]Chunk, len(obj.DataChunks))
|
||||
for i, c := range obj.DataChunks {
|
||||
chunks[i] = copyBytes(c)
|
||||
}
|
||||
contentLength := *obj.contentLength
|
||||
lastModified := *obj.lastModified
|
||||
return &storagePluginStorageInfo{
|
||||
DataChunks: chunks,
|
||||
lastModified: &lastModified,
|
||||
contentLength: &contentLength,
|
||||
}
|
||||
}
|
||||
|
||||
func MockObject(data []Chunk) *storagePluginStorageInfo {
|
||||
lastModified := time.Now()
|
||||
dataChunks := make([]Chunk, len(data))
|
||||
|
||||
@@ -33,9 +33,9 @@ func TestLoopbackOnCreateStorageBucket(t *testing.T) {
|
||||
"aws_s3_err": {},
|
||||
}),
|
||||
WithMockError(PluginMockError{
|
||||
bucketName: "aws_s3_err",
|
||||
errMsg: "invalid credentials",
|
||||
errCode: codes.PermissionDenied,
|
||||
BucketName: "aws_s3_err",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
}),
|
||||
)
|
||||
assert.NoError(err)
|
||||
@@ -131,9 +131,9 @@ func TestLoopbackOnUpdateStorageBucket(t *testing.T) {
|
||||
"aws_s3_err": {},
|
||||
}),
|
||||
WithMockError(PluginMockError{
|
||||
bucketName: "aws_s3_err",
|
||||
errMsg: "invalid credentials",
|
||||
errCode: codes.PermissionDenied,
|
||||
BucketName: "aws_s3_err",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
}),
|
||||
)
|
||||
assert.NoError(err)
|
||||
@@ -306,9 +306,9 @@ func TestLoopbackValidatePermissions(t *testing.T) {
|
||||
"aws_s3_err": {},
|
||||
}),
|
||||
WithMockError(PluginMockError{
|
||||
bucketName: "aws_s3_err",
|
||||
errMsg: "invalid credentials",
|
||||
errCode: codes.PermissionDenied,
|
||||
BucketName: "aws_s3_err",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
}),
|
||||
)
|
||||
assert.NoError(err)
|
||||
@@ -411,10 +411,10 @@ func TestLoopbackHeadObject(t *testing.T) {
|
||||
plg, err := NewLoopbackPlugin(
|
||||
WithMockBuckets(mockStorageMapData),
|
||||
WithMockError(PluginMockError{
|
||||
bucketName: "aws_s3_err",
|
||||
objectKey: "mock_object",
|
||||
errMsg: "invalid credentials",
|
||||
errCode: codes.PermissionDenied,
|
||||
BucketName: "aws_s3_err",
|
||||
ObjectKey: "mock_object",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
}),
|
||||
)
|
||||
assert.NoError(err)
|
||||
@@ -545,10 +545,10 @@ func TestLoopbackGetObject(t *testing.T) {
|
||||
plg, err := NewLoopbackPlugin(
|
||||
WithMockBuckets(mockStorageMapData),
|
||||
WithMockError(PluginMockError{
|
||||
bucketName: "aws_s3_err",
|
||||
objectKey: "mock_object",
|
||||
errMsg: "invalid credentials",
|
||||
errCode: codes.PermissionDenied,
|
||||
BucketName: "aws_s3_err",
|
||||
ObjectKey: "mock_object",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
}),
|
||||
)
|
||||
assert.NoError(err)
|
||||
@@ -693,10 +693,10 @@ func TestLoopbackPutObject(t *testing.T) {
|
||||
plg, err := NewLoopbackPlugin(
|
||||
WithMockBuckets(mockStorageMapData),
|
||||
WithMockError(PluginMockError{
|
||||
bucketName: "object_store_err",
|
||||
objectKey: "mock_object",
|
||||
errMsg: "invalid credentials",
|
||||
errCode: codes.PermissionDenied,
|
||||
BucketName: "object_store_err",
|
||||
ObjectKey: "mock_object",
|
||||
ErrMsg: "invalid credentials",
|
||||
ErrCode: codes.PermissionDenied,
|
||||
}),
|
||||
)
|
||||
require.NoError(err)
|
||||
|
||||
Reference in new issue
Block a user