fix list buckets response for single bucket entry

The xml encoding of the s3.ListBucketsOutput return type was not giving
correct results when there is only a single bucket. This revives the
old aws xsd schema and generated types that will give more accurate xml
encoding results.
This commit is contained in:
Ben McClelland
2023-06-16 10:22:25 -07:00
parent 246dbe4f6b
commit 5c61604e82
10 changed files with 1742 additions and 32 deletions
+3 -3
View File
@@ -31,7 +31,7 @@ type Backend interface {
fmt.Stringer
Shutdown()
ListBuckets() (*s3.ListBucketsOutput, error)
ListBuckets() (s3response.ListAllMyBucketsResult, error)
HeadBucket(bucket string) (*s3.HeadBucketOutput, error)
GetBucketAcl(bucket string) (*auth.GetBucketAclOutput, error)
PutBucket(bucket, owner string) error
@@ -76,8 +76,8 @@ func (BackendUnsupported) Shutdown() {}
func (BackendUnsupported) String() string {
return "Unsupported"
}
func (BackendUnsupported) ListBuckets() (*s3.ListBucketsOutput, error) {
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
func (BackendUnsupported) ListBuckets() (s3response.ListAllMyBucketsResult, error) {
return s3response.ListAllMyBucketsResult{}, s3err.GetAPIError(s3err.ErrNotImplemented)
}
func (BackendUnsupported) PutBucketAcl(*s3.PutBucketAclInput) error {
return s3err.GetAPIError(s3err.ErrNotImplemented)
+3 -3
View File
@@ -67,7 +67,7 @@ var _ Backend = &BackendMock{}
// HeadObjectFunc: func(bucket string, object string) (*s3.HeadObjectOutput, error) {
// panic("mock out the HeadObject method")
// },
// ListBucketsFunc: func() (*s3.ListBucketsOutput, error) {
// ListBucketsFunc: func() (s3response.ListAllMyBucketsResult, error) {
// panic("mock out the ListBuckets method")
// },
// ListMultipartUploadsFunc: func(output *s3.ListMultipartUploadsInput) (s3response.ListMultipartUploadsResponse, error) {
@@ -168,7 +168,7 @@ type BackendMock struct {
HeadObjectFunc func(bucket string, object string) (*s3.HeadObjectOutput, error)
// ListBucketsFunc mocks the ListBuckets method.
ListBucketsFunc func() (*s3.ListBucketsOutput, error)
ListBucketsFunc func() (s3response.ListAllMyBucketsResult, error)
// ListMultipartUploadsFunc mocks the ListMultipartUploads method.
ListMultipartUploadsFunc func(output *s3.ListMultipartUploadsInput) (s3response.ListMultipartUploadsResponse, error)
@@ -1053,7 +1053,7 @@ func (mock *BackendMock) HeadObjectCalls() []struct {
}
// ListBuckets calls ListBucketsFunc.
func (mock *BackendMock) ListBuckets() (*s3.ListBucketsOutput, error) {
func (mock *BackendMock) ListBuckets() (s3response.ListAllMyBucketsResult, error) {
if mock.ListBucketsFunc == nil {
panic("BackendMock.ListBucketsFunc: method is nil but Backend.ListBuckets was just called")
}
+10 -9
View File
@@ -18,11 +18,10 @@ import (
"context"
"testing"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/versity/versitygw/backend/auth"
"github.com/versity/versitygw/s3err"
"github.com/versity/versitygw/s3response"
)
func TestBackend_ListBuckets(t *testing.T) {
@@ -39,11 +38,13 @@ func TestBackend_ListBuckets(t *testing.T) {
tests = append(tests, test{
name: "list-Bucket",
c: &BackendMock{
ListBucketsFunc: func() (*s3.ListBucketsOutput, error) {
return &s3.ListBucketsOutput{
Buckets: []types.Bucket{
{
Name: aws.String("t1"),
ListBucketsFunc: func() (s3response.ListAllMyBucketsResult, error) {
return s3response.ListAllMyBucketsResult{
Buckets: s3response.ListAllMyBucketsList{
Bucket: []s3response.ListAllMyBucketsEntry{
{
Name: "t1",
},
},
},
}, s3err.GetAPIError(0)
@@ -56,8 +57,8 @@ func TestBackend_ListBuckets(t *testing.T) {
}, test{
name: "list-Bucket-error",
c: &BackendMock{
ListBucketsFunc: func() (*s3.ListBucketsOutput, error) {
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
ListBucketsFunc: func() (s3response.ListAllMyBucketsResult, error) {
return s3response.ListAllMyBucketsResult{}, s3err.GetAPIError(s3err.ErrNotImplemented)
},
},
args: args{
+3 -2
View File
@@ -22,6 +22,7 @@ import (
"time"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/versity/versitygw/s3response"
)
var (
@@ -31,11 +32,11 @@ var (
func IsValidBucketName(name string) bool { return true }
type ByBucketName []types.Bucket
type ByBucketName []s3response.ListAllMyBucketsEntry
func (d ByBucketName) Len() int { return len(d) }
func (d ByBucketName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func (d ByBucketName) Less(i, j int) bool { return *d[i].Name < *d[j].Name }
func (d ByBucketName) Less(i, j int) bool { return d[i].Name < d[j].Name }
type ByObjectName []types.Object
+11 -8
View File
@@ -78,13 +78,14 @@ func (p *Posix) Sring() string {
return "Posix Gateway"
}
func (p *Posix) ListBuckets() (*s3.ListBucketsOutput, error) {
func (p *Posix) ListBuckets() (s3response.ListAllMyBucketsResult, error) {
entries, err := os.ReadDir(".")
if err != nil {
return nil, fmt.Errorf("readdir buckets: %w", err)
return s3response.ListAllMyBucketsResult{},
fmt.Errorf("readdir buckets: %w", err)
}
var buckets []types.Bucket
var buckets []s3response.ListAllMyBucketsEntry
for _, entry := range entries {
if !entry.IsDir() {
// buckets must be a directory
@@ -97,16 +98,18 @@ func (p *Posix) ListBuckets() (*s3.ListBucketsOutput, error) {
continue
}
buckets = append(buckets, types.Bucket{
Name: backend.GetStringPtr(entry.Name()),
CreationDate: backend.GetTimePtr(fi.ModTime()),
buckets = append(buckets, s3response.ListAllMyBucketsEntry{
Name: entry.Name(),
CreationDate: fi.ModTime(),
})
}
sort.Sort(backend.ByBucketName(buckets))
return &s3.ListBucketsOutput{
Buckets: buckets,
return s3response.ListAllMyBucketsResult{
Buckets: s3response.ListAllMyBucketsList{
Bucket: buckets,
},
}, nil
}