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

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: Baby's first query! Created 5 years, 4 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
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
17 func mkNum(n int64) []byte { 16 func mkNum(n int64) []byte {
18 buf := &bytes.Buffer{} 17 buf := &bytes.Buffer{}
19 _, err := cmpbin.WriteInt(buf, n) 18 _, err := cmpbin.WriteInt(buf, n)
20 » if err != nil { 19 » memoryCorruption(err)
21 » » panic(fmt.Errorf("your RAM is busted: %s", err)) 20
22 » }
23 return buf.Bytes() 21 return buf.Bytes()
24 } 22 }
25 23
26 func readNum(data []byte) int64 { 24 func readNum(data []byte) int64 {
27 ret, _, err := cmpbin.ReadInt(bytes.NewBuffer(data)) 25 ret, _, err := cmpbin.ReadInt(bytes.NewBuffer(data))
28 » if err != nil { 26 » memoryCorruption(err)
29 » » panic(fmt.Errorf("your RAM is (probably) busted: %s", err)) 27
30 » }
31 return ret 28 return ret
32 } 29 }
33 30
34 func TestIterator(t *testing.T) { 31 func TestIterator(t *testing.T) {
35 t.Parallel() 32 t.Parallel()
36 33
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 = readNum(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 = readNum(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 := newIterator(c, nil, nil) 65 » » » t := newIterator(&iterDefinition{c: c})
67 defer t.stop() 66 defer t.stop()
68 So(get(ctx, t), ShouldEqual, 5) 67 So(get(ctx, t), ShouldEqual, 5)
69 So(get(ctx, t), ShouldEqual, 6) 68 So(get(ctx, t), ShouldEqual, 6)
70 So(get(ctx, t), ShouldEqual, 7) 69 So(get(ctx, t), ShouldEqual, 7)
71 70
72 » » » Convey("And can skip", func() { 71 » » » Convey("And can skip", func(ctx C) {
73 So(skipGet(ctx, t, 10), ShouldEqual, 10) 72 So(skipGet(ctx, t, 10), ShouldEqual, 10)
74 So(get(ctx, t), ShouldEqual, 11) 73 So(get(ctx, t), ShouldEqual, 11)
75 74
76 » » » » Convey("But not forever", func(c C) { 75 » » » » Convey("But not forever", func(ctx C) {
77 t.next(mkNum(200), func(i *gkvlite.Item) { 76 t.next(mkNum(200), func(i *gkvlite.Item) {
78 » » » » » » c.So(i, ShouldBeNil) 77 » » » » » » ctx.So(i, ShouldBeNil)
79 }) 78 })
80 t.next(nil, func(i *gkvlite.Item) { 79 t.next(nil, func(i *gkvlite.Item) {
81 » » » » » » c.So(i, ShouldBeNil) 80 » » » » » » ctx.So(i, ShouldBeNil)
82 }) 81 })
83 }) 82 })
84 }) 83 })
85 84
86 » » » Convey("Can iterate explicitly", func() { 85 » » » Convey("Can iterate explicitly", func(ctx C) {
87 So(skipGet(ctx, t, 7), ShouldEqual, 8) 86 So(skipGet(ctx, t, 7), ShouldEqual, 8)
88 So(skipGet(ctx, t, 8), ShouldEqual, 9) 87 So(skipGet(ctx, t, 8), ShouldEqual, 9)
89 88
90 // Giving the immediately next key doesn't cause an internal reset. 89 // Giving the immediately next key doesn't cause an internal reset.
91 So(skipGet(ctx, t, 10), ShouldEqual, 10) 90 So(skipGet(ctx, t, 10), ShouldEqual, 10)
92 }) 91 })
93 92
94 » » » Convey("Can stop", func(c C) { 93 » » » Convey("Can stop", func(ctx C) {
95 t.stop() 94 t.stop()
96 t.next(mkNum(200), func(i *gkvlite.Item) { 95 t.next(mkNum(200), func(i *gkvlite.Item) {
97 » » » » » c.So(i, ShouldBeNil) 96 » » » » » ctx.So(i, ShouldBeNil)
98 }) 97 })
99 t.next(nil, func(i *gkvlite.Item) { 98 t.next(nil, func(i *gkvlite.Item) {
100 » » » » » c.So(i, ShouldBeNil) 99 » » » » » ctx.So(i, ShouldBeNil)
101 }) 100 })
102 So(t.stop, ShouldNotPanic) 101 So(t.stop, ShouldNotPanic)
103 }) 102 })
104 103
105 » » » Convey("Going backwards is ignored", func(c C) { 104 » » » Convey("Going backwards is ignored", func(ctx C) {
106 So(skipGet(ctx, t, 3), ShouldEqual, 8) 105 So(skipGet(ctx, t, 3), ShouldEqual, 8)
107 So(get(ctx, t), ShouldEqual, 9) 106 So(get(ctx, t), ShouldEqual, 9)
108 So(skipGet(ctx, t, 20), ShouldEqual, 20) 107 So(skipGet(ctx, t, 20), ShouldEqual, 20)
109 So(get(ctx, t), ShouldEqual, 21) 108 So(get(ctx, t), ShouldEqual, 21)
110 }) 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)
119 })
111 }) 120 })
112 121
113 Convey("can have caps on both sides", func(ctx C) { 122 Convey("can have caps on both sides", func(ctx C) {
114 » » » t := newIterator(c, mkNum(20), mkNum(25)) 123 » » » t := newIterator(&iterDefinition{c: c, start: mkNum(20), end: mkNum(25)})
115 So(get(ctx, t), ShouldEqual, 20) 124 So(get(ctx, t), ShouldEqual, 20)
116 So(get(ctx, t), ShouldEqual, 21) 125 So(get(ctx, t), ShouldEqual, 21)
117 So(get(ctx, t), ShouldEqual, 22) 126 So(get(ctx, t), ShouldEqual, 22)
118 So(get(ctx, t), ShouldEqual, 23) 127 So(get(ctx, t), ShouldEqual, 23)
119 So(get(ctx, t), ShouldEqual, 24) 128 So(get(ctx, t), ShouldEqual, 24)
120 t.next(nil, func(i *gkvlite.Item) { 129 t.next(nil, func(i *gkvlite.Item) {
121 ctx.So(i, ShouldBeNil) 130 ctx.So(i, ShouldBeNil)
122 }) 131 })
123 }) 132 })
124 133
125 Convey("can skip over starting cap", func(ctx C) { 134 Convey("can skip over starting cap", func(ctx C) {
126 » » » t := newIterator(c, mkNum(20), mkNum(25)) 135 » » » t := newIterator(&iterDefinition{c: c, start: mkNum(20), end: mkNum(25)})
127 So(skipGet(ctx, t, 22), ShouldEqual, 22) 136 So(skipGet(ctx, t, 22), ShouldEqual, 22)
128 So(get(ctx, t), ShouldEqual, 23) 137 So(get(ctx, t), ShouldEqual, 23)
129 So(get(ctx, t), ShouldEqual, 24) 138 So(get(ctx, t), ShouldEqual, 24)
130 t.next(nil, func(i *gkvlite.Item) { 139 t.next(nil, func(i *gkvlite.Item) {
131 ctx.So(i, ShouldBeNil) 140 ctx.So(i, ShouldBeNil)
132 }) 141 })
133 }) 142 })
134 143
135 }) 144 })
136 } 145 }
137 146
138 func TestMultiIteratorSimple(t *testing.T) { 147 func TestMultiIteratorSimple(t *testing.T) {
139 t.Parallel() 148 t.Parallel()
140 149
141 // Simulate an index with 2 columns (int and int). 150 // Simulate an index with 2 columns (int and int).
142 vals := [][]int64{ 151 vals := [][]int64{
143 {1, 0}, 152 {1, 0},
144 {1, 2}, 153 {1, 2},
145 {1, 4}, 154 {1, 4},
146 {1, 7}, 155 {1, 7},
147 {1, 9}, 156 {1, 9},
148 {3, 10}, 157 {3, 10},
149 {3, 11}, 158 {3, 11},
150 } 159 }
151 160
152 valBytes := make([][]byte, len(vals)) 161 valBytes := make([][]byte, len(vals))
153 for i, nms := range vals { 162 for i, nms := range vals {
154 numbs := make([][]byte, len(nms)) 163 numbs := make([][]byte, len(nms))
155 » » for i, n := range nms { 164 » » for j, n := range nms {
156 » » » numbs[i] = mkNum(n) 165 » » » numbs[j] = mkNum(n)
157 } 166 }
158 valBytes[i] = bjoin(numbs...) 167 valBytes[i] = bjoin(numbs...)
159 } 168 }
160 169
161 otherVals := [][]int64{ 170 otherVals := [][]int64{
162 {3, 0}, 171 {3, 0},
163 {4, 10}, 172 {4, 10},
164 {19, 7}, 173 {19, 7},
165 {20, 2}, 174 {20, 2},
166 {20, 3}, 175 {20, 3},
(...skipping 20 matching lines...) Expand all
187 c2 := s.SetCollection("zup2", nil) 196 c2 := s.SetCollection("zup2", nil)
188 for _, row := range otherValBytes { 197 for _, row := range otherValBytes {
189 c2.Set(row, []byte{}) 198 c2.Set(row, []byte{})
190 } 199 }
191 200
192 Convey("can join the same collection twice", func() { 201 Convey("can join the same collection twice", func() {
193 // get just the (1, *) 202 // get just the (1, *)
194 // starting at (1, 2) (i.e. >= 2) 203 // starting at (1, 2) (i.e. >= 2)
195 // ending at (1, 4) (i.e. < 7) 204 // ending at (1, 4) (i.e. < 7)
196 defs := []*iterDefinition{ 205 defs := []*iterDefinition{
197 » » » » {c, mkNum(1), mkNum(2), mkNum(7)}, 206 » » » » {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) ), start: mkNum(2), end: mkNum(7)},
198 » » » » {c, mkNum(1), mkNum(2), mkNum(7)}, 207 » » » » {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) ), start: mkNum(2), end: mkNum(7)},
199 } 208 }
200 209
201 i := 1 210 i := 1
202 multiIterate(defs, func(suffix []byte) bool { 211 multiIterate(defs, func(suffix []byte) bool {
203 So(readNum(suffix), ShouldEqual, vals[i][1]) 212 So(readNum(suffix), ShouldEqual, vals[i][1])
204 i++ 213 i++
205 return true 214 return true
206 }) 215 })
207 216
208 So(i, ShouldEqual, 3) 217 So(i, ShouldEqual, 3)
209 }) 218 })
210 219
211 Convey("can make empty iteration", func() { 220 Convey("can make empty iteration", func() {
212 // get just the (20, *) (doesn't exist) 221 // get just the (20, *) (doesn't exist)
213 defs := []*iterDefinition{ 222 defs := []*iterDefinition{
214 » » » » {c, mkNum(20), nil, nil}, 223 » » » » {c: c, prefix: mkNum(20)},
215 » » » » {c, mkNum(20), nil, nil}, 224 » » » » {c: c, prefix: mkNum(20)},
216 } 225 }
217 226
218 i := 0 227 i := 0
219 multiIterate(defs, func(suffix []byte) bool { 228 multiIterate(defs, func(suffix []byte) bool {
220 panic("never") 229 panic("never")
221 }) 230 })
222 231
223 So(i, ShouldEqual, 0) 232 So(i, ShouldEqual, 0)
224 }) 233 })
225 234
226 Convey("can join (other, val, val)", func() { 235 Convey("can join (other, val, val)", func() {
227 // 'other' must start with 20, 'vals' must start with 1 236 // 'other' must start with 20, 'vals' must start with 1
228 // no range constraints 237 // no range constraints
229 defs := []*iterDefinition{ 238 defs := []*iterDefinition{
230 » » » » {c2, mkNum(20), nil, nil}, 239 » » » » {c: c2, prefix: mkNum(20)},
231 » » » » {c, mkNum(1), nil, nil}, 240 » » » » {c: c, prefix: mkNum(1)},
232 » » » » {c, mkNum(1), nil, nil}, 241 » » » » {c: c, prefix: mkNum(1)},
233 } 242 }
234 243
235 expect := []int64{2, 4} 244 expect := []int64{2, 4}
236 i := 0 245 i := 0
237 multiIterate(defs, func(suffix []byte) bool { 246 multiIterate(defs, func(suffix []byte) bool {
238 So(readNum(suffix), ShouldEqual, expect[i]) 247 So(readNum(suffix), ShouldEqual, expect[i])
239 i++ 248 i++
240 return true 249 return true
241 }) 250 })
242 }) 251 })
243 252
244 Convey("Can stop early", func() { 253 Convey("Can stop early", func() {
245 defs := []*iterDefinition{ 254 defs := []*iterDefinition{
246 » » » » {c, mkNum(1), nil, nil}, 255 » » » » {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) )},
247 » » » » {c, mkNum(1), nil, nil}, 256 » » » » {c: c, prefix: mkNum(1), prefixLen: len(mkNum(1) )},
248 } 257 }
249 258
250 i := 0 259 i := 0
251 multiIterate(defs, func(suffix []byte) bool { 260 multiIterate(defs, func(suffix []byte) bool {
252 So(readNum(suffix), ShouldEqual, vals[i][1]) 261 So(readNum(suffix), ShouldEqual, vals[i][1])
253 i++ 262 i++
254 return true 263 return true
255 }) 264 })
256 So(i, ShouldEqual, 5) 265 So(i, ShouldEqual, 5)
257 266
258 i = 0 267 i = 0
259 multiIterate(defs, func(suffix []byte) bool { 268 multiIterate(defs, func(suffix []byte) bool {
260 So(readNum(suffix), ShouldEqual, vals[i][1]) 269 So(readNum(suffix), ShouldEqual, vals[i][1])
261 i++ 270 i++
262 return false 271 return false
263 }) 272 })
264 So(i, ShouldEqual, 1) 273 So(i, ShouldEqual, 1)
265 }) 274 })
266 275
267 }) 276 })
268 277
269 } 278 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698