s3browser-backend/internal/s3/mock.go

155 lines
3.0 KiB
Go
Raw Permalink Normal View History

2021-11-23 00:54:02 +00:00
package s3
import (
"bytes"
"context"
"crypto/md5"
"fmt"
"io"
"io/ioutil"
2021-11-23 19:12:24 +00:00
"strings"
2021-11-23 00:54:02 +00:00
"time"
"git.kapelle.org/niklas/s3browser/internal/types"
)
type mockS3 struct {
buckets []string
objects map[types.ID]mockObject
}
type mockObject struct {
content []byte
contentType string
lastMod time.Time
}
type mockObjectReader struct {
*bytes.Reader
}
func (r mockObjectReader) Close() error {
// NOOP
return nil
}
func NewMockS3(buckets []string) (S3Service, error) {
return &mockS3{
buckets: buckets,
objects: map[types.ID]mockObject{},
}, nil
}
2021-11-23 19:12:24 +00:00
func (m *mockS3) ListBuckets(ctx context.Context) ([]string, error) {
return m.buckets, nil
}
func (m *mockS3) ListObjects(ctx context.Context, id types.ID) ([]Object, error) {
var results []Object
2021-11-27 03:07:41 +00:00
dirs := make(map[string]bool)
depth := len(strings.Split(id.Key, "/"))
2021-11-23 19:12:24 +00:00
for k, v := range m.objects {
if k.Bucket == id.Bucket {
if k.Parent().Key == id.Key {
results = append(results, *mockObjToObject(v, k))
2021-11-27 03:07:41 +00:00
} else if strings.HasPrefix(k.Key, id.Key) {
s := strings.Join(strings.Split(k.Key, "/")[:depth], "/") + "/"
dirs[s] = true
2021-11-23 19:12:24 +00:00
}
}
2021-11-23 00:54:02 +00:00
}
2021-11-27 03:07:41 +00:00
for k := range dirs {
results = append(results, Object{
ID: types.ID{
Bucket: id.Bucket,
Key: k,
},
})
}
2021-11-23 19:12:24 +00:00
return results, nil
2021-11-23 00:54:02 +00:00
}
2021-11-23 19:12:24 +00:00
func (m *mockS3) ListObjectsRecursive(ctx context.Context, id types.ID) ([]Object, error) {
var results []Object
2021-11-23 00:54:02 +00:00
for k, v := range m.objects {
if k.Bucket == id.Bucket {
2021-11-23 19:12:24 +00:00
if strings.HasPrefix(k.Key, id.Key) {
2021-11-25 00:56:57 +00:00
results = append(results, *mockObjToObject(v, k))
2021-11-23 00:54:02 +00:00
}
}
}
2021-11-23 19:12:24 +00:00
return results, nil
2021-11-23 00:54:02 +00:00
}
2021-11-23 19:12:24 +00:00
func (m *mockS3) GetObject(ctx context.Context, id types.ID) (ObjectReader, error) {
2021-11-23 00:54:02 +00:00
mockObj, exist := m.objects[id]
if !exist {
return nil, fmt.Errorf("Object not found")
}
reader := bytes.NewReader(mockObj.content)
return mockObjectReader{reader}, nil
}
func (m *mockS3) PutObject(ctx context.Context, id types.ID, reader io.Reader, objectSize int64) error {
content, err := ioutil.ReadAll(reader)
if err != nil {
return err
}
m.objects[id] = mockObject{
content: content,
lastMod: time.Now(),
contentType: "application/octet-stream", // TODO: detect MIME type or dont its just a mock after all
}
return nil
}
func (m *mockS3) CopyObject(ctx context.Context, src types.ID, dest types.ID) error {
srcObj, exist := m.objects[src]
if !exist {
return fmt.Errorf("Object not found")
}
m.objects[dest] = srcObj
return nil
}
2021-11-23 19:12:24 +00:00
func (m *mockS3) StatObject(ctx context.Context, id types.ID) (*Object, error) {
2021-11-23 00:54:02 +00:00
mockObj, exist := m.objects[id]
if !exist {
return nil, fmt.Errorf("Object not found")
}
2021-11-23 19:12:24 +00:00
return mockObjToObject(mockObj, id), nil
2021-11-23 00:54:02 +00:00
}
func (m *mockS3) RemoveObject(ctx context.Context, id types.ID) error {
delete(m.objects, id)
return nil
}
2021-11-23 19:12:24 +00:00
func mockObjToObject(mockObj mockObject, id types.ID) *Object {
return &Object{
2021-11-23 00:54:02 +00:00
ID: id,
Size: int64(len(mockObj.content)),
ContentType: mockObj.contentType,
LastModified: mockObj.lastMod,
ETag: fmt.Sprintf("%x", md5.Sum(mockObj.content)),
}
}