| 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 » "golang.org/x/net/context" | 8 » "infra/gae/libs/wrapper" |
| 9 » "infra/gae/libs/gae" | 9 » "infra/gae/libs/wrapper/unsafe" |
| 10 » "infra/libs/clock/testclock" |
| 10 "testing" | 11 "testing" |
| 11 "time" | 12 "time" |
| 12 | 13 |
| 13 » "github.com/luci/luci-go/common/clock/testclock" | 14 » . "github.com/smartystreets/goconvey/convey" |
| 15 » "golang.org/x/net/context" |
| 14 | 16 |
| 15 » . "github.com/smartystreets/goconvey/convey" | 17 » "appengine/memcache" |
| 16 ) | 18 ) |
| 17 | 19 |
| 18 func TestMemcache(t *testing.T) { | 20 func TestMemcache(t *testing.T) { |
| 19 t.Parallel() | 21 t.Parallel() |
| 20 | 22 |
| 21 Convey("memcache", t, func() { | 23 Convey("memcache", t, func() { |
| 22 now := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) | 24 now := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) |
| 23 c, tc := testclock.UseTime(context.Background(), now) | 25 c, tc := testclock.UseTime(context.Background(), now) |
| 24 c = Use(c) | 26 c = Use(c) |
| 25 » » mc := gae.GetMC(c) | 27 » » mc := wrapper.GetMC(c) |
| 26 » » mci := gae.GetMC(c).(*memcacheImpl) | 28 » » mci := wrapper.GetMC(c).(*memcacheImpl) |
| 27 So(mc, ShouldNotEqual, mci) // two impls with the same memcacheD
ata | 29 So(mc, ShouldNotEqual, mci) // two impls with the same memcacheD
ata |
| 28 | 30 |
| 29 Convey("implements MCSingleReadWriter", func() { | 31 Convey("implements MCSingleReadWriter", func() { |
| 30 Convey("Add", func() { | 32 Convey("Add", func() { |
| 31 » » » » itm := &mcItem{ | 33 » » » » itm := &memcache.Item{ |
| 32 » » » » » key: "sup", | 34 » » » » » Key: "sup", |
| 33 » » » » » value: []byte("cool"), | 35 » » » » » Value: []byte("cool"), |
| 34 » » » » » expiration: time.Second, | 36 » » » » » Expiration: time.Second, |
| 35 } | 37 } |
| 36 err := mc.Add(itm) | 38 err := mc.Add(itm) |
| 37 So(err, ShouldBeNil) | 39 So(err, ShouldBeNil) |
| 38 Convey("which rejects objects already there", fu
nc() { | 40 Convey("which rejects objects already there", fu
nc() { |
| 39 err := mc.Add(itm) | 41 err := mc.Add(itm) |
| 40 » » » » » So(err, ShouldEqual, gae.ErrMCNotStored) | 42 » » » » » So(err, ShouldEqual, memcache.ErrNotStor
ed) |
| 41 }) | 43 }) |
| 42 | 44 |
| 43 Convey("which can be broken intentionally", func
() { | 45 Convey("which can be broken intentionally", func
() { |
| 44 mci.BreakFeatures(nil, "Add") | 46 mci.BreakFeatures(nil, "Add") |
| 45 err := mc.Add(itm) | 47 err := mc.Add(itm) |
| 46 » » » » » So(err, ShouldEqual, gae.ErrMCServerErro
r) | 48 » » » » » So(err, ShouldEqual, memcache.ErrServerE
rror) |
| 47 }) | 49 }) |
| 48 }) | 50 }) |
| 49 | 51 |
| 50 Convey("Get", func() { | 52 Convey("Get", func() { |
| 51 » » » » itm := &mcItem{ | 53 » » » » itm := &memcache.Item{ |
| 52 » » » » » key: "sup", | 54 » » » » » Key: "sup", |
| 53 » » » » » value: []byte("cool"), | 55 » » » » » Value: []byte("cool"), |
| 54 » » » » » expiration: time.Second, | 56 » » » » » Expiration: time.Second, |
| 55 } | 57 } |
| 56 err := mc.Add(itm) | 58 err := mc.Add(itm) |
| 57 So(err, ShouldBeNil) | 59 So(err, ShouldBeNil) |
| 58 | 60 |
| 59 » » » » testItem := &mcItem{ | 61 » » » » testItem := &memcache.Item{ |
| 60 » » » » » key: "sup", | 62 » » » » » Key: "sup", |
| 61 » » » » » value: []byte("cool"), | 63 » » » » » Value: []byte("cool"), |
| 62 » » » » » CasID: 1, | |
| 63 } | 64 } |
| 65 unsafe.MCSetCasID(testItem, 1) |
| 64 i, err := mc.Get("sup") | 66 i, err := mc.Get("sup") |
| 65 So(err, ShouldBeNil) | 67 So(err, ShouldBeNil) |
| 66 So(i, ShouldResemble, testItem) | 68 So(i, ShouldResemble, testItem) |
| 67 | 69 |
| 68 Convey("which can expire", func() { | 70 Convey("which can expire", func() { |
| 69 tc.Add(time.Second * 4) | 71 tc.Add(time.Second * 4) |
| 70 i, err := mc.Get("sup") | 72 i, err := mc.Get("sup") |
| 71 » » » » » So(err, ShouldEqual, gae.ErrMCCacheMiss) | 73 » » » » » So(err, ShouldEqual, memcache.ErrCacheMi
ss) |
| 72 So(i, ShouldBeNil) | 74 So(i, ShouldBeNil) |
| 73 }) | 75 }) |
| 74 | 76 |
| 75 Convey("which can be broken intentionally", func
() { | 77 Convey("which can be broken intentionally", func
() { |
| 76 mci.BreakFeatures(nil, "Get") | 78 mci.BreakFeatures(nil, "Get") |
| 77 _, err := mc.Get("sup") | 79 _, err := mc.Get("sup") |
| 78 » » » » » So(err, ShouldEqual, gae.ErrMCServerErro
r) | 80 » » » » » So(err, ShouldEqual, memcache.ErrServerE
rror) |
| 79 }) | 81 }) |
| 80 }) | 82 }) |
| 81 | 83 |
| 82 Convey("Delete", func() { | 84 Convey("Delete", func() { |
| 83 Convey("works if it's there", func() { | 85 Convey("works if it's there", func() { |
| 84 » » » » » itm := &mcItem{ | 86 » » » » » itm := &memcache.Item{ |
| 85 » » » » » » key: "sup", | 87 » » » » » » Key: "sup", |
| 86 » » » » » » value: []byte("cool"), | 88 » » » » » » Value: []byte("cool"), |
| 87 » » » » » » expiration: time.Second, | 89 » » » » » » Expiration: time.Second, |
| 88 } | 90 } |
| 89 err := mc.Add(itm) | 91 err := mc.Add(itm) |
| 90 So(err, ShouldBeNil) | 92 So(err, ShouldBeNil) |
| 91 | 93 |
| 92 err = mc.Delete("sup") | 94 err = mc.Delete("sup") |
| 93 So(err, ShouldBeNil) | 95 So(err, ShouldBeNil) |
| 94 | 96 |
| 95 i, err := mc.Get("sup") | 97 i, err := mc.Get("sup") |
| 96 » » » » » So(err, ShouldEqual, gae.ErrMCCacheMiss) | 98 » » » » » So(err, ShouldEqual, memcache.ErrCacheMi
ss) |
| 97 So(i, ShouldBeNil) | 99 So(i, ShouldBeNil) |
| 98 }) | 100 }) |
| 99 | 101 |
| 100 Convey("but not if it's not there", func() { | 102 Convey("but not if it's not there", func() { |
| 101 err := mc.Delete("sup") | 103 err := mc.Delete("sup") |
| 102 » » » » » So(err, ShouldEqual, gae.ErrMCCacheMiss) | 104 » » » » » So(err, ShouldEqual, memcache.ErrCacheMi
ss) |
| 103 }) | 105 }) |
| 104 | 106 |
| 105 Convey("and can be broken", func() { | 107 Convey("and can be broken", func() { |
| 106 mci.BreakFeatures(nil, "Delete") | 108 mci.BreakFeatures(nil, "Delete") |
| 107 err := mc.Delete("sup") | 109 err := mc.Delete("sup") |
| 108 » » » » » So(err, ShouldEqual, gae.ErrMCServerErro
r) | 110 » » » » » So(err, ShouldEqual, memcache.ErrServerE
rror) |
| 109 }) | 111 }) |
| 110 }) | 112 }) |
| 111 | 113 |
| 112 Convey("Set", func() { | 114 Convey("Set", func() { |
| 113 » » » » itm := &mcItem{ | 115 » » » » itm := &memcache.Item{ |
| 114 » » » » » key: "sup", | 116 » » » » » Key: "sup", |
| 115 » » » » » value: []byte("cool"), | 117 » » » » » Value: []byte("cool"), |
| 116 » » » » » expiration: time.Second, | 118 » » » » » Expiration: time.Second, |
| 117 } | 119 } |
| 118 err := mc.Add(itm) | 120 err := mc.Add(itm) |
| 119 So(err, ShouldBeNil) | 121 So(err, ShouldBeNil) |
| 120 | 122 |
| 121 » » » » itm.SetValue([]byte("newp")) | 123 » » » » itm.Value = []byte("newp") |
| 122 err = mc.Set(itm) | 124 err = mc.Set(itm) |
| 123 So(err, ShouldBeNil) | 125 So(err, ShouldBeNil) |
| 124 | 126 |
| 125 » » » » testItem := &mcItem{ | 127 » » » » testItem := &memcache.Item{ |
| 126 » » » » » key: "sup", | 128 » » » » » Key: "sup", |
| 127 » » » » » value: []byte("newp"), | 129 » » » » » Value: []byte("newp"), |
| 128 » » » » » CasID: 2, | |
| 129 } | 130 } |
| 131 unsafe.MCSetCasID(testItem, 2) |
| 130 i, err := mc.Get("sup") | 132 i, err := mc.Get("sup") |
| 131 So(err, ShouldBeNil) | 133 So(err, ShouldBeNil) |
| 132 So(i, ShouldResemble, testItem) | 134 So(i, ShouldResemble, testItem) |
| 133 | 135 |
| 134 Convey("and can be broken", func() { | 136 Convey("and can be broken", func() { |
| 135 mci.BreakFeatures(nil, "Set") | 137 mci.BreakFeatures(nil, "Set") |
| 136 err := mc.Set(itm) | 138 err := mc.Set(itm) |
| 137 » » » » » So(err, ShouldEqual, gae.ErrMCServerErro
r) | 139 » » » » » So(err, ShouldEqual, memcache.ErrServerE
rror) |
| 138 }) | 140 }) |
| 139 }) | 141 }) |
| 140 | 142 |
| 141 Convey("CompareAndSwap", func() { | 143 Convey("CompareAndSwap", func() { |
| 142 » » » » itm := gae.MCItem(&mcItem{ | 144 » » » » itm := &memcache.Item{ |
| 143 » » » » » key: "sup", | 145 » » » » » Key: "sup", |
| 144 » » » » » value: []byte("cool"), | 146 » » » » » Value: []byte("cool"), |
| 145 » » » » » expiration: time.Second * 2, | 147 » » » » » Expiration: time.Second * 2, |
| 146 » » » » }) | 148 » » » » } |
| 147 err := mc.Add(itm) | 149 err := mc.Add(itm) |
| 148 So(err, ShouldBeNil) | 150 So(err, ShouldBeNil) |
| 149 | 151 |
| 150 Convey("works after a Get", func() { | 152 Convey("works after a Get", func() { |
| 151 itm, err = mc.Get("sup") | 153 itm, err = mc.Get("sup") |
| 152 So(err, ShouldBeNil) | 154 So(err, ShouldBeNil) |
| 153 » » » » » So(itm.(*mcItem).CasID, ShouldEqual, 1) | 155 » » » » » So(unsafe.MCGetCasID(itm), ShouldEqual,
1) |
| 154 | 156 |
| 155 » » » » » itm.SetValue([]byte("newp")) | 157 » » » » » itm.Value = []byte("newp") |
| 156 err = mc.CompareAndSwap(itm) | 158 err = mc.CompareAndSwap(itm) |
| 157 So(err, ShouldBeNil) | 159 So(err, ShouldBeNil) |
| 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.Value = []byte("newp") |
| 162 err = mc.CompareAndSwap(itm) | 164 err = mc.CompareAndSwap(itm) |
| 163 » » » » » So(err, ShouldEqual, gae.ErrMCCASConflic
t) | 165 » » » » » So(err, ShouldEqual, memcache.ErrCASConf
lict) |
| 164 }) | 166 }) |
| 165 | 167 |
| 166 Convey("and fails if the item is expired/gone",
func() { | 168 Convey("and fails if the item is expired/gone",
func() { |
| 167 tc.Add(3 * time.Second) | 169 tc.Add(3 * time.Second) |
| 168 » » » » » itm.SetValue([]byte("newp")) | 170 » » » » » itm.Value = []byte("newp") |
| 169 err = mc.CompareAndSwap(itm) | 171 err = mc.CompareAndSwap(itm) |
| 170 » » » » » So(err, ShouldEqual, gae.ErrMCNotStored) | 172 » » » » » So(err, ShouldEqual, memcache.ErrNotStor
ed) |
| 171 }) | 173 }) |
| 172 | 174 |
| 173 Convey("and can be broken", func() { | 175 Convey("and can be broken", func() { |
| 174 mci.BreakFeatures(nil, "CompareAndSwap") | 176 mci.BreakFeatures(nil, "CompareAndSwap") |
| 175 err = mc.CompareAndSwap(itm) | 177 err = mc.CompareAndSwap(itm) |
| 176 » » » » » So(err, ShouldEqual, gae.ErrMCServerErro
r) | 178 » » » » » So(err, ShouldEqual, memcache.ErrServerE
rror) |
| 177 }) | 179 }) |
| 178 }) | 180 }) |
| 179 }) | 181 }) |
| 180 | 182 |
| 181 Convey("check that the internal implementation is sane", func()
{ | 183 Convey("check that the internal implementation is sane", func()
{ |
| 182 curTime := now | 184 curTime := now |
| 183 » » » err := mc.Add(&mcItem{ | 185 » » » err := mc.Add(&memcache.Item{ |
| 184 » » » » key: "sup", | 186 » » » » Key: "sup", |
| 185 » » » » value: []byte("cool"), | 187 » » » » Value: []byte("cool"), |
| 186 » » » » expiration: time.Second * 2, | 188 » » » » Expiration: time.Second * 2, |
| 187 }) | 189 }) |
| 188 | 190 |
| 189 So(err, ShouldBeNil) | 191 So(err, ShouldBeNil) |
| 190 So(len(mci.data.items), ShouldEqual, 1) | 192 So(len(mci.data.items), ShouldEqual, 1) |
| 191 So(mci.data.casID, ShouldEqual, 1) | 193 So(mci.data.casID, ShouldEqual, 1) |
| 192 » » » So(mci.data.items["sup"], ShouldResemble, &mcItem{ | 194 » » » So(mci.data.items["sup"], ShouldResemble, &unsafe.Item{ |
| 193 » » » » key: "sup", | 195 » » » » Key: "sup", |
| 194 » » » » value: []byte("cool"), | 196 » » » » Value: []byte("cool"), |
| 195 » » » » expiration: time.Duration(curTime.Add(time.Secon
d * 2).UnixNano()), | |
| 196 CasID: 1, | 197 CasID: 1, |
| 198 Expiration: time.Duration(curTime.Add(time.Secon
d * 2).UnixNano()), |
| 197 }) | 199 }) |
| 198 | 200 |
| 199 el, err := mc.Get("sup") | 201 el, err := mc.Get("sup") |
| 200 So(err, ShouldBeNil) | 202 So(err, ShouldBeNil) |
| 201 So(len(mci.data.items), ShouldEqual, 1) | 203 So(len(mci.data.items), ShouldEqual, 1) |
| 202 So(mci.data.casID, ShouldEqual, 1) | 204 So(mci.data.casID, ShouldEqual, 1) |
| 203 | 205 |
| 204 » » » testItem := &mcItem{ | 206 » » » testItem := &memcache.Item{ |
| 205 » » » » key: "sup", | 207 » » » » Key: "sup", |
| 206 » » » » value: []byte("cool"), | 208 » » » » Value: []byte("cool"), |
| 207 » » » » CasID: 1, | |
| 208 } | 209 } |
| 210 unsafe.MCSetCasID(testItem, 1) |
| 209 So(el, ShouldResemble, testItem) | 211 So(el, ShouldResemble, testItem) |
| 210 }) | 212 }) |
| 211 | 213 |
| 212 }) | 214 }) |
| 213 } | 215 } |
| OLD | NEW |