| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package memory | 5 package memory |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "testing" | 9 "testing" |
| 10 | 10 |
| 11 "github.com/luci/gae/service/datastore" | 11 "github.com/luci/gae/service/datastore" |
| 12 "github.com/luci/gae/service/datastore/serialize" | 12 "github.com/luci/gae/service/datastore/serialize" |
| 13 » "github.com/luci/gkvlite" | 13 |
| 14 "github.com/luci/luci-go/common/data/cmpbin" | 14 "github.com/luci/luci-go/common/data/cmpbin" |
| 15 |
| 15 . "github.com/smartystreets/goconvey/convey" | 16 . "github.com/smartystreets/goconvey/convey" |
| 16 ) | 17 ) |
| 17 | 18 |
| 18 func mkNum(n int64) []byte { | 19 func mkNum(n int64) []byte { |
| 19 buf := &bytes.Buffer{} | 20 buf := &bytes.Buffer{} |
| 20 _, err := cmpbin.WriteInt(buf, n) | 21 _, err := cmpbin.WriteInt(buf, n) |
| 21 memoryCorruption(err) | 22 memoryCorruption(err) |
| 22 | 23 |
| 23 return buf.Bytes() | 24 return buf.Bytes() |
| 24 } | 25 } |
| 25 | 26 |
| 26 func readNum(data []byte) int64 { | 27 func readNum(data []byte) int64 { |
| 27 ret, _, err := cmpbin.ReadInt(bytes.NewBuffer(data)) | 28 ret, _, err := cmpbin.ReadInt(bytes.NewBuffer(data)) |
| 28 memoryCorruption(err) | 29 memoryCorruption(err) |
| 29 | 30 |
| 30 return ret | 31 return ret |
| 31 } | 32 } |
| 32 | 33 |
| 34 func countItems(mc memCollection) int { |
| 35 count := 0 |
| 36 mc.ForEachItem(func(_, _ []byte) bool { |
| 37 count++ |
| 38 return true |
| 39 }) |
| 40 return count |
| 41 } |
| 42 |
| 33 func TestIterator(t *testing.T) { | 43 func TestIterator(t *testing.T) { |
| 34 t.Parallel() | 44 t.Parallel() |
| 35 | 45 |
| 36 s := newMemStore() | 46 s := newMemStore() |
| 37 c := s.GetOrCreateCollection("zup") | 47 c := s.GetOrCreateCollection("zup") |
| 38 prev := []byte{} | 48 prev := []byte{} |
| 39 for i := 5; i < 100; i++ { | 49 for i := 5; i < 100; i++ { |
| 40 data := mkNum(int64(i)) | 50 data := mkNum(int64(i)) |
| 41 c.Set(data, prev) | 51 c.Set(data, prev) |
| 42 prev = data | 52 prev = data |
| 43 } | 53 } |
| 44 c = s.Snapshot().GetCollection("zup") | 54 c = s.Snapshot().GetCollection("zup") |
| 45 | 55 |
| 56 iterCB := func(it *iterator, cb func(k, v []byte)) { |
| 57 for ent := it.next(); ent != nil; ent = it.next() { |
| 58 cb(ent.key, ent.value) |
| 59 } |
| 60 } |
| 61 |
| 46 get := func(c C, t *iterator) interface{} { | 62 get := func(c C, t *iterator) interface{} { |
| 47 » » ret := interface{}(nil) | 63 » » if ent := t.next(); ent != nil { |
| 48 » » t.next(nil, func(i *gkvlite.Item) { | 64 » » » return readNum(ent.key) |
| 49 » » » if i != nil { | 65 » » } |
| 50 » » » » ret = readNum(i.Key) | 66 » » return nil |
| 51 » » » } | |
| 52 » » }) | |
| 53 » » return ret | |
| 54 } | 67 } |
| 55 | 68 |
| 56 skipGet := func(c C, t *iterator, skipTo int64) interface{} { | 69 skipGet := func(c C, t *iterator, skipTo int64) interface{} { |
| 57 » » ret := interface{}(nil) | 70 » » t.skip(mkNum(skipTo)) |
| 58 » » t.next(mkNum(skipTo), func(i *gkvlite.Item) { | 71 » » return get(c, t) |
| 59 » » » if i != nil { | 72 » } |
| 60 » » » » ret = readNum(i.Key) | 73 |
| 61 » » » } | 74 » didIterate := func(t *iterator) (did bool) { |
| 75 » » iterCB(t, func(k, v []byte) { |
| 76 » » » did = true |
| 62 }) | 77 }) |
| 63 » » return ret | 78 » » return |
| 64 } | 79 } |
| 65 | 80 |
| 66 Convey("Test iterator", t, func() { | 81 Convey("Test iterator", t, func() { |
| 67 Convey("start at nil", func(ctx C) { | 82 Convey("start at nil", func(ctx C) { |
| 68 t := (&iterDefinition{c: c}).mkIter() | 83 t := (&iterDefinition{c: c}).mkIter() |
| 69 defer t.stop() | |
| 70 So(get(ctx, t), ShouldEqual, 5) | 84 So(get(ctx, t), ShouldEqual, 5) |
| 71 So(get(ctx, t), ShouldEqual, 6) | 85 So(get(ctx, t), ShouldEqual, 6) |
| 72 So(get(ctx, t), ShouldEqual, 7) | 86 So(get(ctx, t), ShouldEqual, 7) |
| 73 | 87 |
| 74 Convey("And can skip", func(ctx C) { | 88 Convey("And can skip", func(ctx C) { |
| 75 So(skipGet(ctx, t, 10), ShouldEqual, 10) | 89 So(skipGet(ctx, t, 10), ShouldEqual, 10) |
| 76 So(get(ctx, t), ShouldEqual, 11) | 90 So(get(ctx, t), ShouldEqual, 11) |
| 77 | 91 |
| 78 Convey("But not forever", func(ctx C) { | 92 Convey("But not forever", func(ctx C) { |
| 79 » » » » » t.next(mkNum(200), func(i *gkvlite.Item)
{ | 93 » » » » » t.skip(mkNum(200)) |
| 80 » » » » » » ctx.So(i, ShouldBeNil) | 94 » » » » » So(didIterate(t), ShouldBeFalse) |
| 81 » » » » » }) | 95 » » » » » So(didIterate(t), ShouldBeFalse) |
| 82 » » » » » t.next(nil, func(i *gkvlite.Item) { | |
| 83 » » » » » » ctx.So(i, ShouldBeNil) | |
| 84 » » » » » }) | |
| 85 }) | 96 }) |
| 86 }) | 97 }) |
| 87 | 98 |
| 88 Convey("Can iterate explicitly", func(ctx C) { | 99 Convey("Can iterate explicitly", func(ctx C) { |
| 89 So(skipGet(ctx, t, 7), ShouldEqual, 8) | 100 So(skipGet(ctx, t, 7), ShouldEqual, 8) |
| 90 So(skipGet(ctx, t, 8), ShouldEqual, 9) | 101 So(skipGet(ctx, t, 8), ShouldEqual, 9) |
| 91 | 102 |
| 92 // Giving the immediately next key doesn't cause
an internal reset. | 103 // Giving the immediately next key doesn't cause
an internal reset. |
| 93 So(skipGet(ctx, t, 10), ShouldEqual, 10) | 104 So(skipGet(ctx, t, 10), ShouldEqual, 10) |
| 94 }) | 105 }) |
| 95 | 106 |
| 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) { | 107 Convey("Going backwards is ignored", func(ctx C) { |
| 108 So(skipGet(ctx, t, 3), ShouldEqual, 8) | 108 So(skipGet(ctx, t, 3), ShouldEqual, 8) |
| 109 So(get(ctx, t), ShouldEqual, 9) | 109 So(get(ctx, t), ShouldEqual, 9) |
| 110 So(skipGet(ctx, t, 20), ShouldEqual, 20) | 110 So(skipGet(ctx, t, 20), ShouldEqual, 20) |
| 111 So(get(ctx, t), ShouldEqual, 21) | 111 So(get(ctx, t), ShouldEqual, 21) |
| 112 }) | 112 }) |
| 113 | 113 |
| 114 Convey("will stop at the end of the list", func(ctx C) { | 114 Convey("will stop at the end of the list", func(ctx C) { |
| 115 So(skipGet(ctx, t, 95), ShouldEqual, 95) | 115 So(skipGet(ctx, t, 95), ShouldEqual, 95) |
| 116 So(get(ctx, t), ShouldEqual, 96) | 116 So(get(ctx, t), ShouldEqual, 96) |
| 117 So(get(ctx, t), ShouldEqual, 97) | 117 So(get(ctx, t), ShouldEqual, 97) |
| 118 So(get(ctx, t), ShouldEqual, 98) | 118 So(get(ctx, t), ShouldEqual, 98) |
| 119 So(get(ctx, t), ShouldEqual, 99) | 119 So(get(ctx, t), ShouldEqual, 99) |
| 120 So(get(ctx, t), ShouldBeNil) | 120 So(get(ctx, t), ShouldBeNil) |
| 121 So(get(ctx, t), ShouldBeNil) | 121 So(get(ctx, t), ShouldBeNil) |
| 122 }) | 122 }) |
| 123 }) | 123 }) |
| 124 | 124 |
| 125 Convey("can have caps on both sides", func(ctx C) { | 125 Convey("can have caps on both sides", func(ctx C) { |
| 126 t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum
(25)}).mkIter() | 126 t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum
(25)}).mkIter() |
| 127 So(get(ctx, t), ShouldEqual, 20) | 127 So(get(ctx, t), ShouldEqual, 20) |
| 128 So(get(ctx, t), ShouldEqual, 21) | 128 So(get(ctx, t), ShouldEqual, 21) |
| 129 So(get(ctx, t), ShouldEqual, 22) | 129 So(get(ctx, t), ShouldEqual, 22) |
| 130 So(get(ctx, t), ShouldEqual, 23) | 130 So(get(ctx, t), ShouldEqual, 23) |
| 131 So(get(ctx, t), ShouldEqual, 24) | 131 So(get(ctx, t), ShouldEqual, 24) |
| 132 » » » t.next(nil, func(i *gkvlite.Item) { | 132 |
| 133 » » » » ctx.So(i, ShouldBeNil) | 133 » » » So(didIterate(t), ShouldBeFalse) |
| 134 » » » }) | |
| 135 }) | 134 }) |
| 136 | 135 |
| 137 Convey("can skip over starting cap", func(ctx C) { | 136 Convey("can skip over starting cap", func(ctx C) { |
| 138 t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum
(25)}).mkIter() | 137 t := (&iterDefinition{c: c, start: mkNum(20), end: mkNum
(25)}).mkIter() |
| 139 So(skipGet(ctx, t, 22), ShouldEqual, 22) | 138 So(skipGet(ctx, t, 22), ShouldEqual, 22) |
| 140 So(get(ctx, t), ShouldEqual, 23) | 139 So(get(ctx, t), ShouldEqual, 23) |
| 141 So(get(ctx, t), ShouldEqual, 24) | 140 So(get(ctx, t), ShouldEqual, 24) |
| 142 » » » t.next(nil, func(i *gkvlite.Item) { | 141 |
| 143 » » » » ctx.So(i, ShouldBeNil) | 142 » » » So(didIterate(t), ShouldBeFalse) |
| 144 » » » }) | |
| 145 }) | 143 }) |
| 146 | |
| 147 }) | 144 }) |
| 148 } | 145 } |
| 149 | 146 |
| 150 func TestMultiIteratorSimple(t *testing.T) { | 147 func TestMultiIteratorSimple(t *testing.T) { |
| 151 t.Parallel() | 148 t.Parallel() |
| 152 | 149 |
| 153 // Simulate an index with 2 columns (int and int). | 150 // Simulate an index with 2 columns (int and int). |
| 154 vals := [][]int64{ | 151 vals := [][]int64{ |
| 155 {1, 0}, | 152 {1, 0}, |
| 156 {1, 2}, | 153 {1, 2}, |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 So(readNum(suffix), ShouldEqual, vals[i][1]) | 271 So(readNum(suffix), ShouldEqual, vals[i][1]) |
| 275 i++ | 272 i++ |
| 276 return datastore.Stop | 273 return datastore.Stop |
| 277 }), shouldBeSuccessful) | 274 }), shouldBeSuccessful) |
| 278 So(i, ShouldEqual, 1) | 275 So(i, ShouldEqual, 1) |
| 279 }) | 276 }) |
| 280 | 277 |
| 281 }) | 278 }) |
| 282 | 279 |
| 283 } | 280 } |
| OLD | NEW |