2022-06-12 10:26:26 +02:00
|
|
|
package filestore
|
2022-05-25 18:12:03 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
const filecontent = "the content of my file"
|
|
|
|
|
|
|
|
type errorReader struct{}
|
|
|
|
|
|
|
|
func (errorReader) Read(_ []byte) (int, error) {
|
|
|
|
return 0, errors.New("reading error")
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ io.Reader = errorReader{}
|
|
|
|
|
|
|
|
func nameGenAddress(f NameGenerator) string {
|
|
|
|
return fmt.Sprintf("%p", f)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFilestore(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
const bucket = "foo"
|
|
|
|
|
|
|
|
t.Run("Initialize a store", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
|
|
|
|
assert.NoError(err)
|
|
|
|
assert.NotNil(fs)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Selecting a new bucket", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
|
|
|
|
assert.NotNil(b)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Select again a bucket", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
assert.NotNil(b)
|
|
|
|
|
|
|
|
b2 := fs.Bucket(bucket)
|
|
|
|
assert.NotNil(b2)
|
|
|
|
|
|
|
|
assert.Same(b, b2)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("The Default name generator is identity", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
assert.Equal(nameGenAddress(NameIdentity), nameGenAddress(fs.nameGenerator))
|
2022-05-25 18:12:03 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("A custom name generator can be used", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
nameGen := func(s string) (string, error) {
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore(WithNameGen(nameGen))
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
assert.Equal(nameGenAddress(nameGen), nameGenAddress(fs.nameGenerator))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("The Default backend is memory", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
assert.IsType(fs.dataDir, &MemoryBackend{})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("A custom backend can be used", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
|
|
|
fs, err := NewFilestore(WithBackend(NewOSBackend("foo")))
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
assert.IsType(fs.dataDir, &OSBackend{})
|
2022-05-25 18:12:03 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBucket(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
const bucket = "foo"
|
|
|
|
|
|
|
|
t.Run("the name generator of a bucket can be overloaded", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
nameGen := func(s string) (string, error) {
|
|
|
|
return s, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
assert.NotNil(b)
|
|
|
|
|
|
|
|
b.SetNameGenerator(nameGen)
|
|
|
|
assert.NotEqual(nameGenAddress(fs.nameGenerator), nameGenAddress(b.nameGenerator))
|
|
|
|
assert.Equal(nameGenAddress(nameGen), nameGenAddress(b.nameGenerator))
|
|
|
|
})
|
2022-07-03 20:28:50 +02:00
|
|
|
|
|
|
|
t.Run("the backend is the same as the file store", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
|
|
|
|
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
assert.NotNil(b)
|
|
|
|
|
|
|
|
assert.IsType(b.dataDir, fs.dataDir)
|
|
|
|
|
|
|
|
fs, err = NewFilestore(WithBackend(NewOSBackend("foo")))
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
b = fs.Bucket(bucket)
|
|
|
|
assert.NotNil(b)
|
|
|
|
|
|
|
|
assert.IsType(b.dataDir, fs.dataDir)
|
|
|
|
})
|
2022-05-25 18:12:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestBucketPut(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
const (
|
|
|
|
bucket = "foo"
|
|
|
|
filename = "foo.bar"
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("It should store a file", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
|
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-05-25 18:12:03 +02:00
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
|
|
|
|
fr := strings.NewReader(filecontent)
|
|
|
|
|
|
|
|
name, err := b.Put(filename, fr)
|
|
|
|
assert.NoError(err, "cannot store file")
|
|
|
|
assert.Equal("foo.bar", name)
|
|
|
|
|
|
|
|
assert.True(b.Exists(name),
|
|
|
|
"the file does not exist in the store")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("It returns an error if the name cannot be generated", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
errNameGen := func(_ string) (string, error) {
|
|
|
|
return "", errFilenameGeneration
|
|
|
|
}
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore(WithNameGen(errNameGen))
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
fr := strings.NewReader(filecontent)
|
|
|
|
|
|
|
|
name, err := fs.Bucket(bucket).Put(filename, fr)
|
|
|
|
assert.Error(err)
|
|
|
|
assert.Equal("", name)
|
|
|
|
})
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
t.Run("It returns an error if the file cannot be stored", func(t *testing.T) {
|
2022-05-25 18:12:03 +02:00
|
|
|
t.Parallel()
|
2022-07-03 20:28:50 +02:00
|
|
|
t.Skip()
|
2022-05-25 18:12:03 +02:00
|
|
|
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-06-11 21:59:06 +02:00
|
|
|
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
fr := strings.NewReader(filecontent)
|
|
|
|
|
|
|
|
name, err := fs.Bucket(bucket).Put(filename, fr)
|
|
|
|
assert.Error(err)
|
|
|
|
assert.Equal("", name)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("It returns an error if the file cannot be written", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
|
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
fr := errorReader{}
|
|
|
|
|
|
|
|
name, err := fs.Bucket(bucket).Put(filename, fr)
|
|
|
|
assert.Error(err)
|
|
|
|
assert.Equal("", name)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBucketGet(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
const (
|
|
|
|
bucket = "foo"
|
|
|
|
filename = "foo.bar"
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("It should retrieve a file", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
2022-07-03 20:28:50 +02:00
|
|
|
|
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
|
|
|
|
r := strings.NewReader(filecontent)
|
|
|
|
_, err = b.Put(filename, r)
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
rc, err := b.Get(filename)
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
2022-07-03 20:28:50 +02:00
|
|
|
defer func() { _ = rc.Close() }()
|
2022-05-25 18:12:03 +02:00
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
content, err := io.ReadAll(rc)
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
assert.Equal(filecontent, string(content))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("It returns an error if the file is not found", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-05-25 18:12:03 +02:00
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
|
|
|
|
r, err := b.Get(filename)
|
|
|
|
assert.ErrorIs(err, errFileNotFound)
|
|
|
|
assert.Nil(r)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("It returns an error if the file cannot be read", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-07-03 20:28:50 +02:00
|
|
|
t.Skip()
|
2022-05-25 18:12:03 +02:00
|
|
|
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
b := fs.Bucket(bucket)
|
2022-05-25 18:12:03 +02:00
|
|
|
|
|
|
|
r, err := b.Get(filename)
|
|
|
|
assert.Error(err)
|
|
|
|
assert.Nil(r)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBucketExists(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
const (
|
|
|
|
bucket = "foo"
|
|
|
|
filename = "foo.bar"
|
|
|
|
)
|
|
|
|
|
|
|
|
t.Run("It returns true if the file exists", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
wc, err := b.dataDir.Create(filename)
|
2022-05-25 18:12:03 +02:00
|
|
|
assert.NoError(err)
|
2022-07-03 20:28:50 +02:00
|
|
|
wc.Close()
|
2022-05-25 18:12:03 +02:00
|
|
|
|
|
|
|
assert.True(b.Exists(filename))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("It returns false if the file does not exist", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
2022-07-03 20:28:50 +02:00
|
|
|
|
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-05-25 18:12:03 +02:00
|
|
|
b := fs.Bucket(bucket)
|
|
|
|
|
|
|
|
assert.False(b.Exists(filename))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBucketDelete(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
const (
|
|
|
|
bucket = "foo"
|
|
|
|
filename = "foo.bar"
|
|
|
|
)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
t.Run("Removing a file", func(t *testing.T) {
|
2022-05-25 18:12:03 +02:00
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-05-25 18:12:03 +02:00
|
|
|
fr := strings.NewReader(filecontent)
|
|
|
|
|
|
|
|
name, err := fs.Bucket(bucket).Put(filename, fr)
|
|
|
|
assert.NoError(err)
|
|
|
|
defer fs.Bucket(bucket).Delete(filename)
|
|
|
|
|
|
|
|
err = fs.Bucket(bucket).Delete(name)
|
|
|
|
assert.NoError(err)
|
|
|
|
|
2022-07-03 20:28:50 +02:00
|
|
|
assert.False(fs.Bucket(bucket).Exists(name))
|
2022-05-25 18:12:03 +02:00
|
|
|
})
|
2022-07-03 20:28:50 +02:00
|
|
|
|
|
|
|
t.Run("Removing a file that do not exists", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
|
|
|
|
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
err = fs.Bucket(bucket).Delete(filename)
|
|
|
|
assert.NoError(err)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Removing a file with errors", func(t *testing.T) {
|
|
|
|
t.Skip()
|
|
|
|
t.Parallel()
|
|
|
|
assert := require.New(t)
|
|
|
|
|
|
|
|
fs, err := NewFilestore()
|
|
|
|
assert.NoError(err)
|
|
|
|
|
|
|
|
err = fs.Bucket(bucket).Delete(filename)
|
|
|
|
assert.Error(err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIdentityNameGenerator(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
name, err := NameIdentity("foo.txt")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "foo.txt", name)
|
2022-05-25 18:12:03 +02:00
|
|
|
}
|