| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package memory | 5 package memory |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "testing" | 8 "testing" |
| 9 "time" | 9 "time" |
| 10 | 10 |
| 11 mcS "github.com/luci/gae/service/memcache" | 11 mcS "github.com/luci/gae/service/memcache" |
| 12 "github.com/luci/luci-go/common/clock/testclock" | 12 "github.com/luci/luci-go/common/clock/testclock" |
| 13 . "github.com/smartystreets/goconvey/convey" | 13 . "github.com/smartystreets/goconvey/convey" |
| 14 "golang.org/x/net/context" | 14 "golang.org/x/net/context" |
| 15 ) | 15 ) |
| 16 | 16 |
| 17 func TestMemcache(t *testing.T) { | 17 func TestMemcache(t *testing.T) { |
| 18 t.Parallel() | 18 t.Parallel() |
| 19 | 19 |
| 20 Convey("memcache", t, func() { | 20 Convey("memcache", t, func() { |
| 21 now := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) | 21 now := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) |
| 22 c, tc := testclock.UseTime(context.Background(), now) | 22 c, tc := testclock.UseTime(context.Background(), now) |
| 23 c = Use(c) | 23 c = Use(c) |
| 24 mc := mcS.Get(c) | 24 mc := mcS.Get(c) |
| 25 | 25 |
| 26 Convey("implements MCSingleReadWriter", func() { | 26 Convey("implements MCSingleReadWriter", func() { |
| 27 Convey("Add", func() { | 27 Convey("Add", func() { |
| 28 » » » » itm := &mcItem{ | 28 » » » » itm := (mc.NewItem("sup"). |
| 29 » » » » » key: "sup", | 29 » » » » » SetValue([]byte("cool")). |
| 30 » » » » » value: []byte("cool"), | 30 » » » » » SetExpiration(time.Second)) |
| 31 » » » » » expiration: time.Second, | 31 » » » » So(mc.Add(itm), ShouldBeNil) |
| 32 » » » » } | |
| 33 » » » » err := mc.Add(itm) | |
| 34 » » » » So(err, ShouldBeNil) | |
| 35 Convey("which rejects objects already there", fu
nc() { | 32 Convey("which rejects objects already there", fu
nc() { |
| 36 » » » » » err := mc.Add(itm) | 33 » » » » » So(mc.Add(itm), ShouldEqual, mcS.ErrNotS
tored) |
| 37 » » » » » So(err, ShouldEqual, mcS.ErrNotStored) | |
| 38 }) | 34 }) |
| 39 }) | 35 }) |
| 40 | 36 |
| 41 Convey("Get", func() { | 37 Convey("Get", func() { |
| 42 itm := &mcItem{ | 38 itm := &mcItem{ |
| 43 key: "sup", | 39 key: "sup", |
| 44 value: []byte("cool"), | 40 value: []byte("cool"), |
| 45 expiration: time.Second, | 41 expiration: time.Second, |
| 46 } | 42 } |
| 47 » » » » err := mc.Add(itm) | 43 » » » » So(mc.Add(itm), ShouldBeNil) |
| 48 » » » » So(err, ShouldBeNil) | |
| 49 | 44 |
| 50 testItem := &mcItem{ | 45 testItem := &mcItem{ |
| 51 key: "sup", | 46 key: "sup", |
| 52 value: []byte("cool"), | 47 value: []byte("cool"), |
| 53 CasID: 1, | 48 CasID: 1, |
| 54 } | 49 } |
| 55 » » » » i, err := mc.Get("sup") | 50 » » » » getItm := &mcItem{ |
| 56 » » » » So(err, ShouldBeNil) | 51 » » » » » key: "sup", |
| 57 » » » » So(i, ShouldResemble, testItem) | 52 » » » » } |
| 53 » » » » So(mc.Get(getItm), ShouldBeNil) |
| 54 » » » » So(getItm, ShouldResemble, testItem) |
| 58 | 55 |
| 59 Convey("which can expire", func() { | 56 Convey("which can expire", func() { |
| 60 tc.Add(time.Second * 4) | 57 tc.Add(time.Second * 4) |
| 61 » » » » » i, err := mc.Get("sup") | 58 » » » » » getItm := &mcItem{key: "sup"} |
| 62 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) | 59 » » » » » So(mc.Get(getItm), ShouldEqual, mcS.ErrC
acheMiss) |
| 63 » » » » » So(i, ShouldBeNil) | 60 » » » » » So(getItm, ShouldResemble, &mcItem{key:
"sup"}) |
| 64 }) | 61 }) |
| 65 }) | 62 }) |
| 66 | 63 |
| 67 Convey("Delete", func() { | 64 Convey("Delete", func() { |
| 68 Convey("works if it's there", func() { | 65 Convey("works if it's there", func() { |
| 69 itm := &mcItem{ | 66 itm := &mcItem{ |
| 70 key: "sup", | 67 key: "sup", |
| 71 value: []byte("cool"), | 68 value: []byte("cool"), |
| 72 expiration: time.Second, | 69 expiration: time.Second, |
| 73 } | 70 } |
| 74 » » » » » err := mc.Add(itm) | 71 » » » » » So(mc.Add(itm), ShouldBeNil) |
| 75 » » » » » So(err, ShouldBeNil) | |
| 76 | 72 |
| 77 » » » » » err = mc.Delete("sup") | 73 » » » » » So(mc.Delete("sup"), ShouldBeNil) |
| 78 » » » » » So(err, ShouldBeNil) | |
| 79 | 74 |
| 80 » » » » » i, err := mc.Get("sup") | 75 » » » » » So(mc.Get(mc.NewItem("sup")), ShouldEqua
l, mcS.ErrCacheMiss) |
| 81 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) | |
| 82 » » » » » So(i, ShouldBeNil) | |
| 83 }) | 76 }) |
| 84 | 77 |
| 85 Convey("but not if it's not there", func() { | 78 Convey("but not if it's not there", func() { |
| 86 » » » » » err := mc.Delete("sup") | 79 » » » » » So(mc.Delete("sup"), ShouldEqual, mcS.Er
rCacheMiss) |
| 87 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) | |
| 88 }) | 80 }) |
| 89 }) | 81 }) |
| 90 | 82 |
| 91 Convey("Set", func() { | 83 Convey("Set", func() { |
| 92 itm := &mcItem{ | 84 itm := &mcItem{ |
| 93 key: "sup", | 85 key: "sup", |
| 94 value: []byte("cool"), | 86 value: []byte("cool"), |
| 95 expiration: time.Second, | 87 expiration: time.Second, |
| 96 } | 88 } |
| 97 » » » » err := mc.Add(itm) | 89 » » » » So(mc.Add(itm), ShouldBeNil) |
| 98 » » » » So(err, ShouldBeNil) | |
| 99 | 90 |
| 100 itm.SetValue([]byte("newp")) | 91 itm.SetValue([]byte("newp")) |
| 101 » » » » err = mc.Set(itm) | 92 » » » » So(mc.Set(itm), ShouldBeNil) |
| 102 » » » » So(err, ShouldBeNil) | |
| 103 | 93 |
| 104 testItem := &mcItem{ | 94 testItem := &mcItem{ |
| 105 key: "sup", | 95 key: "sup", |
| 106 value: []byte("newp"), | 96 value: []byte("newp"), |
| 107 CasID: 2, | 97 CasID: 2, |
| 108 } | 98 } |
| 109 » » » » i, err := mc.Get("sup") | 99 » » » » getItm := mc.NewItem("sup") |
| 100 » » » » So(mc.Get(getItm), ShouldBeNil) |
| 101 » » » » So(getItm, ShouldResemble, testItem) |
| 102 |
| 103 » » » » Convey("Flush works too", func() { |
| 104 » » » » » mc.Flush() |
| 105 » » » » » So(mc.Get(getItm), ShouldEqual, mcS.ErrC
acheMiss) |
| 106 » » » » }) |
| 107 » » » }) |
| 108 |
| 109 » » » Convey("Increment", func() { |
| 110 » » » » val, err := mc.Increment("num", 7, 2) |
| 110 So(err, ShouldBeNil) | 111 So(err, ShouldBeNil) |
| 111 » » » » So(i, ShouldResemble, testItem) | 112 » » » » So(val, ShouldEqual, 9) |
| 113 |
| 114 » » » » Convey("IncrementExisting", func() { |
| 115 » » » » » val, err := mc.IncrementExisting("num",
-2) |
| 116 » » » » » So(err, ShouldBeNil) |
| 117 » » » » » So(val, ShouldEqual, 7) |
| 118 |
| 119 » » » » » val, err = mc.IncrementExisting("num", -
100) |
| 120 » » » » » So(err, ShouldBeNil) |
| 121 » » » » » So(val, ShouldEqual, 0) |
| 122 |
| 123 » » » » » _, err = mc.IncrementExisting("noexist",
2) |
| 124 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) |
| 125 |
| 126 » » » » » So(mc.Set(mc.NewItem("text").SetValue([]
byte("hello world, hooman!"))), ShouldBeNil) |
| 127 |
| 128 » » » » » _, err = mc.IncrementExisting("text", 2) |
| 129 » » » » » So(err.Error(), ShouldContainSubstring,
"got invalid current value") |
| 130 » » » » }) |
| 112 }) | 131 }) |
| 113 | 132 |
| 114 Convey("CompareAndSwap", func() { | 133 Convey("CompareAndSwap", func() { |
| 115 itm := mcS.Item(&mcItem{ | 134 itm := mcS.Item(&mcItem{ |
| 116 key: "sup", | 135 key: "sup", |
| 117 value: []byte("cool"), | 136 value: []byte("cool"), |
| 118 expiration: time.Second * 2, | 137 expiration: time.Second * 2, |
| 119 }) | 138 }) |
| 120 » » » » err := mc.Add(itm) | 139 » » » » So(mc.Add(itm), ShouldBeNil) |
| 121 » » » » So(err, ShouldBeNil) | |
| 122 | 140 |
| 123 Convey("works after a Get", func() { | 141 Convey("works after a Get", func() { |
| 124 » » » » » itm, err = mc.Get("sup") | 142 » » » » » itm = mc.NewItem("sup") |
| 125 » » » » » So(err, ShouldBeNil) | 143 » » » » » So(mc.Get(itm), ShouldBeNil) |
| 126 So(itm.(*mcItem).CasID, ShouldEqual, 1) | 144 So(itm.(*mcItem).CasID, ShouldEqual, 1) |
| 127 | 145 |
| 128 itm.SetValue([]byte("newp")) | 146 itm.SetValue([]byte("newp")) |
| 129 » » » » » err = mc.CompareAndSwap(itm) | 147 » » » » » So(mc.CompareAndSwap(itm), ShouldBeNil) |
| 130 » » » » » So(err, ShouldBeNil) | |
| 131 }) | 148 }) |
| 132 | 149 |
| 133 Convey("but fails if you don't", func() { | 150 Convey("but fails if you don't", func() { |
| 134 itm.SetValue([]byte("newp")) | 151 itm.SetValue([]byte("newp")) |
| 135 » » » » » err = mc.CompareAndSwap(itm) | 152 » » » » » So(mc.CompareAndSwap(itm), ShouldEqual,
mcS.ErrCASConflict) |
| 136 » » » » » So(err, ShouldEqual, mcS.ErrCASConflict) | |
| 137 }) | 153 }) |
| 138 | 154 |
| 139 Convey("and fails if the item is expired/gone",
func() { | 155 Convey("and fails if the item is expired/gone",
func() { |
| 140 tc.Add(3 * time.Second) | 156 tc.Add(3 * time.Second) |
| 141 itm.SetValue([]byte("newp")) | 157 itm.SetValue([]byte("newp")) |
| 142 » » » » » err = mc.CompareAndSwap(itm) | 158 » » » » » So(mc.CompareAndSwap(itm), ShouldEqual,
mcS.ErrNotStored) |
| 143 » » » » » So(err, ShouldEqual, mcS.ErrNotStored) | |
| 144 }) | 159 }) |
| 145 }) | 160 }) |
| 146 }) | 161 }) |
| 147 | 162 |
| 148 Convey("check that the internal implementation is sane", func()
{ | 163 Convey("check that the internal implementation is sane", func()
{ |
| 149 curTime := now | 164 curTime := now |
| 150 err := mc.Add(&mcItem{ | 165 err := mc.Add(&mcItem{ |
| 151 key: "sup", | 166 key: "sup", |
| 152 value: []byte("cool"), | 167 value: []byte("cool"), |
| 153 expiration: time.Second * 2, | 168 expiration: time.Second * 2, |
| 154 }) | 169 }) |
| 155 | 170 |
| 156 » » » mci := mc.(*memcacheImpl) | 171 » » » mc.Get(mc.NewItem("sup")) |
| 172 » » » mc.Get(mc.NewItem("sup")) |
| 173 » » » mc.Get(mc.NewItem("sup")) |
| 174 » » » mc.Get(mc.NewItem("sup")) |
| 175 » » » mc.Get(mc.NewItem("wot")) |
| 176 |
| 177 » » » mci := mc.Raw().(*memcacheImpl) |
| 157 | 178 |
| 158 So(err, ShouldBeNil) | 179 So(err, ShouldBeNil) |
| 159 » » » So(len(mci.data.items), ShouldEqual, 1) | 180 » » » stats, err := mc.Stats() |
| 181 » » » So(err, ShouldBeNil) |
| 182 » » » So(stats.Items, ShouldEqual, 1) |
| 183 » » » So(stats.Bytes, ShouldEqual, 4) |
| 184 » » » So(stats.Hits, ShouldEqual, 4) |
| 185 » » » So(stats.Misses, ShouldEqual, 1) |
| 186 » » » So(stats.ByteHits, ShouldEqual, 4*4) |
| 160 So(mci.data.casID, ShouldEqual, 1) | 187 So(mci.data.casID, ShouldEqual, 1) |
| 161 So(mci.data.items["sup"], ShouldResemble, &mcItem{ | 188 So(mci.data.items["sup"], ShouldResemble, &mcItem{ |
| 162 key: "sup", | 189 key: "sup", |
| 163 value: []byte("cool"), | 190 value: []byte("cool"), |
| 164 expiration: time.Duration(curTime.Add(time.Secon
d * 2).UnixNano()), | 191 expiration: time.Duration(curTime.Add(time.Secon
d * 2).UnixNano()), |
| 165 CasID: 1, | 192 CasID: 1, |
| 166 }) | 193 }) |
| 167 | 194 |
| 168 » » » el, err := mc.Get("sup") | 195 » » » getItm := mc.NewItem("sup") |
| 169 » » » So(err, ShouldBeNil) | 196 » » » So(mc.Get(getItm), ShouldBeNil) |
| 170 So(len(mci.data.items), ShouldEqual, 1) | 197 So(len(mci.data.items), ShouldEqual, 1) |
| 171 So(mci.data.casID, ShouldEqual, 1) | 198 So(mci.data.casID, ShouldEqual, 1) |
| 172 | 199 |
| 173 testItem := &mcItem{ | 200 testItem := &mcItem{ |
| 174 key: "sup", | 201 key: "sup", |
| 175 value: []byte("cool"), | 202 value: []byte("cool"), |
| 176 CasID: 1, | 203 CasID: 1, |
| 177 } | 204 } |
| 178 » » » So(el, ShouldResemble, testItem) | 205 » » » So(getItm, ShouldResemble, testItem) |
| 179 }) | 206 }) |
| 180 | 207 |
| 181 }) | 208 }) |
| 182 } | 209 } |
| OLD | NEW |