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 |