feature/increase_test_coverage #387
12 changed files with 1017 additions and 81 deletions
|
@ -301,9 +301,9 @@ func TestMultipartUploadWithContentLanguage(t *testing.T) {
|
|||
createTestBucket(hc, bktName)
|
||||
|
||||
partSize := 5 * 1024 * 1024
|
||||
exceptedContentLanguage := "en"
|
||||
expectedContentLanguage := "en"
|
||||
headers := map[string]string{
|
||||
api.ContentLanguage: exceptedContentLanguage,
|
||||
api.ContentLanguage: expectedContentLanguage,
|
||||
}
|
||||
|
||||
multipartUpload := createMultipartUpload(hc, bktName, objName, headers)
|
||||
|
@ -314,7 +314,7 @@ func TestMultipartUploadWithContentLanguage(t *testing.T) {
|
|||
|
||||
w, r := prepareTestRequest(hc, bktName, objName, nil)
|
||||
hc.Handler().HeadObjectHandler(w, r)
|
||||
require.Equal(t, exceptedContentLanguage, w.Header().Get(api.ContentLanguage))
|
||||
require.Equal(t, expectedContentLanguage, w.Header().Get(api.ContentLanguage))
|
||||
}
|
||||
|
||||
func TestMultipartUploadEnabledMD5(t *testing.T) {
|
||||
|
|
|
@ -453,14 +453,14 @@ func getObjectAttribute(obj *object.Object, attrName string) string {
|
|||
func TestPutObjectWithContentLanguage(t *testing.T) {
|
||||
tc := prepareHandlerContext(t)
|
||||
|
||||
exceptedContentLanguage := "en"
|
||||
expectedContentLanguage := "en"
|
||||
bktName, objName := "bucket-1", "object-1"
|
||||
createTestBucket(tc, bktName)
|
||||
|
||||
w, r := prepareTestRequest(tc, bktName, objName, nil)
|
||||
r.Header.Set(api.ContentLanguage, exceptedContentLanguage)
|
||||
r.Header.Set(api.ContentLanguage, expectedContentLanguage)
|
||||
tc.Handler().PutObjectHandler(w, r)
|
||||
|
||||
tc.Handler().HeadObjectHandler(w, r)
|
||||
require.Equal(t, exceptedContentLanguage, w.Header().Get(api.ContentLanguage))
|
||||
require.Equal(t, expectedContentLanguage, w.Header().Get(api.ContentLanguage))
|
||||
}
|
||||
|
|
|
@ -80,3 +80,462 @@ func TestReqTypeDetermination(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetermineBucketOperation(t *testing.T) {
|
||||
const defaultValue = "value"
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
method string
|
||||
queryParam map[string]string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "OptionsOperation",
|
||||
method: http.MethodOptions,
|
||||
expected: OptionsOperation,
|
||||
},
|
||||
{
|
||||
name: "HeadBucketOperation",
|
||||
method: http.MethodHead,
|
||||
expected: HeadBucketOperation,
|
||||
},
|
||||
{
|
||||
name: "ListMultipartUploadsOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{UploadsQuery: defaultValue},
|
||||
expected: ListMultipartUploadsOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketLocationOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{LocationQuery: defaultValue},
|
||||
expected: GetBucketLocationOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketPolicyOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{PolicyQuery: defaultValue},
|
||||
expected: GetBucketPolicyOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketLifecycleOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{LifecycleQuery: defaultValue},
|
||||
expected: GetBucketLifecycleOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketEncryptionOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{EncryptionQuery: defaultValue},
|
||||
expected: GetBucketEncryptionOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketCorsOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{CorsQuery: defaultValue},
|
||||
expected: GetBucketCorsOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketACLOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{ACLQuery: defaultValue},
|
||||
expected: GetBucketACLOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketWebsiteOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{WebsiteQuery: defaultValue},
|
||||
expected: GetBucketWebsiteOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketAccelerateOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{AccelerateQuery: defaultValue},
|
||||
expected: GetBucketAccelerateOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketRequestPaymentOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{RequestPaymentQuery: defaultValue},
|
||||
expected: GetBucketRequestPaymentOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketLoggingOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{LoggingQuery: defaultValue},
|
||||
expected: GetBucketLoggingOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketReplicationOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{ReplicationQuery: defaultValue},
|
||||
expected: GetBucketReplicationOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketTaggingOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{TaggingQuery: defaultValue},
|
||||
expected: GetBucketTaggingOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketObjectLockConfigOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{ObjectLockQuery: defaultValue},
|
||||
expected: GetBucketObjectLockConfigOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketVersioningOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{VersioningQuery: defaultValue},
|
||||
expected: GetBucketVersioningOperation,
|
||||
},
|
||||
{
|
||||
name: "GetBucketNotificationOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{NotificationQuery: defaultValue},
|
||||
expected: GetBucketNotificationOperation,
|
||||
},
|
||||
{
|
||||
name: "ListenBucketNotificationOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{EventsQuery: defaultValue},
|
||||
expected: ListenBucketNotificationOperation,
|
||||
},
|
||||
{
|
||||
name: "ListBucketObjectVersionsOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{VersionsQuery: defaultValue},
|
||||
expected: ListBucketObjectVersionsOperation,
|
||||
},
|
||||
{
|
||||
name: "ListObjectsV2MOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{ListTypeQuery: "2", MetadataQuery: "true"},
|
||||
expected: ListObjectsV2MOperation,
|
||||
},
|
||||
{
|
||||
name: "ListObjectsV2Operation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{ListTypeQuery: "2"},
|
||||
expected: ListObjectsV2Operation,
|
||||
},
|
||||
{
|
||||
name: "ListObjectsV1Operation",
|
||||
method: http.MethodGet,
|
||||
expected: ListObjectsV1Operation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketCorsOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{CorsQuery: defaultValue},
|
||||
expected: PutBucketCorsOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketACLOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{ACLQuery: defaultValue},
|
||||
expected: PutBucketACLOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketLifecycleOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{LifecycleQuery: defaultValue},
|
||||
expected: PutBucketLifecycleOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketEncryptionOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{EncryptionQuery: defaultValue},
|
||||
expected: PutBucketEncryptionOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketPolicyOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{PolicyQuery: defaultValue},
|
||||
expected: PutBucketPolicyOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketObjectLockConfigOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{ObjectLockQuery: defaultValue},
|
||||
expected: PutBucketObjectLockConfigOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketTaggingOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{TaggingQuery: defaultValue},
|
||||
expected: PutBucketTaggingOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketVersioningOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{VersioningQuery: defaultValue},
|
||||
expected: PutBucketVersioningOperation,
|
||||
},
|
||||
{
|
||||
name: "PutBucketNotificationOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{NotificationQuery: defaultValue},
|
||||
expected: PutBucketNotificationOperation,
|
||||
},
|
||||
{
|
||||
name: "CreateBucketOperation",
|
||||
method: http.MethodPut,
|
||||
expected: CreateBucketOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteMultipleObjectsOperation",
|
||||
method: http.MethodPost,
|
||||
queryParam: map[string]string{DeleteQuery: defaultValue},
|
||||
expected: DeleteMultipleObjectsOperation,
|
||||
},
|
||||
{
|
||||
name: "PostObjectOperation",
|
||||
method: http.MethodPost,
|
||||
expected: PostObjectOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteBucketCorsOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{CorsQuery: defaultValue},
|
||||
expected: DeleteBucketCorsOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteBucketWebsiteOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{WebsiteQuery: defaultValue},
|
||||
expected: DeleteBucketWebsiteOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteBucketTaggingOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{TaggingQuery: defaultValue},
|
||||
expected: DeleteBucketTaggingOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteBucketPolicyOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{PolicyQuery: defaultValue},
|
||||
expected: DeleteBucketPolicyOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteBucketLifecycleOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{LifecycleQuery: defaultValue},
|
||||
expected: DeleteBucketLifecycleOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteBucketEncryptionOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{EncryptionQuery: defaultValue},
|
||||
expected: DeleteBucketEncryptionOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteBucketOperation",
|
||||
method: http.MethodDelete,
|
||||
expected: DeleteBucketOperation,
|
||||
},
|
||||
{
|
||||
name: "UnmatchedBucketOperation",
|
||||
method: "invalid-method",
|
||||
expected: "UnmatchedBucketOperation",
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req := httptest.NewRequest(tc.method, "/test", nil)
|
||||
if tc.queryParam != nil {
|
||||
addQueryParams(req, tc.queryParam)
|
||||
}
|
||||
|
||||
actual := determineBucketOperation(req)
|
||||
require.Equal(t, tc.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetermineObjectOperation(t *testing.T) {
|
||||
const (
|
||||
amzCopySource = "X-Amz-Copy-Source"
|
||||
defaultValue = "value"
|
||||
)
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
method string
|
||||
queryParam map[string]string
|
||||
headerKeys []string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "HeadObjectOperation",
|
||||
method: http.MethodHead,
|
||||
expected: HeadObjectOperation,
|
||||
},
|
||||
{
|
||||
name: "ListPartsOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{UploadIDQuery: defaultValue},
|
||||
expected: ListPartsOperation,
|
||||
},
|
||||
{
|
||||
name: "GetObjectACLOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{ACLQuery: defaultValue},
|
||||
expected: GetObjectACLOperation,
|
||||
},
|
||||
{
|
||||
name: "GetObjectTaggingOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{TaggingQuery: defaultValue},
|
||||
expected: GetObjectTaggingOperation,
|
||||
},
|
||||
{
|
||||
name: "GetObjectRetentionOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{RetentionQuery: defaultValue},
|
||||
expected: GetObjectRetentionOperation,
|
||||
},
|
||||
{
|
||||
name: "GetObjectLegalHoldOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{LegalQuery: defaultValue},
|
||||
expected: GetObjectLegalHoldOperation,
|
||||
},
|
||||
{
|
||||
name: "GetObjectAttributesOperation",
|
||||
method: http.MethodGet,
|
||||
queryParam: map[string]string{AttributesQuery: defaultValue},
|
||||
expected: GetObjectAttributesOperation,
|
||||
},
|
||||
{
|
||||
name: "GetObjectOperation",
|
||||
method: http.MethodGet,
|
||||
expected: GetObjectOperation,
|
||||
},
|
||||
{
|
||||
name: "UploadPartCopyOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{PartNumberQuery: defaultValue, UploadIDQuery: defaultValue},
|
||||
headerKeys: []string{amzCopySource},
|
||||
expected: UploadPartCopyOperation,
|
||||
},
|
||||
{
|
||||
name: "UploadPartOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{PartNumberQuery: defaultValue, UploadIDQuery: defaultValue},
|
||||
expected: UploadPartOperation,
|
||||
},
|
||||
{
|
||||
name: "PutObjectACLOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{ACLQuery: defaultValue},
|
||||
expected: PutObjectACLOperation,
|
||||
},
|
||||
{
|
||||
name: "PutObjectTaggingOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{TaggingQuery: defaultValue},
|
||||
expected: PutObjectTaggingOperation,
|
||||
},
|
||||
{
|
||||
name: "CopyObjectOperation",
|
||||
method: http.MethodPut,
|
||||
headerKeys: []string{amzCopySource},
|
||||
expected: CopyObjectOperation,
|
||||
},
|
||||
{
|
||||
name: "PutObjectRetentionOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{RetentionQuery: defaultValue},
|
||||
expected: PutObjectRetentionOperation,
|
||||
},
|
||||
{
|
||||
name: "PutObjectLegalHoldOperation",
|
||||
method: http.MethodPut,
|
||||
queryParam: map[string]string{LegalHoldQuery: defaultValue},
|
||||
expected: PutObjectLegalHoldOperation,
|
||||
},
|
||||
{
|
||||
name: "PutObjectOperation",
|
||||
method: http.MethodPut,
|
||||
expected: PutObjectOperation,
|
||||
},
|
||||
{
|
||||
name: "CompleteMultipartUploadOperation",
|
||||
method: http.MethodPost,
|
||||
queryParam: map[string]string{UploadIDQuery: defaultValue},
|
||||
expected: CompleteMultipartUploadOperation,
|
||||
},
|
||||
{
|
||||
name: "CreateMultipartUploadOperation",
|
||||
method: http.MethodPost,
|
||||
queryParam: map[string]string{UploadsQuery: defaultValue},
|
||||
expected: CreateMultipartUploadOperation,
|
||||
},
|
||||
{
|
||||
name: "SelectObjectContentOperation",
|
||||
method: http.MethodPost,
|
||||
expected: SelectObjectContentOperation,
|
||||
},
|
||||
{
|
||||
name: "AbortMultipartUploadOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{UploadIDQuery: defaultValue},
|
||||
expected: AbortMultipartUploadOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteObjectTaggingOperation",
|
||||
method: http.MethodDelete,
|
||||
queryParam: map[string]string{TaggingQuery: defaultValue},
|
||||
expected: DeleteObjectTaggingOperation,
|
||||
},
|
||||
{
|
||||
name: "DeleteObjectOperation",
|
||||
method: http.MethodDelete,
|
||||
expected: DeleteObjectOperation,
|
||||
},
|
||||
{
|
||||
name: "UnmatchedObjectOperation",
|
||||
method: "invalid-method",
|
||||
expected: "UnmatchedObjectOperation",
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req := httptest.NewRequest(tc.method, "/test", nil)
|
||||
if tc.queryParam != nil {
|
||||
addQueryParams(req, tc.queryParam)
|
||||
}
|
||||
if tc.headerKeys != nil {
|
||||
addHeaderParams(req, tc.headerKeys)
|
||||
}
|
||||
|
||||
actual := determineObjectOperation(req)
|
||||
require.Equal(t, tc.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func addQueryParams(req *http.Request, pairs map[string]string) {
|
||||
values := req.URL.Query()
|
||||
for key, val := range pairs {
|
||||
values.Add(key, val)
|
||||
}
|
||||
req.URL.RawQuery = values.Encode()
|
||||
}
|
||||
|
||||
func addHeaderParams(req *http.Request, keys []string) {
|
||||
for _, key := range keys {
|
||||
req.Header.Set(key, "val")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetermineGeneralOperation(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
actual := determineGeneralOperation(req)
|
||||
require.Equal(t, ListBucketsOperation, actual)
|
||||
|
||||
req = httptest.NewRequest(http.MethodPost, "/test", nil)
|
||||
actual = determineGeneralOperation(req)
|
||||
require.Equal(t, "UnmatchedOperation", actual)
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ type (
|
|||
Namespace string
|
||||
User string // User owner id
|
||||
Tagging *data.Tagging
|
||||
tags []KeyVal // Any additional info not accommodated by above fields
|
||||
}
|
||||
|
||||
// ObjectRequest represents object request data.
|
||||
|
@ -103,50 +102,6 @@ func NewReqInfo(w http.ResponseWriter, r *http.Request, req ObjectRequest, sourc
|
|||
return reqInfo
|
||||
}
|
||||
|
||||
// AppendTags -- appends key/val to ReqInfo.tags.
|
||||
func (r *ReqInfo) AppendTags(key string, val string) *ReqInfo {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
r.tags = append(r.tags, KeyVal{key, val})
|
||||
return r
|
||||
}
|
||||
|
||||
// SetTags -- sets key/val to ReqInfo.tags.
|
||||
func (r *ReqInfo) SetTags(key string, val string) *ReqInfo {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
// Search for a tag key already existing in tags
|
||||
var updated bool
|
||||
for _, tag := range r.tags {
|
||||
if tag.Key == key {
|
||||
tag.Val = val
|
||||
updated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !updated {
|
||||
// Append to the end of tags list
|
||||
r.tags = append(r.tags, KeyVal{key, val})
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// GetTags -- returns the user defined tags.
|
||||
func (r *ReqInfo) GetTags() []KeyVal {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
r.RLock()
|
||||
defer r.RUnlock()
|
||||
return append([]KeyVal(nil), r.tags...)
|
||||
}
|
||||
|
||||
// GetRequestID returns the request ID from the response writer or the context.
|
||||
func GetRequestID(v interface{}) string {
|
||||
switch t := v.(type) {
|
||||
|
|
70
api/middleware/reqinfo_test.go
Normal file
70
api/middleware/reqinfo_test.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetSourceIP(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
req *http.Request
|
||||
}{
|
||||
{
|
||||
name: "headers not set",
|
||||
req: func() *http.Request {
|
||||
request := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
request.RemoteAddr = "192.0.2.1:1234"
|
||||
return request
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "headers not set, and the port is not set",
|
||||
req: func() *http.Request {
|
||||
request := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
request.RemoteAddr = "192.0.2.1"
|
||||
return request
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "x-forwarded-for single-host header",
|
||||
req: func() *http.Request {
|
||||
request := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
request.Header.Set(xForwardedFor, "192.0.2.1")
|
||||
return request
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "x-forwarded-for header by multiple hosts",
|
||||
req: func() *http.Request {
|
||||
request := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
request.Header.Set(xForwardedFor, "192.0.2.1, 10.1.1.1")
|
||||
return request
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "x-real-ip header",
|
||||
req: func() *http.Request {
|
||||
request := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
request.Header.Set(xRealIP, "192.0.2.1")
|
||||
return request
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "forwarded header",
|
||||
req: func() *http.Request {
|
||||
request := httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
request.Header.Set(forwarded, "for=192.0.2.1, 10.1.1.1; proto=https; by=192.0.2.4")
|
||||
return request
|
||||
}(),
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual := getSourceIP(tc.req)
|
||||
require.Equal(t, actual, "192.0.2.1")
|
||||
})
|
||||
}
|
||||
}
|
|
@ -201,18 +201,6 @@ func EncodeResponse(response interface{}) ([]byte, error) {
|
|||
return bytesBuffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// EncodeResponseNoHeader encodes response without setting xml.Header.
|
||||
// Should be used with periodicXMLWriter which sends xml.Header to the client
|
||||
// with whitespaces to keep connection alive.
|
||||
func EncodeResponseNoHeader(response interface{}) ([]byte, error) {
|
||||
var bytesBuffer bytes.Buffer
|
||||
if err := xml.NewEncoder(&bytesBuffer).Encode(response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bytesBuffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// EncodeToResponse encodes the response into ResponseWriter.
|
||||
func EncodeToResponse(w http.ResponseWriter, response interface{}) error {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
|
43
api/middleware/response_test.go
Normal file
43
api/middleware/response_test.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testXMLData struct {
|
||||
XMLName xml.Name `xml:"data"`
|
||||
Text string `xml:"text"`
|
||||
}
|
||||
|
||||
func TestEncodeResponse(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
err := EncodeToResponse(w, []byte{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "encode xml response")
|
||||
|
||||
err = EncodeToResponse(w, testXMLData{Text: "test"})
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedXML := "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<data><text>test</text></data>"
|
||||
require.Equal(t, expectedXML, w.Body.String())
|
||||
}
|
||||
|
||||
func TestErrorResponse(t *testing.T) {
|
||||
errResp := ErrorResponse{Code: "invalid-code"}
|
||||
|
||||
actual := errResp.Error()
|
||||
require.Contains(t, actual, "Error response code")
|
||||
|
||||
errResp.Code = "AccessDenied"
|
||||
actual = errResp.Error()
|
||||
require.Equal(t, "Access Denied.", actual)
|
||||
|
||||
errResp.Message = "Request body is empty."
|
||||
actual = errResp.Error()
|
||||
require.Equal(t, "Request body is empty.", actual)
|
||||
}
|
115
api/middleware/tracing_test.go
Normal file
115
api/middleware/tracing_test.go
Normal file
|
@ -0,0 +1,115 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHTTPResponseCarrierSetGet(t *testing.T) {
|
||||
const (
|
||||
testKey1 = "Key"
|
||||
testValue1 = "Value"
|
||||
)
|
||||
|
||||
respCarrier := httpResponseCarrier{}
|
||||
respCarrier.resp = httptest.NewRecorder()
|
||||
|
||||
actual := respCarrier.Get(testKey1)
|
||||
require.Equal(t, "", actual)
|
||||
|
||||
respCarrier.Set(testKey1, testValue1)
|
||||
actual = respCarrier.Get(testKey1)
|
||||
require.Equal(t, testValue1, actual)
|
||||
}
|
||||
|
||||
func TestHTTPResponseCarrierKeys(t *testing.T) {
|
||||
const (
|
||||
testKey1 = "Key1"
|
||||
testKey2 = "Key2"
|
||||
testKey3 = "Key3"
|
||||
testValue1 = "Value1"
|
||||
testValue2 = "Value2"
|
||||
testValue3 = "Value3"
|
||||
)
|
||||
|
||||
respCarrier := httpResponseCarrier{}
|
||||
respCarrier.resp = httptest.NewRecorder()
|
||||
|
||||
actual := respCarrier.Keys()
|
||||
require.Equal(t, 0, len(actual))
|
||||
|
||||
respCarrier.Set(testKey1, testValue1)
|
||||
respCarrier.Set(testKey2, testValue2)
|
||||
respCarrier.Set(testKey3, testValue3)
|
||||
|
||||
actual = respCarrier.Keys()
|
||||
require.Equal(t, 3, len(actual))
|
||||
require.Contains(t, actual, testKey1)
|
||||
require.Contains(t, actual, testKey2)
|
||||
require.Contains(t, actual, testKey3)
|
||||
}
|
||||
|
||||
func TestHTTPRequestCarrierSet(t *testing.T) {
|
||||
const (
|
||||
testKey = "Key"
|
||||
testValue = "Value"
|
||||
)
|
||||
|
||||
reqCarrier := httpRequestCarrier{}
|
||||
reqCarrier.req = httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
reqCarrier.req.Response = httptest.NewRecorder().Result()
|
||||
|
||||
actual := reqCarrier.req.Response.Header.Get(testKey)
|
||||
require.Equal(t, "", actual)
|
||||
|
||||
reqCarrier.Set(testKey, testValue)
|
||||
actual = reqCarrier.req.Response.Header.Get(testKey)
|
||||
require.Contains(t, testValue, actual)
|
||||
}
|
||||
|
||||
func TestHTTPRequestCarrierGet(t *testing.T) {
|
||||
const (
|
||||
testKey = "Key"
|
||||
testValue = "Value"
|
||||
)
|
||||
|
||||
reqCarrier := httpRequestCarrier{}
|
||||
reqCarrier.req = httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
|
||||
actual := reqCarrier.Get(testKey)
|
||||
require.Equal(t, "", actual)
|
||||
|
||||
reqCarrier.req.Header.Set(testKey, testValue)
|
||||
actual = reqCarrier.Get(testKey)
|
||||
require.Equal(t, testValue, actual)
|
||||
}
|
||||
|
||||
func TestHTTPRequestCarrierKeys(t *testing.T) {
|
||||
const (
|
||||
testKey1 = "Key1"
|
||||
testKey2 = "Key2"
|
||||
testKey3 = "Key3"
|
||||
testValue1 = "Value1"
|
||||
testValue2 = "Value2"
|
||||
testValue3 = "Value3"
|
||||
)
|
||||
|
||||
reqCarrier := httpRequestCarrier{}
|
||||
reqCarrier.req = httptest.NewRequest(http.MethodGet, "/test", nil)
|
||||
|
||||
actual := reqCarrier.Keys()
|
||||
require.Equal(t, 0, len(actual))
|
||||
|
||||
reqCarrier.req.Header.Set(testKey1, testValue1)
|
||||
reqCarrier.req.Header.Set(testKey2, testValue2)
|
||||
reqCarrier.req.Header.Set(testKey3, testValue3)
|
||||
|
||||
actual = reqCarrier.Keys()
|
||||
require.Equal(t, 3, len(actual))
|
||||
require.Contains(t, actual, testKey1)
|
||||
require.Contains(t, actual, testKey2)
|
||||
require.Contains(t, actual, testKey3)
|
||||
}
|
179
api/middleware/util_test.go
Normal file
179
api/middleware/util_test.go
Normal file
|
@ -0,0 +1,179 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/creds/accessbox"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetBoxData(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
value any
|
||||
error string
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
value: &Box{
|
||||
AccessBox: &accessbox.Box{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid data",
|
||||
value: "invalid-data",
|
||||
error: "couldn't get box from context",
|
||||
},
|
||||
{
|
||||
name: "box does not exist",
|
||||
error: "couldn't get box from context",
|
||||
},
|
||||
{
|
||||
name: "access box is nil",
|
||||
value: &Box{},
|
||||
error: "couldn't get box data from context",
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx := context.WithValue(context.Background(), boxKey, tc.value)
|
||||
actual, err := GetBoxData(ctx)
|
||||
if tc.error != "" {
|
||||
require.Contains(t, err.Error(), tc.error)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, actual)
|
||||
require.NotNil(t, actual.Gate)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAuthHeaders(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
value any
|
||||
error bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
value: &Box{
|
||||
AuthHeaders: &AuthHeader{
|
||||
AccessKeyID: "valid-key",
|
||||
Region: "valid-region",
|
||||
SignatureV4: "valid-sign",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid data",
|
||||
value: "invalid-data",
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
name: "box does not exist",
|
||||
error: true,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx := context.WithValue(context.Background(), boxKey, tc.value)
|
||||
actual, err := GetAuthHeaders(ctx)
|
||||
if tc.error {
|
||||
require.Contains(t, err.Error(), "couldn't get box from context")
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.value.(*Box).AuthHeaders.AccessKeyID, actual.AccessKeyID)
|
||||
require.Equal(t, tc.value.(*Box).AuthHeaders.Region, actual.Region)
|
||||
require.Equal(t, tc.value.(*Box).AuthHeaders.SignatureV4, actual.SignatureV4)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetClientTime(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
value any
|
||||
error string
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
value: &Box{
|
||||
ClientTime: time.Now(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid data",
|
||||
value: "invalid-data",
|
||||
error: "couldn't get box from context",
|
||||
},
|
||||
{
|
||||
name: "box does not exist",
|
||||
error: "couldn't get box from context",
|
||||
},
|
||||
{
|
||||
name: "zero time",
|
||||
value: &Box{
|
||||
ClientTime: time.Time{},
|
||||
},
|
||||
error: "couldn't get client time from context",
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx := context.WithValue(context.Background(), boxKey, tc.value)
|
||||
actual, err := GetClientTime(ctx)
|
||||
if tc.error != "" {
|
||||
require.Contains(t, err.Error(), tc.error)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.value.(*Box).ClientTime, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccessBoxAttrs(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
value any
|
||||
error bool
|
||||
}{
|
||||
{
|
||||
name: "valid",
|
||||
value: func() *Box {
|
||||
var attr object.Attribute
|
||||
attr.SetKey("key")
|
||||
attr.SetValue("value")
|
||||
return &Box{Attributes: []object.Attribute{attr}}
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "invalid data",
|
||||
value: "invalid-data",
|
||||
error: true,
|
||||
},
|
||||
{
|
||||
name: "box does not exist",
|
||||
error: true,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx := context.WithValue(context.Background(), boxKey, tc.value)
|
||||
actual, err := GetAccessBoxAttrs(ctx)
|
||||
if tc.error {
|
||||
require.Contains(t, err.Error(), "couldn't get box from context")
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(tc.value.(*Box).Attributes), len(actual))
|
||||
require.Equal(t, tc.value.(*Box).Attributes[0].Key(), actual[0].Key())
|
||||
require.Equal(t, tc.value.(*Box).Attributes[0].Value(), actual[0].Value())
|
||||
})
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
@ -32,12 +33,22 @@ func (p *poolStatisticMock) Statistic() pool.Statistic {
|
|||
}
|
||||
|
||||
type centerMock struct {
|
||||
t *testing.T
|
||||
anon bool
|
||||
attrs []object.Attribute
|
||||
t *testing.T
|
||||
anon bool
|
||||
noAuthHeader bool
|
||||
isError bool
|
||||
attrs []object.Attribute
|
||||
}
|
||||
|
||||
func (c *centerMock) Authenticate(*http.Request) (*middleware.Box, error) {
|
||||
if c.noAuthHeader {
|
||||
return nil, middleware.ErrNoAuthorizationHeader
|
||||
}
|
||||
|
||||
if c.isError {
|
||||
return nil, fmt.Errorf("some error")
|
||||
}
|
||||
|
||||
var token *bearer.Token
|
||||
|
||||
if !c.anon {
|
||||
|
@ -86,14 +97,23 @@ func (r *middlewareSettingsMock) ACLEnabled() bool {
|
|||
}
|
||||
|
||||
type frostFSIDMock struct {
|
||||
tags map[string]string
|
||||
tags map[string]string
|
||||
validateError bool
|
||||
userGroupsError bool
|
||||
}
|
||||
|
||||
func (f *frostFSIDMock) ValidatePublicKey(*keys.PublicKey) error {
|
||||
if f.validateError {
|
||||
return fmt.Errorf("some error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *frostFSIDMock) GetUserGroupIDsAndClaims(util.Uint160) ([]string, map[string]string, error) {
|
||||
if f.userGroupsError {
|
||||
return nil, nil, fmt.Errorf("some error")
|
||||
}
|
||||
return []string{}, f.tags, nil
|
||||
}
|
||||
|
||||
|
@ -105,17 +125,21 @@ func (m *xmlMock) NewXMLDecoder(r io.Reader) *xml.Decoder {
|
|||
}
|
||||
|
||||
type resourceTaggingMock struct {
|
||||
bucketTags map[string]string
|
||||
objectTags map[string]string
|
||||
noSuchKey bool
|
||||
bucketTags map[string]string
|
||||
objectTags map[string]string
|
||||
noSuchObjectKey bool
|
||||
noSuchBucketKey bool
|
||||
}
|
||||
|
||||
func (m *resourceTaggingMock) GetBucketTagging(context.Context, *data.BucketInfo) (map[string]string, error) {
|
||||
if m.noSuchBucketKey {
|
||||
return nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey)
|
||||
}
|
||||
return m.bucketTags, nil
|
||||
}
|
||||
|
||||
func (m *resourceTaggingMock) GetObjectTagging(context.Context, *data.GetObjectTaggingParams) (string, map[string]string, error) {
|
||||
if m.noSuchKey {
|
||||
if m.noSuchObjectKey {
|
||||
return "", nil, apiErrors.GetAPIError(apiErrors.ErrNoSuchKey)
|
||||
}
|
||||
return "", m.objectTags, nil
|
||||
|
@ -215,9 +239,13 @@ func (h *handlerMock) PutObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|||
h.writeResponse(w, res)
|
||||
}
|
||||
|
||||
func (h *handlerMock) DeleteObjectHandler(http.ResponseWriter, *http.Request) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
func (h *handlerMock) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
res := &handlerResult{
|
||||
Method: middleware.DeleteObjectOperation,
|
||||
ReqInfo: middleware.GetReqInfo(r.Context()),
|
||||
}
|
||||
|
||||
h.writeResponse(w, res)
|
||||
}
|
||||
|
||||
func (h *handlerMock) GetBucketLocationHandler(http.ResponseWriter, *http.Request) {
|
||||
|
|
|
@ -43,7 +43,15 @@ func (m *routerMock) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
m.router.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func prepareRouter(t *testing.T) *routerMock {
|
||||
type option func(*Config)
|
||||
|
||||
func frostFSIDValidation(flag bool) option {
|
||||
return func(cfg *Config) {
|
||||
cfg.FrostFSIDValidation = flag
|
||||
}
|
||||
}
|
||||
|
||||
func prepareRouter(t *testing.T, opts ...option) *routerMock {
|
||||
middlewareSettings := &middlewareSettingsMock{}
|
||||
policyChecker := inmemory.NewInMemoryLocalOverrides()
|
||||
|
||||
|
@ -72,6 +80,11 @@ func prepareRouter(t *testing.T) *routerMock {
|
|||
XMLDecoder: &xmlMock{},
|
||||
Tagging: &resourceTaggingMock{},
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&cfg)
|
||||
}
|
||||
|
||||
return &routerMock{
|
||||
t: t,
|
||||
router: NewRouter(cfg),
|
||||
|
@ -191,12 +204,25 @@ func TestPolicyChecker(t *testing.T) {
|
|||
|
||||
// check we can access 'bucket' in default namespace
|
||||
putObject(chiRouter, ns1, bktName1, objName1, nil)
|
||||
deleteObject(chiRouter, ns1, bktName1, objName1, nil)
|
||||
|
||||
// check we can access 'other-bucket' in custom namespace
|
||||
putObject(chiRouter, ns2, bktName2, objName2, nil)
|
||||
deleteObject(chiRouter, ns2, bktName2, objName2, nil)
|
||||
|
||||
// check we cannot access 'bucket' in custom namespace
|
||||
putObjectErr(chiRouter, ns2, bktName1, objName2, nil, apiErrors.ErrAccessDenied)
|
||||
deleteObjectErr(chiRouter, ns2, bktName1, objName2, nil, apiErrors.ErrAccessDenied)
|
||||
}
|
||||
|
||||
func TestPolicyCheckerError(t *testing.T) {
|
||||
chiRouter := prepareRouter(t)
|
||||
ns1, bktName1, objName1 := "", "bucket", "object"
|
||||
putObjectErr(chiRouter, ns1, bktName1, objName1, nil, apiErrors.ErrNoSuchBucket)
|
||||
|
||||
chiRouter = prepareRouter(t)
|
||||
chiRouter.cfg.FrostfsID.(*frostFSIDMock).userGroupsError = true
|
||||
putObjectErr(chiRouter, ns1, bktName1, objName1, nil, apiErrors.ErrInternalError)
|
||||
}
|
||||
|
||||
func TestPolicyCheckerReqTypeDetermination(t *testing.T) {
|
||||
|
@ -507,6 +533,9 @@ func TestRequestTagsCheck(t *testing.T) {
|
|||
tagging, err = xml.Marshal(data.Tagging{TagSet: []data.Tag{{Key: "key", Value: tagValue}}})
|
||||
require.NoError(t, err)
|
||||
putBucketTaggingErr(router, ns, bktName, tagging, apiErrors.ErrAccessDenied)
|
||||
|
||||
tagging = nil
|
||||
putBucketTaggingErr(router, ns, bktName, tagging, apiErrors.ErrMalformedXML)
|
||||
})
|
||||
|
||||
t.Run("put object with tag", func(t *testing.T) {
|
||||
|
@ -588,7 +617,11 @@ func TestResourceTagsCheck(t *testing.T) {
|
|||
|
||||
listObjectsV1Err(router, ns, bktName, "", "", "", apiErrors.ErrNoSuchBucket)
|
||||
|
||||
router.cfg.Tagging.(*resourceTaggingMock).noSuchKey = true
|
||||
router.cfg.Tagging.(*resourceTaggingMock).noSuchBucketKey = true
|
||||
createBucket(router, ns, bktName)
|
||||
getBucketErr(router, ns, bktName, apiErrors.ErrNoSuchKey)
|
||||
|
||||
router.cfg.Tagging.(*resourceTaggingMock).noSuchObjectKey = true
|
||||
createBucket(router, ns, bktName)
|
||||
getObjectErr(router, ns, bktName, objName, apiErrors.ErrNoSuchKey)
|
||||
})
|
||||
|
@ -719,6 +752,18 @@ func listBucketsBase(router *routerMock, namespace string) *httptest.ResponseRec
|
|||
return w
|
||||
}
|
||||
|
||||
func getBucketErr(router *routerMock, namespace, bktName string, errCode apiErrors.ErrorCode) {
|
||||
w := getBucketBase(router, namespace, bktName)
|
||||
assertAPIError(router.t, w, errCode)
|
||||
}
|
||||
|
||||
func getBucketBase(router *routerMock, namespace, bktName string) *httptest.ResponseRecorder {
|
||||
w, r := httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/"+bktName, nil)
|
||||
r.Header.Set(FrostfsNamespaceHeader, namespace)
|
||||
router.ServeHTTP(w, r)
|
||||
return w
|
||||
}
|
||||
|
||||
func putObject(router *routerMock, namespace, bktName, objName string, tag *data.Tag) handlerResult {
|
||||
w := putObjectBase(router, namespace, bktName, objName, tag)
|
||||
resp := readResponse(router.t, w)
|
||||
|
@ -744,6 +789,31 @@ func putObjectBase(router *routerMock, namespace, bktName, objName string, tag *
|
|||
return w
|
||||
}
|
||||
|
||||
func deleteObject(router *routerMock, namespace, bktName, objName string, tag *data.Tag) handlerResult {
|
||||
w := deleteObjectBase(router, namespace, bktName, objName, tag)
|
||||
resp := readResponse(router.t, w)
|
||||
require.Equal(router.t, s3middleware.DeleteObjectOperation, resp.Method)
|
||||
return resp
|
||||
}
|
||||
|
||||
func deleteObjectErr(router *routerMock, namespace, bktName, objName string, tag *data.Tag, errCode apiErrors.ErrorCode) {
|
||||
w := deleteObjectBase(router, namespace, bktName, objName, tag)
|
||||
assertAPIError(router.t, w, errCode)
|
||||
}
|
||||
|
||||
func deleteObjectBase(router *routerMock, namespace, bktName, objName string, tag *data.Tag) *httptest.ResponseRecorder {
|
||||
w, r := httptest.NewRecorder(), httptest.NewRequest(http.MethodDelete, "/"+bktName+"/"+objName, nil)
|
||||
if tag != nil {
|
||||
queries := url.Values{
|
||||
tag.Key: []string{tag.Value},
|
||||
}
|
||||
r.Header.Set(AmzTagging, queries.Encode())
|
||||
}
|
||||
r.Header.Set(FrostfsNamespaceHeader, namespace)
|
||||
router.ServeHTTP(w, r)
|
||||
return w
|
||||
}
|
||||
|
||||
func putBucketTagging(router *routerMock, namespace, bktName string, tagging []byte) handlerResult {
|
||||
w := putBucketTaggingBase(router, namespace, bktName, tagging)
|
||||
resp := readResponse(router.t, w)
|
||||
|
@ -853,6 +923,35 @@ func TestBillingMetrics(t *testing.T) {
|
|||
require.Equal(t, "anon", dump.Requests[0].User)
|
||||
}
|
||||
|
||||
func TestAuthenticate(t *testing.T) {
|
||||
chiRouter := prepareRouter(t)
|
||||
createBucket(chiRouter, "", "bkt-1")
|
||||
|
||||
chiRouter = prepareRouter(t)
|
||||
chiRouter.cfg.Center.(*centerMock).noAuthHeader = true
|
||||
createBucket(chiRouter, "", "bkt-2")
|
||||
|
||||
chiRouter = prepareRouter(t)
|
||||
chiRouter.cfg.Center.(*centerMock).isError = true
|
||||
createBucketErr(chiRouter, "", "bkt-3", nil, apiErrors.ErrAccessDenied)
|
||||
}
|
||||
|
||||
func TestFrostFSIDValidation(t *testing.T) {
|
||||
// successful frostFSID validation
|
||||
chiRouter := prepareRouter(t, frostFSIDValidation(true))
|
||||
createBucket(chiRouter, "", "bkt-1")
|
||||
|
||||
// anon request, skip frostFSID validation
|
||||
chiRouter = prepareRouter(t, frostFSIDValidation(true))
|
||||
chiRouter.cfg.Center.(*centerMock).anon = true
|
||||
createBucket(chiRouter, "", "bkt-2")
|
||||
|
||||
// frostFSID validation failed
|
||||
chiRouter = prepareRouter(t, frostFSIDValidation(true))
|
||||
chiRouter.cfg.FrostfsID.(*frostFSIDMock).validateError = true
|
||||
createBucketErr(chiRouter, "", "bkt-3", nil, apiErrors.ErrInternalError)
|
||||
}
|
||||
|
||||
func readResponse(t *testing.T, w *httptest.ResponseRecorder) handlerResult {
|
||||
var res handlerResult
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ func TestGetLatestNode(t *testing.T) {
|
|||
for _, tc := range []struct {
|
||||
name string
|
||||
nodes []NodeResponse
|
||||
exceptedNodeID uint64
|
||||
expectedNodeID uint64
|
||||
error bool
|
||||
}{
|
||||
{
|
||||
|
@ -208,7 +208,7 @@ func TestGetLatestNode(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
exceptedNodeID: 1,
|
||||
expectedNodeID: 1,
|
||||
},
|
||||
{
|
||||
name: "one node of the object version and one node of the secondary object",
|
||||
|
@ -231,7 +231,7 @@ func TestGetLatestNode(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
exceptedNodeID: 1,
|
||||
expectedNodeID: 1,
|
||||
},
|
||||
{
|
||||
name: "all nodes represent a secondary object",
|
||||
|
@ -289,7 +289,7 @@ func TestGetLatestNode(t *testing.T) {
|
|||
meta: []nodeMeta{},
|
||||
},
|
||||
},
|
||||
exceptedNodeID: 4,
|
||||
expectedNodeID: 4,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
@ -300,7 +300,7 @@ func TestGetLatestNode(t *testing.T) {
|
|||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.exceptedNodeID, actualNode.GetNodeID())
|
||||
require.Equal(t, tc.expectedNodeID, actualNode.GetNodeID())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue