| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be 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 » infoS "github.com/luci/gae/service/info" | 11 » "github.com/luci/gae/service/info" |
| 12 » mcS "github.com/luci/gae/service/memcache" | 12 » mc "github.com/luci/gae/service/memcache" |
| 13 |
| 13 "github.com/luci/luci-go/common/clock/testclock" | 14 "github.com/luci/luci-go/common/clock/testclock" |
| 14 . "github.com/luci/luci-go/common/testing/assertions" | 15 . "github.com/luci/luci-go/common/testing/assertions" |
| 16 |
| 17 "golang.org/x/net/context" |
| 18 |
| 15 . "github.com/smartystreets/goconvey/convey" | 19 . "github.com/smartystreets/goconvey/convey" |
| 16 "golang.org/x/net/context" | |
| 17 ) | 20 ) |
| 18 | 21 |
| 19 func TestMemcache(t *testing.T) { | 22 func TestMemcache(t *testing.T) { |
| 20 t.Parallel() | 23 t.Parallel() |
| 21 | 24 |
| 22 Convey("memcache", t, func() { | 25 Convey("memcache", t, func() { |
| 23 now := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) | 26 now := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) |
| 24 c, tc := testclock.UseTime(context.Background(), now) | 27 c, tc := testclock.UseTime(context.Background(), now) |
| 25 c = Use(c) | 28 c = Use(c) |
| 26 mc := mcS.Get(c) | |
| 27 | 29 |
| 28 Convey("implements MCSingleReadWriter", func() { | 30 Convey("implements MCSingleReadWriter", func() { |
| 29 Convey("Add", func() { | 31 Convey("Add", func() { |
| 30 » » » » itm := (mc.NewItem("sup"). | 32 » » » » itm := (mc.NewItem(c, "sup"). |
| 31 SetValue([]byte("cool")). | 33 SetValue([]byte("cool")). |
| 32 SetExpiration(time.Second)) | 34 SetExpiration(time.Second)) |
| 33 » » » » So(mc.Add(itm), ShouldBeNil) | 35 » » » » So(mc.Add(c, itm), ShouldBeNil) |
| 34 Convey("which rejects objects already there", fu
nc() { | 36 Convey("which rejects objects already there", fu
nc() { |
| 35 » » » » » So(mc.Add(itm), ShouldEqual, mcS.ErrNotS
tored) | 37 » » » » » So(mc.Add(c, itm), ShouldEqual, mc.ErrNo
tStored) |
| 36 }) | 38 }) |
| 37 }) | 39 }) |
| 38 | 40 |
| 39 Convey("Get", func() { | 41 Convey("Get", func() { |
| 40 itm := &mcItem{ | 42 itm := &mcItem{ |
| 41 key: "sup", | 43 key: "sup", |
| 42 value: []byte("cool"), | 44 value: []byte("cool"), |
| 43 expiration: time.Second, | 45 expiration: time.Second, |
| 44 } | 46 } |
| 45 » » » » So(mc.Add(itm), ShouldBeNil) | 47 » » » » So(mc.Add(c, itm), ShouldBeNil) |
| 46 | 48 |
| 47 testItem := &mcItem{ | 49 testItem := &mcItem{ |
| 48 key: "sup", | 50 key: "sup", |
| 49 value: []byte("cool"), | 51 value: []byte("cool"), |
| 50 CasID: 1, | 52 CasID: 1, |
| 51 } | 53 } |
| 52 » » » » getItm, err := mc.Get("sup") | 54 » » » » getItm, err := mc.GetKey(c, "sup") |
| 53 So(err, ShouldBeNil) | 55 So(err, ShouldBeNil) |
| 54 So(getItm, ShouldResemble, testItem) | 56 So(getItm, ShouldResemble, testItem) |
| 55 | 57 |
| 56 Convey("which can expire", func() { | 58 Convey("which can expire", func() { |
| 57 tc.Add(time.Second * 4) | 59 tc.Add(time.Second * 4) |
| 58 » » » » » getItm, err := mc.Get("sup") | 60 » » » » » getItm, err := mc.GetKey(c, "sup") |
| 59 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) | 61 » » » » » So(err, ShouldEqual, mc.ErrCacheMiss) |
| 60 So(getItm, ShouldResemble, &mcItem{key:
"sup"}) | 62 So(getItm, ShouldResemble, &mcItem{key:
"sup"}) |
| 61 }) | 63 }) |
| 62 }) | 64 }) |
| 63 | 65 |
| 64 Convey("Delete", func() { | 66 Convey("Delete", func() { |
| 65 Convey("works if it's there", func() { | 67 Convey("works if it's there", func() { |
| 66 itm := &mcItem{ | 68 itm := &mcItem{ |
| 67 key: "sup", | 69 key: "sup", |
| 68 value: []byte("cool"), | 70 value: []byte("cool"), |
| 69 expiration: time.Second, | 71 expiration: time.Second, |
| 70 } | 72 } |
| 71 » » » » » So(mc.Add(itm), ShouldBeNil) | 73 » » » » » So(mc.Add(c, itm), ShouldBeNil) |
| 72 | 74 |
| 73 » » » » » So(mc.Delete("sup"), ShouldBeNil) | 75 » » » » » So(mc.Delete(c, "sup"), ShouldBeNil) |
| 74 | 76 |
| 75 » » » » » _, err := mc.Get("sup") | 77 » » » » » _, err := mc.GetKey(c, "sup") |
| 76 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) | 78 » » » » » So(err, ShouldEqual, mc.ErrCacheMiss) |
| 77 }) | 79 }) |
| 78 | 80 |
| 79 Convey("but not if it's not there", func() { | 81 Convey("but not if it's not there", func() { |
| 80 » » » » » So(mc.Delete("sup"), ShouldEqual, mcS.Er
rCacheMiss) | 82 » » » » » So(mc.Delete(c, "sup"), ShouldEqual, mc.
ErrCacheMiss) |
| 81 }) | 83 }) |
| 82 }) | 84 }) |
| 83 | 85 |
| 84 Convey("Set", func() { | 86 Convey("Set", func() { |
| 85 itm := &mcItem{ | 87 itm := &mcItem{ |
| 86 key: "sup", | 88 key: "sup", |
| 87 value: []byte("cool"), | 89 value: []byte("cool"), |
| 88 expiration: time.Second, | 90 expiration: time.Second, |
| 89 } | 91 } |
| 90 » » » » So(mc.Add(itm), ShouldBeNil) | 92 » » » » So(mc.Add(c, itm), ShouldBeNil) |
| 91 | 93 |
| 92 itm.SetValue([]byte("newp")) | 94 itm.SetValue([]byte("newp")) |
| 93 » » » » So(mc.Set(itm), ShouldBeNil) | 95 » » » » So(mc.Set(c, itm), ShouldBeNil) |
| 94 | 96 |
| 95 testItem := &mcItem{ | 97 testItem := &mcItem{ |
| 96 key: "sup", | 98 key: "sup", |
| 97 value: []byte("newp"), | 99 value: []byte("newp"), |
| 98 CasID: 2, | 100 CasID: 2, |
| 99 } | 101 } |
| 100 » » » » getItm, err := mc.Get("sup") | 102 » » » » getItm, err := mc.GetKey(c, "sup") |
| 101 So(err, ShouldBeNil) | 103 So(err, ShouldBeNil) |
| 102 So(getItm, ShouldResemble, testItem) | 104 So(getItm, ShouldResemble, testItem) |
| 103 | 105 |
| 104 Convey("Flush works too", func() { | 106 Convey("Flush works too", func() { |
| 105 » » » » » So(mc.Flush(), ShouldBeNil) | 107 » » » » » So(mc.Flush(c), ShouldBeNil) |
| 106 » » » » » _, err := mc.Get("sup") | 108 » » » » » _, err := mc.GetKey(c, "sup") |
| 107 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) | 109 » » » » » So(err, ShouldEqual, mc.ErrCacheMiss) |
| 108 }) | 110 }) |
| 109 }) | 111 }) |
| 110 | 112 |
| 111 Convey("Set (nil) is equivalent to Set([]byte{})", func(
) { | 113 Convey("Set (nil) is equivalent to Set([]byte{})", func(
) { |
| 112 » » » » So(mc.Set(mc.NewItem("bob")), ShouldBeNil) | 114 » » » » So(mc.Set(c, mc.NewItem(c, "bob")), ShouldBeNil) |
| 113 | 115 |
| 114 » » » » bob, err := mc.Get("bob") | 116 » » » » bob, err := mc.GetKey(c, "bob") |
| 115 So(err, ShouldBeNil) | 117 So(err, ShouldBeNil) |
| 116 So(bob.Value(), ShouldResemble, []byte{}) | 118 So(bob.Value(), ShouldResemble, []byte{}) |
| 117 }) | 119 }) |
| 118 | 120 |
| 119 Convey("Increment", func() { | 121 Convey("Increment", func() { |
| 120 » » » » val, err := mc.Increment("num", 7, 2) | 122 » » » » val, err := mc.Increment(c, "num", 7, 2) |
| 121 So(err, ShouldBeNil) | 123 So(err, ShouldBeNil) |
| 122 So(val, ShouldEqual, 9) | 124 So(val, ShouldEqual, 9) |
| 123 | 125 |
| 124 Convey("IncrementExisting", func() { | 126 Convey("IncrementExisting", func() { |
| 125 » » » » » val, err := mc.IncrementExisting("num",
-2) | 127 » » » » » val, err := mc.IncrementExisting(c, "num
", -2) |
| 126 So(err, ShouldBeNil) | 128 So(err, ShouldBeNil) |
| 127 So(val, ShouldEqual, 7) | 129 So(val, ShouldEqual, 7) |
| 128 | 130 |
| 129 » » » » » val, err = mc.IncrementExisting("num", -
100) | 131 » » » » » val, err = mc.IncrementExisting(c, "num"
, -100) |
| 130 So(err, ShouldBeNil) | 132 So(err, ShouldBeNil) |
| 131 So(val, ShouldEqual, 0) | 133 So(val, ShouldEqual, 0) |
| 132 | 134 |
| 133 » » » » » _, err = mc.IncrementExisting("noexist",
2) | 135 » » » » » _, err = mc.IncrementExisting(c, "noexis
t", 2) |
| 134 » » » » » So(err, ShouldEqual, mcS.ErrCacheMiss) | 136 » » » » » So(err, ShouldEqual, mc.ErrCacheMiss) |
| 135 | 137 |
| 136 » » » » » So(mc.Set(mc.NewItem("text").SetValue([]
byte("hello world, hooman!"))), ShouldBeNil) | 138 » » » » » So(mc.Set(c, mc.NewItem(c, "text").SetVa
lue([]byte("hello world, hooman!"))), ShouldBeNil) |
| 137 | 139 |
| 138 » » » » » _, err = mc.IncrementExisting("text", 2) | 140 » » » » » _, err = mc.IncrementExisting(c, "text",
2) |
| 139 So(err.Error(), ShouldContainSubstring,
"got invalid current value") | 141 So(err.Error(), ShouldContainSubstring,
"got invalid current value") |
| 140 }) | 142 }) |
| 141 }) | 143 }) |
| 142 | 144 |
| 143 Convey("CompareAndSwap", func() { | 145 Convey("CompareAndSwap", func() { |
| 144 » » » » itm := mcS.Item(&mcItem{ | 146 » » » » itm := mc.Item(&mcItem{ |
| 145 key: "sup", | 147 key: "sup", |
| 146 value: []byte("cool"), | 148 value: []byte("cool"), |
| 147 expiration: time.Second * 2, | 149 expiration: time.Second * 2, |
| 148 }) | 150 }) |
| 149 » » » » So(mc.Add(itm), ShouldBeNil) | 151 » » » » So(mc.Add(c, itm), ShouldBeNil) |
| 150 | 152 |
| 151 Convey("works after a Get", func() { | 153 Convey("works after a Get", func() { |
| 152 » » » » » itm, err := mc.Get("sup") | 154 » » » » » itm, err := mc.GetKey(c, "sup") |
| 153 So(err, ShouldBeNil) | 155 So(err, ShouldBeNil) |
| 154 So(itm.(*mcItem).CasID, ShouldEqual, 1) | 156 So(itm.(*mcItem).CasID, ShouldEqual, 1) |
| 155 | 157 |
| 156 itm.SetValue([]byte("newp")) | 158 itm.SetValue([]byte("newp")) |
| 157 » » » » » So(mc.CompareAndSwap(itm), ShouldBeNil) | 159 » » » » » So(mc.CompareAndSwap(c, itm), ShouldBeNi
l) |
| 158 }) | 160 }) |
| 159 | 161 |
| 160 Convey("but fails if you don't", func() { | 162 Convey("but fails if you don't", func() { |
| 161 itm.SetValue([]byte("newp")) | 163 itm.SetValue([]byte("newp")) |
| 162 » » » » » So(mc.CompareAndSwap(itm), ShouldEqual,
mcS.ErrCASConflict) | 164 » » » » » So(mc.CompareAndSwap(c, itm), ShouldEqua
l, mc.ErrCASConflict) |
| 163 }) | 165 }) |
| 164 | 166 |
| 165 Convey("and fails if the item is expired/gone",
func() { | 167 Convey("and fails if the item is expired/gone",
func() { |
| 166 tc.Add(3 * time.Second) | 168 tc.Add(3 * time.Second) |
| 167 itm.SetValue([]byte("newp")) | 169 itm.SetValue([]byte("newp")) |
| 168 » » » » » So(mc.CompareAndSwap(itm), ShouldEqual,
mcS.ErrNotStored) | 170 » » » » » So(mc.CompareAndSwap(c, itm), ShouldEqua
l, mc.ErrNotStored) |
| 169 }) | 171 }) |
| 170 }) | 172 }) |
| 171 }) | 173 }) |
| 172 | 174 |
| 173 Convey("check that the internal implementation is sane", func()
{ | 175 Convey("check that the internal implementation is sane", func()
{ |
| 174 curTime := now | 176 curTime := now |
| 175 » » » err := mc.Add(&mcItem{ | 177 » » » err := mc.Add(c, &mcItem{ |
| 176 key: "sup", | 178 key: "sup", |
| 177 value: []byte("cool"), | 179 value: []byte("cool"), |
| 178 expiration: time.Second * 2, | 180 expiration: time.Second * 2, |
| 179 }) | 181 }) |
| 180 | 182 |
| 181 for i := 0; i < 4; i++ { | 183 for i := 0; i < 4; i++ { |
| 182 » » » » _, err := mc.Get("sup") | 184 » » » » _, err := mc.GetKey(c, "sup") |
| 183 So(err, ShouldBeNil) | 185 So(err, ShouldBeNil) |
| 184 } | 186 } |
| 185 » » » _, err = mc.Get("wot") | 187 » » » _, err = mc.GetKey(c, "wot") |
| 186 » » » So(err, ShouldErrLike, mcS.ErrCacheMiss) | 188 » » » So(err, ShouldErrLike, mc.ErrCacheMiss) |
| 187 | 189 |
| 188 » » » mci := mc.Raw().(*memcacheImpl) | 190 » » » mci := mc.Raw(c).(*memcacheImpl) |
| 189 | 191 |
| 190 » » » stats, err := mc.Stats() | 192 » » » stats, err := mc.Stats(c) |
| 191 So(err, ShouldBeNil) | 193 So(err, ShouldBeNil) |
| 192 So(stats.Items, ShouldEqual, 1) | 194 So(stats.Items, ShouldEqual, 1) |
| 193 So(stats.Bytes, ShouldEqual, 4) | 195 So(stats.Bytes, ShouldEqual, 4) |
| 194 So(stats.Hits, ShouldEqual, 4) | 196 So(stats.Hits, ShouldEqual, 4) |
| 195 So(stats.Misses, ShouldEqual, 1) | 197 So(stats.Misses, ShouldEqual, 1) |
| 196 So(stats.ByteHits, ShouldEqual, 4*4) | 198 So(stats.ByteHits, ShouldEqual, 4*4) |
| 197 So(mci.data.casID, ShouldEqual, 1) | 199 So(mci.data.casID, ShouldEqual, 1) |
| 198 So(mci.data.items["sup"], ShouldResemble, &mcDataItem{ | 200 So(mci.data.items["sup"], ShouldResemble, &mcDataItem{ |
| 199 value: []byte("cool"), | 201 value: []byte("cool"), |
| 200 expiration: curTime.Add(time.Second * 2).Truncat
e(time.Second), | 202 expiration: curTime.Add(time.Second * 2).Truncat
e(time.Second), |
| 201 casID: 1, | 203 casID: 1, |
| 202 }) | 204 }) |
| 203 | 205 |
| 204 » » » getItm, err := mc.Get("sup") | 206 » » » getItm, err := mc.GetKey(c, "sup") |
| 205 So(err, ShouldBeNil) | 207 So(err, ShouldBeNil) |
| 206 So(len(mci.data.items), ShouldEqual, 1) | 208 So(len(mci.data.items), ShouldEqual, 1) |
| 207 So(mci.data.casID, ShouldEqual, 1) | 209 So(mci.data.casID, ShouldEqual, 1) |
| 208 | 210 |
| 209 testItem := &mcItem{ | 211 testItem := &mcItem{ |
| 210 key: "sup", | 212 key: "sup", |
| 211 value: []byte("cool"), | 213 value: []byte("cool"), |
| 212 CasID: 1, | 214 CasID: 1, |
| 213 } | 215 } |
| 214 So(getItm, ShouldResemble, testItem) | 216 So(getItm, ShouldResemble, testItem) |
| 215 }) | 217 }) |
| 216 | 218 |
| 217 Convey("When adding an item to an unset namespace", func() { | 219 Convey("When adding an item to an unset namespace", func() { |
| 218 » » » _, has := infoS.Get(c).GetNamespace() | 220 » » » So(info.GetNamespace(c), ShouldEqual, "") |
| 219 » » » So(has, ShouldBeFalse) | |
| 220 | 221 |
| 221 » » » item := mc.NewItem("foo").SetValue([]byte("heya")) | 222 » » » item := mc.NewItem(c, "foo").SetValue([]byte("heya")) |
| 222 » » » So(mc.Set(item), ShouldBeNil) | 223 » » » So(mc.Set(c, item), ShouldBeNil) |
| 223 | 224 |
| 224 Convey("The item can be retrieved from the unset namespa
ce.", func() { | 225 Convey("The item can be retrieved from the unset namespa
ce.", func() { |
| 225 » » » » got, err := mc.Get("foo") | 226 » » » » got, err := mc.GetKey(c, "foo") |
| 226 So(err, ShouldBeNil) | 227 So(err, ShouldBeNil) |
| 227 So(got.Value(), ShouldResemble, []byte("heya")) | 228 So(got.Value(), ShouldResemble, []byte("heya")) |
| 228 }) | 229 }) |
| 229 | 230 |
| 230 Convey("The item can be retrieved from a set, empty name
space.", func() { | 231 Convey("The item can be retrieved from a set, empty name
space.", func() { |
| 231 // Now test with empty namespace. | 232 // Now test with empty namespace. |
| 232 » » » » c = infoS.Get(c).MustNamespace("") | 233 » » » » c = info.MustNamespace(c, "") |
| 233 | 234 |
| 234 » » » » got, err := mc.Get("foo") | 235 » » » » got, err := mc.GetKey(c, "foo") |
| 235 So(err, ShouldBeNil) | 236 So(err, ShouldBeNil) |
| 236 So(got.Value(), ShouldResemble, []byte("heya")) | 237 So(got.Value(), ShouldResemble, []byte("heya")) |
| 237 }) | 238 }) |
| 238 }) | 239 }) |
| 239 }) | 240 }) |
| 240 } | 241 } |
| OLD | NEW |