Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(715)

Side by Side Diff: impl/memory/gkvlite_iter_test.go

Issue 1302813003: impl/memory: Implement Queries (Closed) Base URL: https://github.com/luci/gae.git@add_multi_iterator
Patch Set: stringSet everywhere Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « impl/memory/gkvlite_iter.go ('k') | impl/memory/gkvlite_utils.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "bytes" 8 "bytes"
9 "fmt"
10 "testing" 9 "testing"
11 10
12 "github.com/luci/gkvlite" 11 "github.com/luci/gkvlite"
13 "github.com/luci/luci-go/common/cmpbin" 12 "github.com/luci/luci-go/common/cmpbin"
14 . "github.com/smartystreets/goconvey/convey" 13 . "github.com/smartystreets/goconvey/convey"
15 ) 14 )
16 15
16 func mkNum(n int64) []byte {
17 buf := &bytes.Buffer{}
18 _, err := cmpbin.WriteInt(buf, n)
19 memoryCorruption(err)
20
21 return buf.Bytes()
22 }
23
24 func readNum(data []byte) int64 {
25 ret, _, err := cmpbin.ReadInt(bytes.NewBuffer(data))
26 memoryCorruption(err)
27
28 return ret
29 }
30
17 func TestIterator(t *testing.T) { 31 func TestIterator(t *testing.T) {
18 t.Parallel() 32 t.Parallel()
19 33
20 mkNum := func(n int64) []byte {
21 buf := &bytes.Buffer{}
22 _, err := cmpbin.WriteInt(buf, n)
23 if err != nil {
24 panic(fmt.Errorf("your RAM is busted: %s", err))
25 }
26 return buf.Bytes()
27 }
28
29 getNum := func(data []byte) int64 {
30 ret, _, err := cmpbin.ReadInt(bytes.NewBuffer(data))
31 if err != nil {
32 panic(fmt.Errorf("your RAM is (probably) busted: %s", er r))
33 }
34 return ret
35 }
36
37 s := newMemStore() 34 s := newMemStore()
38 c := s.SetCollection("zup", nil) 35 c := s.SetCollection("zup", nil)
39 prev := []byte{} 36 prev := []byte{}
40 for i := 5; i < 100; i++ { 37 for i := 5; i < 100; i++ {
41 data := mkNum(int64(i)) 38 data := mkNum(int64(i))
42 c.Set(data, prev) 39 c.Set(data, prev)
43 prev = data 40 prev = data
44 } 41 }
45 42
46 » get := func(c C, t *iterator) int64 { 43 » get := func(c C, t *iterator) interface{} {
47 » » ret := int64(0) 44 » » ret := interface{}(nil)
48 t.next(nil, func(i *gkvlite.Item) { 45 t.next(nil, func(i *gkvlite.Item) {
49 » » » c.So(i, ShouldNotBeNil) 46 » » » if i != nil {
50 » » » ret = getNum(i.Key) 47 » » » » ret = readNum(i.Key)
48 » » » }
51 }) 49 })
52 return ret 50 return ret
53 } 51 }
54 52
55 » skipGet := func(c C, t *iterator, skipTo int64) int64 { 53 » skipGet := func(c C, t *iterator, skipTo int64) interface{} {
56 » » ret := int64(0) 54 » » ret := interface{}(nil)
57 t.next(mkNum(skipTo), func(i *gkvlite.Item) { 55 t.next(mkNum(skipTo), func(i *gkvlite.Item) {
58 » » » c.So(i, ShouldNotBeNil) 56 » » » if i != nil {
59 » » » ret = getNum(i.Key) 57 » » » » ret = readNum(i.Key)
58 » » » }
60 }) 59 })
61 return ret 60 return ret
62 } 61 }
63 62
64 Convey("Test iterator", t, func() { 63 Convey("Test iterator", t, func() {
65 Convey("start at nil", func(ctx C) { 64 Convey("start at nil", func(ctx C) {
66 » » » t := newIterable(c, nil) 65 » » » t := (&iterDefinition{c: c}).mkIter()
66 » » » defer t.stop()
67 So(get(ctx, t), ShouldEqual, 5) 67 So(get(ctx, t), ShouldEqual, 5)
68 So(get(ctx, t), ShouldEqual, 6) 68 So(get(ctx, t), ShouldEqual, 6)
69 So(get(ctx, t), ShouldEqual, 7) 69 So(get(ctx, t), ShouldEqual, 7)
70 70
71 » » » Convey("And can skip", func() { 71 » » » Convey("And can skip", func(ctx C) {
72 So(skipGet(ctx, t, 10), ShouldEqual, 10) 72 So(skipGet(ctx, t, 10), ShouldEqual, 10)
73 So(get(ctx, t), ShouldEqual, 11) 73 So(get(ctx, t), ShouldEqual, 11)
74 74
75 » » » » Convey("But not forever", func(c C) { 75 » » » » Convey("But not forever", func(ctx C) {
76 t.next(mkNum(200), func(i *gkvlite.Item) { 76 t.next(mkNum(200), func(i *gkvlite.Item) {
77 » » » » » » c.So(i, ShouldBeNil) 77 » » » » » » ctx.So(i, ShouldBeNil)
78 }) 78 })
79 t.next(nil, func(i *gkvlite.Item) { 79 t.next(nil, func(i *gkvlite.Item) {
80 » » » » » » c.So(i, ShouldBeNil) 80 » » » » » » ctx.So(i, ShouldBeNil)
81 }) 81 })
82 }) 82 })
83 }) 83 })
84 84
85 » » » Convey("Can stop", func(c C) { 85 » » » Convey("Can iterate explicitly", func(ctx C) {
86 » » » » So(skipGet(ctx, t, 7), ShouldEqual, 8)
87 » » » » So(skipGet(ctx, t, 8), ShouldEqual, 9)
88
89 » » » » // Giving the immediately next key doesn't cause an internal reset.
90 » » » » So(skipGet(ctx, t, 10), ShouldEqual, 10)
91 » » » })
92
93 » » » Convey("Can stop", func(ctx C) {
86 t.stop() 94 t.stop()
87 t.next(mkNum(200), func(i *gkvlite.Item) { 95 t.next(mkNum(200), func(i *gkvlite.Item) {
88 » » » » » c.So(i, ShouldBeNil) 96 » » » » » ctx.So(i, ShouldBeNil)
89 }) 97 })
90 t.next(nil, func(i *gkvlite.Item) { 98 t.next(nil, func(i *gkvlite.Item) {
91 » » » » » c.So(i, ShouldBeNil) 99 » » » » » ctx.So(i, ShouldBeNil)
92 }) 100 })
93 So(t.stop, ShouldNotPanic) 101 So(t.stop, ShouldNotPanic)
94 }) 102 })
95 103
96 » » » Convey("Going backwards is fine", func(c C) { 104 » » » Convey("Going backwards is ignored", func(ctx C) {
97 » » » » So(skipGet(ctx, t, 3), ShouldEqual, 5) 105 » » » » So(skipGet(ctx, t, 3), ShouldEqual, 8)
98 » » » » So(get(ctx, t), ShouldEqual, 6) 106 » » » » So(get(ctx, t), ShouldEqual, 9)
107 » » » » So(skipGet(ctx, t, 20), ShouldEqual, 20)
108 » » » » So(get(ctx, t), ShouldEqual, 21)
109 » » » })
110
111 » » » Convey("will stop at the end of the list", func(ctx C) {
112 » » » » So(skipGet(ctx, t, 95), ShouldEqual, 95)
113 » » » » So(get(ctx, t), ShouldEqual, 96)
114 » » » » So(get(ctx, t), ShouldEqual, 97)
115 » » » » So(get(ctx, t), ShouldEqual, 98)
116 » » » » So(get(ctx, t), ShouldEqual, 99)
117 » » » » So(get(ctx, t), ShouldBeNil)
118 » » » » So(get(ctx, t), ShouldBeNil)
99 }) 119 })
100 }) 120 })
101 121
102 Convey("can have caps on both sides", func(ctx C) { 122 Convey("can have caps on both sides", func(ctx C) {
103 » » » t := newIterable(c, mkNum(25)) 123 » » » t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum (25)}).mkIter()
104 » » » So(skipGet(ctx, t, 20), ShouldEqual, 20) 124 » » » So(get(ctx, t), ShouldEqual, 20)
105 So(get(ctx, t), ShouldEqual, 21) 125 So(get(ctx, t), ShouldEqual, 21)
106 So(get(ctx, t), ShouldEqual, 22) 126 So(get(ctx, t), ShouldEqual, 22)
107 So(get(ctx, t), ShouldEqual, 23) 127 So(get(ctx, t), ShouldEqual, 23)
108 So(get(ctx, t), ShouldEqual, 24) 128 So(get(ctx, t), ShouldEqual, 24)
109 t.next(nil, func(i *gkvlite.Item) { 129 t.next(nil, func(i *gkvlite.Item) {
110 ctx.So(i, ShouldBeNil) 130 ctx.So(i, ShouldBeNil)
111 }) 131 })
112 }) 132 })
133
134 Convey("can skip over starting cap", func(ctx C) {
135 t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum (25)}).mkIter()
136 So(skipGet(ctx, t, 22), ShouldEqual, 22)
137 So(get(ctx, t), ShouldEqual, 23)
138 So(get(ctx, t), ShouldEqual, 24)
139 t.next(nil, func(i *gkvlite.Item) {
140 ctx.So(i, ShouldBeNil)
141 })
142 })
143
113 }) 144 })
114 } 145 }
146
147 func TestMultiIteratorSimple(t *testing.T) {
148 t.Parallel()
149
150 // Simulate an index with 2 columns (int and int).
151 vals := [][]int64{
152 {1, 0},
153 {1, 2},
154 {1, 4},
155 {1, 7},
156 {1, 9},
157 {3, 10},
158 {3, 11},
159 }
160
161 valBytes := make([][]byte, len(vals))
162 for i, nms := range vals {
163 numbs := make([][]byte, len(nms))
164 for j, n := range nms {
165 numbs[j] = mkNum(n)
166 }
167 valBytes[i] = bjoin(numbs...)
168 }
169
170 otherVals := [][]int64{
171 {3, 0},
172 {4, 10},
173 {19, 7},
174 {20, 2},
175 {20, 3},
176 {20, 4},
177 {20, 8},
178 {20, 11},
179 }
180
181 otherValBytes := make([][]byte, len(otherVals))
182 for i, nms := range otherVals {
183 numbs := make([][]byte, len(nms))
184 for i, n := range nms {
185 numbs[i] = mkNum(n)
186 }
187 otherValBytes[i] = bjoin(numbs...)
188 }
189
190 Convey("Test MultiIterator", t, func() {
191 s := newMemStore()
192 c := s.SetCollection("zup1", nil)
193 for _, row := range valBytes {
194 c.Set(row, []byte{})
195 }
196 c2 := s.SetCollection("zup2", nil)
197 for _, row := range otherValBytes {
198 c2.Set(row, []byte{})
199 }
200
201 Convey("can join the same collection twice", func() {
202 // get just the (1, *)
203 // starting at (1, 2) (i.e. >= 2)
204 // ending at (1, 4) (i.e. < 7)
205 defs := []*iterDefinition{
206 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) ), start: mkNum(2), end: mkNum(7)},
207 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) ), start: mkNum(2), end: mkNum(7)},
208 }
209
210 i := 1
211 multiIterate(defs, func(suffix []byte) bool {
212 So(readNum(suffix), ShouldEqual, vals[i][1])
213 i++
214 return true
215 })
216
217 So(i, ShouldEqual, 3)
218 })
219
220 Convey("can make empty iteration", func() {
221 // get just the (20, *) (doesn't exist)
222 defs := []*iterDefinition{
223 {c: c, prefix: mkNum(20)},
224 {c: c, prefix: mkNum(20)},
225 }
226
227 i := 0
228 multiIterate(defs, func(suffix []byte) bool {
229 panic("never")
230 })
231
232 So(i, ShouldEqual, 0)
233 })
234
235 Convey("can join (other, val, val)", func() {
236 // 'other' must start with 20, 'vals' must start with 1
237 // no range constraints
238 defs := []*iterDefinition{
239 {c: c2, prefix: mkNum(20)},
240 {c: c, prefix: mkNum(1)},
241 {c: c, prefix: mkNum(1)},
242 }
243
244 expect := []int64{2, 4}
245 i := 0
246 multiIterate(defs, func(suffix []byte) bool {
247 So(readNum(suffix), ShouldEqual, expect[i])
248 i++
249 return true
250 })
251 })
252
253 Convey("Can stop early", func() {
254 defs := []*iterDefinition{
255 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) )},
256 {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) )},
257 }
258
259 i := 0
260 multiIterate(defs, func(suffix []byte) bool {
261 So(readNum(suffix), ShouldEqual, vals[i][1])
262 i++
263 return true
264 })
265 So(i, ShouldEqual, 5)
266
267 i = 0
268 multiIterate(defs, func(suffix []byte) bool {
269 So(readNum(suffix), ShouldEqual, vals[i][1])
270 i++
271 return false
272 })
273 So(i, ShouldEqual, 1)
274 })
275
276 })
277
278 }
OLDNEW
« no previous file with comments | « impl/memory/gkvlite_iter.go ('k') | impl/memory/gkvlite_utils.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698