| 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 "sort" |
| 9 "testing" | 9 "testing" |
| 10 "time" | 10 "time" |
| 11 | 11 |
| 12 ds "github.com/luci/gae/service/datastore" | 12 ds "github.com/luci/gae/service/datastore" |
| 13 "github.com/luci/gae/service/datastore/serialize" |
| 13 "github.com/luci/gkvlite" | 14 "github.com/luci/gkvlite" |
| 14 . "github.com/smartystreets/goconvey/convey" | 15 . "github.com/smartystreets/goconvey/convey" |
| 15 ) | 16 ) |
| 16 | 17 |
| 17 var fakeKey = key("parentKind", "sid", "knd", 10) | 18 var fakeKey = key("parentKind", "sid", "knd", 10) |
| 18 | 19 |
| 19 func TestCollated(t *testing.T) { | |
| 20 t.Parallel() | |
| 21 | |
| 22 Convey("TestCollated", t, func() { | |
| 23 Convey("nil list", func() { | |
| 24 pm := ds.PropertyMap(nil) | |
| 25 sip := partiallySerialize(fakeKey, pm) | |
| 26 | |
| 27 Convey("nil collated", func() { | |
| 28 Convey("defaultIndexes", func() { | |
| 29 idxs := defaultIndexes("knd", pm) | |
| 30 So(len(idxs), ShouldEqual, 1) | |
| 31 So(idxs[0].String(), ShouldEqual, "B:knd
") | |
| 32 }) | |
| 33 Convey("indexEntries", func() { | |
| 34 s := sip.indexEntries("ns", defaultIndex
es("knd", pm)) | |
| 35 numItems, _ := s.GetCollection("idx").Ge
tTotals() | |
| 36 So(numItems, ShouldEqual, 1) | |
| 37 itm := s.GetCollection("idx").MinItem(fa
lse) | |
| 38 So(itm.Key, ShouldResemble, cat(indx("kn
d").PrepForIdxTable())) | |
| 39 numItems, _ = s.GetCollection("idx:ns:"
+ string(itm.Key)).GetTotals() | |
| 40 So(numItems, ShouldEqual, 1) | |
| 41 }) | |
| 42 }) | |
| 43 }) | |
| 44 | |
| 45 Convey("list", func() { | |
| 46 pm := ds.PropertyMap{ | |
| 47 "wat": {propNI("thing"), prop("hat"), prop(100)
}, | |
| 48 "nerd": {prop(103.7)}, | |
| 49 "spaz": {propNI(false)}, | |
| 50 } | |
| 51 sip := partiallySerialize(fakeKey, pm) | |
| 52 So(len(sip), ShouldEqual, 4) | |
| 53 | |
| 54 Convey("single collated", func() { | |
| 55 Convey("indexableMap", func() { | |
| 56 So(sip, ShouldResemble, serializedIndexa
blePmap{ | |
| 57 "wat": { | |
| 58 cat(prop("hat")), | |
| 59 cat(prop(100)), | |
| 60 // 'thing' is skipped, b
ecause it's not NoIndex | |
| 61 }, | |
| 62 "nerd": { | |
| 63 cat(prop(103.7)), | |
| 64 }, | |
| 65 "__key__": { | |
| 66 cat(prop(fakeKey)), | |
| 67 }, | |
| 68 "__ancestor__": { | |
| 69 cat(prop(fakeKey)), | |
| 70 cat(prop(fakeKey.Parent(
))), | |
| 71 }, | |
| 72 }) | |
| 73 }) | |
| 74 Convey("defaultIndexes", func() { | |
| 75 idxs := defaultIndexes("knd", pm) | |
| 76 So(len(idxs), ShouldEqual, 5) | |
| 77 So(idxs[0].String(), ShouldEqual, "B:knd
") | |
| 78 So(idxs[1].String(), ShouldEqual, "B:knd
/nerd") | |
| 79 So(idxs[2].String(), ShouldEqual, "B:knd
/wat") | |
| 80 So(idxs[3].String(), ShouldEqual, "B:knd
/-nerd") | |
| 81 So(idxs[4].String(), ShouldEqual, "B:knd
/-wat") | |
| 82 }) | |
| 83 }) | |
| 84 }) | |
| 85 }) | |
| 86 } | |
| 87 | |
| 88 var rgenComplexTime = time.Date( | 20 var rgenComplexTime = time.Date( |
| 89 1986, time.October, 26, 1, 20, 00, 00, time.UTC) | 21 1986, time.October, 26, 1, 20, 00, 00, time.UTC) |
| 90 var rgenComplexKey = key("kind", "id") | 22 var rgenComplexKey = key("kind", "id") |
| 91 var rgenComplexTimeIdx = prop(rgenComplexTime).ForIndex() | 23 var rgenComplexTimeIdx = prop(rgenComplexTime).ForIndex() |
| 92 | 24 |
| 93 var rowGenTestCases = []struct { | 25 var rowGenTestCases = []struct { |
| 94 name string | 26 name string |
| 95 pmap ds.PropertyMap | 27 pmap ds.PropertyMap |
| 96 withBuiltin bool | 28 withBuiltin bool |
| 97 idxs []*ds.IndexDefinition | 29 idxs []*ds.IndexDefinition |
| 98 | 30 |
| 99 // These are checked in TestIndexRowGen. nil to skip test case. | 31 // These are checked in TestIndexRowGen. nil to skip test case. |
| 100 » expected []serializedPvals | 32 » expected []serialize.SerializedPslice |
| 101 | 33 |
| 102 // just the collections you want to assert. These are checked in | 34 // just the collections you want to assert. These are checked in |
| 103 // TestIndexEntries. nil to skip test case. | 35 // TestIndexEntries. nil to skip test case. |
| 104 collections map[string][][]byte | 36 collections map[string][][]byte |
| 105 }{ | 37 }{ |
| 106 | 38 |
| 107 { | 39 { |
| 108 name: "simple including builtins", | 40 name: "simple including builtins", |
| 109 pmap: ds.PropertyMap{ | 41 pmap: ds.PropertyMap{ |
| 110 "wat": {propNI("thing"), prop("hat"), prop(100)}, | 42 "wat": {propNI("thing"), prop("hat"), prop(100)}, |
| 111 "nerd": {prop(103.7)}, | 43 "nerd": {prop(103.7)}, |
| 112 "spaz": {propNI(false)}, | 44 "spaz": {propNI(false)}, |
| 113 }, | 45 }, |
| 114 withBuiltin: true, | 46 withBuiltin: true, |
| 115 idxs: []*ds.IndexDefinition{ | 47 idxs: []*ds.IndexDefinition{ |
| 116 indx("knd", "-wat", "nerd"), | 48 indx("knd", "-wat", "nerd"), |
| 117 }, | 49 }, |
| 118 » » expected: []serializedPvals{ | 50 » » expected: []serialize.SerializedPslice{ |
| 119 {cat(prop(fakeKey))}, // B:knd | 51 {cat(prop(fakeKey))}, // B:knd |
| 120 {cat(prop(103.7), prop(fakeKey))}, // B:knd/nerd | 52 {cat(prop(103.7), prop(fakeKey))}, // B:knd/nerd |
| 121 { // B:knd/wat | 53 { // B:knd/wat |
| 122 cat(prop(100), prop(fakeKey)), | 54 cat(prop(100), prop(fakeKey)), |
| 123 cat(prop("hat"), prop(fakeKey)), | 55 cat(prop("hat"), prop(fakeKey)), |
| 124 }, | 56 }, |
| 125 { // B:knd/-nerd | 57 { // B:knd/-nerd |
| 126 cat(icat(prop(103.7)), prop(fakeKey)), | 58 cat(icat(prop(103.7)), prop(fakeKey)), |
| 127 }, | 59 }, |
| 128 { // B:knd/-wat | 60 { // B:knd/-wat |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 "wat": { | 97 "wat": { |
| 166 prop(rgenComplexTime), | 98 prop(rgenComplexTime), |
| 167 prop([]byte("value")), | 99 prop([]byte("value")), |
| 168 prop(rgenComplexKey)}, | 100 prop(rgenComplexKey)}, |
| 169 "spaz": {prop(nil), prop(false), prop(true)}, | 101 "spaz": {prop(nil), prop(false), prop(true)}, |
| 170 }, | 102 }, |
| 171 idxs: []*ds.IndexDefinition{ | 103 idxs: []*ds.IndexDefinition{ |
| 172 indx("knd", "-wat", "nerd", "spaz"), // doesn't match, s
o empty | 104 indx("knd", "-wat", "nerd", "spaz"), // doesn't match, s
o empty |
| 173 indx("knd", "yerp", "-wat", "spaz"), | 105 indx("knd", "yerp", "-wat", "spaz"), |
| 174 }, | 106 }, |
| 175 » » expected: []serializedPvals{ | 107 » » expected: []serialize.SerializedPslice{ |
| 176 {}, // C:knd/-wat/nerd/spaz, no match | 108 {}, // C:knd/-wat/nerd/spaz, no match |
| 177 { // C:knd/yerp/-wat/spaz | 109 { // C:knd/yerp/-wat/spaz |
| 178 // thank goodness the binary serialization only
happens 1/val in the | 110 // thank goodness the binary serialization only
happens 1/val in the |
| 179 // real code :). | 111 // real code :). |
| 180 cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(nil), prop(fakeKey)), | 112 cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(nil), prop(fakeKey)), |
| 181 cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(false), prop(fakeKey)), | 113 cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(false), prop(fakeKey)), |
| 182 cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(true), prop(fakeKey)), | 114 cat(prop("hat"), icat(prop(rgenComplexKey)), pro
p(true), prop(fakeKey)), |
| 183 cat(prop("hat"), icat(prop("value")), prop(nil),
prop(fakeKey)), | 115 cat(prop("hat"), icat(prop("value")), prop(nil),
prop(fakeKey)), |
| 184 cat(prop("hat"), icat(prop("value")), prop(false
), prop(fakeKey)), | 116 cat(prop("hat"), icat(prop("value")), prop(false
), prop(fakeKey)), |
| 185 cat(prop("hat"), icat(prop("value")), prop(true)
, prop(fakeKey)), | 117 cat(prop("hat"), icat(prop("value")), prop(true)
, prop(fakeKey)), |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 t.Parallel() | 153 t.Parallel() |
| 222 | 154 |
| 223 Convey("Test Index Row Generation", t, func() { | 155 Convey("Test Index Row Generation", t, func() { |
| 224 for _, tc := range rowGenTestCases { | 156 for _, tc := range rowGenTestCases { |
| 225 if tc.expected == nil { | 157 if tc.expected == nil { |
| 226 Convey(tc.name, nil) // shows up as 'skipped' | 158 Convey(tc.name, nil) // shows up as 'skipped' |
| 227 continue | 159 continue |
| 228 } | 160 } |
| 229 | 161 |
| 230 Convey(tc.name, func() { | 162 Convey(tc.name, func() { |
| 231 » » » » mvals := partiallySerialize(fakeKey, tc.pmap) | 163 » » » » mvals := serialize.PropertyMapPartially(fakeKey,
tc.pmap) |
| 232 idxs := []*ds.IndexDefinition(nil) | 164 idxs := []*ds.IndexDefinition(nil) |
| 233 if tc.withBuiltin { | 165 if tc.withBuiltin { |
| 234 idxs = append(defaultIndexes("coolKind",
tc.pmap), tc.idxs...) | 166 idxs = append(defaultIndexes("coolKind",
tc.pmap), tc.idxs...) |
| 235 } else { | 167 } else { |
| 236 idxs = tc.idxs | 168 idxs = tc.idxs |
| 237 } | 169 } |
| 238 | 170 |
| 239 m := matcher{} | 171 m := matcher{} |
| 240 for i, idx := range idxs { | 172 for i, idx := range idxs { |
| 241 Convey(idx.String(), func() { | 173 Convey(idx.String(), func() { |
| 242 iGen, ok := m.match(idx.GetFullS
ortOrder(), mvals) | 174 iGen, ok := m.match(idx.GetFullS
ortOrder(), mvals) |
| 243 if len(tc.expected[i]) > 0 { | 175 if len(tc.expected[i]) > 0 { |
| 244 So(ok, ShouldBeTrue) | 176 So(ok, ShouldBeTrue) |
| 245 » » » » » » » actual := make(serialize
dPvals, 0, len(tc.expected[i])) | 177 » » » » » » » actual := make(serialize
.SerializedPslice, 0, len(tc.expected[i])) |
| 246 iGen.permute(func(row, _
[]byte) { | 178 iGen.permute(func(row, _
[]byte) { |
| 247 actual = append(
actual, row) | 179 actual = append(
actual, row) |
| 248 }) | 180 }) |
| 249 So(len(actual), ShouldEq
ual, len(tc.expected[i])) | 181 So(len(actual), ShouldEq
ual, len(tc.expected[i])) |
| 250 sort.Sort(actual) | 182 sort.Sort(actual) |
| 251 for j, act := range actu
al { | 183 for j, act := range actu
al { |
| 252 So(act, ShouldRe
semble, tc.expected[i][j]) | 184 So(act, ShouldRe
semble, tc.expected[i][j]) |
| 253 } | 185 } |
| 254 } else { | 186 } else { |
| 255 So(ok, ShouldBeFalse) | 187 So(ok, ShouldBeFalse) |
| 256 } | 188 } |
| 257 }) | 189 }) |
| 258 } | 190 } |
| 259 }) | 191 }) |
| 260 } | 192 } |
| 261 }) | 193 }) |
| 194 |
| 195 Convey("default indexes", t, func() { |
| 196 Convey("nil collated", func() { |
| 197 Convey("defaultIndexes (nil)", func() { |
| 198 idxs := defaultIndexes("knd", ds.PropertyMap(nil
)) |
| 199 So(len(idxs), ShouldEqual, 1) |
| 200 So(idxs[0].String(), ShouldEqual, "B:knd") |
| 201 }) |
| 202 |
| 203 Convey("indexEntries", func() { |
| 204 sip := serialize.PropertyMapPartially(fakeKey, n
il) |
| 205 s := indexEntries(sip, "ns", defaultIndexes("knd
", ds.PropertyMap(nil))) |
| 206 numItems, _ := s.GetCollection("idx").GetTotals(
) |
| 207 So(numItems, ShouldEqual, 1) |
| 208 itm := s.GetCollection("idx").MinItem(false) |
| 209 So(itm.Key, ShouldResemble, cat(indx("knd").Prep
ForIdxTable())) |
| 210 numItems, _ = s.GetCollection("idx:ns:" + string
(itm.Key)).GetTotals() |
| 211 So(numItems, ShouldEqual, 1) |
| 212 }) |
| 213 |
| 214 Convey("defaultIndexes", func() { |
| 215 pm := ds.PropertyMap{ |
| 216 "wat": {propNI("thing"), prop("hat"), p
rop(100)}, |
| 217 "nerd": {prop(103.7)}, |
| 218 "spaz": {propNI(false)}, |
| 219 } |
| 220 idxs := defaultIndexes("knd", pm) |
| 221 So(len(idxs), ShouldEqual, 5) |
| 222 So(idxs[0].String(), ShouldEqual, "B:knd") |
| 223 So(idxs[1].String(), ShouldEqual, "B:knd/nerd") |
| 224 So(idxs[2].String(), ShouldEqual, "B:knd/wat") |
| 225 So(idxs[3].String(), ShouldEqual, "B:knd/-nerd") |
| 226 So(idxs[4].String(), ShouldEqual, "B:knd/-wat") |
| 227 }) |
| 228 |
| 229 }) |
| 230 }) |
| 262 } | 231 } |
| 263 | 232 |
| 264 func TestIndexEntries(t *testing.T) { | 233 func TestIndexEntries(t *testing.T) { |
| 265 t.Parallel() | 234 t.Parallel() |
| 266 | 235 |
| 267 Convey("Test indexEntriesWithBuiltins", t, func() { | 236 Convey("Test indexEntriesWithBuiltins", t, func() { |
| 268 for _, tc := range rowGenTestCases { | 237 for _, tc := range rowGenTestCases { |
| 269 if tc.collections == nil { | 238 if tc.collections == nil { |
| 270 Convey(tc.name, nil) // shows up as 'skipped' | 239 Convey(tc.name, nil) // shows up as 'skipped' |
| 271 continue | 240 continue |
| 272 } | 241 } |
| 273 | 242 |
| 274 Convey(tc.name, func() { | 243 Convey(tc.name, func() { |
| 275 store := (*memStore)(nil) | 244 store := (*memStore)(nil) |
| 276 if tc.withBuiltin { | 245 if tc.withBuiltin { |
| 277 store = indexEntriesWithBuiltins(fakeKey
, tc.pmap, tc.idxs) | 246 store = indexEntriesWithBuiltins(fakeKey
, tc.pmap, tc.idxs) |
| 278 } else { | 247 } else { |
| 279 » » » » » store = partiallySerialize(fakeKey, tc.p
map).indexEntries(fakeKey.Namespace(), tc.idxs) | 248 » » » » » sip := serialize.PropertyMapPartially(fa
keKey, tc.pmap) |
| 249 » » » » » store = indexEntries(sip, fakeKey.Namesp
ace(), tc.idxs) |
| 280 } | 250 } |
| 281 for colName, vals := range tc.collections { | 251 for colName, vals := range tc.collections { |
| 282 i := 0 | 252 i := 0 |
| 283 coll := store.GetCollection(colName) | 253 coll := store.GetCollection(colName) |
| 284 numItems, _ := coll.GetTotals() | 254 numItems, _ := coll.GetTotals() |
| 285 So(numItems, ShouldEqual, len(tc.collect
ions[colName])) | 255 So(numItems, ShouldEqual, len(tc.collect
ions[colName])) |
| 286 coll.VisitItemsAscend(nil, true, func(it
m *gkvlite.Item) bool { | 256 coll.VisitItemsAscend(nil, true, func(it
m *gkvlite.Item) bool { |
| 287 So(itm.Key, ShouldResemble, vals
[i]) | 257 So(itm.Key, ShouldResemble, vals
[i]) |
| 288 i++ | 258 i++ |
| 289 return true | 259 return true |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 So(data[i], ShouldResemble, itm.
Key) | 374 So(data[i], ShouldResemble, itm.
Key) |
| 405 i++ | 375 i++ |
| 406 return true | 376 return true |
| 407 }) | 377 }) |
| 408 So(i, ShouldEqual, len(data)) | 378 So(i, ShouldEqual, len(data)) |
| 409 } | 379 } |
| 410 }) | 380 }) |
| 411 } | 381 } |
| 412 }) | 382 }) |
| 413 } | 383 } |
| OLD | NEW |