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)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 |