From 15a9858cc63f3b60185ca060433eeaccf1977fb8 Mon Sep 17 00:00:00 2001 From: Mark Phelps <209477+markphelps@users.noreply.github.com> Date: Fri, 28 Jul 2023 08:06:04 -0400 Subject: [PATCH] chore: fix cacher interceptor ordering (#1914) * chore: fix cacher interceptor ordering * chore: fix storage cacher tests (#1916) * chore: why are you changing go.work.sum * chore: fixup cacher tests into new eval-v2 branch * chore: rm unknown file --- go.work.sum | 1 + internal/cmd/grpc.go | 15 +- internal/storage/cache/cache_test.go | 108 ++++++---- internal/storage/cache/mocks_test.go | 208 ------------------ internal/storage/cache/support_test.go | 279 +++++++++++++++++++++++++ 5 files changed, 353 insertions(+), 258 deletions(-) delete mode 100644 internal/storage/cache/mocks_test.go create mode 100644 internal/storage/cache/support_test.go diff --git a/go.work.sum b/go.work.sum index bdbd953e3f..fcc4bf0885 100644 --- a/go.work.sum +++ b/go.work.sum @@ -598,6 +598,7 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= diff --git a/internal/cmd/grpc.go b/internal/cmd/grpc.go index ee38688faa..40e13014f7 100644 --- a/internal/cmd/grpc.go +++ b/internal/cmd/grpc.go @@ -237,9 +237,8 @@ func NewGRPCServer( otelgrpc.UnaryServerInterceptor(), } + var cacher cache.Cacher if cfg.Cache.Enabled { - var cacher cache.Cacher - switch cfg.Cache.Backend { case config.CacheMemory: cacher = memory.NewCache(cfg.Cache) @@ -268,7 +267,6 @@ func NewGRPCServer( })) } - interceptors = append(interceptors, middlewaregrpc.CacheUnaryInterceptor(cacher, logger)) store = storagecache.New(store, cacher, logger) logger.Debug("cache enabled", zap.Stringer("backend", cacher)) @@ -325,7 +323,12 @@ func NewGRPCServer( )..., ) - // audit sinks configuration. + // cache must come after auth interceptors + if cfg.Cache.Enabled && cacher != nil { + interceptors = append(interceptors, middlewaregrpc.CacheUnaryInterceptor(cacher, logger)) + } + + // audit sinks configuration sinks := make([]audit.Sink, 0) if cfg.Audit.Sinks.LogFile.Enabled { @@ -337,8 +340,8 @@ func NewGRPCServer( sinks = append(sinks, logFileSink) } - // Based on audit sink configuration from the user, provision the audit sinks and add them to a slice, - // and if the slice has a non-zero length, add the audit sink interceptor. + // based on audit sink configuration from the user, provision the audit sinks and add them to a slice, + // and if the slice has a non-zero length, add the audit sink interceptor if len(sinks) > 0 { sse := audit.NewSinkSpanExporter(logger, sinks) tracingProvider.RegisterSpanProcessor(tracesdk.NewBatchSpanProcessor(sse, tracesdk.WithBatchTimeout(cfg.Audit.Buffer.FlushPeriod), tracesdk.WithMaxExportBatchSize(cfg.Audit.Buffer.Capacity))) diff --git a/internal/storage/cache/cache_test.go b/internal/storage/cache/cache_test.go index 96d6f9c28d..2cc8a208c7 100644 --- a/internal/storage/cache/cache_test.go +++ b/internal/storage/cache/cache_test.go @@ -5,78 +5,98 @@ import ( "errors" "testing" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/assert" "go.flipt.io/flipt/internal/storage" "go.uber.org/zap/zaptest" ) func TestSetCacheHandleMarshalError(t *testing.T) { - store := &mockStore{} - cacher := &mockCacher{} - logger := zaptest.NewLogger(t) - cachedStore, _ := New(store, cacher, logger).(*Store) + var ( + store = &storeMock{} + cacher = &cacheSpy{} + logger = zaptest.NewLogger(t) + cachedStore, _ = New(store, cacher, logger).(*Store) + ) cachedStore.setCache(context.TODO(), "key", make(chan int)) - require.Equal(t, "", cacher.CacheKey) + assert.Empty(t, cacher.cacheKey) } func TestGetCacheHandleGetError(t *testing.T) { - store := &mockStore{} - cacher := &mockCacher{GetErr: errors.New("get error")} - logger := zaptest.NewLogger(t) - cachedStore, _ := New(store, cacher, logger).(*Store) + var ( + store = &storeMock{} + cacher = &cacheSpy{getErr: errors.New("get error")} + logger = zaptest.NewLogger(t) + cachedStore, _ = New(store, cacher, logger).(*Store) + ) value := make(map[string]string) cacheHit := cachedStore.getCache(context.TODO(), "key", &value) - require.False(t, cacheHit) + assert.False(t, cacheHit) } func TestGetCacheHandleUnmarshalError(t *testing.T) { - store := &mockStore{} - cacher := &mockCacher{ - Cached: true, - CachedValue: []byte(`{"invalid":"123"`), - } - logger := zaptest.NewLogger(t) - cachedStore, _ := New(store, cacher, logger).(*Store) + var ( + store = &storeMock{} + cacher = &cacheSpy{ + cached: true, + cachedValue: []byte(`{"invalid":"123"`), + } + logger = zaptest.NewLogger(t) + cachedStore, _ = New(store, cacher, logger).(*Store) + ) value := make(map[string]string) cacheHit := cachedStore.getCache(context.TODO(), "key", &value) - require.False(t, cacheHit) + assert.False(t, cacheHit) } func TestGetEvaluationRules(t *testing.T) { - expectedRules := []*storage.EvaluationRule{{ID: "123"}} - store := &mockStore{ - EvaluationRules: expectedRules, - } - cacher := &mockCacher{} - logger := zaptest.NewLogger(t) - cachedStore := New(store, cacher, logger) + var ( + expectedRules = []*storage.EvaluationRule{{ID: "123"}} + store = &storeMock{} + ) + + store.On("GetEvaluationRules", context.TODO(), "ns", "flag-1").Return( + expectedRules, nil, + ) + + var ( + cacher = &cacheSpy{} + logger = zaptest.NewLogger(t) + cachedStore = New(store, cacher, logger) + ) rules, err := cachedStore.GetEvaluationRules(context.TODO(), "ns", "flag-1") - require.Nil(t, err) - require.Equal(t, expectedRules, rules) + assert.Nil(t, err) + assert.Equal(t, expectedRules, rules) - require.Equal(t, "s:er:ns:flag-1", cacher.CacheKey) - require.Equal(t, []byte(`[{"id":"123"}]`), cacher.CachedValue) + assert.Equal(t, "s:er:ns:flag-1", cacher.cacheKey) + assert.Equal(t, []byte(`[{"id":"123"}]`), cacher.cachedValue) } func TestGetEvaluationRulesCached(t *testing.T) { - expectedRules := []*storage.EvaluationRule{{ID: "123"}} - store := &mockStore{ - EvaluationRules: []*storage.EvaluationRule{{ID: "543"}}, - } - cacher := &mockCacher{ - Cached: true, - CachedValue: []byte(`[{"id":"123"}]`), - } - logger := zaptest.NewLogger(t) - cachedStore := New(store, cacher, logger) + var ( + expectedRules = []*storage.EvaluationRule{{ID: "123"}} + store = &storeMock{} + ) - rules, err := cachedStore.GetEvaluationRules(context.TODO(), "ns", "flag-1") - require.Nil(t, err) - require.Equal(t, expectedRules, rules) + store.On("GetEvaluationRules", context.TODO(), "ns", "flag-1").Return( + expectedRules, nil, + ) - require.Equal(t, "s:er:ns:flag-1", cacher.CacheKey) + var ( + cacher = &cacheSpy{ + cached: true, + cachedValue: []byte(`[{"id":"123"}]`), + } + + logger = zaptest.NewLogger(t) + cachedStore = New(store, cacher, logger) + ) + + rules, err := cachedStore.GetEvaluationRules(context.TODO(), "ns", "flag-1") + assert.Nil(t, err) + assert.Equal(t, expectedRules, rules) + assert.Equal(t, "s:er:ns:flag-1", cacher.cacheKey) } diff --git a/internal/storage/cache/mocks_test.go b/internal/storage/cache/mocks_test.go deleted file mode 100644 index 3bc20bf127..0000000000 --- a/internal/storage/cache/mocks_test.go +++ /dev/null @@ -1,208 +0,0 @@ -package cache - -import ( - "context" - - "go.flipt.io/flipt/internal/cache" - "go.flipt.io/flipt/internal/storage" - "go.flipt.io/flipt/rpc/flipt" -) - -var _ storage.Store = &mockStore{} - -type mockStore struct { - EvaluationRules []*storage.EvaluationRule - Flags []flipt.Flag - ReturnErr error -} - -func (s *mockStore) String() string { - return "mockStore" -} - -func (s *mockStore) GetEvaluationRules(ctx context.Context, namespaceKey, flagKey string) ([]*storage.EvaluationRule, error) { - if s.ReturnErr != nil { - return nil, s.ReturnErr - } - - return s.EvaluationRules, nil -} - -func (s *mockStore) GetEvaluationDistributions(ctx context.Context, ruleID string) ([]*storage.EvaluationDistribution, error) { - return nil, nil -} - -func (s *mockStore) GetNamespace(ctx context.Context, key string) (*flipt.Namespace, error) { - return nil, nil -} - -func (s *mockStore) ListNamespaces(ctx context.Context, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Namespace], error) { - return storage.ResultSet[*flipt.Namespace]{}, nil -} - -func (s *mockStore) CountNamespaces(ctx context.Context) (uint64, error) { - return 0, nil -} - -func (s *mockStore) CreateNamespace(ctx context.Context, r *flipt.CreateNamespaceRequest) (*flipt.Namespace, error) { - return nil, nil -} - -func (s *mockStore) UpdateNamespace(ctx context.Context, r *flipt.UpdateNamespaceRequest) (*flipt.Namespace, error) { - return nil, nil -} - -func (s *mockStore) DeleteNamespace(ctx context.Context, r *flipt.DeleteNamespaceRequest) error { - return nil -} - -func (s *mockStore) GetFlag(ctx context.Context, namespaceKey, key string) (*flipt.Flag, error) { - return nil, nil -} - -func (s *mockStore) ListFlags(ctx context.Context, namespaceKey string, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Flag], error) { - return storage.ResultSet[*flipt.Flag]{}, nil -} - -func (s *mockStore) CountFlags(ctx context.Context, namespaceKey string) (uint64, error) { - return 0, nil -} - -func (s *mockStore) CreateFlag(ctx context.Context, r *flipt.CreateFlagRequest) (*flipt.Flag, error) { - return nil, nil -} - -func (s *mockStore) UpdateFlag(ctx context.Context, r *flipt.UpdateFlagRequest) (*flipt.Flag, error) { - return nil, nil -} - -func (s *mockStore) DeleteFlag(ctx context.Context, r *flipt.DeleteFlagRequest) error { - return nil -} - -func (s *mockStore) CreateVariant(ctx context.Context, r *flipt.CreateVariantRequest) (*flipt.Variant, error) { - return nil, nil -} - -func (s *mockStore) UpdateVariant(ctx context.Context, r *flipt.UpdateVariantRequest) (*flipt.Variant, error) { - return nil, nil -} - -func (s *mockStore) DeleteVariant(ctx context.Context, r *flipt.DeleteVariantRequest) error { - return nil -} - -func (s *mockStore) GetSegment(ctx context.Context, namespaceKey, key string) (*flipt.Segment, error) { - return nil, nil -} - -func (s *mockStore) ListSegments(ctx context.Context, namespaceKey string, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Segment], error) { - return storage.ResultSet[*flipt.Segment]{}, nil -} - -func (s *mockStore) CountSegments(ctx context.Context, namespaceKey string) (uint64, error) { - return 0, nil -} - -func (s *mockStore) CreateSegment(ctx context.Context, r *flipt.CreateSegmentRequest) (*flipt.Segment, error) { - return nil, nil -} - -func (s *mockStore) UpdateSegment(ctx context.Context, r *flipt.UpdateSegmentRequest) (*flipt.Segment, error) { - return nil, nil -} - -func (s *mockStore) DeleteSegment(ctx context.Context, r *flipt.DeleteSegmentRequest) error { - return nil -} - -func (s *mockStore) CreateConstraint(ctx context.Context, r *flipt.CreateConstraintRequest) (*flipt.Constraint, error) { - return nil, nil -} - -func (s *mockStore) UpdateConstraint(ctx context.Context, r *flipt.UpdateConstraintRequest) (*flipt.Constraint, error) { - return nil, nil -} - -func (s *mockStore) DeleteConstraint(ctx context.Context, r *flipt.DeleteConstraintRequest) error { - return nil -} - -func (s *mockStore) GetRule(ctx context.Context, namespaceKey, id string) (*flipt.Rule, error) { - return nil, nil -} - -func (s *mockStore) ListRules(ctx context.Context, namespaceKey, flagKey string, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Rule], error) { - return storage.ResultSet[*flipt.Rule]{}, nil -} - -func (s *mockStore) CountRules(ctx context.Context, namespaceKey, flagKey string) (uint64, error) { - return 0, nil -} - -func (s *mockStore) CreateRule(ctx context.Context, r *flipt.CreateRuleRequest) (*flipt.Rule, error) { - return nil, nil -} - -func (s *mockStore) UpdateRule(ctx context.Context, r *flipt.UpdateRuleRequest) (*flipt.Rule, error) { - return nil, nil -} - -func (s *mockStore) DeleteRule(ctx context.Context, r *flipt.DeleteRuleRequest) error { - return nil -} - -func (s *mockStore) OrderRules(ctx context.Context, r *flipt.OrderRulesRequest) error { - return nil -} - -func (s *mockStore) CreateDistribution(ctx context.Context, r *flipt.CreateDistributionRequest) (*flipt.Distribution, error) { - return nil, nil -} - -func (s *mockStore) UpdateDistribution(ctx context.Context, r *flipt.UpdateDistributionRequest) (*flipt.Distribution, error) { - return nil, nil -} - -func (s *mockStore) DeleteDistribution(ctx context.Context, r *flipt.DeleteDistributionRequest) error { - return nil -} - -var _ cache.Cacher = &mockCacher{} - -type mockCacher struct { - Cached bool - CachedValue []byte - CacheKey string - GetErr error - SetErr error -} - -func (c *mockCacher) String() string { - return "mockCacher" -} - -func (c *mockCacher) Get(ctx context.Context, key string) ([]byte, bool, error) { - c.CacheKey = key - - if c.GetErr != nil || !c.Cached { - return nil, c.Cached, c.GetErr - } - - return c.CachedValue, true, nil -} - -func (c *mockCacher) Set(ctx context.Context, key string, value []byte) error { - c.CacheKey = key - c.CachedValue = value - - if c.SetErr != nil { - return c.SetErr - } - - return nil -} - -func (c *mockCacher) Delete(ctx context.Context, key string) error { - return nil -} diff --git a/internal/storage/cache/support_test.go b/internal/storage/cache/support_test.go new file mode 100644 index 0000000000..2c2fbe03f8 --- /dev/null +++ b/internal/storage/cache/support_test.go @@ -0,0 +1,279 @@ +package cache + +import ( + "context" + + "github.com/stretchr/testify/mock" + "go.flipt.io/flipt/internal/cache" + "go.flipt.io/flipt/internal/storage" + "go.flipt.io/flipt/rpc/flipt" +) + +var _ storage.Store = &storeMock{} + +type storeMock struct { + mock.Mock +} + +func (m *storeMock) String() string { + return "mock" +} + +func (m *storeMock) GetNamespace(ctx context.Context, key string) (*flipt.Namespace, error) { + args := m.Called(ctx, key) + return args.Get(0).(*flipt.Namespace), args.Error(1) +} + +func (m *storeMock) ListNamespaces(ctx context.Context, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Namespace], error) { + args := m.Called(ctx, opts) + return args.Get(0).(storage.ResultSet[*flipt.Namespace]), args.Error(1) +} + +func (m *storeMock) CountNamespaces(ctx context.Context) (uint64, error) { + args := m.Called(ctx) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *storeMock) CreateNamespace(ctx context.Context, r *flipt.CreateNamespaceRequest) (*flipt.Namespace, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Namespace), args.Error(1) +} + +func (m *storeMock) UpdateNamespace(ctx context.Context, r *flipt.UpdateNamespaceRequest) (*flipt.Namespace, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Namespace), args.Error(1) +} + +func (m *storeMock) DeleteNamespace(ctx context.Context, r *flipt.DeleteNamespaceRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) GetFlag(ctx context.Context, namespaceKey string, key string) (*flipt.Flag, error) { + args := m.Called(ctx, namespaceKey, key) + return args.Get(0).(*flipt.Flag), args.Error(1) +} + +func (m *storeMock) ListFlags(ctx context.Context, namespaceKey string, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Flag], error) { + args := m.Called(ctx, namespaceKey, opts) + return args.Get(0).(storage.ResultSet[*flipt.Flag]), args.Error(1) +} + +func (m *storeMock) CountFlags(ctx context.Context, namespaceKey string) (uint64, error) { + args := m.Called(ctx, namespaceKey) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *storeMock) CreateFlag(ctx context.Context, r *flipt.CreateFlagRequest) (*flipt.Flag, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Flag), args.Error(1) +} + +func (m *storeMock) UpdateFlag(ctx context.Context, r *flipt.UpdateFlagRequest) (*flipt.Flag, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Flag), args.Error(1) +} + +func (m *storeMock) DeleteFlag(ctx context.Context, r *flipt.DeleteFlagRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) CreateVariant(ctx context.Context, r *flipt.CreateVariantRequest) (*flipt.Variant, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Variant), args.Error(1) +} + +func (m *storeMock) UpdateVariant(ctx context.Context, r *flipt.UpdateVariantRequest) (*flipt.Variant, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Variant), args.Error(1) +} + +func (m *storeMock) DeleteVariant(ctx context.Context, r *flipt.DeleteVariantRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) GetSegment(ctx context.Context, namespaceKey string, key string) (*flipt.Segment, error) { + args := m.Called(ctx, namespaceKey, key) + return args.Get(0).(*flipt.Segment), args.Error(1) +} + +func (m *storeMock) ListSegments(ctx context.Context, namespaceKey string, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Segment], error) { + args := m.Called(ctx, namespaceKey, opts) + return args.Get(0).(storage.ResultSet[*flipt.Segment]), args.Error(1) +} + +func (m *storeMock) CountSegments(ctx context.Context, namespaceKey string) (uint64, error) { + args := m.Called(ctx, namespaceKey) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *storeMock) CreateSegment(ctx context.Context, r *flipt.CreateSegmentRequest) (*flipt.Segment, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Segment), args.Error(1) +} + +func (m *storeMock) UpdateSegment(ctx context.Context, r *flipt.UpdateSegmentRequest) (*flipt.Segment, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Segment), args.Error(1) +} + +func (m *storeMock) DeleteSegment(ctx context.Context, r *flipt.DeleteSegmentRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) CreateConstraint(ctx context.Context, r *flipt.CreateConstraintRequest) (*flipt.Constraint, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Constraint), args.Error(1) +} + +func (m *storeMock) UpdateConstraint(ctx context.Context, r *flipt.UpdateConstraintRequest) (*flipt.Constraint, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Constraint), args.Error(1) +} + +func (m *storeMock) DeleteConstraint(ctx context.Context, r *flipt.DeleteConstraintRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) ListRollouts(ctx context.Context, namespaceKey string, flagKey string, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Rollout], error) { + args := m.Called(ctx, namespaceKey, flagKey, opts) + return args.Get(0).(storage.ResultSet[*flipt.Rollout]), args.Error(1) +} + +func (m *storeMock) CountRollouts(ctx context.Context, namespaceKey string, flagKey string) (uint64, error) { + args := m.Called(ctx, namespaceKey, flagKey) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *storeMock) GetRollout(ctx context.Context, namespaceKey string, key string) (*flipt.Rollout, error) { + args := m.Called(ctx, namespaceKey, key) + return args.Get(0).(*flipt.Rollout), args.Error(1) +} + +func (m *storeMock) CreateRollout(ctx context.Context, r *flipt.CreateRolloutRequest) (*flipt.Rollout, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Rollout), args.Error(1) +} + +func (m *storeMock) UpdateRollout(ctx context.Context, r *flipt.UpdateRolloutRequest) (*flipt.Rollout, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Rollout), args.Error(1) +} + +func (m *storeMock) DeleteRollout(ctx context.Context, r *flipt.DeleteRolloutRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) OrderRollouts(ctx context.Context, r *flipt.OrderRolloutsRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) GetRule(ctx context.Context, namespaceKey string, id string) (*flipt.Rule, error) { + args := m.Called(ctx, namespaceKey, id) + return args.Get(0).(*flipt.Rule), args.Error(1) +} + +func (m *storeMock) ListRules(ctx context.Context, namespaceKey string, flagKey string, opts ...storage.QueryOption) (storage.ResultSet[*flipt.Rule], error) { + args := m.Called(ctx, namespaceKey, flagKey, opts) + return args.Get(0).(storage.ResultSet[*flipt.Rule]), args.Error(1) +} + +func (m *storeMock) CountRules(ctx context.Context, namespaceKey, flagKey string) (uint64, error) { + args := m.Called(ctx, namespaceKey) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *storeMock) CreateRule(ctx context.Context, r *flipt.CreateRuleRequest) (*flipt.Rule, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Rule), args.Error(1) +} + +func (m *storeMock) UpdateRule(ctx context.Context, r *flipt.UpdateRuleRequest) (*flipt.Rule, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Rule), args.Error(1) +} + +func (m *storeMock) DeleteRule(ctx context.Context, r *flipt.DeleteRuleRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) OrderRules(ctx context.Context, r *flipt.OrderRulesRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) CreateDistribution(ctx context.Context, r *flipt.CreateDistributionRequest) (*flipt.Distribution, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Distribution), args.Error(1) +} + +func (m *storeMock) UpdateDistribution(ctx context.Context, r *flipt.UpdateDistributionRequest) (*flipt.Distribution, error) { + args := m.Called(ctx, r) + return args.Get(0).(*flipt.Distribution), args.Error(1) +} + +func (m *storeMock) DeleteDistribution(ctx context.Context, r *flipt.DeleteDistributionRequest) error { + args := m.Called(ctx, r) + return args.Error(0) +} + +func (m *storeMock) GetEvaluationRules(ctx context.Context, namespaceKey string, flagKey string) ([]*storage.EvaluationRule, error) { + args := m.Called(ctx, namespaceKey, flagKey) + return args.Get(0).([]*storage.EvaluationRule), args.Error(1) +} + +func (m *storeMock) GetEvaluationDistributions(ctx context.Context, ruleID string) ([]*storage.EvaluationDistribution, error) { + args := m.Called(ctx, ruleID) + return args.Get(0).([]*storage.EvaluationDistribution), args.Error(1) +} + +func (m *storeMock) GetEvaluationRollouts(ctx context.Context, namespaceKey, flagKey string) ([]*storage.EvaluationRollout, error) { + args := m.Called(ctx, namespaceKey, flagKey) + return args.Get(0).([]*storage.EvaluationRollout), args.Error(1) +} + +var _ cache.Cacher = &cacheSpy{} + +type cacheSpy struct { + cached bool + cachedValue []byte + cacheKey string + getErr error + setErr error +} + +func (c *cacheSpy) String() string { + return "mockCacher" +} + +func (c *cacheSpy) Get(ctx context.Context, key string) ([]byte, bool, error) { + c.cacheKey = key + + if c.getErr != nil || !c.cached { + return nil, c.cached, c.getErr + } + + return c.cachedValue, true, nil +} + +func (c *cacheSpy) Set(ctx context.Context, key string, value []byte) error { + c.cacheKey = key + c.cachedValue = value + + if c.setErr != nil { + return c.setErr + } + + return nil +} + +func (c *cacheSpy) Delete(ctx context.Context, key string) error { + return nil +}