3
0

add(store): import storage layer and tests

This commit is contained in:
Tit Petric 2018-09-07 16:05:51 +02:00
parent a23137c14e
commit d6d497f16e
4 changed files with 171 additions and 0 deletions

1
store/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/test

23
store/interfaces.go Normal file
View File

@ -0,0 +1,23 @@
package store
import "io"
type (
store struct {
namespace string
originalFn func(id uint64, ext string) string
previewFn func(id uint64, ext string) string
}
Store interface {
Namespace() string
Original(id uint64, ext string) string
Preview(id uint64, ext string) string
Save(filename string, contents io.Reader) error
Remove(filename string) error
Open(filename string) (io.Reader, error)
}
)

75
store/store.go Normal file
View File

@ -0,0 +1,75 @@
package store
import (
"fmt"
"io"
"path"
"github.com/spf13/afero"
"github.com/pkg/errors"
)
func New(namespace string) (Store, error) {
return &store{
namespace: namespace,
originalFn: func(id uint64, ext string) string {
return fmt.Sprintf("%d.%s", id, ext)
},
previewFn: func(id uint64, ext string) string {
return fmt.Sprintf("%d_preview.%s", id, ext)
},
}, nil
}
func (s *store) Namespace() string {
return s.namespace
}
func (s *store) check(filename string) error {
if filename[:len(s.namespace)+1] != s.namespace + "/" {
return errors.Errorf("Invalid namespace when trying to store file: %s (for %s)", filename, s.namespace)
}
return nil
}
func (s *store) Original(id uint64, ext string) string {
return path.Join(s.namespace, s.originalFn(id, ext))
}
func (s *store) Preview(id uint64, ext string) string {
return path.Join(s.namespace, s.previewFn(id, ext))
}
func (s *store) Save(filename string, contents io.Reader) error {
// check filename for validity
if err := s.check(filename); err != nil {
return err
}
folder := path.Dir(filename)
fs := afero.NewOsFs()
fs.MkdirAll(folder, 0755)
return afero.WriteReader(fs, filename, contents)
}
func (s *store) Remove(filename string) error {
// check filename for validity
if err := s.check(filename); err != nil {
return err
}
fs := afero.NewOsFs()
return fs.Remove(filename)
}
func (s *store) Open(filename string) (io.Reader, error) {
// check filename for validity
if err := s.check(filename); err != nil {
return nil, err
}
fs := afero.NewOsFs()
return fs.Open(filename)
}

72
store/store_test.go Normal file
View File

@ -0,0 +1,72 @@
package store_test
import (
"io"
"bytes"
"testing"
"github.com/crusttech/crust/store"
)
func TestStore(t *testing.T) {
assert := func(ok bool, format string, params ...interface{}) {
if !ok {
t.Fatalf(format, params...)
}
}
readerToString := func(r io.Reader) string {
b := new(bytes.Buffer)
b.ReadFrom(r)
return b.String()
}
store, err := store.New("test")
assert(err == nil, "Unexpected error when creating store: %+v", err)
assert(store != nil, "Expected non-nil return for new store")
assert(store.Namespace() == "test", "Unexpected store namespace: test != %s", store.Namespace())
{
fn := store.Original(123, "jpg")
expected := "test/123.jpg"
assert(fn == expected, "Unexpected filename returned: %s != %s", expected, fn)
}
{
fn := store.Preview(123, "jpg")
expected := "test/123_preview.jpg"
assert(fn == expected, "Unexpected filename returned: %s != %s", expected, fn)
}
// write a file
{
buf := bytes.NewBuffer([]byte("This is a testing buffer"))
err := store.Save("test/123.jpg", buf)
assert(err == nil, "Error saving file, %+v", err)
err = store.Save("test123/123.jpg", buf)
assert(err != nil, "Expected error when saving file outside of namespace")
}
// read a file
{
buf, err := store.Open("test/123.jpg")
assert(err == nil, "Unexpected error when reading file: %+v", err)
s := readerToString(buf)
assert(s == "This is a testing buffer", "Unexpected response when reading file: %s", s)
_, err = store.Open("test/1234.jpg")
assert(err != nil, "Expected error when opening non-existent file")
_, err = store.Open("test123/123.jpg")
assert(err != nil, "Expected error when opening file outside of namespace")
}
// delete a file
{
err := store.Remove("test/123.jpg")
assert(err == nil, "Unexpected error when removing file: %+v", err)
err = store.Remove("test/123.jpg")
assert(err != nil, "Expected error when removing missing file")
err = store.Remove("test123/123.jpg")
assert(err != nil, "Expected error when deleting file outside of namespace")
}
}