OLD | NEW |
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 "sort" |
8 "testing" | 9 "testing" |
9 "time" | 10 "time" |
10 | 11 |
11 ds "github.com/luci/gae/service/datastore" | 12 ds "github.com/luci/gae/service/datastore" |
12 "github.com/luci/gkvlite" | 13 "github.com/luci/gkvlite" |
13 . "github.com/smartystreets/goconvey/convey" | 14 . "github.com/smartystreets/goconvey/convey" |
14 ) | 15 ) |
15 | 16 |
16 func init() { | |
17 indexCreationDeterministic = true | |
18 } | |
19 | |
20 var fakeKey = key("knd", 10, key("parentKind", "sid")) | 17 var fakeKey = key("knd", 10, key("parentKind", "sid")) |
21 | 18 |
22 func TestCollated(t *testing.T) { | 19 func TestCollated(t *testing.T) { |
23 t.Parallel() | 20 t.Parallel() |
24 | 21 |
25 Convey("TestCollated", t, func() { | 22 Convey("TestCollated", t, func() { |
26 Convey("nil list", func() { | 23 Convey("nil list", func() { |
27 » » » pm := (ds.PropertyMap)(nil) | 24 » » » pm := ds.PropertyMap(nil) |
28 » » » sip := partiallySerialize(pm) | 25 » » » sip := partiallySerialize(fakeKey, pm) |
29 » » » So(sip, ShouldBeNil) | |
30 | 26 |
31 Convey("nil collated", func() { | 27 Convey("nil collated", func() { |
32 » » » » Convey("defaultIndicies", func() { | 28 » » » » Convey("defaultIndexes", func() { |
33 » » » » » idxs := defaultIndicies("knd", pm) | 29 » » » » » idxs := defaultIndexes("knd", pm) |
34 So(len(idxs), ShouldEqual, 1) | 30 So(len(idxs), ShouldEqual, 1) |
35 So(idxs[0].String(), ShouldEqual, "B:knd
") | 31 So(idxs[0].String(), ShouldEqual, "B:knd
") |
36 }) | 32 }) |
37 Convey("indexEntries", func() { | 33 Convey("indexEntries", func() { |
38 » » » » » s := sip.indexEntries(fakeKey, defaultIn
dicies("knd", pm)) | 34 » » » » » s := sip.indexEntries("ns", defaultIndex
es("knd", pm)) |
39 numItems, _ := s.GetCollection("idx").Ge
tTotals() | 35 numItems, _ := s.GetCollection("idx").Ge
tTotals() |
40 So(numItems, ShouldEqual, 1) | 36 So(numItems, ShouldEqual, 1) |
41 itm := s.GetCollection("idx").MinItem(fa
lse) | 37 itm := s.GetCollection("idx").MinItem(fa
lse) |
42 » » » » » So(itm.Key, ShouldResemble, cat(indx("kn
d"))) | 38 » » » » » So(itm.Key, ShouldResemble, cat(indx("kn
d").PrepForIdxTable())) |
43 numItems, _ = s.GetCollection("idx:ns:"
+ string(itm.Key)).GetTotals() | 39 numItems, _ = s.GetCollection("idx:ns:"
+ string(itm.Key)).GetTotals() |
44 So(numItems, ShouldEqual, 1) | 40 So(numItems, ShouldEqual, 1) |
45 }) | 41 }) |
46 }) | 42 }) |
47 }) | 43 }) |
48 | 44 |
49 Convey("list", func() { | 45 Convey("list", func() { |
50 pm := ds.PropertyMap{ | 46 pm := ds.PropertyMap{ |
51 "wat": {propNI("thing"), prop("hat"), prop(100)
}, | 47 "wat": {propNI("thing"), prop("hat"), prop(100)
}, |
52 "nerd": {prop(103.7)}, | 48 "nerd": {prop(103.7)}, |
53 "spaz": {propNI(false)}, | 49 "spaz": {propNI(false)}, |
54 } | 50 } |
55 » » » sip := partiallySerialize(pm) | 51 » » » sip := partiallySerialize(fakeKey, pm) |
56 » » » So(len(sip), ShouldEqual, 2) | 52 » » » So(len(sip), ShouldEqual, 4) |
57 | 53 |
58 Convey("single collated", func() { | 54 Convey("single collated", func() { |
59 Convey("indexableMap", func() { | 55 Convey("indexableMap", func() { |
60 So(sip, ShouldResemble, serializedIndexa
blePmap{ | 56 So(sip, ShouldResemble, serializedIndexa
blePmap{ |
61 "wat": { | 57 "wat": { |
62 » » » » » » » cat(ds.PTInt, 100), | 58 » » » » » » » cat(prop("hat")), |
63 » » » » » » » cat(ds.PTString, "hat"), | 59 » » » » » » » cat(prop(100)), |
64 // 'thing' is skipped, b
ecause it's not NoIndex | 60 // 'thing' is skipped, b
ecause it's not NoIndex |
65 }, | 61 }, |
66 "nerd": { | 62 "nerd": { |
67 » » » » » » » cat(ds.PTFloat, 103.7), | 63 » » » » » » » cat(prop(103.7)), |
| 64 » » » » » » }, |
| 65 » » » » » » "__key__": { |
| 66 » » » » » » » cat(prop(fakeKey)), |
| 67 » » » » » » }, |
| 68 » » » » » » "__ancestor__": { |
| 69 » » » » » » » cat(prop(fakeKey)), |
| 70 » » » » » » » cat(prop(fakeKey.Parent(
))), |
68 }, | 71 }, |
69 }) | 72 }) |
70 }) | 73 }) |
71 » » » » Convey("defaultIndicies", func() { | 74 » » » » Convey("defaultIndexes", func() { |
72 » » » » » idxs := defaultIndicies("knd", pm) | 75 » » » » » idxs := defaultIndexes("knd", pm) |
73 So(len(idxs), ShouldEqual, 5) | 76 So(len(idxs), ShouldEqual, 5) |
74 So(idxs[0].String(), ShouldEqual, "B:knd
") | 77 So(idxs[0].String(), ShouldEqual, "B:knd
") |
75 So(idxs[1].String(), ShouldEqual, "B:knd
/nerd") | 78 So(idxs[1].String(), ShouldEqual, "B:knd
/nerd") |
76 So(idxs[2].String(), ShouldEqual, "B:knd
/wat") | 79 So(idxs[2].String(), ShouldEqual, "B:knd
/wat") |
77 So(idxs[3].String(), ShouldEqual, "B:knd
/-nerd") | 80 So(idxs[3].String(), ShouldEqual, "B:knd
/-nerd") |
78 So(idxs[4].String(), ShouldEqual, "B:knd
/-wat") | 81 So(idxs[4].String(), ShouldEqual, "B:knd
/-wat") |
79 }) | 82 }) |
80 }) | 83 }) |
81 }) | 84 }) |
82 }) | 85 }) |
83 } | 86 } |
84 | 87 |
85 var rgenComplexTime = time.Date( | 88 var rgenComplexTime = time.Date( |
86 1986, time.October, 26, 1, 20, 00, 00, time.UTC) | 89 1986, time.October, 26, 1, 20, 00, 00, time.UTC) |
87 var rgenComplexKey = key("kind", "id") | 90 var rgenComplexKey = key("kind", "id") |
88 | 91 |
89 var rowGenTestCases = []struct { | 92 var rowGenTestCases = []struct { |
90 name string | 93 name string |
91 pmap ds.PropertyMap | 94 pmap ds.PropertyMap |
92 withBuiltin bool | 95 withBuiltin bool |
93 idxs []*ds.IndexDefinition | 96 idxs []*ds.IndexDefinition |
94 | 97 |
95 // These are checked in TestIndexRowGen. nil to skip test case. | 98 // These are checked in TestIndexRowGen. nil to skip test case. |
96 expected []serializedPvals | 99 expected []serializedPvals |
97 | 100 |
98 // just the collections you want to assert. These are checked in | 101 // just the collections you want to assert. These are checked in |
99 // TestIndexEntries. nil to skip test case. | 102 // TestIndexEntries. nil to skip test case. |
100 » collections map[string][]kv | 103 » collections map[string][][]byte |
101 }{ | 104 }{ |
| 105 |
102 { | 106 { |
103 name: "simple including builtins", | 107 name: "simple including builtins", |
104 pmap: ds.PropertyMap{ | 108 pmap: ds.PropertyMap{ |
105 "wat": {propNI("thing"), prop("hat"), prop(100)}, | 109 "wat": {propNI("thing"), prop("hat"), prop(100)}, |
106 "nerd": {prop(103.7)}, | 110 "nerd": {prop(103.7)}, |
107 "spaz": {propNI(false)}, | 111 "spaz": {propNI(false)}, |
108 }, | 112 }, |
109 withBuiltin: true, | 113 withBuiltin: true, |
110 idxs: []*ds.IndexDefinition{ | 114 idxs: []*ds.IndexDefinition{ |
111 indx("knd", "-wat", "nerd"), | 115 indx("knd", "-wat", "nerd"), |
112 }, | 116 }, |
113 expected: []serializedPvals{ | 117 expected: []serializedPvals{ |
114 » » » {{}}, // B:knd | 118 » » » {cat(prop(fakeKey))}, // B:knd |
115 » » » {cat(ds.PTFloat, 103.7)}, // B:kn
d/nerd | 119 » » » {cat(prop(103.7), prop(fakeKey))}, // B:knd/nerd |
116 » » » {cat(ds.PTInt, 100), cat(ds.PTString, "hat")}, // B:kn
d/wat | 120 » » » { // B:knd/wat |
117 » » » {icat(ds.PTFloat, 103.7)}, // B:kn
d/-nerd | 121 » » » » cat(prop(100), prop(fakeKey)), |
118 » » » {icat(ds.PTString, "hat"), icat(ds.PTInt, 100)}, // B:kn
d/-wat | 122 » » » » cat(prop("hat"), prop(fakeKey)), |
| 123 » » » }, |
| 124 » » » { // B:knd/-nerd |
| 125 » » » » cat(icat(prop(103.7)), prop(fakeKey)), |
| 126 » » » }, |
| 127 » » » { // B:knd/-wat |
| 128 » » » » cat(icat(prop("hat")), prop(fakeKey)), |
| 129 » » » » cat(icat(prop(100)), prop(fakeKey)), |
| 130 » » » }, |
119 { // C:knd/-wat/nerd | 131 { // C:knd/-wat/nerd |
120 » » » » cat(icat(ds.PTString, "hat"), cat(ds.PTFloat, 10
3.7)), | 132 » » » » cat(icat(prop("hat")), prop(103.7), prop(fakeKey
)), |
121 » » » » cat(icat(ds.PTInt, 100), cat(ds.PTFloat, 103.7))
, | 133 » » » » cat(icat(prop(100)), prop(103.7), prop(fakeKey))
, |
122 }, | 134 }, |
123 }, | 135 }, |
124 » » collections: map[string][]kv{ | 136 |
| 137 » » collections: map[string][][]byte{ |
125 "idx": { | 138 "idx": { |
126 » » » » // 0 == builtin, 1 == complex | 139 » » » » cat("knd", byte(0), byte(1), byte(0), "__key__",
byte(0)), |
127 » » » » {cat(byte(0), "knd", byte(0), 0), []byte{}}, | 140 » » » » cat("knd", byte(0), byte(1), byte(0), "__key__",
byte(1), byte(0), "nerd", byte(0)), |
128 » » » » {cat(byte(0), "knd", byte(0), 1, byte(0), "nerd"
), []byte{}}, | 141 » » » » cat("knd", byte(0), byte(1), byte(0), "__key__",
byte(1), byte(0), "nerd", byte(1), byte(1), "wat", byte(0)), |
129 » » » » {cat(byte(0), "knd", byte(0), 1, byte(0), "wat")
, []byte{}}, | 142 » » » » cat("knd", byte(0), byte(1), byte(0), "__key__",
byte(1), byte(0), "wat", byte(0)), |
130 » » » » {cat(byte(0), "knd", byte(0), 1, byte(1), "nerd"
), []byte{}}, | 143 » » » » cat("knd", byte(0), byte(1), byte(0), "__key__",
byte(1), byte(1), "nerd", byte(0)), |
131 » » » » {cat(byte(0), "knd", byte(0), 1, byte(1), "wat")
, []byte{}}, | 144 » » » » cat("knd", byte(0), byte(1), byte(0), "__key__",
byte(1), byte(1), "wat", byte(0)), |
132 » » » » {cat(byte(1), "knd", byte(0), 2, byte(1), "wat",
byte(0), "nerd"), []byte{}}, | |
133 }, | 145 }, |
134 » » » "idx:ns:" + sat(indx("knd")): { | 146 » » » "idx:ns:" + sat(indx("knd").PrepForIdxTable()): { |
135 » » » » {cat(fakeKey), []byte{}}, | 147 » » » » cat(prop(fakeKey)), |
136 }, | 148 }, |
137 » » » "idx:ns:" + sat(indx("knd", "wat")): { | 149 » » » "idx:ns:" + sat(indx("knd", "wat").PrepForIdxTable()): { |
138 » » » » {cat(ds.PTInt, 100, fakeKey), []byte{}}, | 150 » » » » cat(prop(100), prop(fakeKey)), |
139 » » » » {cat(ds.PTString, "hat", fakeKey), cat(ds.PTInt,
100)}, | 151 » » » » cat(prop("hat"), prop(fakeKey)), |
140 }, | 152 }, |
141 » » » "idx:ns:" + sat(indx("knd", "-wat")): { | 153 » » » "idx:ns:" + sat(indx("knd", "-wat").PrepForIdxTable()):
{ |
142 » » » » {cat(icat(ds.PTString, "hat"), fakeKey), []byte{
}}, | 154 » » » » cat(icat(prop("hat")), prop(fakeKey)), |
143 » » » » {cat(icat(ds.PTInt, 100), fakeKey), icat(ds.PTSt
ring, "hat")}, | 155 » » » » cat(icat(prop(100)), prop(fakeKey)), |
144 }, | 156 }, |
145 }, | 157 }, |
146 }, | 158 }, |
| 159 |
147 { | 160 { |
148 name: "complex", | 161 name: "complex", |
149 pmap: ds.PropertyMap{ | 162 pmap: ds.PropertyMap{ |
150 "yerp": {prop("hat"), prop(73.9)}, | 163 "yerp": {prop("hat"), prop(73.9)}, |
151 "wat": { | 164 "wat": { |
152 prop(rgenComplexTime), | 165 prop(rgenComplexTime), |
153 prop(ds.ByteString("value")), | 166 prop(ds.ByteString("value")), |
154 prop(rgenComplexKey)}, | 167 prop(rgenComplexKey)}, |
155 "spaz": {prop(nil), prop(false), prop(true)}, | 168 "spaz": {prop(nil), prop(false), prop(true)}, |
156 }, | 169 }, |
157 idxs: []*ds.IndexDefinition{ | 170 idxs: []*ds.IndexDefinition{ |
158 indx("knd", "-wat", "nerd", "spaz"), // doesn't match, s
o empty | 171 indx("knd", "-wat", "nerd", "spaz"), // doesn't match, s
o empty |
159 indx("knd", "yerp", "-wat", "spaz"), | 172 indx("knd", "yerp", "-wat", "spaz"), |
160 }, | 173 }, |
161 expected: []serializedPvals{ | 174 expected: []serializedPvals{ |
162 {}, // C:knd/-wat/nerd/spaz, no match | 175 {}, // C:knd/-wat/nerd/spaz, no match |
163 { // C:knd/yerp/-wat/spaz | 176 { // C:knd/yerp/-wat/spaz |
164 // thank goodness the binary serialization only
happens 1/val in the | 177 // thank goodness the binary serialization only
happens 1/val in the |
165 // real code :). | 178 // real code :). |
166 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTKey, rgen
ComplexKey), cat(ds.PTNull)), | 179 » » » » cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(nil), prop(fakeKey)), |
167 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTKey, rgen
ComplexKey), cat(ds.PTBoolFalse)), | 180 » » » » cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(false), prop(fakeKey)), |
168 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTKey, rgen
ComplexKey), cat(ds.PTBoolTrue)), | 181 » » » » cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(true), prop(fakeKey)), |
169 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTBytes, "v
alue"), cat(ds.PTNull)), | 182 » » » » cat(prop("hat"), icat(prop(ds.ByteString("value"
))), prop(nil), prop(fakeKey)), |
170 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTBytes, "v
alue"), cat(ds.PTBoolFalse)), | 183 » » » » cat(prop("hat"), icat(prop(ds.ByteString("value"
))), prop(false), prop(fakeKey)), |
171 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTBytes, "v
alue"), cat(ds.PTBoolTrue)), | 184 » » » » cat(prop("hat"), icat(prop(ds.ByteString("value"
))), prop(true), prop(fakeKey)), |
172 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTTime, rge
nComplexTime), cat(ds.PTNull)), | 185 » » » » cat(prop("hat"), icat(prop(rgenComplexTime)), pr
op(nil), prop(fakeKey)), |
173 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTTime, rge
nComplexTime), cat(ds.PTBoolFalse)), | 186 » » » » cat(prop("hat"), icat(prop(rgenComplexTime)), pr
op(false), prop(fakeKey)), |
174 » » » » cat(cat(ds.PTString, "hat"), icat(ds.PTTime, rge
nComplexTime), cat(ds.PTBoolTrue)), | 187 » » » » cat(prop("hat"), icat(prop(rgenComplexTime)), pr
op(true), prop(fakeKey)), |
175 | 188 |
176 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTKey, rgenCo
mplexKey), cat(ds.PTNull)), | 189 » » » » cat(prop(73.9), icat(prop(rgenComplexKey)), prop
(nil), prop(fakeKey)), |
177 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTKey, rgenCo
mplexKey), cat(ds.PTBoolFalse)), | 190 » » » » cat(prop(73.9), icat(prop(rgenComplexKey)), prop
(false), prop(fakeKey)), |
178 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTKey, rgenCo
mplexKey), cat(ds.PTBoolTrue)), | 191 » » » » cat(prop(73.9), icat(prop(rgenComplexKey)), prop
(true), prop(fakeKey)), |
179 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTBytes, "val
ue"), cat(ds.PTNull)), | 192 » » » » cat(prop(73.9), icat(prop(ds.ByteString("value")
)), prop(nil), prop(fakeKey)), |
180 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTBytes, "val
ue"), cat(ds.PTBoolFalse)), | 193 » » » » cat(prop(73.9), icat(prop(ds.ByteString("value")
)), prop(false), prop(fakeKey)), |
181 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTBytes, "val
ue"), cat(ds.PTBoolTrue)), | 194 » » » » cat(prop(73.9), icat(prop(ds.ByteString("value")
)), prop(true), prop(fakeKey)), |
182 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTTime, rgenC
omplexTime), cat(ds.PTNull)), | 195 » » » » cat(prop(73.9), icat(prop(rgenComplexTime)), pro
p(nil), prop(fakeKey)), |
183 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTTime, rgenC
omplexTime), cat(ds.PTBoolFalse)), | 196 » » » » cat(prop(73.9), icat(prop(rgenComplexTime)), pro
p(false), prop(fakeKey)), |
184 » » » » cat(cat(ds.PTFloat, 73.9), icat(ds.PTTime, rgenC
omplexTime), cat(ds.PTBoolTrue)), | 197 » » » » cat(prop(73.9), icat(prop(rgenComplexTime)), pro
p(true), prop(fakeKey)), |
185 }, | 198 }, |
186 }, | 199 }, |
187 }, | 200 }, |
| 201 |
188 { | 202 { |
189 name: "ancestor", | 203 name: "ancestor", |
190 pmap: ds.PropertyMap{ | 204 pmap: ds.PropertyMap{ |
191 "wat": {prop("sup")}, | 205 "wat": {prop("sup")}, |
192 }, | 206 }, |
193 idxs: []*ds.IndexDefinition{ | 207 idxs: []*ds.IndexDefinition{ |
194 indx("knd!", "wat"), | 208 indx("knd!", "wat"), |
195 }, | 209 }, |
196 » » collections: map[string][]kv{ | 210 » » collections: map[string][][]byte{ |
197 » » » "idx:ns:" + sat(indx("knd!", "wat")): { | 211 » » » "idx:ns:" + sat(indx("knd!", "wat").PrepForIdxTable()):
{ |
198 » » » » {cat(fakeKey.Parent(), ds.PTString, "sup", fakeK
ey), []byte{}}, | 212 » » » » cat(prop(fakeKey.Parent()), prop("sup"), prop(fa
keKey)), |
199 » » » » {cat(fakeKey, ds.PTString, "sup", fakeKey), []by
te{}}, | 213 » » » » cat(prop(fakeKey), prop("sup"), prop(fakeKey)), |
200 }, | 214 }, |
201 }, | 215 }, |
202 }, | 216 }, |
203 } | 217 } |
204 | 218 |
205 func TestIndexRowGen(t *testing.T) { | 219 func TestIndexRowGen(t *testing.T) { |
206 t.Parallel() | 220 t.Parallel() |
207 | 221 |
208 Convey("Test Index Row Generation", t, func() { | 222 Convey("Test Index Row Generation", t, func() { |
209 for _, tc := range rowGenTestCases { | 223 for _, tc := range rowGenTestCases { |
210 if tc.expected == nil { | 224 if tc.expected == nil { |
211 Convey(tc.name, nil) // shows up as 'skipped' | 225 Convey(tc.name, nil) // shows up as 'skipped' |
212 continue | 226 continue |
213 } | 227 } |
214 | 228 |
215 Convey(tc.name, func() { | 229 Convey(tc.name, func() { |
216 » » » » mvals := partiallySerialize(tc.pmap) | 230 » » » » mvals := partiallySerialize(fakeKey, tc.pmap) |
217 idxs := []*ds.IndexDefinition(nil) | 231 idxs := []*ds.IndexDefinition(nil) |
218 if tc.withBuiltin { | 232 if tc.withBuiltin { |
219 » » » » » idxs = append(defaultIndicies("coolKind"
, tc.pmap), tc.idxs...) | 233 » » » » » idxs = append(defaultIndexes("coolKind",
tc.pmap), tc.idxs...) |
220 } else { | 234 } else { |
221 idxs = tc.idxs | 235 idxs = tc.idxs |
222 } | 236 } |
223 | 237 |
224 m := matcher{} | 238 m := matcher{} |
225 for i, idx := range idxs { | 239 for i, idx := range idxs { |
226 Convey(idx.String(), func() { | 240 Convey(idx.String(), func() { |
227 » » » » » » iGen, ok := m.match(idx, mvals) | 241 » » » » » » iGen, ok := m.match(idx.GetFullS
ortOrder(), mvals) |
228 if len(tc.expected[i]) > 0 { | 242 if len(tc.expected[i]) > 0 { |
229 So(ok, ShouldBeTrue) | 243 So(ok, ShouldBeTrue) |
230 » » » » » » » j := 0 | 244 » » » » » » » actual := make(serialize
dPvals, 0, len(tc.expected[i])) |
231 » » » » » » » iGen.permute(func(row []
byte) { | 245 » » » » » » » iGen.permute(func(row, _
[]byte) { |
232 » » » » » » » » So([]byte(row),
ShouldResemble, tc.expected[i][j]) | 246 » » » » » » » » actual = append(
actual, row) |
233 » » » » » » » » j++ | |
234 }) | 247 }) |
235 » » » » » » » So(j, ShouldEqual, len(t
c.expected[i])) | 248 » » » » » » » So(len(actual), ShouldEq
ual, len(tc.expected[i])) |
| 249 » » » » » » » sort.Sort(actual) |
| 250 » » » » » » » for j, act := range actu
al { |
| 251 » » » » » » » » So(act, ShouldRe
semble, tc.expected[i][j]) |
| 252 » » » » » » » } |
236 } else { | 253 } else { |
237 So(ok, ShouldBeFalse) | 254 So(ok, ShouldBeFalse) |
238 } | 255 } |
239 }) | 256 }) |
240 } | 257 } |
241 }) | 258 }) |
242 } | 259 } |
243 }) | 260 }) |
244 } | 261 } |
245 | 262 |
246 func TestIndexEntries(t *testing.T) { | 263 func TestIndexEntries(t *testing.T) { |
247 t.Parallel() | 264 t.Parallel() |
248 | 265 |
249 Convey("Test indexEntriesWithBuiltins", t, func() { | 266 Convey("Test indexEntriesWithBuiltins", t, func() { |
250 for _, tc := range rowGenTestCases { | 267 for _, tc := range rowGenTestCases { |
251 if tc.collections == nil { | 268 if tc.collections == nil { |
252 Convey(tc.name, nil) // shows up as 'skipped' | 269 Convey(tc.name, nil) // shows up as 'skipped' |
253 continue | 270 continue |
254 } | 271 } |
255 | 272 |
256 Convey(tc.name, func() { | 273 Convey(tc.name, func() { |
257 store := (*memStore)(nil) | 274 store := (*memStore)(nil) |
258 if tc.withBuiltin { | 275 if tc.withBuiltin { |
259 store = indexEntriesWithBuiltins(fakeKey
, tc.pmap, tc.idxs) | 276 store = indexEntriesWithBuiltins(fakeKey
, tc.pmap, tc.idxs) |
260 } else { | 277 } else { |
261 » » » » » store = partiallySerialize(tc.pmap).inde
xEntries(fakeKey, tc.idxs) | 278 » » » » » store = partiallySerialize(fakeKey, tc.p
map).indexEntries(fakeKey.Namespace(), tc.idxs) |
262 } | 279 } |
263 for colName, vals := range tc.collections { | 280 for colName, vals := range tc.collections { |
264 i := 0 | 281 i := 0 |
265 » » » » » store.GetCollection(colName).VisitItemsA
scend(nil, true, func(itm *gkvlite.Item) bool { | 282 » » » » » coll := store.GetCollection(colName) |
266 » » » » » » So(itm.Key, ShouldResemble, vals
[i].k) | 283 » » » » » numItems, _ := coll.GetTotals() |
267 » » » » » » So(itm.Val, ShouldResemble, vals
[i].v) | 284 » » » » » So(numItems, ShouldEqual, len(tc.collect
ions[colName])) |
| 285 » » » » » coll.VisitItemsAscend(nil, true, func(it
m *gkvlite.Item) bool { |
| 286 » » » » » » So(itm.Key, ShouldResemble, vals
[i]) |
268 i++ | 287 i++ |
269 return true | 288 return true |
270 }) | 289 }) |
271 So(i, ShouldEqual, len(vals)) | 290 So(i, ShouldEqual, len(vals)) |
272 } | 291 } |
273 }) | 292 }) |
274 } | 293 } |
275 }) | 294 }) |
276 } | 295 } |
277 | 296 |
278 type dumbItem struct { | 297 type dumbItem struct { |
279 key ds.Key | 298 key ds.Key |
280 props ds.PropertyMap | 299 props ds.PropertyMap |
281 } | 300 } |
282 | 301 |
283 var updateIndiciesTests = []struct { | 302 var updateIndexesTests = []struct { |
284 name string | 303 name string |
285 idxs []*ds.IndexDefinition | 304 idxs []*ds.IndexDefinition |
286 data []dumbItem | 305 data []dumbItem |
287 expected map[string][][]byte | 306 expected map[string][][]byte |
288 }{ | 307 }{ |
| 308 |
289 { | 309 { |
290 name: "basic", | 310 name: "basic", |
291 data: []dumbItem{ | 311 data: []dumbItem{ |
292 {key("knd", 1), ds.PropertyMap{ | 312 {key("knd", 1), ds.PropertyMap{ |
293 "wat": {prop(10)}, | 313 "wat": {prop(10)}, |
294 "yerp": {prop(10)}}, | 314 "yerp": {prop(10)}}, |
295 }, | 315 }, |
296 {key("knd", 10), ds.PropertyMap{ | 316 {key("knd", 10), ds.PropertyMap{ |
297 "wat": {prop(1)}, | 317 "wat": {prop(1)}, |
298 "yerp": {prop(200)}}, | 318 "yerp": {prop(200)}}, |
299 }, | 319 }, |
300 {key("knd", 1), ds.PropertyMap{ | 320 {key("knd", 1), ds.PropertyMap{ |
301 "wat": {prop(10)}, | 321 "wat": {prop(10)}, |
302 "yerp": {prop(202)}}, | 322 "yerp": {prop(202)}}, |
303 }, | 323 }, |
304 }, | 324 }, |
305 expected: map[string][][]byte{ | 325 expected: map[string][][]byte{ |
306 » » » "idx:ns:" + sat(indx("knd", "wat")): { | 326 » » » "idx:ns:" + sat(indx("knd", "wat").PrepForIdxTable()): { |
307 » » » » cat(ds.PTInt, 1, key("knd", 10)), | 327 » » » » cat(prop(1), prop(key("knd", 10))), |
308 » » » » cat(ds.PTInt, 10, key("knd", 1)), | 328 » » » » cat(prop(10), prop(key("knd", 1))), |
309 }, | 329 }, |
310 » » » "idx:ns:" + sat(indx("knd", "-wat")): { | 330 » » » "idx:ns:" + sat(indx("knd", "-wat").PrepForIdxTable()):
{ |
311 » » » » cat(icat(ds.PTInt, 10), key("knd", 1)), | 331 » » » » cat(icat(prop(10)), prop(key("knd", 1))), |
312 » » » » cat(icat(ds.PTInt, 1), key("knd", 10)), | 332 » » » » cat(icat(prop(1)), prop(key("knd", 10))), |
313 }, | 333 }, |
314 » » » "idx:ns:" + sat(indx("knd", "yerp")): { | 334 » » » "idx:ns:" + sat(indx("knd", "yerp").PrepForIdxTable()):
{ |
315 » » » » cat(ds.PTInt, 200, key("knd", 10)), | 335 » » » » cat(prop(200), prop(key("knd", 10))), |
316 » » » » cat(ds.PTInt, 202, key("knd", 1)), | 336 » » » » cat(prop(202), prop(key("knd", 1))), |
317 }, | 337 }, |
318 }, | 338 }, |
319 }, | 339 }, |
| 340 |
320 { | 341 { |
321 name: "compound", | 342 name: "compound", |
322 idxs: []*ds.IndexDefinition{indx("knd", "yerp", "-wat")}, | 343 idxs: []*ds.IndexDefinition{indx("knd", "yerp", "-wat")}, |
323 data: []dumbItem{ | 344 data: []dumbItem{ |
324 {key("knd", 1), ds.PropertyMap{ | 345 {key("knd", 1), ds.PropertyMap{ |
325 "wat": {prop(10)}, | 346 "wat": {prop(10)}, |
326 "yerp": {prop(100)}}, | 347 "yerp": {prop(100)}}, |
327 }, | 348 }, |
328 {key("knd", 10), ds.PropertyMap{ | 349 {key("knd", 10), ds.PropertyMap{ |
329 "wat": {prop(1)}, | 350 "wat": {prop(1)}, |
330 "yerp": {prop(200)}}, | 351 "yerp": {prop(200)}}, |
331 }, | 352 }, |
332 {key("knd", 11), ds.PropertyMap{ | 353 {key("knd", 11), ds.PropertyMap{ |
333 "wat": {prop(20)}, | 354 "wat": {prop(20)}, |
334 "yerp": {prop(200)}}, | 355 "yerp": {prop(200)}}, |
335 }, | 356 }, |
336 {key("knd", 14), ds.PropertyMap{ | 357 {key("knd", 14), ds.PropertyMap{ |
337 "wat": {prop(20)}, | 358 "wat": {prop(20)}, |
338 "yerp": {prop(200)}}, | 359 "yerp": {prop(200)}}, |
339 }, | 360 }, |
340 {key("knd", 1), ds.PropertyMap{ | 361 {key("knd", 1), ds.PropertyMap{ |
341 "wat": {prop(10)}, | 362 "wat": {prop(10)}, |
342 "yerp": {prop(202)}}, | 363 "yerp": {prop(202)}}, |
343 }, | 364 }, |
344 }, | 365 }, |
345 expected: map[string][][]byte{ | 366 expected: map[string][][]byte{ |
346 » » » "idx:ns:" + sat(indx("knd", "yerp", "-wat")): { | 367 » » » "idx:ns:" + sat(indx("knd", "yerp", "-wat").PrepForIdxTa
ble()): { |
347 » » » » cat(ds.PTInt, 200, icat(ds.PTInt, 20), key("knd"
, 11)), | 368 » » » » cat(prop(200), icat(prop(20)), prop(key("knd", 1
1))), |
348 » » » » cat(ds.PTInt, 200, icat(ds.PTInt, 20), key("knd"
, 14)), | 369 » » » » cat(prop(200), icat(prop(20)), prop(key("knd", 1
4))), |
349 » » » » cat(ds.PTInt, 200, icat(ds.PTInt, 1), key("knd",
10)), | 370 » » » » cat(prop(200), icat(prop(1)), prop(key("knd", 10
))), |
350 » » » » cat(ds.PTInt, 202, icat(ds.PTInt, 10), key("knd"
, 1)), | 371 » » » » cat(prop(202), icat(prop(10)), prop(key("knd", 1
))), |
351 }, | 372 }, |
352 }, | 373 }, |
353 }, | 374 }, |
354 } | 375 } |
355 | 376 |
356 func TestUpdateIndicies(t *testing.T) { | 377 func TestUpdateIndexes(t *testing.T) { |
357 t.Parallel() | 378 t.Parallel() |
358 | 379 |
359 » Convey("Test updateIndicies", t, func() { | 380 » Convey("Test updateIndexes", t, func() { |
360 » » for _, tc := range updateIndiciesTests { | 381 » » for _, tc := range updateIndexesTests { |
361 Convey(tc.name, func() { | 382 Convey(tc.name, func() { |
362 store := newMemStore() | 383 store := newMemStore() |
363 idxColl := store.SetCollection("idx", nil) | 384 idxColl := store.SetCollection("idx", nil) |
364 for _, i := range tc.idxs { | 385 for _, i := range tc.idxs { |
365 » » » » » idxColl.Set(cat(i), []byte{}) | 386 » » » » » idxColl.Set(cat(i.PrepForIdxTable()), []
byte{}) |
366 } | 387 } |
367 | 388 |
368 tmpLoader := map[string]ds.PropertyMap{} | 389 tmpLoader := map[string]ds.PropertyMap{} |
369 for _, itm := range tc.data { | 390 for _, itm := range tc.data { |
370 ks := itm.key.String() | 391 ks := itm.key.String() |
371 prev := tmpLoader[ks] | 392 prev := tmpLoader[ks] |
372 » » » » » updateIndicies(store, itm.key, prev, itm
.props) | 393 » » » » » updateIndexes(store, itm.key, prev, itm.
props) |
373 tmpLoader[ks] = itm.props | 394 tmpLoader[ks] = itm.props |
374 } | 395 } |
375 tmpLoader = nil | 396 tmpLoader = nil |
376 | 397 |
377 for colName, data := range tc.expected { | 398 for colName, data := range tc.expected { |
378 coll := store.GetCollection(colName) | 399 coll := store.GetCollection(colName) |
379 So(coll, ShouldNotBeNil) | 400 So(coll, ShouldNotBeNil) |
380 i := 0 | 401 i := 0 |
381 coll.VisitItemsAscend(nil, false, func(i
tm *gkvlite.Item) bool { | 402 coll.VisitItemsAscend(nil, false, func(i
tm *gkvlite.Item) bool { |
382 So(data[i], ShouldResemble, itm.
Key) | 403 So(data[i], ShouldResemble, itm.
Key) |
383 i++ | 404 i++ |
384 return true | 405 return true |
385 }) | 406 }) |
386 So(i, ShouldEqual, len(data)) | 407 So(i, ShouldEqual, len(data)) |
387 } | 408 } |
388 }) | 409 }) |
389 } | 410 } |
390 }) | 411 }) |
391 } | 412 } |
OLD | NEW |