frostfs-s3-gw/api/handler/bucket_list_test.go
Nikita Zinkevich 619385836d [#585] Add ListBuckets handler test
Modify containers field in TestFrostFS in order to get determined order of containers between test runs

Signed-off-by: Nikita Zinkevich <n.zinkevich@yadro.com>
2025-01-21 07:49:19 +00:00

174 lines
5 KiB
Go

package handler
import (
"encoding/xml"
"net/http"
"net/http/httptest"
"net/url"
"sort"
"testing"
apierr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
"github.com/stretchr/testify/require"
)
func TestHandler_ListBucketsHandler(t *testing.T) {
const defaultConstraint = "default"
region := "us-west-1"
hc := prepareHandlerContext(t)
hc.config.putLocationConstraint(region)
props := []Bucket{
{Name: "first"},
{Name: "regional", BucketRegion: "us-west-1"},
{Name: "third"},
}
sort.Slice(props, func(i, j int) bool {
return props[i].Name < props[j].Name
})
for _, bkt := range props {
createBucketWithConstraint(hc, bkt.Name, bkt.BucketRegion)
}
for _, tt := range []struct {
title string
token string
prefix string
bucketRegion string
maxBuckets string
expectErr bool
expected []Bucket
expectedToken string
}{
{
title: "no params",
expected: []Bucket{
{Name: "first", BucketRegion: defaultConstraint},
{Name: "regional", BucketRegion: "us-west-1"},
{Name: "third", BucketRegion: defaultConstraint},
},
},
{
title: "negative max-buckets",
maxBuckets: "-1",
expected: []Bucket{},
expectErr: true,
},
{
title: "zero max-buckets",
maxBuckets: "0",
expected: []Bucket{},
},
{
title: "prefix",
prefix: "thi",
expected: []Bucket{{Name: "third", BucketRegion: defaultConstraint}},
},
{
title: "wrong prefix",
prefix: "sdh",
expected: []Bucket{},
},
{
title: "bucket region",
bucketRegion: region,
expected: []Bucket{{Name: "regional", BucketRegion: "us-west-1"}},
},
{
title: "default bucket region",
bucketRegion: defaultConstraint,
expected: []Bucket{
{Name: "first", BucketRegion: defaultConstraint},
{Name: "third", BucketRegion: defaultConstraint},
},
},
{
title: "wrong bucket region",
bucketRegion: "sj dfdlsj",
expected: []Bucket{},
},
} {
t.Run(tt.title, func(t *testing.T) {
if tt.expectErr {
listBucketsErr(hc, tt.prefix, tt.token, tt.bucketRegion, tt.maxBuckets, apierr.GetAPIError(apierr.ErrInvalidMaxKeys))
return
}
resp := listBuckets(hc, tt.prefix, tt.token, tt.bucketRegion, tt.maxBuckets)
require.Len(t, resp.Buckets.Buckets, len(tt.expected))
require.Equal(t, tt.prefix, resp.Prefix)
require.Equal(t, hc.owner.String(), resp.Owner.ID)
if len(resp.Buckets.Buckets) > 0 {
t.Log(resp.Buckets.Buckets[0].Name)
}
for i, bkt := range resp.Buckets.Buckets {
require.Equal(t, tt.expected[i].Name, bkt.Name)
require.Equal(t, tt.expected[i].BucketRegion, bkt.BucketRegion)
}
})
}
t.Run("pagination", func(t *testing.T) {
t.Run("happy path", func(t *testing.T) {
resp := listBuckets(hc, "", "", "", "1")
require.Len(t, resp.Buckets.Buckets, 1)
require.Equal(t, props[0].Name, resp.Buckets.Buckets[0].Name)
require.NotEmpty(t, resp.ContinuationToken)
resp = listBuckets(hc, "", resp.ContinuationToken, "", "1")
require.Len(t, resp.Buckets.Buckets, 1)
require.Equal(t, props[1].Name, resp.Buckets.Buckets[0].Name)
require.NotEmpty(t, resp.ContinuationToken)
resp = listBuckets(hc, "", resp.ContinuationToken, "", "1")
require.Len(t, resp.Buckets.Buckets, 1)
require.Equal(t, props[2].Name, resp.Buckets.Buckets[0].Name)
require.Empty(t, resp.ContinuationToken)
})
t.Run("wrong continuation-token", func(t *testing.T) {
resp := listBuckets(hc, "", "CebuVwfRpdMqi9dvgV2SUNbrkfteGtudchKKhNabXUu9", "", "1")
require.Len(t, resp.Buckets.Buckets, 0)
require.Empty(t, resp.ContinuationToken)
})
})
}
func listBuckets(hc *handlerContext, prefix, token, bucketRegion, maxBuckets string) ListBucketsResponse {
query := url.Values{
middleware.QueryPrefix: []string{prefix},
middleware.QueryContinuationToken: []string{token},
middleware.QueryBucketRegion: []string{bucketRegion},
middleware.QueryMaxBuckets: []string{maxBuckets},
}
w := listBucketsBase(hc, bucketPrm{query: query})
assertStatus(hc.t, w, http.StatusOK)
var resp ListBucketsResponse
err := xml.NewDecoder(w.Body).Decode(&resp)
require.NoError(hc.t, err)
return resp
}
func listBucketsErr(hc *handlerContext, prefix, token, bucketRegion, maxBuckets string, err apierr.Error) {
query := url.Values{
middleware.QueryPrefix: []string{prefix},
middleware.QueryContinuationToken: []string{token},
middleware.QueryBucketRegion: []string{bucketRegion},
middleware.QueryMaxBuckets: []string{maxBuckets},
}
w := listBucketsBase(hc, bucketPrm{query: query})
assertS3Error(hc.t, w, err)
}
func listBucketsBase(hc *handlerContext, prm bucketPrm) *httptest.ResponseRecorder {
box, _ := createAccessBox(hc.t)
w, r := prepareTestFullRequest(hc, "", "", prm.query, nil)
ctx := middleware.SetBox(r.Context(), &middleware.Box{AccessBox: box})
r = r.WithContext(ctx)
hc.Handler().ListBucketsHandler(w, r)
return w
}