add(store): import storage layer and tests
This commit is contained in:
parent
a23137c14e
commit
d6d497f16e
1
store/.gitignore
vendored
Normal file
1
store/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/test
|
||||
23
store/interfaces.go
Normal file
23
store/interfaces.go
Normal 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
75
store/store.go
Normal 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
72
store/store_test.go
Normal 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")
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user