OLD | NEW |
| (Empty) |
1 // Copyright 2015 The LUCI Authors. All rights reserved. | |
2 // Use of this source code is governed under the Apache License, Version 2.0 | |
3 // that can be found in the LICENSE file. | |
4 | |
5 package memory | |
6 | |
7 import ( | |
8 "bytes" | |
9 "testing" | |
10 | |
11 "github.com/luci/gae/service/datastore" | |
12 "github.com/luci/gae/service/datastore/serialize" | |
13 "github.com/luci/gkvlite" | |
14 "github.com/luci/luci-go/common/data/cmpbin" | |
15 . "github.com/smartystreets/goconvey/convey" | |
16 ) | |
17 | |
18 func mkNum(n int64) []byte { | |
19 buf := &bytes.Buffer{} | |
20 _, err := cmpbin.WriteInt(buf, n) | |
21 memoryCorruption(err) | |
22 | |
23 return buf.Bytes() | |
24 } | |
25 | |
26 func readNum(data []byte) int64 { | |
27 ret, _, err := cmpbin.ReadInt(bytes.NewBuffer(data)) | |
28 memoryCorruption(err) | |
29 | |
30 return ret | |
31 } | |
32 | |
33 func TestIterator(t *testing.T) { | |
34 t.Parallel() | |
35 | |
36 s := newMemStore() | |
37 c := s.GetOrCreateCollection("zup") | |
38 prev := []byte{} | |
39 for i := 5; i < 100; i++ { | |
40 data := mkNum(int64(i)) | |
41 c.Set(data, prev) | |
42 prev = data | |
43 } | |
44 c = s.Snapshot().GetCollection("zup") | |
45 | |
46 get := func(c C, t *iterator) interface{} { | |
47 ret := interface{}(nil) | |
48 t.next(nil, func(i *gkvlite.Item) { | |
49 if i != nil { | |
50 ret = readNum(i.Key) | |
51 } | |
52 }) | |
53 return ret | |
54 } | |
55 | |
56 skipGet := func(c C, t *iterator, skipTo int64) interface{} { | |
57 ret := interface{}(nil) | |
58 t.next(mkNum(skipTo), func(i *gkvlite.Item) { | |
59 if i != nil { | |
60 ret = readNum(i.Key) | |
61 } | |
62 }) | |
63 return ret | |
64 } | |
65 | |
66 Convey("Test iterator", t, func() { | |
67 Convey("start at nil", func(ctx C) { | |
68 t := (&iterDefinition{c: c}).mkIter() | |
69 defer t.stop() | |
70 So(get(ctx, t), ShouldEqual, 5) | |
71 So(get(ctx, t), ShouldEqual, 6) | |
72 So(get(ctx, t), ShouldEqual, 7) | |
73 | |
74 Convey("And can skip", func(ctx C) { | |
75 So(skipGet(ctx, t, 10), ShouldEqual, 10) | |
76 So(get(ctx, t), ShouldEqual, 11) | |
77 | |
78 Convey("But not forever", func(ctx C) { | |
79 t.next(mkNum(200), func(i *gkvlite.Item)
{ | |
80 ctx.So(i, ShouldBeNil) | |
81 }) | |
82 t.next(nil, func(i *gkvlite.Item) { | |
83 ctx.So(i, ShouldBeNil) | |
84 }) | |
85 }) | |
86 }) | |
87 | |
88 Convey("Can iterate explicitly", func(ctx C) { | |
89 So(skipGet(ctx, t, 7), ShouldEqual, 8) | |
90 So(skipGet(ctx, t, 8), ShouldEqual, 9) | |
91 | |
92 // Giving the immediately next key doesn't cause
an internal reset. | |
93 So(skipGet(ctx, t, 10), ShouldEqual, 10) | |
94 }) | |
95 | |
96 Convey("Can stop", func(ctx C) { | |
97 t.stop() | |
98 t.next(mkNum(200), func(i *gkvlite.Item) { | |
99 ctx.So(i, ShouldBeNil) | |
100 }) | |
101 t.next(nil, func(i *gkvlite.Item) { | |
102 ctx.So(i, ShouldBeNil) | |
103 }) | |
104 So(t.stop, ShouldNotPanic) | |
105 }) | |
106 | |
107 Convey("Going backwards is ignored", func(ctx C) { | |
108 So(skipGet(ctx, t, 3), ShouldEqual, 8) | |
109 So(get(ctx, t), ShouldEqual, 9) | |
110 So(skipGet(ctx, t, 20), ShouldEqual, 20) | |
111 So(get(ctx, t), ShouldEqual, 21) | |
112 }) | |
113 | |
114 Convey("will stop at the end of the list", func(ctx C) { | |
115 So(skipGet(ctx, t, 95), ShouldEqual, 95) | |
116 So(get(ctx, t), ShouldEqual, 96) | |
117 So(get(ctx, t), ShouldEqual, 97) | |
118 So(get(ctx, t), ShouldEqual, 98) | |
119 So(get(ctx, t), ShouldEqual, 99) | |
120 So(get(ctx, t), ShouldBeNil) | |
121 So(get(ctx, t), ShouldBeNil) | |
122 }) | |
123 }) | |
124 | |
125 Convey("can have caps on both sides", func(ctx C) { | |
126 t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum
(25)}).mkIter() | |
127 So(get(ctx, t), ShouldEqual, 20) | |
128 So(get(ctx, t), ShouldEqual, 21) | |
129 So(get(ctx, t), ShouldEqual, 22) | |
130 So(get(ctx, t), ShouldEqual, 23) | |
131 So(get(ctx, t), ShouldEqual, 24) | |
132 t.next(nil, func(i *gkvlite.Item) { | |
133 ctx.So(i, ShouldBeNil) | |
134 }) | |
135 }) | |
136 | |
137 Convey("can skip over starting cap", func(ctx C) { | |
138 t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum
(25)}).mkIter() | |
139 So(skipGet(ctx, t, 22), ShouldEqual, 22) | |
140 So(get(ctx, t), ShouldEqual, 23) | |
141 So(get(ctx, t), ShouldEqual, 24) | |
142 t.next(nil, func(i *gkvlite.Item) { | |
143 ctx.So(i, ShouldBeNil) | |
144 }) | |
145 }) | |
146 | |
147 }) | |
148 } | |
149 | |
150 func TestMultiIteratorSimple(t *testing.T) { | |
151 t.Parallel() | |
152 | |
153 // Simulate an index with 2 columns (int and int). | |
154 vals := [][]int64{ | |
155 {1, 0}, | |
156 {1, 2}, | |
157 {1, 4}, | |
158 {1, 7}, | |
159 {1, 9}, | |
160 {3, 10}, | |
161 {3, 11}, | |
162 } | |
163 | |
164 valBytes := make([][]byte, len(vals)) | |
165 for i, nms := range vals { | |
166 numbs := make([][]byte, len(nms)) | |
167 for j, n := range nms { | |
168 numbs[j] = mkNum(n) | |
169 } | |
170 valBytes[i] = serialize.Join(numbs...) | |
171 } | |
172 | |
173 otherVals := [][]int64{ | |
174 {3, 0}, | |
175 {4, 10}, | |
176 {19, 7}, | |
177 {20, 2}, | |
178 {20, 3}, | |
179 {20, 4}, | |
180 {20, 8}, | |
181 {20, 11}, | |
182 } | |
183 | |
184 otherValBytes := make([][]byte, len(otherVals)) | |
185 for i, nms := range otherVals { | |
186 numbs := make([][]byte, len(nms)) | |
187 for i, n := range nms { | |
188 numbs[i] = mkNum(n) | |
189 } | |
190 otherValBytes[i] = serialize.Join(numbs...) | |
191 } | |
192 | |
193 Convey("Test MultiIterator", t, func() { | |
194 s := newMemStore() | |
195 c := s.GetOrCreateCollection("zup1") | |
196 for _, row := range valBytes { | |
197 c.Set(row, []byte{}) | |
198 } | |
199 c2 := s.GetOrCreateCollection("zup2") | |
200 for _, row := range otherValBytes { | |
201 c2.Set(row, []byte{}) | |
202 } | |
203 c = s.Snapshot().GetCollection("zup1") | |
204 c2 = s.Snapshot().GetCollection("zup2") | |
205 | |
206 Convey("can join the same collection twice", func() { | |
207 // get just the (1, *) | |
208 // starting at (1, 2) (i.e. >= 2) | |
209 // ending at (1, 4) (i.e. < 7) | |
210 defs := []*iterDefinition{ | |
211 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1)
), start: mkNum(2), end: mkNum(7)}, | |
212 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1)
), start: mkNum(2), end: mkNum(7)}, | |
213 } | |
214 | |
215 i := 1 | |
216 So(multiIterate(defs, func(suffix []byte) error { | |
217 So(readNum(suffix), ShouldEqual, vals[i][1]) | |
218 i++ | |
219 return nil | |
220 }), shouldBeSuccessful) | |
221 | |
222 So(i, ShouldEqual, 3) | |
223 }) | |
224 | |
225 Convey("can make empty iteration", func() { | |
226 // get just the (20, *) (doesn't exist) | |
227 defs := []*iterDefinition{ | |
228 {c: c, prefix: mkNum(20)}, | |
229 {c: c, prefix: mkNum(20)}, | |
230 } | |
231 | |
232 i := 0 | |
233 So(multiIterate(defs, func(suffix []byte) error { | |
234 panic("never") | |
235 }), shouldBeSuccessful) | |
236 | |
237 So(i, ShouldEqual, 0) | |
238 }) | |
239 | |
240 Convey("can join (other, val, val)", func() { | |
241 // 'other' must start with 20, 'vals' must start with 1 | |
242 // no range constraints | |
243 defs := []*iterDefinition{ | |
244 {c: c2, prefix: mkNum(20)}, | |
245 {c: c, prefix: mkNum(1)}, | |
246 {c: c, prefix: mkNum(1)}, | |
247 } | |
248 | |
249 expect := []int64{2, 4} | |
250 i := 0 | |
251 So(multiIterate(defs, func(suffix []byte) error { | |
252 So(readNum(suffix), ShouldEqual, expect[i]) | |
253 i++ | |
254 return nil | |
255 }), shouldBeSuccessful) | |
256 }) | |
257 | |
258 Convey("Can stop early", func() { | |
259 defs := []*iterDefinition{ | |
260 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1)
)}, | |
261 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1)
)}, | |
262 } | |
263 | |
264 i := 0 | |
265 So(multiIterate(defs, func(suffix []byte) error { | |
266 So(readNum(suffix), ShouldEqual, vals[i][1]) | |
267 i++ | |
268 return nil | |
269 }), shouldBeSuccessful) | |
270 So(i, ShouldEqual, 5) | |
271 | |
272 i = 0 | |
273 So(multiIterate(defs, func(suffix []byte) error { | |
274 So(readNum(suffix), ShouldEqual, vals[i][1]) | |
275 i++ | |
276 return datastore.Stop | |
277 }), shouldBeSuccessful) | |
278 So(i, ShouldEqual, 1) | |
279 }) | |
280 | |
281 }) | |
282 | |
283 } | |
OLD | NEW |