OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 package memory | |
6 | |
7 import ( | |
8 "testing" | |
9 "time" | |
10 | |
11 "github.com/luci/gae" | |
12 "github.com/luci/luci-go/common/clock/testclock" | |
13 . "github.com/smartystreets/goconvey/convey" | |
14 "golang.org/x/net/context" | |
15 ) | |
16 | |
17 func TestMemcache(t *testing.T) { | |
18 t.Parallel() | |
19 | |
20 Convey("memcache", t, func() { | |
21 now := time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC) | |
22 c, tc := testclock.UseTime(context.Background(), now) | |
23 c = Use(c) | |
24 mc := gae.GetMC(c) | |
25 | |
26 Convey("implements MCSingleReadWriter", func() { | |
27 Convey("Add", func() { | |
28 itm := &mcItem{ | |
29 key: "sup", | |
30 value: []byte("cool"), | |
31 expiration: time.Second, | |
32 } | |
33 err := mc.Add(itm) | |
34 So(err, ShouldBeNil) | |
35 Convey("which rejects objects already there", fu
nc() { | |
36 err := mc.Add(itm) | |
37 So(err, ShouldEqual, gae.ErrMCNotStored) | |
38 }) | |
39 }) | |
40 | |
41 Convey("Get", func() { | |
42 itm := &mcItem{ | |
43 key: "sup", | |
44 value: []byte("cool"), | |
45 expiration: time.Second, | |
46 } | |
47 err := mc.Add(itm) | |
48 So(err, ShouldBeNil) | |
49 | |
50 testItem := &mcItem{ | |
51 key: "sup", | |
52 value: []byte("cool"), | |
53 CasID: 1, | |
54 } | |
55 i, err := mc.Get("sup") | |
56 So(err, ShouldBeNil) | |
57 So(i, ShouldResemble, testItem) | |
58 | |
59 Convey("which can expire", func() { | |
60 tc.Add(time.Second * 4) | |
61 i, err := mc.Get("sup") | |
62 So(err, ShouldEqual, gae.ErrMCCacheMiss) | |
63 So(i, ShouldBeNil) | |
64 }) | |
65 }) | |
66 | |
67 Convey("Delete", func() { | |
68 Convey("works if it's there", func() { | |
69 itm := &mcItem{ | |
70 key: "sup", | |
71 value: []byte("cool"), | |
72 expiration: time.Second, | |
73 } | |
74 err := mc.Add(itm) | |
75 So(err, ShouldBeNil) | |
76 | |
77 err = mc.Delete("sup") | |
78 So(err, ShouldBeNil) | |
79 | |
80 i, err := mc.Get("sup") | |
81 So(err, ShouldEqual, gae.ErrMCCacheMiss) | |
82 So(i, ShouldBeNil) | |
83 }) | |
84 | |
85 Convey("but not if it's not there", func() { | |
86 err := mc.Delete("sup") | |
87 So(err, ShouldEqual, gae.ErrMCCacheMiss) | |
88 }) | |
89 }) | |
90 | |
91 Convey("Set", func() { | |
92 itm := &mcItem{ | |
93 key: "sup", | |
94 value: []byte("cool"), | |
95 expiration: time.Second, | |
96 } | |
97 err := mc.Add(itm) | |
98 So(err, ShouldBeNil) | |
99 | |
100 itm.SetValue([]byte("newp")) | |
101 err = mc.Set(itm) | |
102 So(err, ShouldBeNil) | |
103 | |
104 testItem := &mcItem{ | |
105 key: "sup", | |
106 value: []byte("newp"), | |
107 CasID: 2, | |
108 } | |
109 i, err := mc.Get("sup") | |
110 So(err, ShouldBeNil) | |
111 So(i, ShouldResemble, testItem) | |
112 }) | |
113 | |
114 Convey("CompareAndSwap", func() { | |
115 itm := gae.MCItem(&mcItem{ | |
116 key: "sup", | |
117 value: []byte("cool"), | |
118 expiration: time.Second * 2, | |
119 }) | |
120 err := mc.Add(itm) | |
121 So(err, ShouldBeNil) | |
122 | |
123 Convey("works after a Get", func() { | |
124 itm, err = mc.Get("sup") | |
125 So(err, ShouldBeNil) | |
126 So(itm.(*mcItem).CasID, ShouldEqual, 1) | |
127 | |
128 itm.SetValue([]byte("newp")) | |
129 err = mc.CompareAndSwap(itm) | |
130 So(err, ShouldBeNil) | |
131 }) | |
132 | |
133 Convey("but fails if you don't", func() { | |
134 itm.SetValue([]byte("newp")) | |
135 err = mc.CompareAndSwap(itm) | |
136 So(err, ShouldEqual, gae.ErrMCCASConflic
t) | |
137 }) | |
138 | |
139 Convey("and fails if the item is expired/gone",
func() { | |
140 tc.Add(3 * time.Second) | |
141 itm.SetValue([]byte("newp")) | |
142 err = mc.CompareAndSwap(itm) | |
143 So(err, ShouldEqual, gae.ErrMCNotStored) | |
144 }) | |
145 }) | |
146 }) | |
147 | |
148 Convey("check that the internal implementation is sane", func()
{ | |
149 curTime := now | |
150 err := mc.Add(&mcItem{ | |
151 key: "sup", | |
152 value: []byte("cool"), | |
153 expiration: time.Second * 2, | |
154 }) | |
155 | |
156 mci := mc.(*memcacheImpl) | |
157 | |
158 So(err, ShouldBeNil) | |
159 So(len(mci.data.items), ShouldEqual, 1) | |
160 So(mci.data.casID, ShouldEqual, 1) | |
161 So(mci.data.items["sup"], ShouldResemble, &mcItem{ | |
162 key: "sup", | |
163 value: []byte("cool"), | |
164 expiration: time.Duration(curTime.Add(time.Secon
d * 2).UnixNano()), | |
165 CasID: 1, | |
166 }) | |
167 | |
168 el, err := mc.Get("sup") | |
169 So(err, ShouldBeNil) | |
170 So(len(mci.data.items), ShouldEqual, 1) | |
171 So(mci.data.casID, ShouldEqual, 1) | |
172 | |
173 testItem := &mcItem{ | |
174 key: "sup", | |
175 value: []byte("cool"), | |
176 CasID: 1, | |
177 } | |
178 So(el, ShouldResemble, testItem) | |
179 }) | |
180 | |
181 }) | |
182 } | |
OLD | NEW |