| 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         "fmt" | 8         "fmt" | 
| 9 »       "infra/gae/libs/gae" | 9 »       "infra/gae/libs/meta" | 
| 10 »       "infra/gae/libs/gae/helper" | 10 »       "infra/gae/libs/wrapper" | 
| 11         "math" | 11         "math" | 
| 12         "testing" | 12         "testing" | 
| 13 | 13 | 
| 14         . "github.com/smartystreets/goconvey/convey" | 14         . "github.com/smartystreets/goconvey/convey" | 
| 15         "golang.org/x/net/context" | 15         "golang.org/x/net/context" | 
|  | 16 | 
|  | 17         "appengine/datastore" | 
| 16 ) | 18 ) | 
| 17 | 19 | 
| 18 func TestDatastoreKinder(t *testing.T) { | 20 func TestDatastoreKinder(t *testing.T) { | 
| 19         t.Parallel() | 21         t.Parallel() | 
| 20 | 22 | 
| 21 »       Convey("Datastore keys", t, func() { | 23 »       Convey("Datastore kinds and keys", t, func() { | 
| 22                 c := Use(context.Background()) | 24                 c := Use(context.Background()) | 
| 23 »       »       rds := gae.GetRDS(c) | 25 »       »       ds := wrapper.GetDS(c) | 
| 24 »       »       So(rds, ShouldNotBeNil) | 26 »       »       So(ds, ShouldNotBeNil) | 
|  | 27 | 
|  | 28 »       »       Convey("implements DSKinder", func() { | 
|  | 29 »       »       »       type Foo struct{} | 
|  | 30 »       »       »       So(ds.Kind(&Foo{}), ShouldEqual, "Foo") | 
|  | 31 | 
|  | 32 »       »       »       Convey("which can be tweaked by DSKindSetter", func() { | 
|  | 33 »       »       »       »       ds.SetKindNameResolver(func(interface{}) string 
     { return "spam" }) | 
|  | 34 »       »       »       »       So(ds.Kind(&Foo{}), ShouldEqual, "spam") | 
|  | 35 | 
|  | 36 »       »       »       »       Convey("and it retains the function so you can s
     tack them", func() { | 
|  | 37 »       »       »       »       »       cur := ds.KindNameResolver() | 
|  | 38 »       »       »       »       »       ds.SetKindNameResolver(func(o interface{
     }) string { return "wat" + cur(o) }) | 
|  | 39 »       »       »       »       »       So(ds.Kind(&Foo{}), ShouldEqual, "watspa
     m") | 
|  | 40 »       »       »       »       }) | 
|  | 41 »       »       »       }) | 
|  | 42 »       »       }) | 
| 25 | 43 | 
| 26                 Convey("implements DSNewKeyer", func() { | 44                 Convey("implements DSNewKeyer", func() { | 
| 27                         Convey("NewKey", func() { | 45                         Convey("NewKey", func() { | 
| 28 »       »       »       »       key := rds.NewKey("nerd", "stringID", 0, nil) | 46 »       »       »       »       key := ds.NewKey("nerd", "stringID", 0, nil) | 
| 29                                 So(key, ShouldNotBeNil) | 47                                 So(key, ShouldNotBeNil) | 
| 30                                 So(key.Kind(), ShouldEqual, "nerd") | 48                                 So(key.Kind(), ShouldEqual, "nerd") | 
| 31                                 So(key.StringID(), ShouldEqual, "stringID") | 49                                 So(key.StringID(), ShouldEqual, "stringID") | 
| 32                                 So(key.IntID(), ShouldEqual, 0) | 50                                 So(key.IntID(), ShouldEqual, 0) | 
| 33                                 So(key.Parent(), ShouldBeNil) | 51                                 So(key.Parent(), ShouldBeNil) | 
| 34 »       »       »       »       So(key.AppID(), ShouldEqual, "dev~app") | 52 »       »       »       »       So(key.AppID(), ShouldEqual, "dev~my~app") | 
| 35                                 So(key.Namespace(), ShouldEqual, "") | 53                                 So(key.Namespace(), ShouldEqual, "") | 
| 36                                 So(key.String(), ShouldEqual, "/nerd,stringID") | 54                                 So(key.String(), ShouldEqual, "/nerd,stringID") | 
| 37 »       »       »       »       So(helper.DSKeyIncomplete(key), ShouldBeFalse) | 55 »       »       »       »       So(key.Incomplete(), ShouldBeFalse) | 
| 38 »       »       »       »       So(helper.DSKeyValid(key, "", false), ShouldBeTr
     ue) | 56 »       »       »       »       So(keyValid("", key, userKeyOnly), ShouldBeTrue) | 
|  | 57 | 
|  | 58 »       »       »       »       chkey := ds.NewKey("wat", "", 100, key) | 
|  | 59 »       »       »       »       So(chkey, ShouldNotBeNil) | 
|  | 60 »       »       »       »       So(chkey.Kind(), ShouldEqual, "wat") | 
|  | 61 »       »       »       »       So(chkey.StringID(), ShouldEqual, "") | 
|  | 62 »       »       »       »       So(chkey.IntID(), ShouldEqual, 100) | 
|  | 63 »       »       »       »       So(chkey.Parent(), ShouldEqual, key) | 
|  | 64 »       »       »       »       So(chkey.AppID(), ShouldEqual, "dev~my~app") | 
|  | 65 »       »       »       »       So(chkey.Namespace(), ShouldEqual, "") | 
|  | 66 »       »       »       »       So(chkey.String(), ShouldEqual, "/nerd,stringID/
     wat,100") | 
|  | 67 »       »       »       »       So(key.Incomplete(), ShouldBeFalse) | 
|  | 68 »       »       »       »       So(keyValid("", chkey, userKeyOnly), ShouldBeTru
     e) | 
|  | 69 | 
|  | 70 »       »       »       »       incompl := ds.NewKey("sup", "", 0, key) | 
|  | 71 »       »       »       »       So(incompl, ShouldNotBeNil) | 
|  | 72 »       »       »       »       So(incompl.Incomplete(), ShouldBeTrue) | 
|  | 73 »       »       »       »       So(keyValid("", incompl, userKeyOnly), ShouldBeT
     rue) | 
|  | 74 »       »       »       »       So(incompl.String(), ShouldEqual, "/nerd,stringI
     D/sup,0") | 
|  | 75 | 
|  | 76 »       »       »       »       bad := ds.NewKey("nooo", "", 10, incompl) | 
|  | 77 »       »       »       »       So(bad, ShouldNotBeNil) | 
|  | 78 »       »       »       »       So(bad.Incomplete(), ShouldBeFalse) | 
|  | 79 »       »       »       »       So(keyValid("", bad, userKeyOnly), ShouldBeFalse
     ) | 
|  | 80 »       »       »       »       So(bad.String(), ShouldEqual, "/nerd,stringID/su
     p,0/nooo,10") | 
|  | 81 | 
|  | 82 »       »       »       »       So(rootKey(bad), ShouldEqual, key) | 
|  | 83 | 
|  | 84 »       »       »       »       Convey("other key validation", func() { | 
|  | 85 »       »       »       »       »       So(keyValid("", nil, userKeyOnly), Shoul
     dBeFalse) | 
|  | 86 | 
|  | 87 »       »       »       »       »       key := ds.NewKey("", "", 0, nil) | 
|  | 88 »       »       »       »       »       So(key, ShouldNotBeNil) | 
|  | 89 | 
|  | 90 »       »       »       »       »       So(keyValid("", key, userKeyOnly), Shoul
     dBeFalse) | 
|  | 91 | 
|  | 92 »       »       »       »       »       key = ds.NewKey("noop", "power level", 9
     000, nil) | 
|  | 93 »       »       »       »       »       So(key, ShouldNotBeNil) | 
|  | 94 | 
|  | 95 »       »       »       »       »       So(keyValid("", key, userKeyOnly), Shoul
     dBeFalse) | 
|  | 96 »       »       »       »       }) | 
|  | 97 »       »       »       }) | 
|  | 98 | 
|  | 99 »       »       »       Convey("NewKeyObj", func() { | 
|  | 100 »       »       »       »       type Foo struct { | 
|  | 101 »       »       »       »       »       _knd   string         `goon:"kind,coool"
     ` | 
|  | 102 »       »       »       »       »       ID     int64          `goon:"id"` | 
|  | 103 »       »       »       »       »       Parent *datastore.Key `goon:"parent"` | 
|  | 104 »       »       »       »       } | 
|  | 105 »       »       »       »       f := &Foo{ID: 100} | 
|  | 106 »       »       »       »       k := ds.NewKeyObj(f) | 
|  | 107 »       »       »       »       So(k.String(), ShouldEqual, "/coool,100") | 
|  | 108 | 
|  | 109 »       »       »       »       f.Parent = k | 
|  | 110 »       »       »       »       f._knd = "weevils" | 
|  | 111 »       »       »       »       f.ID = 19 | 
|  | 112 »       »       »       »       k = ds.NewKeyObj(f) | 
|  | 113 »       »       »       »       So(k.String(), ShouldEqual, "/coool,100/weevils,
     19") | 
|  | 114 | 
|  | 115 »       »       »       »       Convey("panics when you do a dumb thing", func()
      { | 
|  | 116 »       »       »       »       »       type Foo struct { | 
|  | 117 »       »       »       »       »       »       ID []byte `goon:"id"` | 
|  | 118 »       »       »       »       »       } | 
|  | 119 »       »       »       »       »       So(func() { ds.NewKeyObj(&Foo{}) }, Shou
     ldPanic) | 
|  | 120 »       »       »       »       }) | 
|  | 121 »       »       »       }) | 
|  | 122 | 
|  | 123 »       »       »       Convey("NewKeyObjError", func() { | 
|  | 124 »       »       »       »       type Foo struct { | 
|  | 125 »       »       »       »       »       ID []byte `goon:"id"` | 
|  | 126 »       »       »       »       } | 
|  | 127 »       »       »       »       _, err := ds.NewKeyObjError(&Foo{}) | 
|  | 128 »       »       »       »       So(err.Error(), ShouldContainSubstring, "must be
      int64 or string") | 
| 39                         }) | 129                         }) | 
| 40                 }) | 130                 }) | 
| 41 | 131 | 
| 42         }) | 132         }) | 
| 43 } | 133 } | 
| 44 | 134 | 
| 45 func testGetMeta(c context.Context, k gae.DSKey) int64 { |  | 
| 46         rds := gae.GetRDS(c) |  | 
| 47         k = rds.NewKey("__entity_group__", "", 1, helper.DSKeyRoot(k)) |  | 
| 48         pmap := gae.DSPropertyMap{} |  | 
| 49         rds.Get(k, &pmap) |  | 
| 50         return pmap["__version__"][0].Value().(int64) |  | 
| 51 } |  | 
| 52 |  | 
| 53 func TestDatastoreSingleReadWriter(t *testing.T) { | 135 func TestDatastoreSingleReadWriter(t *testing.T) { | 
| 54         t.Parallel() | 136         t.Parallel() | 
| 55 | 137 | 
| 56         Convey("Datastore single reads and writes", t, func() { | 138         Convey("Datastore single reads and writes", t, func() { | 
| 57                 c := Use(context.Background()) | 139                 c := Use(context.Background()) | 
| 58 »       »       rds := gae.GetRDS(c) | 140 »       »       ds := wrapper.GetDS(c) | 
| 59 »       »       So(rds, ShouldNotBeNil) | 141 »       »       So(ds, ShouldNotBeNil) | 
| 60 | 142 | 
| 61                 Convey("implements DSSingleReadWriter", func() { | 143                 Convey("implements DSSingleReadWriter", func() { | 
| 62                         type Foo struct { | 144                         type Foo struct { | 
| 63 »       »       »       »       Val int | 145 »       »       »       »       ID     int64          `goon:"id" datastore:"-"` | 
|  | 146 »       »       »       »       Parent *datastore.Key `goon:"parent" datastore:"
     -"` | 
|  | 147 »       »       »       »       Val    int | 
| 64                         } | 148                         } | 
| 65 | 149 | 
| 66                         Convey("invalid keys break", func() { | 150                         Convey("invalid keys break", func() { | 
| 67 »       »       »       »       k := rds.NewKey("Foo", "", 0, nil) | 151 »       »       »       »       k := ds.NewKeyObj(&Foo{}) | 
| 68 »       »       »       »       So(rds.Get(k, nil), ShouldEqual, gae.ErrDSInvali
     dKey) | 152 »       »       »       »       f := &Foo{Parent: k} | 
| 69 | 153 »       »       »       »       So(ds.Get(f), ShouldEqual, datastore.ErrInvalidK
     ey) | 
| 70 »       »       »       »       _, err := rds.Put(rds.NewKey("Foo", "", 0, k), &
     Foo{}) | 154 | 
| 71 »       »       »       »       So(err, ShouldEqual, gae.ErrDSInvalidKey) | 155 »       »       »       »       _, err := ds.Put(f) | 
|  | 156 »       »       »       »       So(err, ShouldEqual, datastore.ErrInvalidKey) | 
| 72                         }) | 157                         }) | 
| 73 | 158 | 
| 74                         Convey("getting objects that DNE is an error", func() { | 159                         Convey("getting objects that DNE is an error", func() { | 
| 75 »       »       »       »       k := rds.NewKey("Foo", "", 1, nil) | 160 »       »       »       »       So(ds.Get(&Foo{ID: 1}), ShouldEqual, datastore.E
     rrNoSuchEntity) | 
| 76 »       »       »       »       So(rds.Get(k, nil), ShouldEqual, gae.ErrDSNoSuch
     Entity) |  | 
| 77                         }) | 161                         }) | 
| 78 | 162 | 
| 79                         Convey("Can Put stuff", func() { | 163                         Convey("Can Put stuff", func() { | 
| 80                                 // with an incomplete key! | 164                                 // with an incomplete key! | 
| 81                                 k := rds.NewKey("Foo", "", 0, nil) |  | 
| 82                                 f := &Foo{Val: 10} | 165                                 f := &Foo{Val: 10} | 
| 83 »       »       »       »       k, err := rds.Put(k, f) | 166 »       »       »       »       k, err := ds.Put(f) | 
| 84                                 So(err, ShouldBeNil) | 167                                 So(err, ShouldBeNil) | 
| 85                                 So(k.String(), ShouldEqual, "/Foo,1") | 168                                 So(k.String(), ShouldEqual, "/Foo,1") | 
|  | 169                                 So(ds.NewKeyObj(f), ShouldResemble, k) | 
| 86 | 170 | 
| 87                                 Convey("and Get it back", func() { | 171                                 Convey("and Get it back", func() { | 
| 88 »       »       »       »       »       newFoo := &Foo{} | 172 »       »       »       »       »       newFoo := &Foo{ID: 1} | 
| 89 »       »       »       »       »       err := rds.Get(k, newFoo) | 173 »       »       »       »       »       err := ds.Get(newFoo) | 
| 90                                         So(err, ShouldBeNil) | 174                                         So(err, ShouldBeNil) | 
| 91                                         So(newFoo, ShouldResemble, f) | 175                                         So(newFoo, ShouldResemble, f) | 
| 92 | 176 | 
| 93                                         Convey("and we can Delete it", func() { | 177                                         Convey("and we can Delete it", func() { | 
| 94 »       »       »       »       »       »       err := rds.Delete(k) | 178 »       »       »       »       »       »       err := ds.Delete(ds.NewKey("Foo"
     , "", 1, nil)) | 
| 95                                                 So(err, ShouldBeNil) | 179                                                 So(err, ShouldBeNil) | 
| 96 | 180 | 
| 97 »       »       »       »       »       »       err = rds.Get(k, newFoo) | 181 »       »       »       »       »       »       err = ds.Get(newFoo) | 
| 98 »       »       »       »       »       »       So(err, ShouldEqual, gae.ErrDSNo
     SuchEntity) | 182 »       »       »       »       »       »       So(err, ShouldEqual, datastore.E
     rrNoSuchEntity) | 
| 99                                         }) | 183                                         }) | 
| 100                                 }) | 184                                 }) | 
| 101                                 Convey("Deleteing with a bogus key is bad", func
     () { | 185                                 Convey("Deleteing with a bogus key is bad", func
     () { | 
| 102 »       »       »       »       »       err := rds.Delete(rds.NewKey("Foo", "wat
     ", 100, nil)) | 186 »       »       »       »       »       err := ds.Delete(ds.NewKey("Foo", "wat",
      100, nil)) | 
| 103 »       »       »       »       »       So(err, ShouldEqual, gae.ErrDSInvalidKey
     ) | 187 »       »       »       »       »       So(err, ShouldEqual, datastore.ErrInvali
     dKey) | 
| 104                                 }) | 188                                 }) | 
| 105                                 Convey("Deleteing a DNE entity is fine", func() 
     { | 189                                 Convey("Deleteing a DNE entity is fine", func() 
     { | 
| 106 »       »       »       »       »       err := rds.Delete(rds.NewKey("Foo", "wat
     ", 0, nil)) | 190 »       »       »       »       »       err := ds.Delete(ds.NewKey("Foo", "wat",
      0, nil)) | 
| 107                                         So(err, ShouldBeNil) | 191                                         So(err, ShouldBeNil) | 
| 108                                 }) | 192                                 }) | 
| 109 | 193 | 
| 110                                 Convey("serialization breaks in the normal ways"
     , func() { | 194                                 Convey("serialization breaks in the normal ways"
     , func() { | 
| 111                                         type BadFoo struct { | 195                                         type BadFoo struct { | 
| 112 »       »       »       »       »       »       Val uint8 | 196 »       »       »       »       »       »       _kind string `goon:"kind,Foo"` | 
|  | 197 »       »       »       »       »       »       ID    int64  `goon:"id" datastor
     e:"-"` | 
|  | 198 »       »       »       »       »       »       Val   uint8 | 
| 113                                         } | 199                                         } | 
| 114 »       »       »       »       »       _, err := rds.Put(k, &BadFoo{}) | 200 »       »       »       »       »       _, err := ds.Put(&BadFoo{}) | 
| 115 »       »       »       »       »       So(err.Error(), ShouldContainSubstring, 
     "invalid type: uint8") | 201 »       »       »       »       »       So(err.Error(), ShouldContainSubstring, | 
| 116 | 202 »       »       »       »       »       »       "unsupported struct field type: 
     uint8") | 
| 117 »       »       »       »       »       err = rds.Get(k, &BadFoo{}) | 203 | 
| 118 »       »       »       »       »       So(err.Error(), ShouldContainSubstring, 
     "invalid type: uint8") | 204 »       »       »       »       »       err = ds.Get(&BadFoo{ID: 1}) | 
|  | 205 »       »       »       »       »       So(err.Error(), ShouldContainSubstring, | 
|  | 206 »       »       »       »       »       »       "type mismatch: int versus uint8
     ") | 
| 119                                 }) | 207                                 }) | 
| 120 | 208 | 
| 121                                 Convey("check that metadata works", func() { | 209                                 Convey("check that metadata works", func() { | 
| 122 »       »       »       »       »       So(testGetMeta(c, k), ShouldEqual, 1) | 210 »       »       »       »       »       val, _ := meta.GetEntityGroupVersion(c, 
     k) | 
| 123 | 211 »       »       »       »       »       So(val, ShouldEqual, 1) | 
| 124 »       »       »       »       »       pkey := k | 212 | 
| 125                                         for i := 0; i < 10; i++ { | 213                                         for i := 0; i < 10; i++ { | 
| 126 »       »       »       »       »       »       k := rds.NewKey("Foo", "", 0, pk
     ey) | 214 »       »       »       »       »       »       _, err = ds.Put(&Foo{Val: 10, Pa
     rent: k}) | 
| 127 »       »       »       »       »       »       _, err = rds.Put(k, &Foo{Val: 10
     }) |  | 
| 128                                                 So(err, ShouldBeNil) | 215                                                 So(err, ShouldBeNil) | 
| 129                                         } | 216                                         } | 
| 130 »       »       »       »       »       So(testGetMeta(c, k), ShouldEqual, 11) | 217 »       »       »       »       »       val, _ = meta.GetEntityGroupVersion(c, k
     ) | 
|  | 218 »       »       »       »       »       So(val, ShouldEqual, 11) | 
| 131 | 219 | 
| 132                                         Convey("ensure that group versions persi
     st across deletes", func() { | 220                                         Convey("ensure that group versions persi
     st across deletes", func() { | 
| 133 »       »       »       »       »       »       So(rds.Delete(k), ShouldBeNil) | 221 »       »       »       »       »       »       So(ds.Delete(k), ShouldBeNil) | 
| 134                                                 for i := int64(1); i < 11; i++ { | 222                                                 for i := int64(1); i < 11; i++ { | 
| 135 »       »       »       »       »       »       »       So(rds.Delete(rds.NewKey
     ("Foo", "", i, k)), ShouldBeNil) | 223 »       »       »       »       »       »       »       So(ds.Delete(ds.NewKey("
     Foo", "", i, k)), ShouldBeNil) | 
| 136                                                 } | 224                                                 } | 
| 137                                                 // TODO(riannucci): replace with
      a Count query instead of this cast | 225                                                 // TODO(riannucci): replace with
      a Count query instead of this cast | 
| 138 »       »       »       »       »       »       ents := rds.(*dsImpl).data.store
     .GetCollection("ents:") | 226 »       »       »       »       »       »       ents := ds.(*dsImpl).data.store.
     GetCollection("ents:") | 
| 139                                                 num, _ := ents.GetTotals() | 227                                                 num, _ := ents.GetTotals() | 
| 140                                                 // /__entity_root_ids__,Foo | 228                                                 // /__entity_root_ids__,Foo | 
| 141                                                 // /Foo,1/__entity_group__,1 | 229                                                 // /Foo,1/__entity_group__,1 | 
| 142                                                 // /Foo,1/__entity_group_ids__,1 | 230                                                 // /Foo,1/__entity_group_ids__,1 | 
| 143                                                 So(num, ShouldEqual, 3) | 231                                                 So(num, ShouldEqual, 3) | 
| 144 | 232 | 
| 145                                                 version, err := curVersion(ents,
      groupMetaKey(k)) | 233                                                 version, err := curVersion(ents,
      groupMetaKey(k)) | 
| 146                                                 So(err, ShouldBeNil) | 234                                                 So(err, ShouldBeNil) | 
| 147                                                 So(version, ShouldEqual, 22) | 235                                                 So(version, ShouldEqual, 22) | 
| 148 | 236 | 
| 149 »       »       »       »       »       »       k, err := rds.Put(k, f) | 237 »       »       »       »       »       »       k, err := ds.Put(f) | 
| 150                                                 So(err, ShouldBeNil) | 238                                                 So(err, ShouldBeNil) | 
| 151 »       »       »       »       »       »       So(testGetMeta(c, k), ShouldEqua
     l, 23) | 239 »       »       »       »       »       »       val, _ := meta.GetEntityGroupVer
     sion(c, k) | 
|  | 240 »       »       »       »       »       »       So(val, ShouldEqual, 23) | 
| 152                                         }) | 241                                         }) | 
| 153                                 }) | 242                                 }) | 
| 154                         }) | 243                         }) | 
| 155                 }) | 244                 }) | 
| 156 | 245 | 
| 157                 Convey("implements DSTransactioner", func() { | 246                 Convey("implements DSTransactioner", func() { | 
| 158                         type Foo struct { | 247                         type Foo struct { | 
| 159 »       »       »       »       Val int | 248 »       »       »       »       ID     int64          `goon:"id" datastore:"-"` | 
|  | 249 »       »       »       »       Parent *datastore.Key `goon:"parent" datastore:"
     -"` | 
|  | 250 »       »       »       »       Val    int | 
| 160                         } | 251                         } | 
| 161                         Convey("Put", func() { | 252                         Convey("Put", func() { | 
| 162                                 k := rds.NewKey("Foo", "", 0, nil) |  | 
| 163                                 f := &Foo{Val: 10} | 253                                 f := &Foo{Val: 10} | 
| 164 »       »       »       »       k, err := rds.Put(k, f) | 254 »       »       »       »       k, err := ds.Put(f) | 
| 165                                 So(err, ShouldBeNil) | 255                                 So(err, ShouldBeNil) | 
| 166                                 So(k.String(), ShouldEqual, "/Foo,1") | 256                                 So(k.String(), ShouldEqual, "/Foo,1") | 
|  | 257                                 So(ds.NewKeyObj(f), ShouldResemble, k) | 
| 167 | 258 | 
| 168                                 Convey("can Put new entity groups", func() { | 259                                 Convey("can Put new entity groups", func() { | 
| 169 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 260 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 170 »       »       »       »       »       »       rds := gae.GetRDS(c) | 261 »       »       »       »       »       »       ds := wrapper.GetDS(c) | 
| 171 »       »       »       »       »       »       So(rds, ShouldNotBeNil) | 262 »       »       »       »       »       »       So(ds, ShouldNotBeNil) | 
| 172 | 263 | 
| 173                                                 f1 := &Foo{Val: 100} | 264                                                 f1 := &Foo{Val: 100} | 
| 174 »       »       »       »       »       »       k, err := rds.Put(rds.NewKey("Fo
     o", "", 0, nil), f1) | 265 »       »       »       »       »       »       k, err := ds.Put(f1) | 
| 175                                                 So(err, ShouldBeNil) | 266                                                 So(err, ShouldBeNil) | 
| 176                                                 So(k.String(), ShouldEqual, "/Fo
     o,2") | 267                                                 So(k.String(), ShouldEqual, "/Fo
     o,2") | 
| 177 | 268 | 
| 178                                                 f2 := &Foo{Val: 200} | 269                                                 f2 := &Foo{Val: 200} | 
| 179 »       »       »       »       »       »       k, err = rds.Put(rds.NewKey("Foo
     ", "", 0, nil), f2) | 270 »       »       »       »       »       »       k, err = ds.Put(f2) | 
| 180                                                 So(err, ShouldBeNil) | 271                                                 So(err, ShouldBeNil) | 
| 181                                                 So(k.String(), ShouldEqual, "/Fo
     o,3") | 272                                                 So(k.String(), ShouldEqual, "/Fo
     o,3") | 
| 182 | 273 | 
| 183                                                 return nil | 274                                                 return nil | 
| 184 »       »       »       »       »       }, &gae.DSTransactionOptions{XG: true}) | 275 »       »       »       »       »       }, &datastore.TransactionOptions{XG: tru
     e}) | 
| 185                                         So(err, ShouldBeNil) | 276                                         So(err, ShouldBeNil) | 
| 186 | 277 | 
| 187 »       »       »       »       »       f := &Foo{} | 278 »       »       »       »       »       f := &Foo{ID: 2} | 
| 188 »       »       »       »       »       So(rds.Get(rds.NewKey("Foo", "", 2, nil)
     , f), ShouldBeNil) | 279 »       »       »       »       »       So(ds.Get(f), ShouldBeNil) | 
| 189                                         So(f.Val, ShouldEqual, 100) | 280                                         So(f.Val, ShouldEqual, 100) | 
| 190 | 281 | 
| 191 »       »       »       »       »       f = &Foo{} | 282 »       »       »       »       »       f = &Foo{ID: 3} | 
| 192 »       »       »       »       »       So(rds.Get(rds.NewKey("Foo", "", 3, nil)
     , f), ShouldBeNil) | 283 »       »       »       »       »       So(ds.Get(f), ShouldBeNil) | 
| 193                                         So(f.Val, ShouldEqual, 200) | 284                                         So(f.Val, ShouldEqual, 200) | 
| 194                                 }) | 285                                 }) | 
| 195 | 286 | 
| 196                                 Convey("can Put new entities in a current group"
     , func() { | 287                                 Convey("can Put new entities in a current group"
     , func() { | 
| 197 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 288 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 198 »       »       »       »       »       »       rds := gae.GetRDS(c) | 289 »       »       »       »       »       »       ds := wrapper.GetDS(c) | 
| 199 »       »       »       »       »       »       So(rds, ShouldNotBeNil) | 290 »       »       »       »       »       »       So(ds, ShouldNotBeNil) | 
| 200 | 291 | 
| 201 »       »       »       »       »       »       par := k | 292 »       »       »       »       »       »       f1 := &Foo{Val: 100, Parent: ds.
     NewKeyObj(f)} | 
| 202 | 293 »       »       »       »       »       »       k, err := ds.Put(f1) | 
| 203 »       »       »       »       »       »       f1 := &Foo{Val: 100} |  | 
| 204 »       »       »       »       »       »       k, err := rds.Put(rds.NewKey("Fo
     o", "", 0, par), f1) |  | 
| 205                                                 So(err, ShouldBeNil) | 294                                                 So(err, ShouldBeNil) | 
| 206                                                 So(k.String(), ShouldEqual, "/Fo
     o,1/Foo,1") | 295                                                 So(k.String(), ShouldEqual, "/Fo
     o,1/Foo,1") | 
| 207 | 296 | 
| 208 »       »       »       »       »       »       f2 := &Foo{Val: 200} | 297 »       »       »       »       »       »       f2 := &Foo{Val: 200, Parent: ds.
     NewKeyObj(f)} | 
| 209 »       »       »       »       »       »       k, err = rds.Put(rds.NewKey("Foo
     ", "", 0, par), f2) | 298 »       »       »       »       »       »       k, err = ds.Put(f2) | 
| 210                                                 So(err, ShouldBeNil) | 299                                                 So(err, ShouldBeNil) | 
| 211                                                 So(k.String(), ShouldEqual, "/Fo
     o,1/Foo,2") | 300                                                 So(k.String(), ShouldEqual, "/Fo
     o,1/Foo,2") | 
| 212 | 301 | 
| 213                                                 return nil | 302                                                 return nil | 
| 214                                         }, nil) | 303                                         }, nil) | 
| 215                                         So(err, ShouldBeNil) | 304                                         So(err, ShouldBeNil) | 
| 216 | 305 | 
| 217 »       »       »       »       »       f1 := &Foo{} | 306 »       »       »       »       »       f1 := &Foo{ID: 1, Parent: ds.NewKeyObj(&
     Foo{ID: 1})} | 
| 218 »       »       »       »       »       So(rds.Get(rds.NewKey("Foo", "", 1, k), 
     f1), ShouldBeNil) | 307 »       »       »       »       »       So(ds.Get(f1), ShouldBeNil) | 
| 219                                         So(f1.Val, ShouldEqual, 100) | 308                                         So(f1.Val, ShouldEqual, 100) | 
| 220 | 309 | 
| 221 »       »       »       »       »       f2 := &Foo{} | 310 »       »       »       »       »       f2 := &Foo{ID: 2, Parent: f1.Parent} | 
| 222 »       »       »       »       »       So(rds.Get(rds.NewKey("Foo", "", 2, k), 
     f2), ShouldBeNil) | 311 »       »       »       »       »       So(ds.Get(f2), ShouldBeNil) | 
| 223                                         So(f2.Val, ShouldEqual, 200) | 312                                         So(f2.Val, ShouldEqual, 200) | 
| 224                                 }) | 313                                 }) | 
| 225 | 314 | 
| 226                                 Convey("Deletes work too", func() { | 315                                 Convey("Deletes work too", func() { | 
| 227 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 316 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 228 »       »       »       »       »       »       rds := gae.GetRDS(c) | 317 »       »       »       »       »       »       ds := wrapper.GetDS(c) | 
| 229 »       »       »       »       »       »       So(rds, ShouldNotBeNil) | 318 »       »       »       »       »       »       So(ds, ShouldNotBeNil) | 
| 230 »       »       »       »       »       »       So(rds.Delete(k), ShouldBeNil) | 319 »       »       »       »       »       »       So(ds.Delete(ds.NewKeyObj(f)), S
     houldBeNil) | 
| 231                                                 return nil | 320                                                 return nil | 
| 232                                         }, nil) | 321                                         }, nil) | 
| 233                                         So(err, ShouldBeNil) | 322                                         So(err, ShouldBeNil) | 
| 234 »       »       »       »       »       So(rds.Get(k, f), ShouldEqual, gae.ErrDS
     NoSuchEntity) | 323 »       »       »       »       »       So(ds.Get(f), ShouldEqual, datastore.Err
     NoSuchEntity) | 
| 235                                 }) | 324                                 }) | 
| 236 | 325 | 
| 237                                 Convey("A Get counts against your group count", 
     func() { | 326                                 Convey("A Get counts against your group count", 
     func() { | 
| 238 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 327 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 239 »       »       »       »       »       »       rds := gae.GetRDS(c) | 328 »       »       »       »       »       »       ds := wrapper.GetDS(c) | 
| 240 »       »       »       »       »       »       f := &Foo{} | 329 »       »       »       »       »       »       f := &Foo{ID: 20} | 
| 241 »       »       »       »       »       »       So(rds.Get(rds.NewKey("Foo", "",
      20, nil), f), ShouldEqual, gae.ErrDSNoSuchEntity) | 330 »       »       »       »       »       »       So(ds.Get(f), ShouldEqual, datas
     tore.ErrNoSuchEntity) | 
| 242 | 331 | 
| 243 »       »       »       »       »       »       So(rds.Get(k, f).Error(), Should
     ContainSubstring, "cross-group") | 332 »       »       »       »       »       »       f.ID = 1 | 
|  | 333 »       »       »       »       »       »       So(ds.Get(f).Error(), ShouldCont
     ainSubstring, "cross-group") | 
| 244                                                 return nil | 334                                                 return nil | 
| 245                                         }, nil) | 335                                         }, nil) | 
| 246                                         So(err, ShouldBeNil) | 336                                         So(err, ShouldBeNil) | 
| 247                                 }) | 337                                 }) | 
| 248 | 338 | 
| 249                                 Convey("Get takes a snapshot", func() { | 339                                 Convey("Get takes a snapshot", func() { | 
| 250 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 340 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 251 »       »       »       »       »       »       txnDS := gae.GetRDS(c) | 341 »       »       »       »       »       »       txnDS := wrapper.GetDS(c) | 
| 252                                                 So(txnDS, ShouldNotBeNil) | 342                                                 So(txnDS, ShouldNotBeNil) | 
| 253 | 343 | 
| 254 »       »       »       »       »       »       So(txnDS.Get(k, f), ShouldBeNil) | 344 »       »       »       »       »       »       f := &Foo{ID: 1} | 
|  | 345 »       »       »       »       »       »       So(txnDS.Get(f), ShouldBeNil) | 
| 255                                                 So(f.Val, ShouldEqual, 10) | 346                                                 So(f.Val, ShouldEqual, 10) | 
| 256 | 347 | 
| 257                                                 // Don't ever do this in a real 
     program unless you want to guarantee | 348                                                 // Don't ever do this in a real 
     program unless you want to guarantee | 
| 258                                                 // a failed transaction :) | 349                                                 // a failed transaction :) | 
| 259                                                 f.Val = 11 | 350                                                 f.Val = 11 | 
| 260 »       »       »       »       »       »       _, err := rds.Put(k, f) | 351 »       »       »       »       »       »       _, err := ds.Put(f) | 
| 261                                                 So(err, ShouldBeNil) | 352                                                 So(err, ShouldBeNil) | 
| 262 | 353 | 
| 263 »       »       »       »       »       »       So(txnDS.Get(k, f), ShouldBeNil) | 354 »       »       »       »       »       »       So(txnDS.Get(f), ShouldBeNil) | 
| 264                                                 So(f.Val, ShouldEqual, 10) | 355                                                 So(f.Val, ShouldEqual, 10) | 
| 265 | 356 | 
| 266                                                 return nil | 357                                                 return nil | 
| 267                                         }, nil) | 358                                         }, nil) | 
| 268                                         So(err, ShouldBeNil) | 359                                         So(err, ShouldBeNil) | 
| 269 | 360 | 
| 270 »       »       »       »       »       f := &Foo{} | 361 »       »       »       »       »       f := &Foo{ID: 1} | 
| 271 »       »       »       »       »       So(rds.Get(k, f), ShouldBeNil) | 362 »       »       »       »       »       So(ds.Get(f), ShouldBeNil) | 
| 272                                         So(f.Val, ShouldEqual, 11) | 363                                         So(f.Val, ShouldEqual, 11) | 
|  | 364 | 
| 273                                 }) | 365                                 }) | 
| 274 | 366 | 
| 275                                 Convey("and snapshots are consistent even after 
     Puts", func() { | 367                                 Convey("and snapshots are consistent even after 
     Puts", func() { | 
| 276 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 368 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 277 »       »       »       »       »       »       txnDS := gae.GetRDS(c) | 369 »       »       »       »       »       »       txnDS := wrapper.GetDS(c) | 
| 278                                                 So(txnDS, ShouldNotBeNil) | 370                                                 So(txnDS, ShouldNotBeNil) | 
| 279 | 371 | 
| 280 »       »       »       »       »       »       f := &Foo{} | 372 »       »       »       »       »       »       f := &Foo{ID: 1} | 
| 281 »       »       »       »       »       »       So(txnDS.Get(k, f), ShouldBeNil) | 373 »       »       »       »       »       »       So(txnDS.Get(f), ShouldBeNil) | 
| 282                                                 So(f.Val, ShouldEqual, 10) | 374                                                 So(f.Val, ShouldEqual, 10) | 
| 283 | 375 | 
| 284                                                 // Don't ever do this in a real 
     program unless you want to guarantee | 376                                                 // Don't ever do this in a real 
     program unless you want to guarantee | 
| 285                                                 // a failed transaction :) | 377                                                 // a failed transaction :) | 
| 286                                                 f.Val = 11 | 378                                                 f.Val = 11 | 
| 287 »       »       »       »       »       »       _, err := rds.Put(k, f) | 379 »       »       »       »       »       »       _, err := ds.Put(f) | 
| 288                                                 So(err, ShouldBeNil) | 380                                                 So(err, ShouldBeNil) | 
| 289 | 381 | 
| 290 »       »       »       »       »       »       So(txnDS.Get(k, f), ShouldBeNil) | 382 »       »       »       »       »       »       So(txnDS.Get(f), ShouldBeNil) | 
| 291                                                 So(f.Val, ShouldEqual, 10) | 383                                                 So(f.Val, ShouldEqual, 10) | 
| 292 | 384 | 
| 293                                                 f.Val = 20 | 385                                                 f.Val = 20 | 
| 294 »       »       »       »       »       »       _, err = txnDS.Put(k, f) | 386 »       »       »       »       »       »       _, err = txnDS.Put(f) | 
| 295                                                 So(err, ShouldBeNil) | 387                                                 So(err, ShouldBeNil) | 
| 296 | 388 | 
| 297 »       »       »       »       »       »       So(txnDS.Get(k, f), ShouldBeNil) | 389 »       »       »       »       »       »       So(txnDS.Get(f), ShouldBeNil) | 
| 298                                                 So(f.Val, ShouldEqual, 10) // st
     ill gets 10 | 390                                                 So(f.Val, ShouldEqual, 10) // st
     ill gets 10 | 
| 299 | 391 | 
| 300                                                 return nil | 392                                                 return nil | 
| 301                                         }, nil) | 393                                         }, nil) | 
| 302                                         So(err.Error(), ShouldContainSubstring, 
     "concurrent") | 394                                         So(err.Error(), ShouldContainSubstring, 
     "concurrent") | 
| 303 | 395 | 
| 304 »       »       »       »       »       f := &Foo{} | 396 »       »       »       »       »       f := &Foo{ID: 1} | 
| 305 »       »       »       »       »       So(rds.Get(k, f), ShouldBeNil) | 397 »       »       »       »       »       So(ds.Get(f), ShouldBeNil) | 
| 306                                         So(f.Val, ShouldEqual, 11) | 398                                         So(f.Val, ShouldEqual, 11) | 
| 307                                 }) | 399                                 }) | 
| 308 | 400 | 
| 309                                 Convey("Reusing a transaction context is bad new
     s", func() { | 401                                 Convey("Reusing a transaction context is bad new
     s", func() { | 
| 310 »       »       »       »       »       k := rds.NewKey("Foo", "", 1, nil) | 402 »       »       »       »       »       txnDS := wrapper.Datastore(nil) | 
| 311 »       »       »       »       »       txnDS := gae.RawDatastore(nil) | 403 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 312 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 404 »       »       »       »       »       »       txnDS = wrapper.GetDS(c) | 
| 313 »       »       »       »       »       »       txnDS = gae.GetRDS(c) | 405 »       »       »       »       »       »       So(txnDS.Get(&Foo{ID: 1}), Shoul
     dBeNil) | 
| 314 »       »       »       »       »       »       So(txnDS.Get(k, &Foo{}), ShouldB
     eNil) |  | 
| 315                                                 return nil | 406                                                 return nil | 
| 316                                         }, nil) | 407                                         }, nil) | 
| 317                                         So(err, ShouldBeNil) | 408                                         So(err, ShouldBeNil) | 
| 318 »       »       »       »       »       So(txnDS.Get(k, &Foo{}).Error(), ShouldC
     ontainSubstring, "expired") | 409 »       »       »       »       »       So(txnDS.Get(&Foo{ID: 1}).Error(), Shoul
     dContainSubstring, "expired") | 
| 319                                 }) | 410                                 }) | 
| 320 | 411 | 
| 321                                 Convey("Nested transactions are rejected", func(
     ) { | 412                                 Convey("Nested transactions are rejected", func(
     ) { | 
| 322 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 413 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 323 »       »       »       »       »       »       err := gae.GetRDS(c).RunInTransa
     ction(func(c context.Context) error { | 414 »       »       »       »       »       »       err := wrapper.GetDS(c).RunInTra
     nsaction(func(c context.Context) error { | 
| 324                                                         panic("noooo") | 415                                                         panic("noooo") | 
| 325                                                 }, nil) | 416                                                 }, nil) | 
| 326                                                 So(err.Error(), ShouldContainSub
     string, "nested transactions") | 417                                                 So(err.Error(), ShouldContainSub
     string, "nested transactions") | 
| 327                                                 return nil | 418                                                 return nil | 
| 328                                         }, nil) | 419                                         }, nil) | 
| 329                                         So(err, ShouldBeNil) | 420                                         So(err, ShouldBeNil) | 
| 330                                 }) | 421                                 }) | 
| 331 | 422 | 
| 332                                 Convey("Concurrent transactions only accept one 
     set of changes", func() { | 423                                 Convey("Concurrent transactions only accept one 
     set of changes", func() { | 
| 333                                         // Note: I think this implementation is 
     actually /slightly/ wrong. | 424                                         // Note: I think this implementation is 
     actually /slightly/ wrong. | 
| 334                                         // Accorting to my read of the docs for 
     appengine, when you open a | 425                                         // Accorting to my read of the docs for 
     appengine, when you open a | 
| 335                                         // transaction it actually (essentially)
      holds a reference to the | 426                                         // transaction it actually (essentially)
      holds a reference to the | 
| 336                                         // entire datastore. Our implementation 
     takes a snapshot of the | 427                                         // entire datastore. Our implementation 
     takes a snapshot of the | 
| 337                                         // entity group as soon as something obs
     erves/affects it. | 428                                         // entity group as soon as something obs
     erves/affects it. | 
| 338                                         // | 429                                         // | 
| 339                                         // That said... I'm not sure if there's 
     really a semantic difference. | 430                                         // That said... I'm not sure if there's 
     really a semantic difference. | 
| 340 »       »       »       »       »       err := rds.RunInTransaction(func(c conte
     xt.Context) error { | 431 »       »       »       »       »       err := ds.RunInTransaction(func(c contex
     t.Context) error { | 
| 341 »       »       »       »       »       »       txnDS := gae.GetRDS(c) | 432 »       »       »       »       »       »       txnDS := wrapper.GetDS(c) | 
| 342 »       »       »       »       »       »       f := &Foo{Val: 21} | 433 »       »       »       »       »       »       f := &Foo{ID: 1, Val: 21} | 
| 343 »       »       »       »       »       »       _, err = txnDS.Put(k, f) | 434 »       »       »       »       »       »       _, err = txnDS.Put(f) | 
| 344                                                 So(err, ShouldBeNil) | 435                                                 So(err, ShouldBeNil) | 
| 345 | 436 | 
| 346 »       »       »       »       »       »       err := rds.RunInTransaction(func
     (c context.Context) error { | 437 »       »       »       »       »       »       err := ds.RunInTransaction(func(
     c context.Context) error { | 
| 347 »       »       »       »       »       »       »       txnDS := gae.GetRDS(c) | 438 »       »       »       »       »       »       »       txnDS := wrapper.GetDS(c
     ) | 
| 348 »       »       »       »       »       »       »       f := &Foo{Val: 27} | 439 »       »       »       »       »       »       »       f := &Foo{ID: 1, Val: 27
     } | 
| 349 »       »       »       »       »       »       »       _, err := txnDS.Put(k, f
     ) | 440 »       »       »       »       »       »       »       _, err := txnDS.Put(f) | 
| 350                                                         So(err, ShouldBeNil) | 441                                                         So(err, ShouldBeNil) | 
| 351                                                         return nil | 442                                                         return nil | 
| 352                                                 }, nil) | 443                                                 }, nil) | 
| 353                                                 So(err, ShouldBeNil) | 444                                                 So(err, ShouldBeNil) | 
| 354 | 445 | 
| 355                                                 return nil | 446                                                 return nil | 
| 356                                         }, nil) | 447                                         }, nil) | 
| 357                                         So(err.Error(), ShouldContainSubstring, 
     "concurrent") | 448                                         So(err.Error(), ShouldContainSubstring, 
     "concurrent") | 
| 358 | 449 | 
| 359 »       »       »       »       »       f := &Foo{} | 450 »       »       »       »       »       f := &Foo{ID: 1} | 
| 360 »       »       »       »       »       So(rds.Get(k, f), ShouldBeNil) | 451 »       »       »       »       »       So(ds.Get(f), ShouldBeNil) | 
| 361                                         So(f.Val, ShouldEqual, 27) | 452                                         So(f.Val, ShouldEqual, 27) | 
| 362                                 }) | 453                                 }) | 
| 363 | 454 | 
| 364                                 Convey("XG", func() { | 455                                 Convey("XG", func() { | 
| 365                                         Convey("Modifying two groups with XG=fal
     se is invalid", func() { | 456                                         Convey("Modifying two groups with XG=fal
     se is invalid", func() { | 
| 366 »       »       »       »       »       »       err := rds.RunInTransaction(func
     (c context.Context) error { | 457 »       »       »       »       »       »       err := ds.RunInTransaction(func(
     c context.Context) error { | 
| 367 »       »       »       »       »       »       »       rds := gae.GetRDS(c) | 458 »       »       »       »       »       »       »       ds := wrapper.GetDS(c) | 
| 368 »       »       »       »       »       »       »       f := &Foo{Val: 200} | 459 »       »       »       »       »       »       »       f := &Foo{ID: 1, Val: 20
     0} | 
| 369 »       »       »       »       »       »       »       _, err := rds.Put(k, f) | 460 »       »       »       »       »       »       »       _, err := ds.Put(f) | 
| 370                                                         So(err, ShouldBeNil) | 461                                                         So(err, ShouldBeNil) | 
| 371 | 462 | 
| 372 »       »       »       »       »       »       »       _, err = rds.Put(rds.New
     Key("Foo", "", 2, nil), f) | 463 »       »       »       »       »       »       »       f.ID = 2 | 
|  | 464 »       »       »       »       »       »       »       _, err = ds.Put(f) | 
| 373                                                         So(err.Error(), ShouldCo
     ntainSubstring, "cross-group") | 465                                                         So(err.Error(), ShouldCo
     ntainSubstring, "cross-group") | 
| 374                                                         return err | 466                                                         return err | 
| 375                                                 }, nil) | 467                                                 }, nil) | 
| 376                                                 So(err.Error(), ShouldContainSub
     string, "cross-group") | 468                                                 So(err.Error(), ShouldContainSub
     string, "cross-group") | 
| 377                                         }) | 469                                         }) | 
| 378 | 470 | 
| 379                                         Convey("Modifying >25 groups with XG=tru
     e is invald", func() { | 471                                         Convey("Modifying >25 groups with XG=tru
     e is invald", func() { | 
| 380 »       »       »       »       »       »       err := rds.RunInTransaction(func
     (c context.Context) error { | 472 »       »       »       »       »       »       err := ds.RunInTransaction(func(
     c context.Context) error { | 
| 381 »       »       »       »       »       »       »       rds := gae.GetRDS(c) | 473 »       »       »       »       »       »       »       ds := wrapper.GetDS(c) | 
| 382                                                         for i := int64(1); i < 2
     6; i++ { | 474                                                         for i := int64(1); i < 2
     6; i++ { | 
| 383 »       »       »       »       »       »       »       »       k := rds.NewKey(
     "Foo", "", i, nil) | 475 »       »       »       »       »       »       »       »       f := &Foo{ID: i,
      Val: 200} | 
| 384 »       »       »       »       »       »       »       »       f := &Foo{Val: 2
     00} | 476 »       »       »       »       »       »       »       »       _, err := ds.Put
     (f) | 
| 385 »       »       »       »       »       »       »       »       _, err := rds.Pu
     t(k, f) |  | 
| 386                                                                 So(err, ShouldBe
     Nil) | 477                                                                 So(err, ShouldBe
     Nil) | 
| 387                                                         } | 478                                                         } | 
| 388 »       »       »       »       »       »       »       f := &Foo{Val: 200} | 479 »       »       »       »       »       »       »       f := &Foo{ID: 27, Val: 2
     00} | 
| 389 »       »       »       »       »       »       »       _, err := rds.Put(rds.Ne
     wKey("Foo", "", 27, nil), f) | 480 »       »       »       »       »       »       »       _, err := ds.Put(f) | 
| 390                                                         So(err.Error(), ShouldCo
     ntainSubstring, "too many entity groups") | 481                                                         So(err.Error(), ShouldCo
     ntainSubstring, "too many entity groups") | 
| 391                                                         return err | 482                                                         return err | 
| 392 »       »       »       »       »       »       }, &gae.DSTransactionOptions{XG:
      true}) | 483 »       »       »       »       »       »       }, &datastore.TransactionOptions
     {XG: true}) | 
| 393                                                 So(err.Error(), ShouldContainSub
     string, "too many entity groups") | 484                                                 So(err.Error(), ShouldContainSub
     string, "too many entity groups") | 
| 394                                         }) | 485                                         }) | 
| 395                                 }) | 486                                 }) | 
| 396 | 487 | 
| 397                                 Convey("Errors and panics", func() { | 488                                 Convey("Errors and panics", func() { | 
| 398                                         Convey("returning an error aborts", func
     () { | 489                                         Convey("returning an error aborts", func
     () { | 
| 399 »       »       »       »       »       »       err := rds.RunInTransaction(func
     (c context.Context) error { | 490 »       »       »       »       »       »       err := ds.RunInTransaction(func(
     c context.Context) error { | 
| 400 »       »       »       »       »       »       »       rds := gae.GetRDS(c) | 491 »       »       »       »       »       »       »       ds := wrapper.GetDS(c) | 
| 401 »       »       »       »       »       »       »       f := &Foo{Val: 200} | 492 »       »       »       »       »       »       »       f := &Foo{ID: 1, Val: 20
     0} | 
| 402 »       »       »       »       »       »       »       _, err := rds.Put(k, f) | 493 »       »       »       »       »       »       »       _, err := ds.Put(f) | 
| 403                                                         So(err, ShouldBeNil) | 494                                                         So(err, ShouldBeNil) | 
| 404 | 495 | 
| 405                                                         return fmt.Errorf("thing
     y") | 496                                                         return fmt.Errorf("thing
     y") | 
| 406                                                 }, nil) | 497                                                 }, nil) | 
| 407                                                 So(err.Error(), ShouldEqual, "th
     ingy") | 498                                                 So(err.Error(), ShouldEqual, "th
     ingy") | 
| 408 | 499 | 
| 409 »       »       »       »       »       »       f := &Foo{} | 500 »       »       »       »       »       »       f := &Foo{ID: 1} | 
| 410 »       »       »       »       »       »       So(rds.Get(k, f), ShouldBeNil) | 501 »       »       »       »       »       »       So(ds.Get(f), ShouldBeNil) | 
| 411                                                 So(f.Val, ShouldEqual, 10) | 502                                                 So(f.Val, ShouldEqual, 10) | 
| 412                                         }) | 503                                         }) | 
| 413 | 504 | 
| 414                                         Convey("panicing aborts", func() { | 505                                         Convey("panicing aborts", func() { | 
| 415                                                 So(func() { | 506                                                 So(func() { | 
| 416 »       »       »       »       »       »       »       rds.RunInTransaction(fun
     c(c context.Context) error { | 507 »       »       »       »       »       »       »       ds.RunInTransaction(func
     (c context.Context) error { | 
| 417 »       »       »       »       »       »       »       »       rds := gae.GetRD
     S(c) | 508 »       »       »       »       »       »       »       »       ds := wrapper.Ge
     tDS(c) | 
| 418 »       »       »       »       »       »       »       »       f := &Foo{Val: 2
     00} | 509 »       »       »       »       »       »       »       »       f := &Foo{ID: 1,
      Val: 200} | 
| 419 »       »       »       »       »       »       »       »       _, err := rds.Pu
     t(k, f) | 510 »       »       »       »       »       »       »       »       _, err := ds.Put
     (f) | 
| 420                                                                 So(err, ShouldBe
     Nil) | 511                                                                 So(err, ShouldBe
     Nil) | 
| 421                                                                 panic("wheeeeee"
     ) | 512                                                                 panic("wheeeeee"
     ) | 
| 422                                                         }, nil) | 513                                                         }, nil) | 
| 423                                                 }, ShouldPanic) | 514                                                 }, ShouldPanic) | 
| 424 | 515 | 
| 425 »       »       »       »       »       »       f := &Foo{} | 516 »       »       »       »       »       »       f := &Foo{ID: 1} | 
| 426 »       »       »       »       »       »       So(rds.Get(k, f), ShouldBeNil) | 517 »       »       »       »       »       »       So(ds.Get(f), ShouldBeNil) | 
| 427                                                 So(f.Val, ShouldEqual, 10) | 518                                                 So(f.Val, ShouldEqual, 10) | 
| 428                                         }) | 519                                         }) | 
| 429                                 }) | 520                                 }) | 
| 430                         }) | 521                         }) | 
| 431                 }) | 522                 }) | 
| 432 | 523 | 
| 433         }) | 524         }) | 
| 434 } | 525 } | 
| 435 | 526 | 
| 436 const MaxUint = ^uint(0) | 527 const MaxUint = ^uint(0) | 
| 437 const MaxInt = int(MaxUint >> 1) | 528 const MaxInt = int(MaxUint >> 1) | 
| 438 const IntIs32Bits = int64(MaxInt) < math.MaxInt64 | 529 const IntIs32Bits = int64(MaxInt) < math.MaxInt64 | 
| 439 | 530 | 
| 440 func TestDatastoreQueryer(t *testing.T) { | 531 func TestDatastoreQueryer(t *testing.T) { | 
| 441         Convey("Datastore Query suport", t, func() { | 532         Convey("Datastore Query suport", t, func() { | 
| 442                 c := Use(context.Background()) | 533                 c := Use(context.Background()) | 
| 443 »       »       rds := gae.GetRDS(c) | 534 »       »       ds := wrapper.GetDS(c) | 
| 444 »       »       So(rds, ShouldNotBeNil) | 535 »       »       So(ds, ShouldNotBeNil) | 
| 445 | 536 | 
| 446                 Convey("can create good queries", func() { | 537                 Convey("can create good queries", func() { | 
| 447 »       »       »       q := rds.NewQuery("Foo").KeysOnly().Limit(10).Offset(39) | 538 »       »       »       q := ds.NewQuery("Foo").KeysOnly().Limit(10).Offset(39) | 
| 448                         q = q.Start(queryCursor("kosmik")).End(queryCursor("krab
     s")) | 539                         q = q.Start(queryCursor("kosmik")).End(queryCursor("krab
     s")) | 
| 449                         So(q, ShouldNotBeNil) | 540                         So(q, ShouldNotBeNil) | 
| 450                         So(q.(*queryImpl).err, ShouldBeNil) | 541                         So(q.(*queryImpl).err, ShouldBeNil) | 
| 451                         qi := q.(*queryImpl).checkCorrectness("", false) | 542                         qi := q.(*queryImpl).checkCorrectness("", false) | 
| 452                         So(qi.err, ShouldBeNil) | 543                         So(qi.err, ShouldBeNil) | 
| 453                 }) | 544                 }) | 
| 454 | 545 | 
| 455                 Convey("normalize ensures orders make sense", func() { | 546                 Convey("normalize ensures orders make sense", func() { | 
| 456 »       »       »       q := rds.NewQuery("Cool") | 547 »       »       »       q := ds.NewQuery("Cool") | 
| 457                         q = q.Filter("cat =", 19).Filter("bob =", 10).Order("bob
     ").Order("bob") | 548                         q = q.Filter("cat =", 19).Filter("bob =", 10).Order("bob
     ").Order("bob") | 
| 458 | 549 | 
| 459                         Convey("removes dups and equality orders", func() { | 550                         Convey("removes dups and equality orders", func() { | 
| 460                                 q = q.Order("wat") | 551                                 q = q.Order("wat") | 
| 461                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 552                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 
| 462                                 So(qi.err, ShouldBeNil) | 553                                 So(qi.err, ShouldBeNil) | 
| 463                                 So(qi.order, ShouldResemble, []queryOrder{{"wat"
     , qASC}}) | 554                                 So(qi.order, ShouldResemble, []queryOrder{{"wat"
     , qASC}}) | 
| 464                         }) | 555                         }) | 
| 465 | 556 | 
| 466                         Convey("keeps inequality orders", func() { | 557                         Convey("keeps inequality orders", func() { | 
| 467                                 q = q.Order("wat") | 558                                 q = q.Order("wat") | 
| 468                                 q := q.Filter("bob >", 10).Filter("wat <", 29) | 559                                 q := q.Filter("bob >", 10).Filter("wat <", 29) | 
| 469                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 560                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 
| 470                                 So(qi.order, ShouldResemble, []queryOrder{{"bob"
     , qASC}, {"wat", qASC}}) | 561                                 So(qi.order, ShouldResemble, []queryOrder{{"bob"
     , qASC}, {"wat", qASC}}) | 
| 471                                 So(qi.err.Error(), ShouldContainSubstring, "Only
      one inequality") | 562                                 So(qi.err.Error(), ShouldContainSubstring, "Only
      one inequality") | 
| 472                         }) | 563                         }) | 
| 473 | 564 | 
| 474                         Convey("if we equality-filter on __key__, order is ditch
     ed", func() { | 565                         Convey("if we equality-filter on __key__, order is ditch
     ed", func() { | 
| 475                                 q = q.Order("wat") | 566                                 q = q.Order("wat") | 
| 476 »       »       »       »       q := q.Filter("__key__ =", rds.NewKey("Foo", "wa
     t", 0, nil)) | 567 »       »       »       »       q := q.Filter("__key__ =", ds.NewKey("Foo", "wat
     ", 0, nil)) | 
| 477                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 568                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 
| 478                                 So(qi.order, ShouldResemble, []queryOrder(nil)) | 569                                 So(qi.order, ShouldResemble, []queryOrder(nil)) | 
| 479                                 So(qi.err, ShouldBeNil) | 570                                 So(qi.err, ShouldBeNil) | 
| 480                         }) | 571                         }) | 
| 481 | 572 | 
| 482                         Convey("if we order by key and something else, key domin
     ates", func() { | 573                         Convey("if we order by key and something else, key domin
     ates", func() { | 
| 483                                 q := q.Order("__key__").Order("wat") | 574                                 q := q.Order("__key__").Order("wat") | 
| 484                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 575                                 qi := q.(*queryImpl).normalize().checkCorrectnes
     s("", false) | 
| 485                                 So(qi.order, ShouldResemble, []queryOrder{{"__ke
     y__", qASC}}) | 576                                 So(qi.order, ShouldResemble, []queryOrder{{"__ke
     y__", qASC}}) | 
| 486                                 So(qi.err, ShouldBeNil) | 577                                 So(qi.err, ShouldBeNil) | 
| 487                         }) | 578                         }) | 
| 488                 }) | 579                 }) | 
| 489 | 580 | 
| 490                 Convey("can create bad queries", func() { | 581                 Convey("can create bad queries", func() { | 
| 491 »       »       »       q := rds.NewQuery("Foo") | 582 »       »       »       q := ds.NewQuery("Foo") | 
| 492 | 583 | 
| 493                         Convey("bad filter ops", func() { | 584                         Convey("bad filter ops", func() { | 
| 494                                 q := q.Filter("Bob !", "value") | 585                                 q := q.Filter("Bob !", "value") | 
| 495                                 So(q.(*queryImpl).err.Error(), ShouldContainSubs
     tring, "invalid operator \"!\"") | 586                                 So(q.(*queryImpl).err.Error(), ShouldContainSubs
     tring, "invalid operator \"!\"") | 
| 496                         }) | 587                         }) | 
| 497                         Convey("bad filter", func() { | 588                         Convey("bad filter", func() { | 
| 498                                 q := q.Filter("Bob", "value") | 589                                 q := q.Filter("Bob", "value") | 
| 499                                 So(q.(*queryImpl).err.Error(), ShouldContainSubs
     tring, "invalid filter") | 590                                 So(q.(*queryImpl).err.Error(), ShouldContainSubs
     tring, "invalid filter") | 
| 500                         }) | 591                         }) | 
| 501                         Convey("bad order", func() { | 592                         Convey("bad order", func() { | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
| 522                                 if !IntIs32Bits { | 613                                 if !IntIs32Bits { | 
| 523                                         q := q.Offset(MaxInt) | 614                                         q := q.Offset(MaxInt) | 
| 524                                         So(q.(*queryImpl).err.Error(), ShouldCon
     tainSubstring, "query offset overflow") | 615                                         So(q.(*queryImpl).err.Error(), ShouldCon
     tainSubstring, "query offset overflow") | 
| 525                                 } | 616                                 } | 
| 526                         }) | 617                         }) | 
| 527                         Convey("Bad cursors", func() { | 618                         Convey("Bad cursors", func() { | 
| 528                                 q := q.Start(queryCursor("")).End(queryCursor(""
     )) | 619                                 q := q.Start(queryCursor("")).End(queryCursor(""
     )) | 
| 529                                 So(q.(*queryImpl).err.Error(), ShouldContainSubs
     tring, "invalid cursor") | 620                                 So(q.(*queryImpl).err.Error(), ShouldContainSubs
     tring, "invalid cursor") | 
| 530                         }) | 621                         }) | 
| 531                         Convey("Bad ancestors", func() { | 622                         Convey("Bad ancestors", func() { | 
| 532 »       »       »       »       q := q.Ancestor(rds.NewKey("Goop", "wat", 10, ni
     l)) | 623 »       »       »       »       q := q.Ancestor(ds.NewKey("Goop", "wat", 10, nil
     )) | 
| 533                                 So(q, ShouldNotBeNil) | 624                                 So(q, ShouldNotBeNil) | 
| 534                                 qi := q.(*queryImpl).checkCorrectness("", false) | 625                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 535 »       »       »       »       So(qi.err, ShouldEqual, gae.ErrDSInvalidKey) | 626 »       »       »       »       So(qi.err, ShouldEqual, datastore.ErrInvalidKey) | 
| 536                         }) | 627                         }) | 
| 537                         Convey("nil ancestors", func() { | 628                         Convey("nil ancestors", func() { | 
| 538                                 qi := q.Ancestor(nil).(*queryImpl).checkCorrectn
     ess("", false) | 629                                 qi := q.Ancestor(nil).(*queryImpl).checkCorrectn
     ess("", false) | 
| 539                                 So(qi.err.Error(), ShouldContainSubstring, "nil 
     query ancestor") | 630                                 So(qi.err.Error(), ShouldContainSubstring, "nil 
     query ancestor") | 
| 540                         }) | 631                         }) | 
| 541                         Convey("Bad key filters", func() { | 632                         Convey("Bad key filters", func() { | 
| 542 »       »       »       »       q := q.Filter("__key__ =", rds.NewKey("Goop", "w
     at", 10, nil)) | 633 »       »       »       »       q := q.Filter("__key__ =", ds.NewKey("Goop", "wa
     t", 10, nil)) | 
| 543                                 qi := q.(*queryImpl).checkCorrectness("", false) | 634                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 544 »       »       »       »       So(qi.err, ShouldEqual, gae.ErrDSInvalidKey) | 635 »       »       »       »       So(qi.err, ShouldEqual, datastore.ErrInvalidKey) | 
| 545                         }) | 636                         }) | 
| 546                         Convey("non-ancestor queries in a transaction", func() { | 637                         Convey("non-ancestor queries in a transaction", func() { | 
| 547                                 qi := q.(*queryImpl).checkCorrectness("", true) | 638                                 qi := q.(*queryImpl).checkCorrectness("", true) | 
| 548                                 So(qi.err.Error(), ShouldContainSubstring, "Only
      ancestor queries") | 639                                 So(qi.err.Error(), ShouldContainSubstring, "Only
      ancestor queries") | 
| 549                         }) | 640                         }) | 
| 550                         Convey("absurd numbers of filters are prohibited", func(
     ) { | 641                         Convey("absurd numbers of filters are prohibited", func(
     ) { | 
| 551 »       »       »       »       q := q.Ancestor(rds.NewKey("thing", "wat", 0, ni
     l)) | 642 »       »       »       »       q := q.Ancestor(ds.NewKey("thing", "wat", 0, nil
     )) | 
| 552                                 for i := 0; i < 100; i++ { | 643                                 for i := 0; i < 100; i++ { | 
| 553                                         q = q.Filter("something =", 10) | 644                                         q = q.Filter("something =", 10) | 
| 554                                 } | 645                                 } | 
| 555                                 qi := q.(*queryImpl).checkCorrectness("", false) | 646                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 556                                 So(qi.err.Error(), ShouldContainSubstring, "quer
     y is too large") | 647                                 So(qi.err.Error(), ShouldContainSubstring, "quer
     y is too large") | 
| 557                         }) | 648                         }) | 
| 558                         Convey("filters for __key__ that aren't keys", func() { | 649                         Convey("filters for __key__ that aren't keys", func() { | 
| 559                                 q := q.Filter("__key__ = ", 10) | 650                                 q := q.Filter("__key__ = ", 10) | 
| 560                                 qi := q.(*queryImpl).checkCorrectness("", false) | 651                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 561                                 So(qi.err.Error(), ShouldContainSubstring, "must
      be a Key") | 652                                 So(qi.err.Error(), ShouldContainSubstring, "must
      be a Key") | 
| 562                         }) | 653                         }) | 
| 563                         Convey("multiple inequalities", func() { | 654                         Convey("multiple inequalities", func() { | 
| 564                                 q := q.Filter("bob > ", 19).Filter("charlie < ",
      20) | 655                                 q := q.Filter("bob > ", 19).Filter("charlie < ",
      20) | 
| 565                                 qi := q.(*queryImpl).checkCorrectness("", false) | 656                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 566                                 So(qi.err.Error(), ShouldContainSubstring, "one 
     inequality filter") | 657                                 So(qi.err.Error(), ShouldContainSubstring, "one 
     inequality filter") | 
| 567                         }) | 658                         }) | 
| 568                         Convey("bad sort orders", func() { | 659                         Convey("bad sort orders", func() { | 
| 569                                 q := q.Filter("bob > ", 19).Order("-charlie") | 660                                 q := q.Filter("bob > ", 19).Order("-charlie") | 
| 570                                 qi := q.(*queryImpl).checkCorrectness("", false) | 661                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 571                                 So(qi.err.Error(), ShouldContainSubstring, "firs
     t sort property") | 662                                 So(qi.err.Error(), ShouldContainSubstring, "firs
     t sort property") | 
| 572                         }) | 663                         }) | 
| 573                         Convey("kindless with non-__key__ filters", func() { | 664                         Convey("kindless with non-__key__ filters", func() { | 
| 574 »       »       »       »       q := rds.NewQuery("").Filter("face <", 25.3) | 665 »       »       »       »       q := ds.NewQuery("").Filter("face <", 25.3) | 
| 575                                 qi := q.(*queryImpl).checkCorrectness("", false) | 666                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 576                                 So(qi.err.Error(), ShouldContainSubstring, "kind
      is required for non-__key__") | 667                                 So(qi.err.Error(), ShouldContainSubstring, "kind
      is required for non-__key__") | 
| 577                         }) | 668                         }) | 
| 578                         Convey("kindless with non-__key__ orders", func() { | 669                         Convey("kindless with non-__key__ orders", func() { | 
| 579 »       »       »       »       q := rds.NewQuery("").Order("face") | 670 »       »       »       »       q := ds.NewQuery("").Order("face") | 
| 580                                 qi := q.(*queryImpl).checkCorrectness("", false) | 671                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 581                                 So(qi.err.Error(), ShouldContainSubstring, "kind
      is required for all orders") | 672                                 So(qi.err.Error(), ShouldContainSubstring, "kind
      is required for all orders") | 
| 582                         }) | 673                         }) | 
| 583                         Convey("kindless with decending-__key__ orders", func() 
     { | 674                         Convey("kindless with decending-__key__ orders", func() 
     { | 
| 584 »       »       »       »       q := rds.NewQuery("").Order("-__key__") | 675 »       »       »       »       q := ds.NewQuery("").Order("-__key__") | 
| 585                                 qi := q.(*queryImpl).checkCorrectness("", false) | 676                                 qi := q.(*queryImpl).checkCorrectness("", false) | 
| 586                                 So(qi.err.Error(), ShouldContainSubstring, "kind
      is required for all orders") | 677                                 So(qi.err.Error(), ShouldContainSubstring, "kind
      is required for all orders") | 
| 587                         }) | 678                         }) | 
| 588                 }) | 679                 }) | 
| 589 | 680 | 
| 590         }) | 681         }) | 
| 591 } | 682 } | 
| OLD | NEW | 
|---|