You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
5.4 KiB
227 lines
5.4 KiB
package s3api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/aws/aws-sdk-go/service/s3"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
|
"reflect"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type BucketMetadataTestCase struct {
|
|
filerEntry *filer_pb.Entry
|
|
expectBucketMetadata *BucketMetaData
|
|
}
|
|
|
|
var (
|
|
//bad entry
|
|
badEntry = &filer_pb.Entry{
|
|
Name: "badEntry",
|
|
}
|
|
|
|
//good entry
|
|
goodEntryAcl, _ = json.Marshal(s3_constants.PublicRead)
|
|
goodEntry = &filer_pb.Entry{
|
|
Name: "entryWithValidAcp",
|
|
Extended: map[string][]byte{
|
|
s3_constants.ExtOwnershipKey: []byte(s3_constants.OwnershipBucketOwnerEnforced),
|
|
s3_constants.ExtAmzOwnerKey: []byte(AccountAdmin.DisplayName),
|
|
s3_constants.ExtAmzAclKey: goodEntryAcl,
|
|
},
|
|
}
|
|
|
|
//ownership is ""
|
|
ownershipEmptyStr = &filer_pb.Entry{
|
|
Name: "ownershipEmptyStr",
|
|
Extended: map[string][]byte{
|
|
s3_constants.ExtOwnershipKey: []byte(""),
|
|
},
|
|
}
|
|
|
|
//ownership valid
|
|
ownershipValid = &filer_pb.Entry{
|
|
Name: "ownershipValid",
|
|
Extended: map[string][]byte{
|
|
s3_constants.ExtOwnershipKey: []byte(s3_constants.OwnershipBucketOwnerEnforced),
|
|
},
|
|
}
|
|
|
|
//owner is ""
|
|
acpEmptyStr = &filer_pb.Entry{
|
|
Name: "acpEmptyStr",
|
|
Extended: map[string][]byte{
|
|
s3_constants.ExtAmzOwnerKey: []byte(""),
|
|
},
|
|
}
|
|
|
|
//owner not exists
|
|
acpEmptyObject = &filer_pb.Entry{
|
|
Name: "acpEmptyObject",
|
|
Extended: map[string][]byte{
|
|
s3_constants.ExtAmzOwnerKey: []byte("xxxxx"),
|
|
},
|
|
}
|
|
|
|
//grants is nil
|
|
acpOwnerNilAcp, _ = json.Marshal(make([]*s3.Grant, 0))
|
|
acpOwnerNil = &filer_pb.Entry{
|
|
Name: "acpOwnerNil",
|
|
Extended: map[string][]byte{
|
|
s3_constants.ExtAmzAclKey: acpOwnerNilAcp,
|
|
},
|
|
}
|
|
|
|
//load filer is
|
|
loadFilerBucket = make(map[string]int, 1)
|
|
//override `loadBucketMetadataFromFiler` to avoid really load from filer
|
|
)
|
|
|
|
var tcs = []*BucketMetadataTestCase{
|
|
{
|
|
badEntry, &BucketMetaData{
|
|
Name: badEntry.Name,
|
|
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
|
Owner: &s3.Owner{
|
|
DisplayName: &AccountAdmin.DisplayName,
|
|
ID: &AccountAdmin.Id,
|
|
},
|
|
Acl: nil,
|
|
},
|
|
},
|
|
{
|
|
goodEntry, &BucketMetaData{
|
|
Name: goodEntry.Name,
|
|
ObjectOwnership: s3_constants.OwnershipBucketOwnerEnforced,
|
|
Owner: &s3.Owner{
|
|
DisplayName: &AccountAdmin.DisplayName,
|
|
ID: &AccountAdmin.Id,
|
|
},
|
|
Acl: s3_constants.PublicRead,
|
|
},
|
|
},
|
|
{
|
|
ownershipEmptyStr, &BucketMetaData{
|
|
Name: ownershipEmptyStr.Name,
|
|
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
|
Owner: &s3.Owner{
|
|
DisplayName: &AccountAdmin.DisplayName,
|
|
ID: &AccountAdmin.Id,
|
|
},
|
|
Acl: nil,
|
|
},
|
|
},
|
|
{
|
|
ownershipValid, &BucketMetaData{
|
|
Name: ownershipValid.Name,
|
|
ObjectOwnership: s3_constants.OwnershipBucketOwnerEnforced,
|
|
Owner: &s3.Owner{
|
|
DisplayName: &AccountAdmin.DisplayName,
|
|
ID: &AccountAdmin.Id,
|
|
},
|
|
Acl: nil,
|
|
},
|
|
},
|
|
{
|
|
acpEmptyStr, &BucketMetaData{
|
|
Name: acpEmptyStr.Name,
|
|
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
|
Owner: &s3.Owner{
|
|
DisplayName: &AccountAdmin.DisplayName,
|
|
ID: &AccountAdmin.Id,
|
|
},
|
|
Acl: nil,
|
|
},
|
|
},
|
|
{
|
|
acpEmptyObject, &BucketMetaData{
|
|
Name: acpEmptyObject.Name,
|
|
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
|
Owner: &s3.Owner{
|
|
DisplayName: &AccountAdmin.DisplayName,
|
|
ID: &AccountAdmin.Id,
|
|
},
|
|
Acl: nil,
|
|
},
|
|
},
|
|
{
|
|
acpOwnerNil, &BucketMetaData{
|
|
Name: acpOwnerNil.Name,
|
|
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
|
Owner: &s3.Owner{
|
|
DisplayName: &AccountAdmin.DisplayName,
|
|
ID: &AccountAdmin.Id,
|
|
},
|
|
Acl: make([]*s3.Grant, 0),
|
|
},
|
|
},
|
|
}
|
|
|
|
func TestBuildBucketMetadata(t *testing.T) {
|
|
iam := &IdentityAccessManagement{}
|
|
_ = iam.loadS3ApiConfiguration(&iam_pb.S3ApiConfiguration{})
|
|
for _, tc := range tcs {
|
|
resultBucketMetadata := buildBucketMetadata(iam, tc.filerEntry)
|
|
if !reflect.DeepEqual(resultBucketMetadata, tc.expectBucketMetadata) {
|
|
t.Fatalf("result is unexpect: \nresult: %v, \nexpect: %v", resultBucketMetadata, tc.expectBucketMetadata)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetBucketMetadata(t *testing.T) {
|
|
loadBucketMetadataFromFiler = func(r *BucketRegistry, bucketName string) (*BucketMetaData, error) {
|
|
time.Sleep(time.Second)
|
|
loadFilerBucket[bucketName] = loadFilerBucket[bucketName] + 1
|
|
return &BucketMetaData{
|
|
Name: bucketName,
|
|
}, nil
|
|
}
|
|
|
|
br := &BucketRegistry{
|
|
metadataCache: make(map[string]*BucketMetaData),
|
|
notFound: make(map[string]struct{}),
|
|
s3a: nil,
|
|
}
|
|
|
|
//start 40 goroutine for
|
|
var wg sync.WaitGroup
|
|
closeCh := make(chan struct{})
|
|
for i := 0; i < 40; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
outLoop:
|
|
for {
|
|
for j := 0; j < 5; j++ {
|
|
select {
|
|
case <-closeCh:
|
|
break outLoop
|
|
default:
|
|
reqBucket := fmt.Sprintf("%c", 67+j)
|
|
_, errCode := br.GetBucketMetadata(reqBucket)
|
|
if errCode != s3err.ErrNone {
|
|
close(closeCh)
|
|
t.Error("not expect")
|
|
}
|
|
}
|
|
}
|
|
time.Sleep(10 * time.Microsecond)
|
|
}
|
|
}()
|
|
}
|
|
time.Sleep(time.Second)
|
|
close(closeCh)
|
|
wg.Wait()
|
|
|
|
//Each bucket is loaded from the filer only once
|
|
for bucketName, loadCount := range loadFilerBucket {
|
|
if loadCount != 1 {
|
|
t.Fatalf("lock is uneffict: %s, %d", bucketName, loadCount)
|
|
}
|
|
}
|
|
}
|