Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: service/datastore/datastore_test.go

Issue 2342063003: Differentiate between single- and multi- props. (Closed)
Patch Set: Slice is now always a clone. This is marginally worse performance, but a much safer UI. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « impl/prod/raw_datastore_type_converter.go ('k') | service/datastore/dumper/dumper.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // adapted from github.com/golang/appengine/datastore 5 // adapted from github.com/golang/appengine/datastore
6 6
7 package datastore 7 package datastore
8 8
9 import ( 9 import (
10 "bytes" 10 "bytes"
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 if v, ok := fq.eqFilts["$err_single"]; ok { 75 if v, ok := fq.eqFilts["$err_single"]; ok {
76 idx := fq.eqFilts["$err_single_idx"][0].Value().(int64) 76 idx := fq.eqFilts["$err_single_idx"][0].Value().(int64)
77 if idx == int64(i) { 77 if idx == int64(i) {
78 return errors.New(v[0].Value().(string)) 78 return errors.New(v[0].Value().(string))
79 } 79 }
80 } 80 }
81 k := f.mkKey("Kind", i+1) 81 k := f.mkKey("Kind", i+1)
82 if i == 10 { 82 if i == 10 {
83 k = f.mkKey("Kind", "eleven") 83 k = f.mkKey("Kind", "eleven")
84 } 84 }
85 » » pm := PropertyMap{"Value": {MkProperty(i)}} 85 » » pm := PropertyMap{"Value": MkProperty(i)}
86 if err := cb(k, pm, cursCB); err != nil { 86 if err := cb(k, pm, cursCB); err != nil {
87 if err == Stop { 87 if err == Stop {
88 err = nil 88 err = nil
89 } 89 }
90 return err 90 return err
91 } 91 }
92 } 92 }
93 return nil 93 return nil
94 } 94 }
95 95
96 func (f *fakeDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb NewKeyCB) e rror { 96 func (f *fakeDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb NewKeyCB) e rror {
97 if keys[0].Kind() == "FailAll" { 97 if keys[0].Kind() == "FailAll" {
98 return errFailAll 98 return errFailAll
99 } 99 }
100 _, assertExtra := vals[0].GetMeta("assertExtra") 100 _, assertExtra := vals[0].GetMeta("assertExtra")
101 for i, k := range keys { 101 for i, k := range keys {
102 err := error(nil) 102 err := error(nil)
103 if k.Kind() == "Fail" { 103 if k.Kind() == "Fail" {
104 err = errFail 104 err = errFail
105 } else { 105 } else {
106 » » » So(vals[i]["Value"], ShouldResemble, []Property{MkProper ty(i)}) 106 » » » So(vals[i].Slice("Value"), ShouldResemble, PropertySlice {MkProperty(i)})
107 if assertExtra { 107 if assertExtra {
108 » » » » So(vals[i]["Extra"], ShouldResemble, []Property{ MkProperty("whoa")}) 108 » » » » So(vals[i].Slice("Extra"), ShouldResemble, Prope rtySlice{MkProperty("whoa")})
109 } 109 }
110 if k.IsIncomplete() { 110 if k.IsIncomplete() {
111 k = NewKey(k.AppID(), k.Namespace(), k.Kind(), " ", int64(i+1), k.Parent()) 111 k = NewKey(k.AppID(), k.Namespace(), k.Kind(), " ", int64(i+1), k.Parent())
112 } 112 }
113 } 113 }
114 cb(k, err) 114 cb(k, err)
115 } 115 }
116 return nil 116 return nil
117 } 117 }
118 118
119 const noSuchEntityID = 0xdead 119 const noSuchEntityID = 0xdead
120 120
121 func (f *fakeDatastore) GetMulti(keys []*Key, _meta MultiMetaGetter, cb GetMulti CB) error { 121 func (f *fakeDatastore) GetMulti(keys []*Key, _meta MultiMetaGetter, cb GetMulti CB) error {
122 if keys[0].Kind() == "FailAll" { 122 if keys[0].Kind() == "FailAll" {
123 return errFailAll 123 return errFailAll
124 } 124 }
125 for i, k := range keys { 125 for i, k := range keys {
126 if k.Kind() == "Fail" { 126 if k.Kind() == "Fail" {
127 cb(nil, errFail) 127 cb(nil, errFail)
128 } else if k.Kind() == "DNE" || k.IntID() == noSuchEntityID { 128 } else if k.Kind() == "DNE" || k.IntID() == noSuchEntityID {
129 cb(nil, ErrNoSuchEntity) 129 cb(nil, ErrNoSuchEntity)
130 } else { 130 } else {
131 » » » cb(PropertyMap{"Value": {MkProperty(i + 1)}}, nil) 131 » » » cb(PropertyMap{"Value": MkProperty(i + 1)}, nil)
132 } 132 }
133 } 133 }
134 return nil 134 return nil
135 } 135 }
136 136
137 func (f *fakeDatastore) DeleteMulti(keys []*Key, cb DeleteMultiCB) error { 137 func (f *fakeDatastore) DeleteMulti(keys []*Key, cb DeleteMultiCB) error {
138 if keys[0].Kind() == "FailAll" { 138 if keys[0].Kind() == "FailAll" {
139 return errFailAll 139 return errFailAll
140 } 140 }
141 for _, k := range keys { 141 for _, k := range keys {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 failSetMeta bool 190 failSetMeta bool
191 } 191 }
192 192
193 var _ PropertyLoadSaver = (*FakePLS)(nil) 193 var _ PropertyLoadSaver = (*FakePLS)(nil)
194 194
195 func (f *FakePLS) Load(pm PropertyMap) error { 195 func (f *FakePLS) Load(pm PropertyMap) error {
196 if f.failLoad { 196 if f.failLoad {
197 return errors.New("FakePLS.Load") 197 return errors.New("FakePLS.Load")
198 } 198 }
199 f.gotLoaded = true 199 f.gotLoaded = true
200 » f.Value = pm["Value"][0].Value().(int64) 200 » f.Value = pm.Slice("Value")[0].Value().(int64)
201 return nil 201 return nil
202 } 202 }
203 203
204 func (f *FakePLS) Save(withMeta bool) (PropertyMap, error) { 204 func (f *FakePLS) Save(withMeta bool) (PropertyMap, error) {
205 if f.failSave { 205 if f.failSave {
206 return nil, errors.New("FakePLS.Save") 206 return nil, errors.New("FakePLS.Save")
207 } 207 }
208 ret := PropertyMap{ 208 ret := PropertyMap{
209 » » "Value": {MkProperty(f.Value)}, 209 » » "Value": MkProperty(f.Value),
210 » » "Extra": {MkProperty("whoa")}, 210 » » "Extra": MkProperty("whoa"),
211 } 211 }
212 if withMeta { 212 if withMeta {
213 id, _ := f.GetMeta("id") 213 id, _ := f.GetMeta("id")
214 So(ret.SetMeta("id", id), ShouldBeTrue) 214 So(ret.SetMeta("id", id), ShouldBeTrue)
215 if f.Kind == "" { 215 if f.Kind == "" {
216 So(ret.SetMeta("kind", "FakePLS"), ShouldBeTrue) 216 So(ret.SetMeta("kind", "FakePLS"), ShouldBeTrue)
217 } else { 217 } else {
218 So(ret.SetMeta("kind", f.Kind), ShouldBeTrue) 218 So(ret.SetMeta("kind", f.Kind), ShouldBeTrue)
219 } 219 }
220 So(ret.SetMeta("assertExtra", true), ShouldBeTrue) 220 So(ret.SetMeta("assertExtra", true), ShouldBeTrue)
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 case "kind": 294 case "kind":
295 return "plsChan", true 295 return "plsChan", true
296 case "id": 296 case "id":
297 return "whyDoIExist", true 297 return "whyDoIExist", true
298 } 298 }
299 return nil, false 299 return nil, false
300 } 300 }
301 301
302 func (c plsChan) GetAllMeta() PropertyMap { 302 func (c plsChan) GetAllMeta() PropertyMap {
303 return PropertyMap{ 303 return PropertyMap{
304 » » "kind": []Property{MkProperty("plsChan")}, 304 » » "kind": MkProperty("plsChan"),
305 » » "id": []Property{MkProperty("whyDoIExist")}, 305 » » "id": MkProperty("whyDoIExist"),
306 } 306 }
307 } 307 }
308 308
309 type MGSWithNoKind struct { 309 type MGSWithNoKind struct {
310 S string 310 S string
311 } 311 }
312 312
313 func (s *MGSWithNoKind) GetMeta(key string) (interface{}, bool) { 313 func (s *MGSWithNoKind) GetMeta(key string) (interface{}, bool) {
314 return nil, false 314 return nil, false
315 } 315 }
316 316
317 func (s *MGSWithNoKind) GetAllMeta() PropertyMap { 317 func (s *MGSWithNoKind) GetAllMeta() PropertyMap {
318 » return PropertyMap{"$kind": []Property{MkProperty("ohai")}} 318 » return PropertyMap{"$kind": MkProperty("ohai")}
319 } 319 }
320 320
321 func (s *MGSWithNoKind) SetMeta(key string, val interface{}) bool { 321 func (s *MGSWithNoKind) SetMeta(key string, val interface{}) bool {
322 return false 322 return false
323 } 323 }
324 324
325 var _ MetaGetterSetter = (*MGSWithNoKind)(nil) 325 var _ MetaGetterSetter = (*MGSWithNoKind)(nil)
326 326
327 func TestKeyForObj(t *testing.T) { 327 func TestKeyForObj(t *testing.T) {
328 t.Parallel() 328 t.Parallel()
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 } 661 }
662 So(ds.Put(fplss), ShouldBeNil) 662 So(ds.Put(fplss), ShouldBeNil)
663 for i, fpls := range fplss { 663 for i, fpls := range fplss {
664 expect := int64(i + 1) 664 expect := int64(i + 1)
665 if i == 4 { 665 if i == 4 {
666 expect = 200 666 expect = 200
667 } 667 }
668 So(fpls.IntID, ShouldEqual, expe ct) 668 So(fpls.IntID, ShouldEqual, expe ct)
669 } 669 }
670 670
671 » » » » » pm := PropertyMap{"Value": {MkProperty(0 )}, "$kind": {MkPropertyNI("Pmap")}} 671 » » » » » pm := PropertyMap{"Value": MkProperty(0) , "$kind": MkPropertyNI("Pmap")}
672 So(ds.Put(pm), ShouldBeNil) 672 So(ds.Put(pm), ShouldBeNil)
673 So(ds.KeyForObj(pm).IntID(), ShouldEqual , 1) 673 So(ds.KeyForObj(pm).IntID(), ShouldEqual , 1)
674 }) 674 })
675 675
676 Convey("[]P (map)", func() { 676 Convey("[]P (map)", func() {
677 pms := make([]PropertyMap, 7) 677 pms := make([]PropertyMap, 7)
678 for i := range pms { 678 for i := range pms {
679 pms[i] = PropertyMap{ 679 pms[i] = PropertyMap{
680 » » » » » » » "$kind": {MkProperty("Pm ap")}, 680 » » » » » » » "$kind": MkProperty("Pma p"),
681 » » » » » » » "Value": {MkProperty(i)} , 681 » » » » » » » "Value": MkProperty(i),
682 } 682 }
683 if i == 4 { 683 if i == 4 {
684 So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue) 684 So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue)
685 } 685 }
686 } 686 }
687 So(ds.Put(pms), ShouldBeNil) 687 So(ds.Put(pms), ShouldBeNil)
688 for i, pm := range pms { 688 for i, pm := range pms {
689 expect := int64(i + 1) 689 expect := int64(i + 1)
690 if i == 4 { 690 if i == 4 {
691 expect = 200 691 expect = 200
(...skipping 17 matching lines...) Expand all
709 expect = 200 709 expect = 200
710 } 710 }
711 So(fpls.IntID, ShouldEqual, expe ct) 711 So(fpls.IntID, ShouldEqual, expe ct)
712 } 712 }
713 }) 713 })
714 714
715 Convey("[]*P (map)", func() { 715 Convey("[]*P (map)", func() {
716 pms := make([]*PropertyMap, 7) 716 pms := make([]*PropertyMap, 7)
717 for i := range pms { 717 for i := range pms {
718 pms[i] = &PropertyMap{ 718 pms[i] = &PropertyMap{
719 » » » » » » » "$kind": {MkProperty("Pm ap")}, 719 » » » » » » » "$kind": MkProperty("Pma p"),
720 » » » » » » » "Value": {MkProperty(i)} , 720 » » » » » » » "Value": MkProperty(i),
721 } 721 }
722 if i == 4 { 722 if i == 4 {
723 So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue) 723 So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue)
724 } 724 }
725 } 725 }
726 So(ds.Put(pms), ShouldBeNil) 726 So(ds.Put(pms), ShouldBeNil)
727 for i, pm := range pms { 727 for i, pm := range pms {
728 expect := int64(i + 1) 728 expect := int64(i + 1)
729 if i == 4 { 729 if i == 4 {
730 expect = 200 730 expect = 200
731 } 731 }
732 So(ds.KeyForObj(*pm).String(), S houldEqual, fmt.Sprintf("s~aid:ns:/Pmap,%d", expect)) 732 So(ds.KeyForObj(*pm).String(), S houldEqual, fmt.Sprintf("s~aid:ns:/Pmap,%d", expect))
733 } 733 }
734 }) 734 })
735 735
736 Convey("[]I", func() { 736 Convey("[]I", func() {
737 ifs := []interface{}{ 737 ifs := []interface{}{
738 &CommonStruct{Value: 0}, 738 &CommonStruct{Value: 0},
739 &FakePLS{Value: 1}, 739 &FakePLS{Value: 1},
740 » » » » » » PropertyMap{"Value": {MkProperty (2)}, "$kind": {MkPropertyNI("Pmap")}}, 740 » » » » » » PropertyMap{"Value": MkProperty( 2), "$kind": MkPropertyNI("Pmap")},
741 » » » » » » &PropertyMap{"Value": {MkPropert y(3)}, "$kind": {MkPropertyNI("Pmap")}}, 741 » » » » » » &PropertyMap{"Value": MkProperty (3), "$kind": MkPropertyNI("Pmap")},
742 } 742 }
743 So(ds.Put(ifs), ShouldBeNil) 743 So(ds.Put(ifs), ShouldBeNil)
744 for i := range ifs { 744 for i := range ifs {
745 switch i { 745 switch i {
746 case 0: 746 case 0:
747 So(ifs[i].(*CommonStruct ).ID, ShouldEqual, 1) 747 So(ifs[i].(*CommonStruct ).ID, ShouldEqual, 1)
748 case 1: 748 case 1:
749 fpls := ifs[i].(*FakePLS ) 749 fpls := ifs[i].(*FakePLS )
750 So(fpls.IntID, ShouldEqu al, 2) 750 So(fpls.IntID, ShouldEqu al, 2)
751 case 2: 751 case 2:
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 cs := &CommonStruct{ID: 1} 1017 cs := &CommonStruct{ID: 1}
1018 So(ds.Get(cs), ShouldBeNil) 1018 So(ds.Get(cs), ShouldBeNil)
1019 So(cs.Value, ShouldEqual, 1) 1019 So(cs.Value, ShouldEqual, 1)
1020 }) 1020 })
1021 1021
1022 Convey("Raw access too", func() { 1022 Convey("Raw access too", func() {
1023 rds := ds.Raw() 1023 rds := ds.Raw()
1024 keys := []*Key{ds.MakeKey("Kind", 1)} 1024 keys := []*Key{ds.MakeKey("Kind", 1)}
1025 So(rds.GetMulti(keys, nil, func(pm Prope rtyMap, err error) error { 1025 So(rds.GetMulti(keys, nil, func(pm Prope rtyMap, err error) error {
1026 So(err, ShouldBeNil) 1026 So(err, ShouldBeNil)
1027 » » » » » » So(pm["Value"][0].Value(), Shoul dEqual, 1) 1027 » » » » » » So(pm.Slice("Value")[0].Value(), ShouldEqual, 1)
1028 return nil 1028 return nil
1029 }), ShouldBeNil) 1029 }), ShouldBeNil)
1030 }) 1030 })
1031 1031
1032 Convey("but general failure to save is fine on a Get", func() { 1032 Convey("but general failure to save is fine on a Get", func() {
1033 cs := &FakePLS{failSave: true, IntID: 7} 1033 cs := &FakePLS{failSave: true, IntID: 7}
1034 So(ds.Get(cs), ShouldBeNil) 1034 So(ds.Get(cs), ShouldBeNil)
1035 }) 1035 })
1036 1036
1037 Convey("vararg", func() { 1037 Convey("vararg", func() {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1138 }) 1138 })
1139 1139
1140 Convey("*[]P (map)", func() { 1140 Convey("*[]P (map)", func() {
1141 output := []PropertyMap(nil) 1141 output := []PropertyMap(nil)
1142 So(ds.GetAll(q, &output), ShouldBeNil) 1142 So(ds.GetAll(q, &output), ShouldBeNil)
1143 So(len(output), ShouldEqual, 5) 1143 So(len(output), ShouldEqual, 5)
1144 for i, o := range output { 1144 for i, o := range output {
1145 k, ok := o.GetMeta("key") 1145 k, ok := o.GetMeta("key")
1146 So(ok, ShouldBeTrue) 1146 So(ok, ShouldBeTrue)
1147 So(k.(*Key).IntID(), ShouldEqual, i+1) 1147 So(k.(*Key).IntID(), ShouldEqual, i+1)
1148 » » » » » So(o["Value"][0].Value().(int64), Should Equal, i) 1148 » » » » » So(o.Slice("Value")[0].Value().(int64), ShouldEqual, i)
1149 } 1149 }
1150 }) 1150 })
1151 1151
1152 Convey("*[]P (chan)", func() { 1152 Convey("*[]P (chan)", func() {
1153 output := []plsChan(nil) 1153 output := []plsChan(nil)
1154 So(ds.GetAll(q, &output), ShouldBeNil) 1154 So(ds.GetAll(q, &output), ShouldBeNil)
1155 So(output, ShouldHaveLength, 5) 1155 So(output, ShouldHaveLength, 5)
1156 for _, o := range output { 1156 for _, o := range output {
1157 So(ds.KeyForObj(o).StringID(), ShouldEqu al, "whyDoIExist") 1157 So(ds.KeyForObj(o).StringID(), ShouldEqu al, "whyDoIExist")
1158 } 1158 }
(...skipping 12 matching lines...) Expand all
1171 1171
1172 Convey("*[]*P (map)", func() { 1172 Convey("*[]*P (map)", func() {
1173 output := []*PropertyMap(nil) 1173 output := []*PropertyMap(nil)
1174 So(ds.GetAll(q, &output), ShouldBeNil) 1174 So(ds.GetAll(q, &output), ShouldBeNil)
1175 So(len(output), ShouldEqual, 5) 1175 So(len(output), ShouldEqual, 5)
1176 for i, op := range output { 1176 for i, op := range output {
1177 o := *op 1177 o := *op
1178 k, ok := o.GetMeta("key") 1178 k, ok := o.GetMeta("key")
1179 So(ok, ShouldBeTrue) 1179 So(ok, ShouldBeTrue)
1180 So(k.(*Key).IntID(), ShouldEqual, i+1) 1180 So(k.(*Key).IntID(), ShouldEqual, i+1)
1181 » » » » » So(o["Value"][0].Value().(int64), Should Equal, i) 1181 » » » » » So(o.Slice("Value")[0].Value().(int64), ShouldEqual, i)
1182 } 1182 }
1183 }) 1183 })
1184 1184
1185 Convey("*[]*P (chan)", func() { 1185 Convey("*[]*P (chan)", func() {
1186 output := []*plsChan(nil) 1186 output := []*plsChan(nil)
1187 So(ds.GetAll(q, &output), ShouldBeNil) 1187 So(ds.GetAll(q, &output), ShouldBeNil)
1188 So(output, ShouldHaveLength, 5) 1188 So(output, ShouldHaveLength, 5)
1189 for _, o := range output { 1189 for _, o := range output {
1190 So(ds.KeyForObj(o).StringID(), ShouldEqu al, "whyDoIExist") 1190 So(ds.KeyForObj(o).StringID(), ShouldEqu al, "whyDoIExist")
1191 } 1191 }
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
1331 i++ 1331 i++
1332 }), ShouldBeNil) 1332 }), ShouldBeNil)
1333 }) 1333 })
1334 1334
1335 Convey("*P (map)", func() { 1335 Convey("*P (map)", func() {
1336 i := 0 1336 i := 0
1337 So(ds.Run(q, func(pm *PropertyMap) { 1337 So(ds.Run(q, func(pm *PropertyMap) {
1338 k, ok := pm.GetMeta("key") 1338 k, ok := pm.GetMeta("key")
1339 So(ok, ShouldBeTrue) 1339 So(ok, ShouldBeTrue)
1340 So(k.(*Key).IntID(), ShouldEqual, i+1) 1340 So(k.(*Key).IntID(), ShouldEqual, i+1)
1341 » » » » » So((*pm)["Value"][0].Value(), ShouldEqua l, i) 1341 » » » » » So((*pm).Slice("Value")[0].Value(), Shou ldEqual, i)
1342 i++ 1342 i++
1343 }), ShouldBeNil) 1343 }), ShouldBeNil)
1344 }) 1344 })
1345 1345
1346 Convey("*P (chan)", func() { 1346 Convey("*P (chan)", func() {
1347 So(ds.Run(q, func(c *plsChan) { 1347 So(ds.Run(q, func(c *plsChan) {
1348 So(ds.KeyForObj(c).StringID(), ShouldEqu al, "whyDoIExist") 1348 So(ds.KeyForObj(c).StringID(), ShouldEqu al, "whyDoIExist")
1349 }), ShouldBeNil) 1349 }), ShouldBeNil)
1350 }) 1350 })
1351 1351
(...skipping 15 matching lines...) Expand all
1367 i++ 1367 i++
1368 }), ShouldBeNil) 1368 }), ShouldBeNil)
1369 }) 1369 })
1370 1370
1371 Convey("P (map)", func() { 1371 Convey("P (map)", func() {
1372 i := 0 1372 i := 0
1373 So(ds.Run(q, func(pm PropertyMap) { 1373 So(ds.Run(q, func(pm PropertyMap) {
1374 k, ok := pm.GetMeta("key") 1374 k, ok := pm.GetMeta("key")
1375 So(ok, ShouldBeTrue) 1375 So(ok, ShouldBeTrue)
1376 So(k.(*Key).IntID(), ShouldEqual, i+1) 1376 So(k.(*Key).IntID(), ShouldEqual, i+1)
1377 » » » » » So(pm["Value"][0].Value(), ShouldEqual, i) 1377 » » » » » So(pm.Slice("Value")[0].Value(), ShouldE qual, i)
1378 i++ 1378 i++
1379 }), ShouldBeNil) 1379 }), ShouldBeNil)
1380 }) 1380 })
1381 1381
1382 Convey("P (chan)", func() { 1382 Convey("P (chan)", func() {
1383 So(ds.Run(q, func(c plsChan) { 1383 So(ds.Run(q, func(c plsChan) {
1384 So(ds.KeyForObj(c).StringID(), ShouldEqu al, "whyDoIExist") 1384 So(ds.KeyForObj(c).StringID(), ShouldEqu al, "whyDoIExist")
1385 }), ShouldBeNil) 1385 }), ShouldBeNil)
1386 }) 1386 })
1387 1387
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1431 1431
1432 func TestSchemaChange(t *testing.T) { 1432 func TestSchemaChange(t *testing.T) {
1433 t.Parallel() 1433 t.Parallel()
1434 1434
1435 Convey("Test changing schemas", t, func() { 1435 Convey("Test changing schemas", t, func() {
1436 fds := fixedDataDatastore{} 1436 fds := fixedDataDatastore{}
1437 ds := &datastoreImpl{&fds, "", ""} 1437 ds := &datastoreImpl{&fds, "", ""}
1438 1438
1439 Convey("Can add fields", func() { 1439 Convey("Can add fields", func() {
1440 initial := PropertyMap{ 1440 initial := PropertyMap{
1441 » » » » "$key": {mpNI(ds.MakeKey("Val", 10))}, 1441 » » » » "$key": mpNI(ds.MakeKey("Val", 10)),
1442 » » » » "Val": {mp(100)}, 1442 » » » » "Val": mp(100),
1443 } 1443 }
1444 So(ds.Put(initial), ShouldBeNil) 1444 So(ds.Put(initial), ShouldBeNil)
1445 1445
1446 type Val struct { 1446 type Val struct {
1447 ID int64 `gae:"$id"` 1447 ID int64 `gae:"$id"`
1448 1448
1449 Val int64 1449 Val int64
1450 TwoVal int64 // whoa, TWO vals! amazing 1450 TwoVal int64 // whoa, TWO vals! amazing
1451 } 1451 }
1452 tv := &Val{ID: 10, TwoVal: 2} 1452 tv := &Val{ID: 10, TwoVal: 2}
1453 So(ds.Get(tv), ShouldBeNil) 1453 So(ds.Get(tv), ShouldBeNil)
1454 So(tv, ShouldResemble, &Val{ID: 10, Val: 100, TwoVal: 2} ) 1454 So(tv, ShouldResemble, &Val{ID: 10, Val: 100, TwoVal: 2} )
1455 }) 1455 })
1456 1456
1457 Convey("Removing fields", func() { 1457 Convey("Removing fields", func() {
1458 initial := PropertyMap{ 1458 initial := PropertyMap{
1459 » » » » "$key": {mpNI(ds.MakeKey("Val", 10))}, 1459 » » » » "$key": mpNI(ds.MakeKey("Val", 10)),
1460 » » » » "Val": {mp(100)}, 1460 » » » » "Val": mp(100),
1461 » » » » "TwoVal": {mp(200)}, 1461 » » » » "TwoVal": mp(200),
1462 } 1462 }
1463 So(ds.Put(initial), ShouldBeNil) 1463 So(ds.Put(initial), ShouldBeNil)
1464 1464
1465 Convey("is normally an error", func() { 1465 Convey("is normally an error", func() {
1466 type Val struct { 1466 type Val struct {
1467 ID int64 `gae:"$id"` 1467 ID int64 `gae:"$id"`
1468 1468
1469 Val int64 1469 Val int64
1470 } 1470 }
1471 tv := &Val{ID: 10} 1471 tv := &Val{ID: 10}
1472 So(ds.Get(tv), ShouldErrLike, 1472 So(ds.Get(tv), ShouldErrLike,
1473 `gae: cannot load field "TwoVal" into a "datastore.Val`) 1473 `gae: cannot load field "TwoVal" into a "datastore.Val`)
1474 So(tv, ShouldResemble, &Val{ID: 10, Val: 100}) 1474 So(tv, ShouldResemble, &Val{ID: 10, Val: 100})
1475 }) 1475 })
1476 1476
1477 Convey("Unless you have an ,extra field!", func() { 1477 Convey("Unless you have an ,extra field!", func() {
1478 type Val struct { 1478 type Val struct {
1479 ID int64 `gae:"$id"` 1479 ID int64 `gae:"$id"`
1480 1480
1481 Val int64 1481 Val int64
1482 Extra PropertyMap `gae:",extra"` 1482 Extra PropertyMap `gae:",extra"`
1483 } 1483 }
1484 tv := &Val{ID: 10} 1484 tv := &Val{ID: 10}
1485 So(ds.Get(tv), ShouldBeNil) 1485 So(ds.Get(tv), ShouldBeNil)
1486 So(tv, ShouldResemble, &Val{ 1486 So(tv, ShouldResemble, &Val{
1487 ID: 10, 1487 ID: 10,
1488 Val: 100, 1488 Val: 100,
1489 Extra: PropertyMap{ 1489 Extra: PropertyMap{
1490 » » » » » » "TwoVal": {mp(200)}, 1490 » » » » » » "TwoVal": PropertySlice{mp(200)} ,
1491 }, 1491 },
1492 }) 1492 })
1493 }) 1493 })
1494 }) 1494 })
1495 1495
1496 Convey("Can round-trip extra fields", func() { 1496 Convey("Can round-trip extra fields", func() {
1497 type Expando struct { 1497 type Expando struct {
1498 ID int64 `gae:"$id"` 1498 ID int64 `gae:"$id"`
1499 1499
1500 Something int 1500 Something int
1501 Extra PropertyMap `gae:",extra"` 1501 Extra PropertyMap `gae:",extra"`
1502 } 1502 }
1503 ex := &Expando{10, 17, PropertyMap{ 1503 ex := &Expando{10, 17, PropertyMap{
1504 » » » » "Hello": {mp("Hello")}, 1504 » » » » "Hello": mp("Hello"),
1505 » » » » "World": {mp(true)}, 1505 » » » » "World": mp(true),
1506 }} 1506 }}
1507 So(ds.Put(ex), ShouldBeNil) 1507 So(ds.Put(ex), ShouldBeNil)
1508 1508
1509 ex = &Expando{ID: 10} 1509 ex = &Expando{ID: 10}
1510 So(ds.Get(ex), ShouldBeNil) 1510 So(ds.Get(ex), ShouldBeNil)
1511 So(ex, ShouldResemble, &Expando{ 1511 So(ex, ShouldResemble, &Expando{
1512 ID: 10, 1512 ID: 10,
1513 Something: 17, 1513 Something: 17,
1514 Extra: PropertyMap{ 1514 Extra: PropertyMap{
1515 » » » » » "Hello": {mp("Hello")}, 1515 » » » » » "Hello": PropertySlice{mp("Hello")},
1516 » » » » » "World": {mp(true)}, 1516 » » » » » "World": PropertySlice{mp(true)},
1517 }, 1517 },
1518 }) 1518 })
1519 }) 1519 })
1520 1520
1521 Convey("Can read-but-not-write", func() { 1521 Convey("Can read-but-not-write", func() {
1522 initial := PropertyMap{ 1522 initial := PropertyMap{
1523 » » » » "$key": {mpNI(ds.MakeKey("Convert", 10))}, 1523 » » » » "$key": mpNI(ds.MakeKey("Convert", 10)),
1524 » » » » "Val": {mp(100)}, 1524 » » » » "Val": mp(100),
1525 » » » » "TwoVal": {mp(200)}, 1525 » » » » "TwoVal": mp(200),
1526 } 1526 }
1527 So(ds.Put(initial), ShouldBeNil) 1527 So(ds.Put(initial), ShouldBeNil)
1528 type Convert struct { 1528 type Convert struct {
1529 ID int64 `gae:"$id"` 1529 ID int64 `gae:"$id"`
1530 1530
1531 Val int64 1531 Val int64
1532 NewVal int64 1532 NewVal int64
1533 Extra PropertyMap `gae:"-,extra"` 1533 Extra PropertyMap `gae:"-,extra"`
1534 } 1534 }
1535 c := &Convert{ID: 10} 1535 c := &Convert{ID: 10}
1536 So(ds.Get(c), ShouldBeNil) 1536 So(ds.Get(c), ShouldBeNil)
1537 So(c, ShouldResemble, &Convert{ 1537 So(c, ShouldResemble, &Convert{
1538 » » » » ID: 10, Val: 100, NewVal: 0, Extra: PropertyMap{ "TwoVal": {mp(200)}}, 1538 » » » » ID: 10, Val: 100, NewVal: 0, Extra: PropertyMap{ "TwoVal": PropertySlice{mp(200)}},
1539 }) 1539 })
1540 » » » c.NewVal = c.Extra["TwoVal"][0].Value().(int64) 1540 » » » c.NewVal = c.Extra.Slice("TwoVal")[0].Value().(int64)
1541 So(ds.Put(c), ShouldBeNil) 1541 So(ds.Put(c), ShouldBeNil)
1542 1542
1543 c = &Convert{ID: 10} 1543 c = &Convert{ID: 10}
1544 So(ds.Get(c), ShouldBeNil) 1544 So(ds.Get(c), ShouldBeNil)
1545 So(c, ShouldResemble, &Convert{ 1545 So(c, ShouldResemble, &Convert{
1546 ID: 10, Val: 100, NewVal: 200, Extra: nil, 1546 ID: 10, Val: 100, NewVal: 200, Extra: nil,
1547 }) 1547 })
1548 }) 1548 })
1549 1549
1550 Convey("Can black hole", func() { 1550 Convey("Can black hole", func() {
1551 initial := PropertyMap{ 1551 initial := PropertyMap{
1552 » » » » "$key": {mpNI(ds.MakeKey("BlackHole", 10))}, 1552 » » » » "$key": mpNI(ds.MakeKey("BlackHole", 10)),
1553 » » » » "Val": {mp(100)}, 1553 » » » » "Val": mp(100),
1554 » » » » "TwoVal": {mp(200)}, 1554 » » » » "TwoVal": mp(200),
1555 } 1555 }
1556 So(ds.Put(initial), ShouldBeNil) 1556 So(ds.Put(initial), ShouldBeNil)
1557 type BlackHole struct { 1557 type BlackHole struct {
1558 ID int64 `gae:"$id"` 1558 ID int64 `gae:"$id"`
1559 1559
1560 NewStuff string 1560 NewStuff string
1561 blackHole PropertyMap `gae:"-,extra"` 1561 blackHole PropertyMap `gae:"-,extra"`
1562 } 1562 }
1563 b := &BlackHole{ID: 10, NewStuff: "(╯°□°)╯︵ ┻━┻"} 1563 b := &BlackHole{ID: 10, NewStuff: "(╯°□°)╯︵ ┻━┻"}
1564 So(ds.Get(b), ShouldBeNil) 1564 So(ds.Get(b), ShouldBeNil)
1565 So(b, ShouldResemble, &BlackHole{ID: 10, NewStuff: "(╯°□ °)╯︵ ┻━┻"}) 1565 So(b, ShouldResemble, &BlackHole{ID: 10, NewStuff: "(╯°□ °)╯︵ ┻━┻"})
1566 }) 1566 })
1567 1567
1568 Convey("Can change field types", func() { 1568 Convey("Can change field types", func() {
1569 initial := PropertyMap{ 1569 initial := PropertyMap{
1570 » » » » "$key": {mpNI(ds.MakeKey("IntChange", 10))}, 1570 » » » » "$key": mpNI(ds.MakeKey("IntChange", 10)),
1571 » » » » "Val": {mp(100)}, 1571 » » » » "Val": mp(100),
1572 } 1572 }
1573 So(ds.Put(initial), ShouldBeNil) 1573 So(ds.Put(initial), ShouldBeNil)
1574 1574
1575 type IntChange struct { 1575 type IntChange struct {
1576 ID int64 `gae:"$id"` 1576 ID int64 `gae:"$id"`
1577 Val string 1577 Val string
1578 Extra PropertyMap `gae:"-,extra"` 1578 Extra PropertyMap `gae:"-,extra"`
1579 } 1579 }
1580 i := &IntChange{ID: 10} 1580 i := &IntChange{ID: 10}
1581 So(ds.Get(i), ShouldBeNil) 1581 So(ds.Get(i), ShouldBeNil)
1582 » » » So(i, ShouldResemble, &IntChange{ID: 10, Extra: Property Map{"Val": {mp(100)}}}) 1582 » » » So(i, ShouldResemble, &IntChange{ID: 10, Extra: Property Map{"Val": PropertySlice{mp(100)}}})
1583 » » » i.Val = fmt.Sprint(i.Extra["Val"][0].Value()) 1583 » » » i.Val = fmt.Sprint(i.Extra.Slice("Val")[0].Value())
1584 So(ds.Put(i), ShouldBeNil) 1584 So(ds.Put(i), ShouldBeNil)
1585 1585
1586 i = &IntChange{ID: 10} 1586 i = &IntChange{ID: 10}
1587 So(ds.Get(i), ShouldBeNil) 1587 So(ds.Get(i), ShouldBeNil)
1588 So(i, ShouldResemble, &IntChange{ID: 10, Val: "100"}) 1588 So(i, ShouldResemble, &IntChange{ID: 10, Val: "100"})
1589 }) 1589 })
1590 1590
1591 Convey("Native fields have priority over Extra fields", func() { 1591 Convey("Native fields have priority over Extra fields", func() {
1592 type Dup struct { 1592 type Dup struct {
1593 ID int64 `gae:"$id"` 1593 ID int64 `gae:"$id"`
1594 Val int64 1594 Val int64
1595 Extra PropertyMap `gae:",extra"` 1595 Extra PropertyMap `gae:",extra"`
1596 } 1596 }
1597 d := &Dup{ID: 10, Val: 100, Extra: PropertyMap{ 1597 d := &Dup{ID: 10, Val: 100, Extra: PropertyMap{
1598 » » » » "Val": {mp(200)}, 1598 » » » » "Val": PropertySlice{mp(200)},
1599 » » » » "Other": {mp("other")}, 1599 » » » » "Other": PropertySlice{mp("other")},
1600 }} 1600 }}
1601 So(ds.Put(d), ShouldBeNil) 1601 So(ds.Put(d), ShouldBeNil)
1602 1602
1603 d = &Dup{ID: 10} 1603 d = &Dup{ID: 10}
1604 So(ds.Get(d), ShouldBeNil) 1604 So(ds.Get(d), ShouldBeNil)
1605 So(d, ShouldResemble, &Dup{ 1605 So(d, ShouldResemble, &Dup{
1606 » » » » ID: 10, Val: 100, Extra: PropertyMap{"Other": {m p("other")}}, 1606 » » » » ID: 10, Val: 100, Extra: PropertyMap{"Other": Pr opertySlice{mp("other")}},
1607 }) 1607 })
1608 }) 1608 })
1609 1609
1610 Convey("Can change repeated field to non-repeating field", func( ) { 1610 Convey("Can change repeated field to non-repeating field", func( ) {
1611 initial := PropertyMap{ 1611 initial := PropertyMap{
1612 » » » » "$key": {mpNI(ds.MakeKey("NonRepeating", 10))}, 1612 » » » » "$key": mpNI(ds.MakeKey("NonRepeating", 10)),
1613 » » » » "Val": {mp(100), mp(200), mp(400)}, 1613 » » » » "Val": PropertySlice{mp(100), mp(200), mp(400)} ,
1614 } 1614 }
1615 So(ds.Put(initial), ShouldBeNil) 1615 So(ds.Put(initial), ShouldBeNil)
1616 1616
1617 type NonRepeating struct { 1617 type NonRepeating struct {
1618 ID int64 `gae:"$id"` 1618 ID int64 `gae:"$id"`
1619 Val int64 1619 Val int64
1620 Extra PropertyMap `gae:",extra"` 1620 Extra PropertyMap `gae:",extra"`
1621 } 1621 }
1622 n := &NonRepeating{ID: 10} 1622 n := &NonRepeating{ID: 10}
1623 So(ds.Get(n), ShouldBeNil) 1623 So(ds.Get(n), ShouldBeNil)
1624 So(n, ShouldResemble, &NonRepeating{ 1624 So(n, ShouldResemble, &NonRepeating{
1625 ID: 10, Val: 0, Extra: PropertyMap{ 1625 ID: 10, Val: 0, Extra: PropertyMap{
1626 » » » » » "Val": {mp(100), mp(200), mp(400)}, 1626 » » » » » "Val": PropertySlice{mp(100), mp(200), m p(400)},
1627 }, 1627 },
1628 }) 1628 })
1629 }) 1629 })
1630 1630
1631 Convey("Deals correctly with recursive types", func() { 1631 Convey("Deals correctly with recursive types", func() {
1632 initial := PropertyMap{ 1632 initial := PropertyMap{
1633 » » » » "$key": {mpNI(ds.MakeKey("Outer", 10))}, 1633 » » » » "$key": mpNI(ds.MakeKey("Outer", 10)),
1634 » » » » "I.A": {mp(1), mp(2), mp(4)}, 1634 » » » » "I.A": PropertySlice{mp(1), mp(2), mp(4)},
1635 » » » » "I.B": {mp(10), mp(20), mp(40)}, 1635 » » » » "I.B": PropertySlice{mp(10), mp(20), mp(40)},
1636 » » » » "I.C": {mp(100), mp(200), mp(400)}, 1636 » » » » "I.C": PropertySlice{mp(100), mp(200), mp(400)} ,
1637 } 1637 }
1638 So(ds.Put(initial), ShouldBeNil) 1638 So(ds.Put(initial), ShouldBeNil)
1639 type Inner struct { 1639 type Inner struct {
1640 A int64 1640 A int64
1641 B int64 1641 B int64
1642 } 1642 }
1643 type Outer struct { 1643 type Outer struct {
1644 ID int64 `gae:"$id"` 1644 ID int64 `gae:"$id"`
1645 1645
1646 I []Inner 1646 I []Inner
1647 Extra PropertyMap `gae:",extra"` 1647 Extra PropertyMap `gae:",extra"`
1648 } 1648 }
1649 o := &Outer{ID: 10} 1649 o := &Outer{ID: 10}
1650 So(ds.Get(o), ShouldBeNil) 1650 So(ds.Get(o), ShouldBeNil)
1651 So(o, ShouldResemble, &Outer{ 1651 So(o, ShouldResemble, &Outer{
1652 ID: 10, 1652 ID: 10,
1653 I: []Inner{ 1653 I: []Inner{
1654 {1, 10}, 1654 {1, 10},
1655 {2, 20}, 1655 {2, 20},
1656 {4, 40}, 1656 {4, 40},
1657 }, 1657 },
1658 Extra: PropertyMap{ 1658 Extra: PropertyMap{
1659 » » » » » "I.C": {mp(100), mp(200), mp(400)}, 1659 » » » » » "I.C": PropertySlice{mp(100), mp(200), m p(400)},
1660 }, 1660 },
1661 }) 1661 })
1662 }) 1662 })
1663 1663
1664 Convey("Problems", func() { 1664 Convey("Problems", func() {
1665 Convey("multiple extra fields", func() { 1665 Convey("multiple extra fields", func() {
1666 type Bad struct { 1666 type Bad struct {
1667 A PropertyMap `gae:",extra"` 1667 A PropertyMap `gae:",extra"`
1668 B PropertyMap `gae:",extra"` 1668 B PropertyMap `gae:",extra"`
1669 } 1669 }
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
1914 if err != nil { 1914 if err != nil {
1915 panic(fmt.Errorf("failed to find absolute path f or `%s`", sameLevelDir)) 1915 panic(fmt.Errorf("failed to find absolute path f or `%s`", sameLevelDir))
1916 } 1916 }
1917 1917
1918 ids, err := FindAndParseIndexYAML(abs) 1918 ids, err := FindAndParseIndexYAML(abs)
1919 So(err, ShouldBeNil) 1919 So(err, ShouldBeNil)
1920 So(ids[1].Kind, ShouldEqual, "Test Foo") 1920 So(ids[1].Kind, ShouldEqual, "Test Foo")
1921 }) 1921 })
1922 }) 1922 })
1923 } 1923 }
OLDNEW
« no previous file with comments | « impl/prod/raw_datastore_type_converter.go ('k') | service/datastore/dumper/dumper.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698