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 |