| 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 |