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/test" oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test" "github.com/stretchr/testify/require" "go.etcd.io/bbolt" "go.uber.org/zap" ) func TestFlush(t *testing.T) { testlogger := test.NewLogger(t, true) createCacheFn := func(t *testing.T, smallSize uint64, mb *meta.DB, bs writecache.MainStorage, opts ...Option) writecache.Cache { return New( append([]Option{ WithLogger(testlogger), WithPath(filepath.Join(t.TempDir(), "writecache")), WithSmallObjectSize(smallSize), WithMetabase(mb), WithBlobstor(bs), }, opts...)...) } errCountOpt := func() (Option, *atomic.Uint32) { cnt := &atomic.Uint32{} return WithReportErrorFunc(func(msg string, err error) { cnt.Add(1) testlogger.Warn(msg, zap.Uint32("error_count", cnt.Load()), zap.Error(err)) }), 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...) }