| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. |
| 4 |
| 5 package memcache |
| 6 |
| 7 import ( |
| 8 "math/rand" |
| 9 "testing" |
| 10 "time" |
| 11 |
| 12 "github.com/luci/luci-go/common/clock/testclock" |
| 13 memconfig "github.com/luci/luci-go/common/config/impl/memory" |
| 14 "github.com/luci/luci-go/common/errors" |
| 15 "github.com/luci/luci-go/luci_config/server/cfgclient" |
| 16 "github.com/luci/luci-go/luci_config/server/cfgclient/backend" |
| 17 "github.com/luci/luci-go/luci_config/server/cfgclient/backend/caching" |
| 18 "github.com/luci/luci-go/luci_config/server/cfgclient/backend/client" |
| 19 "github.com/luci/luci-go/luci_config/server/cfgclient/backend/testconfig
" |
| 20 |
| 21 "github.com/luci/gae/filter/featureBreaker" |
| 22 "github.com/luci/gae/impl/memory" |
| 23 mc "github.com/luci/gae/service/memcache" |
| 24 |
| 25 "golang.org/x/net/context" |
| 26 |
| 27 . "github.com/smartystreets/goconvey/convey" |
| 28 ) |
| 29 |
| 30 func TestMemcache(t *testing.T) { |
| 31 t.Parallel() |
| 32 |
| 33 Convey("Test cache", t, func() { |
| 34 c := context.Background() |
| 35 c = memory.Use(c) |
| 36 |
| 37 c, clk := testclock.UseTime(c, testclock.TestTimeUTC) |
| 38 _ = clk |
| 39 |
| 40 c, mcFB := featureBreaker.FilterMC(c, nil) |
| 41 |
| 42 getMCStats := func(c context.Context) *mc.Statistics { |
| 43 st, err := mc.Stats(c) |
| 44 if err != nil { |
| 45 panic(err) |
| 46 } |
| 47 return st |
| 48 } |
| 49 |
| 50 configDB := map[string]memconfig.ConfigSet{ |
| 51 "projects/foo": { |
| 52 "test.cfg": "foo", |
| 53 }, |
| 54 } |
| 55 |
| 56 var be backend.B |
| 57 be = &client.Backend{ |
| 58 Provider: &testconfig.Provider{ |
| 59 Base: memconfig.New(configDB), |
| 60 }, |
| 61 } |
| 62 be = Backend(be, time.Minute) |
| 63 c = backend.WithBackend(c, be) |
| 64 |
| 65 Convey(`Pulling items from memcache`, func() { |
| 66 var content string |
| 67 |
| 68 Convey(`Should be able to fetch a config as service`, fu
nc() { |
| 69 So(cfgclient.Get(c, cfgclient.AsService, "projec
ts/foo", "test.cfg", cfgclient.String(&content), nil), ShouldBeNil) |
| 70 So(content, ShouldEqual, "foo") |
| 71 So(getMCStats(c).Misses, ShouldEqual, 1) |
| 72 So(getMCStats(c).Hits, ShouldEqual, 0) |
| 73 So(getMCStats(c).Items, ShouldEqual, 1) |
| 74 |
| 75 // A second fetch hits memcache. |
| 76 So(cfgclient.Get(c, cfgclient.AsService, "projec
ts/foo", "test.cfg", cfgclient.String(&content), nil), ShouldBeNil) |
| 77 So(content, ShouldEqual, "foo") |
| 78 So(getMCStats(c).Misses, ShouldEqual, 1) |
| 79 So(getMCStats(c).Hits, ShouldEqual, 1) |
| 80 So(getMCStats(c).Items, ShouldEqual, 1) |
| 81 |
| 82 // Memcache expires, full reload. |
| 83 clk.Add(time.Minute) |
| 84 |
| 85 So(cfgclient.Get(c, cfgclient.AsService, "projec
ts/foo", "test.cfg", cfgclient.String(&content), nil), ShouldBeNil) |
| 86 So(content, ShouldEqual, "foo") |
| 87 So(getMCStats(c).Misses, ShouldEqual, 2) |
| 88 So(getMCStats(c).Hits, ShouldEqual, 1) |
| 89 So(getMCStats(c).Items, ShouldEqual, 1) |
| 90 }) |
| 91 |
| 92 Convey(`When memcache is broken`, func() { |
| 93 testErr := errors.New("test error") |
| 94 mcFB.BreakFeatures(testErr, "GetMulti") |
| 95 |
| 96 So(cfgclient.Get(c, cfgclient.AsService, "projec
ts/foo", "test.cfg", cfgclient.String(&content), nil), ShouldBeNil) |
| 97 So(content, ShouldEqual, "foo") |
| 98 So(getMCStats(c).Misses, ShouldEqual, 0) |
| 99 So(getMCStats(c).Hits, ShouldEqual, 0) |
| 100 So(getMCStats(c).Items, ShouldEqual, 0) |
| 101 }) |
| 102 |
| 103 Convey(`When a cached entry is corrupted`, func() { |
| 104 cacheKey := caching.Key{ |
| 105 Schema: caching.Schema, |
| 106 Op: caching.OpGet, |
| 107 ConfigSet: "projects/foo", |
| 108 Path: "test.cfg", |
| 109 Content: true, |
| 110 Authority: backend.AsService, |
| 111 } |
| 112 So(mc.Set(c, mc.NewItem(c, memcacheKey(&cacheKey
)).SetValue([]byte("!!! trash !!!"))), ShouldBeNil) |
| 113 So(cfgclient.Get(c, cfgclient.AsService, "projec
ts/foo", "test.cfg", cfgclient.String(&content), nil), ShouldBeNil) |
| 114 So(content, ShouldEqual, "foo") |
| 115 So(getMCStats(c).Misses, ShouldEqual, 0) |
| 116 So(getMCStats(c).Hits, ShouldEqual, 1) |
| 117 So(getMCStats(c).Items, ShouldEqual, 1) |
| 118 }) |
| 119 |
| 120 Convey(`Will skip the cache if an item is too large.`, f
unc() { |
| 121 // We need to use a pseudo-random string b/c we
compress it. |
| 122 buf := make([]byte, maxMemCacheSize*2) |
| 123 rng := rand.New(rand.NewSource(0)) |
| 124 _, _ = rng.Read(buf) |
| 125 |
| 126 orig := string(buf) |
| 127 configDB["projects/foo"]["test.cfg"] = orig |
| 128 |
| 129 So(cfgclient.Get(c, cfgclient.AsService, "projec
ts/foo", "test.cfg", cfgclient.String(&content), nil), ShouldBeNil) |
| 130 So(content, ShouldEqual, orig) |
| 131 So(getMCStats(c).Misses, ShouldEqual, 1) |
| 132 So(getMCStats(c).Hits, ShouldEqual, 0) |
| 133 So(getMCStats(c).Items, ShouldEqual, 0) |
| 134 }) |
| 135 }) |
| 136 }) |
| 137 } |
| OLD | NEW |