2023-06-22 11:55:30 +00:00
|
|
|
package writecachebbolt
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sync/atomic"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
objectCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
|
|
|
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/writecache"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/writecache/writecachetest"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
|
|
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.etcd.io/bbolt"
|
2023-08-17 12:49:24 +00:00
|
|
|
"go.uber.org/zap"
|
2023-06-22 11:55:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestFlush(t *testing.T) {
|
2023-08-09 12:54:08 +00:00
|
|
|
createCacheFn := func(t *testing.T, smallSize uint64, mb *meta.DB, bs writecache.MainStorage, opts ...Option) writecache.Cache {
|
2023-06-22 11:55:30 +00:00
|
|
|
return New(
|
|
|
|
append([]Option{
|
2023-08-17 12:49:24 +00:00
|
|
|
WithLogger(&logger.Logger{Logger: zap.L()}),
|
2023-06-22 11:55:30 +00:00
|
|
|
WithPath(filepath.Join(t.TempDir(), "writecache")),
|
|
|
|
WithSmallObjectSize(smallSize),
|
|
|
|
WithMetabase(mb),
|
|
|
|
WithBlobstor(bs),
|
|
|
|
}, opts...)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
errCountOpt := func() (Option, *atomic.Uint32) {
|
|
|
|
cnt := &atomic.Uint32{}
|
|
|
|
return WithReportErrorFunc(func(string, error) {
|
|
|
|
cnt.Add(1)
|
|
|
|
}), cnt
|
|
|
|
}
|
|
|
|
|
|
|
|
failures := []writecachetest.TestFailureInjector[Option]{
|
|
|
|
{
|
|
|
|
Desc: "db, invalid address",
|
|
|
|
InjectFn: func(t *testing.T, wc writecache.Cache) {
|
|
|
|
c := wc.(*cache)
|
|
|
|
obj := testutil.GenerateObject()
|
|
|
|
data, err := obj.Marshal()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, c.db.Batch(func(tx *bbolt.Tx) error {
|
|
|
|
b := tx.Bucket(defaultBucket)
|
|
|
|
return b.Put([]byte{1, 2, 3}, data)
|
|
|
|
}))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Desc: "db, invalid object",
|
|
|
|
InjectFn: func(t *testing.T, wc writecache.Cache) {
|
|
|
|
c := wc.(*cache)
|
|
|
|
require.NoError(t, c.db.Batch(func(tx *bbolt.Tx) error {
|
|
|
|
b := tx.Bucket(defaultBucket)
|
|
|
|
k := []byte(oidtest.Address().EncodeToString())
|
|
|
|
v := []byte{1, 2, 3}
|
|
|
|
return b.Put(k, v)
|
|
|
|
}))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Desc: "fs, read error",
|
|
|
|
InjectFn: func(t *testing.T, wc writecache.Cache) {
|
|
|
|
c := wc.(*cache)
|
|
|
|
obj := testutil.GenerateObject()
|
|
|
|
data, err := obj.Marshal()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var prm common.PutPrm
|
|
|
|
prm.Address = objectCore.AddressOf(obj)
|
|
|
|
prm.RawData = data
|
|
|
|
|
|
|
|
_, err = c.fsTree.Put(context.Background(), prm)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
p := prm.Address.Object().EncodeToString() + "." + prm.Address.Container().EncodeToString()
|
|
|
|
p = filepath.Join(c.fsTree.RootPath, p[:1], p[1:])
|
|
|
|
|
|
|
|
_, err = os.Stat(p) // sanity check
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, os.Truncate(p, 0)) // corrupt the file contents, so that it can't be unmarshalled
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Desc: "fs, invalid object",
|
|
|
|
InjectFn: func(t *testing.T, wc writecache.Cache) {
|
|
|
|
c := wc.(*cache)
|
|
|
|
var prm common.PutPrm
|
|
|
|
prm.Address = oidtest.Address()
|
|
|
|
prm.RawData = []byte{1, 2, 3}
|
|
|
|
_, err := c.fsTree.Put(context.Background(), prm)
|
|
|
|
require.NoError(t, err)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
writecachetest.TestFlush(t, createCacheFn, errCountOpt, failures...)
|
|
|
|
}
|