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 |