From 60817c22494f9e6167102eabb096e0339beaaefb Mon Sep 17 00:00:00 2001 From: Djeeberjr Date: Tue, 23 Nov 2021 01:54:02 +0100 Subject: [PATCH] added mock s3 implementation --- internal/s3/mock.go | 141 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 internal/s3/mock.go diff --git a/internal/s3/mock.go b/internal/s3/mock.go new file mode 100644 index 0000000..f9d79dd --- /dev/null +++ b/internal/s3/mock.go @@ -0,0 +1,141 @@ +package s3 + +import ( + "bytes" + "context" + "crypto/md5" + "fmt" + "io" + "io/ioutil" + "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 +} + +func (m *mockS3) ListBuckets(ctx context.Context) ([]Bucket, error) { + var rtn []Bucket + for _, v := range m.buckets { + rtn = append(rtn, Bucket(v)) + } + + return rtn, nil +} + +func (m *mockS3) ListObjects(ctx context.Context, id types.ID) ([]types.File, []types.Directory, error) { + var files []types.File + var dirs []types.Directory + + for k, v := range m.objects { + if k.Bucket == id.Bucket { + if k.Parent().Key == id.Key { + if k.IsDirectory() { + dirs = append(dirs, *mockObjToDir(v, k)) + } else { + files = append(files, *mockObjToFile(v, k)) + } + } + } + } + + return files, dirs, nil +} + +func (m *mockS3) GetObject(ctx context.Context, id types.ID) (Object, error) { + 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 +} + +func (m *mockS3) StatObject(ctx context.Context, id types.ID) (*types.File, error) { + mockObj, exist := m.objects[id] + + if !exist { + return nil, fmt.Errorf("Object not found") + } + + return mockObjToFile(mockObj, id), nil +} + +func (m *mockS3) RemoveObject(ctx context.Context, id types.ID) error { + delete(m.objects, id) + return nil +} + +func mockObjToFile(mockObj mockObject, id types.ID) *types.File { + return &types.File{ + ID: id, + Name: id.Name(), + Size: int64(len(mockObj.content)), + ContentType: mockObj.contentType, + LastModified: mockObj.lastMod, + ETag: fmt.Sprintf("%x", md5.Sum(mockObj.content)), + } +} + +func mockObjToDir(mockObj mockObject, id types.ID) *types.Directory { + return &types.Directory{ + ID: id, + Name: id.Name(), + } +}