forked from TrueCloudLab/frostfs-node
235 lines
6 KiB
Go
235 lines
6 KiB
Go
// Package teststore provides a common.Storage implementation for testing/mocking purposes.
|
|
//
|
|
// A new teststore.TestStore can be obtained with teststore.New. Whenever one of the common.Storage
|
|
// methods is called, the implementation selects what function to call in the following order:
|
|
// 1. If an override for that method was provided at construction time (via teststore.WithXXX()) or
|
|
// afterwards via SetOption, that override is used.
|
|
// 2. If a substorage was provided at construction time (via teststore.WithSubstorage()) or afterwars
|
|
// via SetOption, the corresponding method in the substorage is used.
|
|
// 3. If none of the above apply, the call panics with an error describing the unexpected call.
|
|
//
|
|
// It's safe to call SetOption and the overrides from multiple goroutines, but it's the override's
|
|
// responsibility to ensure safety of whatever operation it executes.
|
|
package teststore
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/compression"
|
|
)
|
|
|
|
// TestStore is a common.Storage implementation for testing/mocking purposes.
|
|
type TestStore struct {
|
|
mu sync.RWMutex
|
|
*cfg
|
|
}
|
|
|
|
// ErrDiskExploded is a phony error which can be used for testing purposes to differentiate it from
|
|
// more common errors.
|
|
var ErrDiskExploded = errors.New("disk exploded")
|
|
|
|
// New returns a teststore.TestStore from the given options.
|
|
func New(opts ...Option) *TestStore {
|
|
c := &cfg{}
|
|
for _, opt := range opts {
|
|
opt(c)
|
|
}
|
|
return &TestStore{cfg: c}
|
|
}
|
|
|
|
// SetOption overrides an option of an existing teststore.TestStore.
|
|
// This is useful for overriding methods during a test so that different
|
|
// behaviors are simulated.
|
|
func (s *TestStore) SetOption(opt Option) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
opt(s.cfg)
|
|
}
|
|
|
|
func (s *TestStore) Open(readOnly bool) error {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Open != nil:
|
|
return s.overrides.Open(readOnly)
|
|
case s.st != nil:
|
|
return s.st.Open(readOnly)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: Open(%v)", readOnly))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Init() error {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Init != nil:
|
|
return s.overrides.Init()
|
|
case s.st != nil:
|
|
return s.st.Init()
|
|
default:
|
|
panic("unexpected storage call: Init()")
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Close() error {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Close != nil:
|
|
return s.overrides.Close()
|
|
case s.st != nil:
|
|
return s.st.Close()
|
|
default:
|
|
panic("unexpected storage call: Close()")
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Type() string {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Type != nil:
|
|
return s.overrides.Type()
|
|
case s.st != nil:
|
|
return s.st.Type()
|
|
default:
|
|
panic("unexpected storage call: Type()")
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Path() string {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Path != nil:
|
|
return s.overrides.Path()
|
|
case s.st != nil:
|
|
return s.st.Path()
|
|
default:
|
|
panic("unexpected storage call: Path()")
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) SetCompressor(cc *compression.Config) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.SetCompressor != nil:
|
|
s.overrides.SetCompressor(cc)
|
|
case s.st != nil:
|
|
s.st.SetCompressor(cc)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: SetCompressor(%+v)", cc))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Compressor() *compression.Config {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Compressor != nil:
|
|
return s.overrides.Compressor()
|
|
case s.st != nil:
|
|
return s.st.Compressor()
|
|
default:
|
|
panic("unexpected storage call: Compressor()")
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) SetReportErrorFunc(f func(string, error)) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.SetReportErrorFunc != nil:
|
|
s.overrides.SetReportErrorFunc(f)
|
|
case s.st != nil:
|
|
s.st.SetReportErrorFunc(f)
|
|
default:
|
|
panic("unexpected storage call: SetReportErrorFunc(<func>)")
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Get(ctx context.Context, req common.GetPrm) (common.GetRes, error) {
|
|
switch {
|
|
case s.overrides.Get != nil:
|
|
return s.overrides.Get(req)
|
|
case s.st != nil:
|
|
return s.st.Get(ctx, req)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: Get(%+v)", req))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) GetRange(ctx context.Context, req common.GetRangePrm) (common.GetRangeRes, error) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.GetRange != nil:
|
|
return s.overrides.GetRange(req)
|
|
case s.st != nil:
|
|
return s.st.GetRange(ctx, req)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: GetRange(%+v)", req))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Exists(ctx context.Context, req common.ExistsPrm) (common.ExistsRes, error) {
|
|
switch {
|
|
case s.overrides.Exists != nil:
|
|
return s.overrides.Exists(req)
|
|
case s.st != nil:
|
|
return s.st.Exists(ctx, req)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: Exists(%+v)", req))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Put(ctx context.Context, req common.PutPrm) (common.PutRes, error) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Put != nil:
|
|
return s.overrides.Put(req)
|
|
case s.st != nil:
|
|
return s.st.Put(ctx, req)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: Put(%+v)", req))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Delete(ctx context.Context, req common.DeletePrm) (common.DeleteRes, error) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Delete != nil:
|
|
return s.overrides.Delete(req)
|
|
case s.st != nil:
|
|
return s.st.Delete(ctx, req)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: Delete(%+v)", req))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) Iterate(ctx context.Context, req common.IteratePrm) (common.IterateRes, error) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
switch {
|
|
case s.overrides.Iterate != nil:
|
|
return s.overrides.Iterate(req)
|
|
case s.st != nil:
|
|
return s.st.Iterate(ctx, req)
|
|
default:
|
|
panic(fmt.Sprintf("unexpected storage call: Iterate(%+v)", req))
|
|
}
|
|
}
|
|
|
|
func (s *TestStore) SetParentID(string) {}
|
|
|
|
func (s *TestStore) Rebuild(_ context.Context, _ common.RebuildPrm) (common.RebuildRes, error) {
|
|
return common.RebuildRes{}, nil
|
|
}
|