diff --git a/internal/cache/gache/gache.go b/internal/cache/gache/gache.go index a242c15058..28d2cf9921 100644 --- a/internal/cache/gache/gache.go +++ b/internal/cache/gache/gache.go @@ -31,6 +31,7 @@ type cache struct { expiredHook func(context.Context, string) } +// New loads a cache model and returns a new cache struct. func New(opts ...Option) (c *cache) { c = new(cache) for _, opt := range append(defaultOptions(), opts...) { @@ -45,19 +46,28 @@ func New(opts ...Option) (c *cache) { return c } +// Start calls StartExpired func of c.gache. func (c *cache) Start(ctx context.Context) { c.gache.StartExpired(ctx, c.expireCheckDur) } + +// Get calls StartExpired func of c.gache and returns (interface{}, bool) according to key. func (c *cache) Get(key string) (interface{}, bool) { return c.gache.Get(key) } + +// Set calls Set func of c.gache. func (c *cache) Set(key string, val interface{}) { c.gache.Set(key, val) } + +// Delete calls Delete func of c.gache. func (c *cache) Delete(key string) { c.gache.Delete(key) } +// GetAndDelete returns (interface{}, bool) and delete value according to key when value of key is set. +// When value of key is not set, returns (nil, false). func (c *cache) GetAndDelete(key string) (interface{}, bool) { v, ok := c.gache.Get(key) if !ok { diff --git a/internal/cache/gache/gache_test.go b/internal/cache/gache/gache_test.go index 283fcf9681..e797a0a080 100644 --- a/internal/cache/gache/gache_test.go +++ b/internal/cache/gache/gache_test.go @@ -23,8 +23,17 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp" "github.com/kpango/gache" "github.com/vdaas/vald/internal/errors" + "go.uber.org/goleak" +) + +var ( + // Goroutine leak is detected by `fastime`, but it should be ignored in the test because it is an external package. + goleakIgnoreOptions = []goleak.Option{ + goleak.IgnoreTopFunction("github.com/kpango/fastime.(*Fastime).StartTimerD.func1"), + } ) func TestNew(t *testing.T) { @@ -43,41 +52,62 @@ func TestNew(t *testing.T) { afterFunc func(args) } defaultCheckFunc := func(w want, gotC *cache) error { - if !reflect.DeepEqual(gotC, w.wantC) { + opts := []cmp.Option{ + cmp.AllowUnexported(*w.wantC), + cmp.AllowUnexported(*gotC), + cmp.Comparer(func(want, got gache.Gache) bool { + return want != nil && got != nil + }), + cmp.Comparer(func(want, got func(context.Context, string)) bool { + return reflect.ValueOf(want).Pointer() == reflect.ValueOf(got).Pointer() + }), + } + if diff := cmp.Diff(w.wantC, gotC, opts...); diff != "" { return errors.Errorf("got = %v, want %v", gotC, w.wantC) } return nil } tests := []test{ - // TODO test cases - /* - { - name: "test_case_1", - args: args { - opts: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - }, - */ - - // TODO test cases - /* - func() test { - return test { - name: "test_case_2", - args: args { - opts: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - } - }(), - */ + func() test { + c := new(cache) + for _, opt := range defaultOptions() { + opt(c) + } + c.gache.SetDefaultExpire(c.expireDur) + return test{ + name: "set success when opts is nil", + want: want{ + wantC: c, + }, + } + }(), + func() test { + expiredHook := func(context.Context, string) {} + c := new(cache) + for _, opt := range append(defaultOptions(), WithExpiredHook(expiredHook)) { + opt(c) + } + c.gache.SetDefaultExpire(c.expireDur) + if c.expiredHook != nil { + c.gache = c.gache.SetExpiredHook(c.expiredHook).EnableExpiredHook() + } + return test{ + name: "set success when opts is not nil", + args: args{ + opts: []Option{ + WithExpiredHook(expiredHook), + }, + }, + want: want{ + wantC: c, + }, + } + }(), } for _, test := range tests { t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(tt, goleakIgnoreOptions...) if test.beforeFunc != nil { test.beforeFunc(test.args) } @@ -87,12 +117,10 @@ func TestNew(t *testing.T) { if test.checkFunc == nil { test.checkFunc = defaultCheckFunc } - gotC := New(test.args.opts...) if err := test.checkFunc(test.want, gotC); err != nil { tt.Errorf("error = %v", err) } - }) } } @@ -122,47 +150,27 @@ func Test_cache_Start(t *testing.T) { return nil } tests := []test{ - // TODO test cases - /* - { - name: "test_case_1", - args: args { - ctx: nil, - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - }, - */ - - // TODO test cases - /* - func() test { - return test { - name: "test_case_2", - args: args { - ctx: nil, - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - } - }(), - */ + { + name: "Call Start", + args: args{ + ctx: func() context.Context { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + return ctx + }(), + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + }, } for _, test := range tests { t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(tt, goleakIgnoreOptions...) if test.beforeFunc != nil { test.beforeFunc(test.args) } @@ -178,7 +186,6 @@ func Test_cache_Start(t *testing.T) { expireCheckDur: test.fields.expireCheckDur, expiredHook: test.fields.expiredHook, } - c.Start(test.args.ctx) if err := test.checkFunc(test.want); err != nil { tt.Errorf("error = %v", err) @@ -207,7 +214,7 @@ func Test_cache_Get(t *testing.T) { fields fields want want checkFunc func(want, interface{}, bool) error - beforeFunc func(args) + beforeFunc func(args, *cache) afterFunc func(args) } defaultCheckFunc := func(w want, got interface{}, got1 bool) error { @@ -220,49 +227,54 @@ func Test_cache_Get(t *testing.T) { return nil } tests := []test{ - // TODO test cases - /* - { - name: "test_case_1", - args: args { - key: "", - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - }, - */ - - // TODO test cases - /* - func() test { - return test { - name: "test_case_2", - args: args { - key: "", - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - } - }(), - */ + { + name: "Call Get when gache is empty", + args: args{ + key: "vdaas", + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + want: want{ + want: nil, + want1: false, + }, + }, + { + name: "Call Get when gache is not empty", + args: args{ + key: "vdaas", + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + want: want{ + want: "vald", + want1: true, + }, + beforeFunc: func(args args, c *cache) { + c.Set(args.key, "vald") + }, + }, } for _, test := range tests { t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(tt, goleakIgnoreOptions...) + c := &cache{ + gache: test.fields.gache, + expireDur: test.fields.expireDur, + expireCheckDur: test.fields.expireCheckDur, + expiredHook: test.fields.expiredHook, + } if test.beforeFunc != nil { - test.beforeFunc(test.args) + test.beforeFunc(test.args, c) } if test.afterFunc != nil { defer test.afterFunc(test.args) @@ -270,18 +282,10 @@ func Test_cache_Get(t *testing.T) { if test.checkFunc == nil { test.checkFunc = defaultCheckFunc } - c := &cache{ - gache: test.fields.gache, - expireDur: test.fields.expireDur, - expireCheckDur: test.fields.expireCheckDur, - expiredHook: test.fields.expiredHook, - } - got, got1 := c.Get(test.args.key) if err := test.checkFunc(test.want, got, got1); err != nil { tt.Errorf("error = %v", err) } - }) } } @@ -298,63 +302,53 @@ func Test_cache_Set(t *testing.T) { expiredHook func(context.Context, string) } type want struct { + key string + want interface{} + want1 bool } type test struct { name string args args fields fields want want - checkFunc func(want) error + checkFunc func(want, *cache) error beforeFunc func(args) afterFunc func(args) } - defaultCheckFunc := func(w want) error { + defaultCheckFunc := func(w want, c *cache) error { + got, got1 := c.Get(w.key) + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want = %v", got, w.want) + } + if !reflect.DeepEqual(got1, w.want1) { + return errors.Errorf("got = %v, want = %v", got1, w.want1) + } return nil } tests := []test{ - // TODO test cases - /* - { - name: "test_case_1", - args: args { - key: "", - val: nil, - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - }, - */ - - // TODO test cases - /* - func() test { - return test { - name: "test_case_2", - args: args { - key: "", - val: nil, - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - } - }(), - */ + { + name: "Call Set", + args: args{ + key: "vdaas", + val: "vald", + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + want: want{ + key: "vdaas", + want: "vald", + want1: true, + }, + }, } for _, test := range tests { t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(tt, goleakIgnoreOptions...) if test.beforeFunc != nil { test.beforeFunc(test.args) } @@ -372,7 +366,7 @@ func Test_cache_Set(t *testing.T) { } c.Set(test.args.key, test.args.val) - if err := test.checkFunc(test.want); err != nil { + if err := test.checkFunc(test.want, c); err != nil { tt.Errorf("error = %v", err) } }) @@ -390,63 +384,80 @@ func Test_cache_Delete(t *testing.T) { expiredHook func(context.Context, string) } type want struct { + key string + want interface{} + want1 bool } type test struct { name string args args fields fields want want - checkFunc func(want) error - beforeFunc func(args) + checkFunc func(want, *cache) error + beforeFunc func(args, *cache) afterFunc func(args) } - defaultCheckFunc := func(w want) error { + defaultCheckFunc := func(w want, c *cache) error { + got, got1 := c.Get(w.key) + if !reflect.DeepEqual(got, w.want) { + return errors.Errorf("got = %v, want = %v", got, w.want) + } + if !reflect.DeepEqual(got1, w.want1) { + return errors.Errorf("got = %v, want = %v", got1, w.want1) + } return nil } tests := []test{ - // TODO test cases - /* - { - name: "test_case_1", - args: args { - key: "", - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - }, - */ - - // TODO test cases - /* - func() test { - return test { - name: "test_case_2", - args: args { - key: "", - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - } - }(), - */ + { + name: "Call Delete when gache is empty", + args: args{ + key: "vdaas", + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + want: want{ + key: "vdaas", + want: nil, + want1: false, + }, + }, + { + name: "Call Delete when gache is not empty", + args: args{ + key: "vdaas", + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + want: want{ + key: "vdaas", + want: nil, + want1: false, + }, + beforeFunc: func(args args, c *cache) { + c.Set(args.key, "vald") + }, + }, } for _, test := range tests { t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(tt, goleakIgnoreOptions...) + c := &cache{ + gache: test.fields.gache, + expireDur: test.fields.expireDur, + expireCheckDur: test.fields.expireCheckDur, + expiredHook: test.fields.expiredHook, + } if test.beforeFunc != nil { - test.beforeFunc(test.args) + test.beforeFunc(test.args, c) } if test.afterFunc != nil { defer test.afterFunc(test.args) @@ -454,15 +465,9 @@ func Test_cache_Delete(t *testing.T) { if test.checkFunc == nil { test.checkFunc = defaultCheckFunc } - c := &cache{ - gache: test.fields.gache, - expireDur: test.fields.expireDur, - expireCheckDur: test.fields.expireCheckDur, - expiredHook: test.fields.expiredHook, - } c.Delete(test.args.key) - if err := test.checkFunc(test.want); err != nil { + if err := test.checkFunc(test.want, c); err != nil { tt.Errorf("error = %v", err) } }) @@ -489,7 +494,7 @@ func Test_cache_GetAndDelete(t *testing.T) { fields fields want want checkFunc func(want, interface{}, bool) error - beforeFunc func(args) + beforeFunc func(args, *cache) afterFunc func(args) } defaultCheckFunc := func(w want, got interface{}, got1 bool) error { @@ -502,49 +507,54 @@ func Test_cache_GetAndDelete(t *testing.T) { return nil } tests := []test{ - // TODO test cases - /* - { - name: "test_case_1", - args: args { - key: "", - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - }, - */ - - // TODO test cases - /* - func() test { - return test { - name: "test_case_2", - args: args { - key: "", - }, - fields: fields { - gache: nil, - expireDur: nil, - expireCheckDur: nil, - expiredHook: nil, - }, - want: want{}, - checkFunc: defaultCheckFunc, - } - }(), - */ + { + name: "Call GetAndDelete when gache is empty", + args: args{ + key: "vdaas", + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + want: want{ + want: nil, + want1: false, + }, + }, + { + name: "Call GetAndDelete when gache is not empty", + args: args{ + key: "vdaas", + }, + fields: fields{ + gache: gache.New(), + expireDur: 1 * time.Second, + expireCheckDur: 1 * time.Second, + expiredHook: nil, + }, + want: want{ + want: "vald", + want1: true, + }, + beforeFunc: func(args args, c *cache) { + c.Set(args.key, "vald") + }, + }, } for _, test := range tests { t.Run(test.name, func(tt *testing.T) { + defer goleak.VerifyNone(tt, goleakIgnoreOptions...) + c := &cache{ + gache: test.fields.gache, + expireDur: test.fields.expireDur, + expireCheckDur: test.fields.expireCheckDur, + expiredHook: test.fields.expiredHook, + } if test.beforeFunc != nil { - test.beforeFunc(test.args) + test.beforeFunc(test.args, c) } if test.afterFunc != nil { defer test.afterFunc(test.args) @@ -552,12 +562,6 @@ func Test_cache_GetAndDelete(t *testing.T) { if test.checkFunc == nil { test.checkFunc = defaultCheckFunc } - c := &cache{ - gache: test.fields.gache, - expireDur: test.fields.expireDur, - expireCheckDur: test.fields.expireCheckDur, - expiredHook: test.fields.expiredHook, - } got, got1 := c.GetAndDelete(test.args.key) if err := test.checkFunc(test.want, got, got1); err != nil { diff --git a/internal/cache/gache/option_test.go b/internal/cache/gache/option_test.go index 9bd6355ad9..b5e7787892 100644 --- a/internal/cache/gache/option_test.go +++ b/internal/cache/gache/option_test.go @@ -30,13 +30,6 @@ import ( "go.uber.org/goleak" ) -var ( - // Goroutine leak is detected by `fastime`, but it should be ignored in the test because it is an external package. - goleakIgnoreOptions = []goleak.Option{ - goleak.IgnoreTopFunction("github.com/kpango/fastime.(*Fastime).StartTimerD.func1"), - } -) - func TestDefaultOptions(t *testing.T) { type args struct{} type want struct {