| 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 "math" | 9 "math" |
| 10 "testing" | 10 "testing" |
| 11 | 11 |
| 12 dsS "github.com/luci/gae/service/datastore" | 12 dsS "github.com/luci/gae/service/datastore" |
| 13 infoS "github.com/luci/gae/service/info" |
| 13 . "github.com/smartystreets/goconvey/convey" | 14 . "github.com/smartystreets/goconvey/convey" |
| 14 "golang.org/x/net/context" | 15 "golang.org/x/net/context" |
| 15 ) | 16 ) |
| 16 | 17 |
| 17 func TestDatastoreKinder(t *testing.T) { | 18 func TestDatastoreKinder(t *testing.T) { |
| 18 t.Parallel() | 19 t.Parallel() |
| 19 | 20 |
| 20 Convey("Datastore keys", t, func() { | 21 Convey("Datastore keys", t, func() { |
| 21 c := Use(context.Background()) | 22 c := Use(context.Background()) |
| 22 ds := dsS.Get(c) | 23 ds := dsS.Get(c) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 34 So(key.Namespace(), ShouldEqual, "") | 35 So(key.Namespace(), ShouldEqual, "") |
| 35 So(key.String(), ShouldEqual, "/nerd,stringID") | 36 So(key.String(), ShouldEqual, "/nerd,stringID") |
| 36 So(dsS.KeyIncomplete(key), ShouldBeFalse) | 37 So(dsS.KeyIncomplete(key), ShouldBeFalse) |
| 37 So(dsS.KeyValid(key, false, "dev~app", ""), Shou
ldBeTrue) | 38 So(dsS.KeyValid(key, false, "dev~app", ""), Shou
ldBeTrue) |
| 38 }) | 39 }) |
| 39 }) | 40 }) |
| 40 | 41 |
| 41 }) | 42 }) |
| 42 } | 43 } |
| 43 | 44 |
| 45 type MetaGroup struct { |
| 46 _id int64 `gae:"$id,1"` |
| 47 _kind string `gae:"$kind,__entity_group__"` |
| 48 Parent dsS.Key `gae:"$parent"` |
| 49 |
| 50 Version int64 `gae:"__version__"` |
| 51 } |
| 52 |
| 44 func testGetMeta(c context.Context, k dsS.Key) int64 { | 53 func testGetMeta(c context.Context, k dsS.Key) int64 { |
| 45 ds := dsS.Get(c) | 54 ds := dsS.Get(c) |
| 46 » retval := int64(0) | 55 » mg := &MetaGroup{Parent: dsS.KeyRoot(k)} |
| 47 » err := ds.GetMulti([]dsS.Key{ds.NewKey("__entity_group__", "", 1, dsS.Ke
yRoot(k))}, func(val dsS.PropertyMap, err error) { | 56 » if err := ds.Get(mg); err != nil { |
| 48 » » if err != nil { | |
| 49 » » » panic(err) | |
| 50 » » } | |
| 51 » » retval = val["__version__"][0].Value().(int64) | |
| 52 » }) | |
| 53 » if err != nil { | |
| 54 panic(err) | 57 panic(err) |
| 55 } | 58 } |
| 56 » return retval | 59 » return mg.Version |
| 57 } | 60 } |
| 58 | 61 |
| 59 var pls = dsS.GetPLS | 62 var pls = dsS.GetPLS |
| 60 | 63 |
| 64 type Foo struct { |
| 65 Id int64 `gae:"$id"` |
| 66 Parent dsS.Key `gae:"$parent"` |
| 67 |
| 68 Val int |
| 69 } |
| 70 |
| 61 func TestDatastoreSingleReadWriter(t *testing.T) { | 71 func TestDatastoreSingleReadWriter(t *testing.T) { |
| 62 t.Parallel() | 72 t.Parallel() |
| 63 | 73 |
| 64 getOnePM := func(ds dsS.Interface, key dsS.Key) (pmap dsS.PropertyMap, e
rr error) { | |
| 65 blankErr := ds.GetMulti([]dsS.Key{key}, func(itmPmap dsS.Propert
yMap, itmErr error) { | |
| 66 pmap = itmPmap | |
| 67 err = itmErr | |
| 68 }) | |
| 69 So(blankErr, ShouldBeNil) | |
| 70 return | |
| 71 } | |
| 72 | |
| 73 delOneErr := func(ds dsS.Interface, key dsS.Key) (err error) { | |
| 74 blankErr := ds.DeleteMulti([]dsS.Key{key}, func(itmErr error) { | |
| 75 err = itmErr | |
| 76 }) | |
| 77 So(blankErr, ShouldBeNil) | |
| 78 return | |
| 79 } | |
| 80 | |
| 81 delOne := func(ds dsS.Interface, key dsS.Key) { | |
| 82 So(delOneErr(ds, key), ShouldBeNil) | |
| 83 } | |
| 84 | |
| 85 getOne := func(ds dsS.Interface, key dsS.Key, dst interface{}) { | |
| 86 pm, err := getOnePM(ds, key) | |
| 87 So(err, ShouldBeNil) | |
| 88 So(pls(dst).Load(pm), ShouldBeNil) | |
| 89 } | |
| 90 | |
| 91 putOneErr := func(ds dsS.Interface, key dsS.Key, val interface{}) (retKe
y dsS.Key, err error) { | |
| 92 blankErr := ds.PutMulti([]dsS.Key{key}, []dsS.PropertyLoadSaver{
pls(val)}, func(itmKey dsS.Key, itmErr error) { | |
| 93 err = itmErr | |
| 94 retKey = itmKey | |
| 95 }) | |
| 96 So(blankErr, ShouldBeNil) | |
| 97 return | |
| 98 } | |
| 99 | |
| 100 putOne := func(ds dsS.Interface, key dsS.Key, val interface{}) (retKey d
sS.Key) { | |
| 101 key, err := putOneErr(ds, key, val) | |
| 102 So(err, ShouldBeNil) | |
| 103 return key | |
| 104 } | |
| 105 | |
| 106 Convey("Datastore single reads and writes", t, func() { | 74 Convey("Datastore single reads and writes", t, func() { |
| 107 c := Use(context.Background()) | 75 c := Use(context.Background()) |
| 108 ds := dsS.Get(c) | 76 ds := dsS.Get(c) |
| 109 So(ds, ShouldNotBeNil) | 77 So(ds, ShouldNotBeNil) |
| 110 | 78 |
| 111 » » Convey("implements DSSingleReadWriter", func() { | 79 » » Convey("getting objects that DNE is an error", func() { |
| 112 » » » type Foo struct { | 80 » » » So(ds.Get(&Foo{Id: 1}), ShouldEqual, dsS.ErrNoSuchEntity
) |
| 113 » » » » Val int | 81 » » }) |
| 114 » » » } | 82 |
| 115 | 83 » » Convey("bad namespaces fail", func() { |
| 116 » » » Convey("getting objects that DNE is an error", func() { | 84 » » » _, err := infoS.Get(c).Namespace("$$blzyall") |
| 117 » » » » _, err := getOnePM(ds, ds.NewKey("Foo", "", 1, n
il)) | 85 » » » So(err.Error(), ShouldContainSubstring, "namespace \"$$b
lzyall\" does not match") |
| 118 » » » » So(err, ShouldEqual, dsS.ErrNoSuchEntity) | 86 » » }) |
| 119 » » » }) | 87 |
| 120 | 88 » » Convey("Can Put stuff", func() { |
| 121 » » » Convey("Can Put stuff", func() { | 89 » » » // with an incomplete key! |
| 122 » » » » // with an incomplete key! | 90 » » » f := &Foo{Val: 10} |
| 123 » » » » k := ds.NewKey("Foo", "", 0, nil) | 91 » » » So(ds.Put(f), ShouldBeNil) |
| 124 » » » » f := &Foo{Val: 10} | 92 » » » k := ds.KeyForObj(f) |
| 125 » » » » k = putOne(ds, k, f) | 93 » » » So(k.String(), ShouldEqual, "/Foo,1") |
| 126 » » » » So(k.String(), ShouldEqual, "/Foo,1") | 94 |
| 127 | 95 » » » Convey("and Get it back", func() { |
| 128 » » » » Convey("and Get it back", func() { | 96 » » » » newFoo := &Foo{Id: 1} |
| 129 » » » » » newFoo := &Foo{} | 97 » » » » So(ds.Get(newFoo), ShouldBeNil) |
| 130 » » » » » getOne(ds, k, newFoo) | 98 » » » » So(newFoo, ShouldResemble, f) |
| 131 » » » » » So(newFoo, ShouldResemble, f) | 99 |
| 132 | 100 » » » » Convey("but it's hidden from a different namespa
ce", func() { |
| 133 » » » » » Convey("and we can Delete it", func() { | 101 » » » » » c, err := infoS.Get(c).Namespace("whomba
t") |
| 134 » » » » » » delOne(ds, k) | 102 » » » » » So(err, ShouldBeNil) |
| 135 » » » » » » _, err := getOnePM(ds, k) | 103 » » » » » ds = dsS.Get(c) |
| 136 » » » » » » So(err, ShouldEqual, dsS.ErrNoSu
chEntity) | 104 » » » » » So(ds.Get(f), ShouldEqual, dsS.ErrNoSuch
Entity) |
| 137 » » » » » }) | 105 » » » » }) |
| 138 » » » » }) | 106 |
| 139 » » » » Convey("Deleteing with a bogus key is bad", func
() { | 107 » » » » Convey("and we can Delete it", func() { |
| 140 » » » » » So(delOneErr(ds, ds.NewKey("Foo", "wat",
100, nil)), ShouldEqual, dsS.ErrInvalidKey) | 108 » » » » » So(ds.Delete(k), ShouldBeNil) |
| 141 » » » » }) | 109 » » » » » So(ds.Get(newFoo), ShouldEqual, dsS.ErrN
oSuchEntity) |
| 142 » » » » Convey("Deleteing a DNE entity is fine", func()
{ | 110 » » » » }) |
| 143 » » » » » delOne(ds, ds.NewKey("Foo", "wat", 0, ni
l)) | 111 |
| 144 » » » » }) | 112 » » » }) |
| 145 | 113 » » » Convey("Deleteing with a bogus key is bad", func() { |
| 146 » » » » Convey("with multiple puts", func() { | 114 » » » » So(ds.Delete(ds.NewKey("Foo", "wat", 100, nil)),
ShouldEqual, dsS.ErrInvalidKey) |
| 147 » » » » » So(testGetMeta(c, k), ShouldEqual, 1) | 115 » » » }) |
| 148 | 116 » » » Convey("Deleteing a DNE entity is fine", func() { |
| 149 » » » » » keys := []dsS.Key{} | 117 » » » » So(ds.Delete(ds.NewKey("Foo", "wat", 0, nil)), S
houldBeNil) |
| 150 » » » » » vals := []dsS.PropertyLoadSaver{} | 118 » » » }) |
| 151 | 119 |
| 152 » » » » » pkey := k | 120 » » » Convey("with multiple puts", func() { |
| 153 » » » » » for i := 0; i < 10; i++ { | 121 » » » » So(testGetMeta(c, k), ShouldEqual, 1) |
| 154 » » » » » » keys = append(keys, ds.NewKey("F
oo", "", 0, pkey)) | 122 |
| 155 » » » » » » vals = append(vals, pls(&Foo{Val
: 10})) | 123 » » » » foos := make([]Foo, 10) |
| 124 » » » » for i := range foos { |
| 125 » » » » » foos[i].Val = 10 |
| 126 » » » » » foos[i].Parent = k |
| 127 » » » » } |
| 128 » » » » So(ds.PutMulti(foos), ShouldBeNil) |
| 129 » » » » So(testGetMeta(c, k), ShouldEqual, 11) |
| 130 |
| 131 » » » » keys := make([]dsS.Key, len(foos)) |
| 132 » » » » for i, f := range foos { |
| 133 » » » » » keys[i] = ds.KeyForObj(&f) |
| 134 » » » » } |
| 135 |
| 136 » » » » Convey("ensure that group versions persist acros
s deletes", func() { |
| 137 » » » » » So(ds.DeleteMulti(append(keys, k)), Shou
ldBeNil) |
| 138 |
| 139 » » » » » // TODO(riannucci): replace with a Count
query instead of this cast |
| 140 » » » » » /* |
| 141 » » » » » » ents := ds.(*dsImpl).data.store.
GetCollection("ents:") |
| 142 » » » » » » num, _ := ents.GetTotals() |
| 143 » » » » » » // /__entity_root_ids__,Foo |
| 144 » » » » » » // /Foo,1/__entity_group__,1 |
| 145 » » » » » » // /Foo,1/__entity_group_ids__,1 |
| 146 » » » » » » So(num, ShouldEqual, 3) |
| 147 » » » » » */ |
| 148 |
| 149 » » » » » So(testGetMeta(c, k), ShouldEqual, 22) |
| 150 |
| 151 » » » » » So(ds.Put(&Foo{Id: 1}), ShouldBeNil) |
| 152 » » » » » So(testGetMeta(c, k), ShouldEqual, 23) |
| 153 » » » » }) |
| 154 |
| 155 » » » » Convey("can Get", func() { |
| 156 » » » » » vals := make([]dsS.PropertyMap, len(keys
)) |
| 157 » » » » » for i := range vals { |
| 158 » » » » » » vals[i] = dsS.PropertyMap{} |
| 159 » » » » » » vals[i].SetMeta("key", keys[i]) |
| 156 } | 160 } |
| 157 » » » » » i := 0 | 161 » » » » » So(ds.GetMulti(vals), ShouldBeNil) |
| 158 » » » » » err := ds.PutMulti(keys, vals, func(k ds
S.Key, err error) { | 162 |
| 159 » » » » » » So(err, ShouldBeNil) | 163 » » » » » for i, val := range vals { |
| 160 » » » » » » keys[i] = k | 164 » » » » » » So(val, ShouldResemble, dsS.Prop
ertyMap{ |
| 161 » » » » » » i++ | 165 » » » » » » » "Val": {dsS.MkProperty(
10)}, |
| 162 » » » » » }) | 166 » » » » » » » "$key": {dsS.MkPropertyN
I(keys[i])}, |
| 163 » » » » » So(err, ShouldBeNil) | |
| 164 » » » » » So(testGetMeta(c, k), ShouldEqual, 11) | |
| 165 | |
| 166 » » » » » Convey("ensure that group versions persi
st across deletes", func() { | |
| 167 » » » » » » keys = append(keys, pkey) | |
| 168 » » » » » » err := ds.DeleteMulti(keys, func
(err error) { | |
| 169 » » » » » » » So(err, ShouldBeNil) | |
| 170 }) | 167 }) |
| 171 » » » » » » So(err, ShouldBeNil) | 168 » » » » » } |
| 172 | 169 » » » » }) |
| 173 » » » » » » // TODO(riannucci): replace with
a Count query instead of this cast | 170 |
| 174 » » » » » » /* | |
| 175 » » » » » » » ents := ds.(*dsImpl).dat
a.store.GetCollection("ents:") | |
| 176 » » » » » » » num, _ := ents.GetTotals
() | |
| 177 » » » » » » » // /__entity_root_ids__,
Foo | |
| 178 » » » » » » » // /Foo,1/__entity_group
__,1 | |
| 179 » » » » » » » // /Foo,1/__entity_group
_ids__,1 | |
| 180 » » » » » » » So(num, ShouldEqual, 3) | |
| 181 » » » » » » */ | |
| 182 | |
| 183 » » » » » » So(testGetMeta(c, k), ShouldEqua
l, 22) | |
| 184 | |
| 185 » » » » » » putOne(ds, k, f) | |
| 186 » » » » » » So(testGetMeta(c, k), ShouldEqua
l, 23) | |
| 187 » » » » » }) | |
| 188 | |
| 189 » » » » » Convey("can Get", func() { | |
| 190 » » » » » » vals := []dsS.PropertyMap{} | |
| 191 » » » » » » err := ds.GetMulti(keys, func(pm
dsS.PropertyMap, err error) { | |
| 192 » » » » » » » So(err, ShouldBeNil) | |
| 193 » » » » » » » vals = append(vals, pm) | |
| 194 » » » » » » }) | |
| 195 » » » » » » So(err, ShouldBeNil) | |
| 196 | |
| 197 » » » » » » for _, val := range vals { | |
| 198 » » » » » » » So(val, ShouldResemble,
dsS.PropertyMap{"Val": {dsS.MkProperty(10)}}) | |
| 199 » » » » » » } | |
| 200 » » » » » }) | |
| 201 » » » » }) | |
| 202 }) | 171 }) |
| 203 }) | 172 }) |
| 204 | 173 |
| 205 Convey("implements DSTransactioner", func() { | 174 Convey("implements DSTransactioner", func() { |
| 206 type Foo struct { | |
| 207 Val int | |
| 208 } | |
| 209 Convey("Put", func() { | 175 Convey("Put", func() { |
| 210 f := &Foo{Val: 10} | 176 f := &Foo{Val: 10} |
| 211 » » » » origKey := ds.NewKey("Foo", "", 0, nil) | 177 » » » » So(ds.Put(f), ShouldBeNil) |
| 212 » » » » k := putOne(ds, origKey, f) | 178 » » » » k := ds.KeyForObj(f) |
| 213 So(k.String(), ShouldEqual, "/Foo,1") | 179 So(k.String(), ShouldEqual, "/Foo,1") |
| 214 | 180 |
| 215 Convey("can Put new entity groups", func() { | 181 Convey("can Put new entity groups", func() { |
| 216 err := ds.RunInTransaction(func(c contex
t.Context) error { | 182 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 217 ds := dsS.Get(c) | 183 ds := dsS.Get(c) |
| 218 | 184 |
| 219 » » » » » » f1 := &Foo{Val: 100} | 185 » » » » » » f := &Foo{Val: 100} |
| 220 » » » » » » k := putOne(ds, origKey, f1) | 186 » » » » » » So(ds.Put(f), ShouldBeNil) |
| 221 » » » » » » So(k.String(), ShouldEqual, "/Fo
o,2") | 187 » » » » » » So(f.Id, ShouldEqual, 2) |
| 222 | 188 |
| 223 » » » » » » f2 := &Foo{Val: 200} | 189 » » » » » » f.Id = 0 |
| 224 » » » » » » k = putOne(ds, origKey, f2) | 190 » » » » » » f.Val = 200 |
| 225 » » » » » » So(k.String(), ShouldEqual, "/Fo
o,3") | 191 » » » » » » So(ds.Put(f), ShouldBeNil) |
| 192 » » » » » » So(f.Id, ShouldEqual, 3) |
| 226 | 193 |
| 227 return nil | 194 return nil |
| 228 }, &dsS.TransactionOptions{XG: true}) | 195 }, &dsS.TransactionOptions{XG: true}) |
| 229 So(err, ShouldBeNil) | 196 So(err, ShouldBeNil) |
| 230 | 197 |
| 231 » » » » » f := &Foo{} | 198 » » » » » f := &Foo{Id: 2} |
| 232 » » » » » getOne(ds, ds.NewKey("Foo", "", 2, nil),
f) | 199 » » » » » So(ds.Get(f), ShouldBeNil) |
| 233 So(f.Val, ShouldEqual, 100) | 200 So(f.Val, ShouldEqual, 100) |
| 234 | 201 |
| 235 » » » » » getOne(ds, ds.NewKey("Foo", "", 3, nil),
f) | 202 » » » » » f.Id = 3 |
| 203 » » » » » So(ds.Get(f), ShouldBeNil) |
| 236 So(f.Val, ShouldEqual, 200) | 204 So(f.Val, ShouldEqual, 200) |
| 237 }) | 205 }) |
| 238 | 206 |
| 239 Convey("can Put new entities in a current group"
, func() { | 207 Convey("can Put new entities in a current group"
, func() { |
| 240 par := k | |
| 241 err := ds.RunInTransaction(func(c contex
t.Context) error { | 208 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 242 ds := dsS.Get(c) | 209 ds := dsS.Get(c) |
| 243 » » » » » » So(ds, ShouldNotBeNil) | 210 |
| 244 | 211 » » » » » » f := &Foo{Val: 100, Parent: k} |
| 245 » » » » » » f1 := &Foo{Val: 100} | 212 » » » » » » So(ds.Put(f), ShouldBeNil) |
| 246 » » » » » » k := putOne(ds, ds.NewKey("Foo",
"", 0, par), f1) | 213 » » » » » » So(ds.KeyForObj(f).String(), Sho
uldEqual, "/Foo,1/Foo,1") |
| 247 » » » » » » So(k.String(), ShouldEqual, "/Fo
o,1/Foo,1") | 214 |
| 248 | 215 » » » » » » f.Id = 0 |
| 249 » » » » » » f2 := &Foo{Val: 200} | 216 » » » » » » f.Val = 200 |
| 250 » » » » » » k = putOne(ds, ds.NewKey("Foo",
"", 0, par), f2) | 217 » » » » » » So(ds.Put(f), ShouldBeNil) |
| 251 » » » » » » So(k.String(), ShouldEqual, "/Fo
o,1/Foo,2") | 218 » » » » » » So(ds.KeyForObj(f).String(), Sho
uldEqual, "/Foo,1/Foo,2") |
| 252 | 219 |
| 253 return nil | 220 return nil |
| 254 }, nil) | 221 }, nil) |
| 255 So(err, ShouldBeNil) | 222 So(err, ShouldBeNil) |
| 256 | 223 |
| 257 » » » » » f := &Foo{} | 224 » » » » » f := &Foo{Id: 1, Parent: k} |
| 258 » » » » » getOne(ds, ds.NewKey("Foo", "", 1, k), f
) | 225 » » » » » So(ds.Get(f), ShouldBeNil) |
| 259 So(f.Val, ShouldEqual, 100) | 226 So(f.Val, ShouldEqual, 100) |
| 260 | 227 |
| 261 » » » » » getOne(ds, ds.NewKey("Foo", "", 2, k), f
) | 228 » » » » » f.Id = 2 |
| 229 » » » » » So(ds.Get(f), ShouldBeNil) |
| 262 So(f.Val, ShouldEqual, 200) | 230 So(f.Val, ShouldEqual, 200) |
| 263 }) | 231 }) |
| 264 | 232 |
| 265 Convey("Deletes work too", func() { | 233 Convey("Deletes work too", func() { |
| 266 err := ds.RunInTransaction(func(c contex
t.Context) error { | 234 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 235 return dsS.Get(c).Delete(k) |
| 236 }, nil) |
| 237 So(err, ShouldBeNil) |
| 238 So(ds.Get(&Foo{Id: 1}), ShouldEqual, dsS
.ErrNoSuchEntity) |
| 239 }) |
| 240 |
| 241 Convey("A Get counts against your group count",
func() { |
| 242 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 267 ds := dsS.Get(c) | 243 ds := dsS.Get(c) |
| 268 » » » » » » So(ds, ShouldNotBeNil) | 244 |
| 269 » » » » » » delOne(ds, k) | 245 » » » » » » pm := dsS.PropertyMap{} |
| 246 » » » » » » pm.SetMeta("key", ds.NewKey("Foo
", "", 20, nil)) |
| 247 » » » » » » So(ds.Get(pm), ShouldEqual, dsS.
ErrNoSuchEntity) |
| 248 |
| 249 » » » » » » pm.SetMeta("key", k) |
| 250 » » » » » » So(ds.Get(pm).Error(), ShouldCon
tainSubstring, "cross-group") |
| 270 return nil | 251 return nil |
| 271 }, nil) | 252 }, nil) |
| 272 So(err, ShouldBeNil) | 253 So(err, ShouldBeNil) |
| 273 _, err = getOnePM(ds, k) | |
| 274 So(err, ShouldEqual, dsS.ErrNoSuchEntity
) | |
| 275 }) | |
| 276 | |
| 277 Convey("A Get counts against your group count",
func() { | |
| 278 err := ds.RunInTransaction(func(c contex
t.Context) error { | |
| 279 ds := dsS.Get(c) | |
| 280 | |
| 281 _, err := getOnePM(ds, ds.NewKey
("Foo", "", 20, nil)) | |
| 282 So(err, ShouldEqual, dsS.ErrNoSu
chEntity) | |
| 283 | |
| 284 err = ds.GetMulti([]dsS.Key{k},
func(_ dsS.PropertyMap, err error) { | |
| 285 So(err, ShouldBeNil) | |
| 286 }) | |
| 287 So(err.Error(), ShouldContainSub
string, "cross-group") | |
| 288 return nil | |
| 289 }, nil) | |
| 290 So(err, ShouldBeNil) | |
| 291 }) | 254 }) |
| 292 | 255 |
| 293 Convey("Get takes a snapshot", func() { | 256 Convey("Get takes a snapshot", func() { |
| 294 err := ds.RunInTransaction(func(c contex
t.Context) error { | 257 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 295 txnDS := dsS.Get(c) | 258 txnDS := dsS.Get(c) |
| 296 So(txnDS, ShouldNotBeNil) | |
| 297 | 259 |
| 298 » » » » » » getOne(txnDS, k, f) | 260 » » » » » » So(txnDS.Get(f), ShouldBeNil) |
| 299 So(f.Val, ShouldEqual, 10) | 261 So(f.Val, ShouldEqual, 10) |
| 300 | 262 |
| 301 // Don't ever do this in a real
program unless you want to guarantee | 263 // Don't ever do this in a real
program unless you want to guarantee |
| 302 // a failed transaction :) | 264 // a failed transaction :) |
| 303 f.Val = 11 | 265 f.Val = 11 |
| 304 » » » » » » putOne(ds, k, f) | 266 » » » » » » So(ds.Put(f), ShouldBeNil) |
| 305 | 267 |
| 306 » » » » » » getOne(txnDS, k, f) | 268 » » » » » » So(txnDS.Get(f), ShouldBeNil) |
| 307 So(f.Val, ShouldEqual, 10) | 269 So(f.Val, ShouldEqual, 10) |
| 308 | 270 |
| 309 return nil | 271 return nil |
| 310 }, nil) | 272 }, nil) |
| 311 So(err, ShouldBeNil) | 273 So(err, ShouldBeNil) |
| 312 | 274 |
| 313 » » » » » f := &Foo{} | 275 » » » » » f := &Foo{Id: 1} |
| 314 » » » » » getOne(ds, k, f) | 276 » » » » » So(ds.Get(f), ShouldBeNil) |
| 315 So(f.Val, ShouldEqual, 11) | 277 So(f.Val, ShouldEqual, 11) |
| 316 }) | 278 }) |
| 317 | 279 |
| 318 Convey("and snapshots are consistent even after
Puts", func() { | 280 Convey("and snapshots are consistent even after
Puts", func() { |
| 319 err := ds.RunInTransaction(func(c contex
t.Context) error { | 281 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 320 txnDS := dsS.Get(c) | 282 txnDS := dsS.Get(c) |
| 321 So(txnDS, ShouldNotBeNil) | |
| 322 | 283 |
| 323 » » » » » » f := &Foo{} | 284 » » » » » » f := &Foo{Id: 1} |
| 324 » » » » » » getOne(txnDS, k, f) | 285 » » » » » » So(txnDS.Get(f), ShouldBeNil) |
| 325 So(f.Val, ShouldEqual, 10) | 286 So(f.Val, ShouldEqual, 10) |
| 326 | 287 |
| 327 // Don't ever do this in a real
program unless you want to guarantee | 288 // Don't ever do this in a real
program unless you want to guarantee |
| 328 // a failed transaction :) | 289 // a failed transaction :) |
| 329 f.Val = 11 | 290 f.Val = 11 |
| 330 » » » » » » putOne(ds, k, f) | 291 » » » » » » So(ds.Put(f), ShouldBeNil) |
| 331 | 292 |
| 332 » » » » » » getOne(txnDS, k, f) | 293 » » » » » » So(txnDS.Get(f), ShouldBeNil) |
| 333 So(f.Val, ShouldEqual, 10) | 294 So(f.Val, ShouldEqual, 10) |
| 334 | 295 |
| 335 f.Val = 20 | 296 f.Val = 20 |
| 336 » » » » » » putOne(txnDS, k, f) | 297 » » » » » » So(txnDS.Put(f), ShouldBeNil) |
| 337 | 298 |
| 338 » » » » » » getOne(txnDS, k, f) | 299 » » » » » » So(txnDS.Get(f), ShouldBeNil) |
| 339 So(f.Val, ShouldEqual, 10) // st
ill gets 10 | 300 So(f.Val, ShouldEqual, 10) // st
ill gets 10 |
| 340 | 301 |
| 341 return nil | 302 return nil |
| 342 }, nil) | 303 }, nil) |
| 343 So(err.Error(), ShouldContainSubstring,
"concurrent") | 304 So(err.Error(), ShouldContainSubstring,
"concurrent") |
| 344 | 305 |
| 345 » » » » » f := &Foo{} | 306 » » » » » f := &Foo{Id: 1} |
| 346 » » » » » getOne(ds, k, f) | 307 » » » » » So(ds.Get(f), ShouldBeNil) |
| 347 So(f.Val, ShouldEqual, 11) | 308 So(f.Val, ShouldEqual, 11) |
| 348 }) | 309 }) |
| 349 | 310 |
| 350 Convey("Reusing a transaction context is bad new
s", func() { | 311 Convey("Reusing a transaction context is bad new
s", func() { |
| 351 k := ds.NewKey("Foo", "", 1, nil) | |
| 352 txnDS := dsS.Interface(nil) | 312 txnDS := dsS.Interface(nil) |
| 353 err := ds.RunInTransaction(func(c contex
t.Context) error { | 313 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 354 txnDS = dsS.Get(c) | 314 txnDS = dsS.Get(c) |
| 355 » » » » » » getOnePM(txnDS, k) | 315 » » » » » » So(txnDS.Get(f), ShouldBeNil) |
| 356 return nil | 316 return nil |
| 357 }, nil) | 317 }, nil) |
| 358 So(err, ShouldBeNil) | 318 So(err, ShouldBeNil) |
| 359 » » » » » err = txnDS.GetMulti([]dsS.Key{k}, func(
_ dsS.PropertyMap, err error) { | 319 » » » » » So(txnDS.Get(f).Error(), ShouldContainSu
bstring, "expired") |
| 360 » » » » » » So(err, ShouldBeNil) | |
| 361 » » » » » }) | |
| 362 » » » » » So(err.Error(), ShouldContainSubstring,
"expired") | |
| 363 }) | 320 }) |
| 364 | 321 |
| 365 Convey("Nested transactions are rejected", func(
) { | 322 Convey("Nested transactions are rejected", func(
) { |
| 366 err := ds.RunInTransaction(func(c contex
t.Context) error { | 323 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 367 err := dsS.Get(c).RunInTransacti
on(func(c context.Context) error { | 324 err := dsS.Get(c).RunInTransacti
on(func(c context.Context) error { |
| 368 panic("noooo") | 325 panic("noooo") |
| 369 }, nil) | 326 }, nil) |
| 370 So(err.Error(), ShouldContainSub
string, "nested transactions") | 327 So(err.Error(), ShouldContainSub
string, "nested transactions") |
| 371 return nil | 328 return nil |
| 372 }, nil) | 329 }, nil) |
| 373 So(err, ShouldBeNil) | 330 So(err, ShouldBeNil) |
| 374 }) | 331 }) |
| 375 | 332 |
| 376 Convey("Concurrent transactions only accept one
set of changes", func() { | 333 Convey("Concurrent transactions only accept one
set of changes", func() { |
| 377 // Note: I think this implementation is
actually /slightly/ wrong. | 334 // Note: I think this implementation is
actually /slightly/ wrong. |
| 378 // Accorting to my read of the docs for
appengine, when you open a | 335 // Accorting to my read of the docs for
appengine, when you open a |
| 379 // transaction it actually (essentially)
holds a reference to the | 336 // transaction it actually (essentially)
holds a reference to the |
| 380 // entire datastore. Our implementation
takes a snapshot of the | 337 // entire datastore. Our implementation
takes a snapshot of the |
| 381 // entity group as soon as something obs
erves/affects it. | 338 // entity group as soon as something obs
erves/affects it. |
| 382 // | 339 // |
| 383 // That said... I'm not sure if there's
really a semantic difference. | 340 // That said... I'm not sure if there's
really a semantic difference. |
| 384 err := ds.RunInTransaction(func(c contex
t.Context) error { | 341 err := ds.RunInTransaction(func(c contex
t.Context) error { |
| 385 » » » » » » txnDS := dsS.Get(c) | 342 » » » » » » So(dsS.Get(c).Put(&Foo{Id: 1, Va
l: 21}), ShouldBeNil) |
| 386 » » » » » » f := &Foo{Val: 21} | |
| 387 » » » » » » putOne(txnDS, k, f) | |
| 388 | 343 |
| 389 err := ds.RunInTransaction(func(
c context.Context) error { | 344 err := ds.RunInTransaction(func(
c context.Context) error { |
| 390 » » » » » » » txnDS := dsS.Get(c) | 345 » » » » » » » So(dsS.Get(c).Put(&Foo{I
d: 1, Val: 27}), ShouldBeNil) |
| 391 » » » » » » » f := &Foo{Val: 27} | |
| 392 » » » » » » » putOne(txnDS, k, f) | |
| 393 return nil | 346 return nil |
| 394 }, nil) | 347 }, nil) |
| 395 So(err, ShouldBeNil) | 348 So(err, ShouldBeNil) |
| 396 | 349 |
| 397 return nil | 350 return nil |
| 398 }, nil) | 351 }, nil) |
| 399 So(err.Error(), ShouldContainSubstring,
"concurrent") | 352 So(err.Error(), ShouldContainSubstring,
"concurrent") |
| 400 | 353 |
| 401 » » » » » f := &Foo{} | 354 » » » » » f := &Foo{Id: 1} |
| 402 » » » » » getOne(ds, k, f) | 355 » » » » » So(ds.Get(f), ShouldBeNil) |
| 403 So(f.Val, ShouldEqual, 27) | 356 So(f.Val, ShouldEqual, 27) |
| 404 }) | 357 }) |
| 405 | 358 |
| 406 Convey("XG", func() { | 359 Convey("XG", func() { |
| 407 Convey("Modifying two groups with XG=fal
se is invalid", func() { | 360 Convey("Modifying two groups with XG=fal
se is invalid", func() { |
| 408 err := ds.RunInTransaction(func(
c context.Context) error { | 361 err := ds.RunInTransaction(func(
c context.Context) error { |
| 409 ds := dsS.Get(c) | 362 ds := dsS.Get(c) |
| 410 » » » » » » » f := &Foo{Val: 200} | 363 » » » » » » » f := &Foo{Id: 1, Val: 20
0} |
| 411 » » » » » » » putOne(ds, k, f) | 364 » » » » » » » So(ds.Put(f), ShouldBeNi
l) |
| 412 | 365 |
| 413 » » » » » » » _, err := putOneErr(ds,
ds.NewKey("Foo", "", 2, nil), f) | 366 » » » » » » » f.Id = 2 |
| 367 » » » » » » » err := ds.Put(f) |
| 414 So(err.Error(), ShouldCo
ntainSubstring, "cross-group") | 368 So(err.Error(), ShouldCo
ntainSubstring, "cross-group") |
| 415 return err | 369 return err |
| 416 }, nil) | 370 }, nil) |
| 417 So(err.Error(), ShouldContainSub
string, "cross-group") | 371 So(err.Error(), ShouldContainSub
string, "cross-group") |
| 418 }) | 372 }) |
| 419 | 373 |
| 420 Convey("Modifying >25 groups with XG=tru
e is invald", func() { | 374 Convey("Modifying >25 groups with XG=tru
e is invald", func() { |
| 421 err := ds.RunInTransaction(func(
c context.Context) error { | 375 err := ds.RunInTransaction(func(
c context.Context) error { |
| 422 ds := dsS.Get(c) | 376 ds := dsS.Get(c) |
| 377 foos := make([]Foo, 25) |
| 423 for i := int64(1); i < 2
6; i++ { | 378 for i := int64(1); i < 2
6; i++ { |
| 424 » » » » » » » » k := ds.NewKey("
Foo", "", i, nil) | 379 » » » » » » » » foos[i-1].Id = i |
| 425 » » » » » » » » f := &Foo{Val: 2
00} | 380 » » » » » » » » foos[i-1].Val =
200 |
| 426 » » » » » » » » putOne(ds, k, f) | |
| 427 } | 381 } |
| 428 » » » » » » » f := &Foo{Val: 200} | 382 » » » » » » » So(ds.PutMulti(foos), Sh
ouldBeNil) |
| 429 » » » » » » » _, err := putOneErr(ds,
ds.NewKey("Foo", "", 27, nil), f) | 383 » » » » » » » err := ds.Put(&Foo{Id: 2
6}) |
| 430 So(err.Error(), ShouldCo
ntainSubstring, "too many entity groups") | 384 So(err.Error(), ShouldCo
ntainSubstring, "too many entity groups") |
| 431 return err | 385 return err |
| 432 }, &dsS.TransactionOptions{XG: t
rue}) | 386 }, &dsS.TransactionOptions{XG: t
rue}) |
| 433 So(err.Error(), ShouldContainSub
string, "too many entity groups") | 387 So(err.Error(), ShouldContainSub
string, "too many entity groups") |
| 434 }) | 388 }) |
| 435 }) | 389 }) |
| 436 | 390 |
| 437 Convey("Errors and panics", func() { | 391 Convey("Errors and panics", func() { |
| 438 Convey("returning an error aborts", func
() { | 392 Convey("returning an error aborts", func
() { |
| 439 err := ds.RunInTransaction(func(
c context.Context) error { | 393 err := ds.RunInTransaction(func(
c context.Context) error { |
| 440 ds := dsS.Get(c) | 394 ds := dsS.Get(c) |
| 441 » » » » » » » f := &Foo{Val: 200} | 395 » » » » » » » So(ds.Put(&Foo{Id: 1, Va
l: 200}), ShouldBeNil) |
| 442 » » » » » » » putOne(ds, k, f) | |
| 443 | |
| 444 return fmt.Errorf("thing
y") | 396 return fmt.Errorf("thing
y") |
| 445 }, nil) | 397 }, nil) |
| 446 So(err.Error(), ShouldEqual, "th
ingy") | 398 So(err.Error(), ShouldEqual, "th
ingy") |
| 447 | 399 |
| 448 » » » » » » f := &Foo{} | 400 » » » » » » f := &Foo{Id: 1} |
| 449 » » » » » » getOne(ds, k, f) | 401 » » » » » » So(ds.Get(f), ShouldBeNil) |
| 450 So(f.Val, ShouldEqual, 10) | 402 So(f.Val, ShouldEqual, 10) |
| 451 }) | 403 }) |
| 452 | 404 |
| 453 Convey("panicing aborts", func() { | 405 Convey("panicing aborts", func() { |
| 454 So(func() { | 406 So(func() { |
| 455 ds.RunInTransaction(func
(c context.Context) error { | 407 ds.RunInTransaction(func
(c context.Context) error { |
| 456 ds := dsS.Get(c) | 408 ds := dsS.Get(c) |
| 457 » » » » » » » » f := &Foo{Val: 2
00} | 409 » » » » » » » » So(ds.Put(&Foo{V
al: 200}), ShouldBeNil) |
| 458 » » » » » » » » putOne(ds, k, f) | |
| 459 panic("wheeeeee"
) | 410 panic("wheeeeee"
) |
| 460 }, nil) | 411 }, nil) |
| 461 }, ShouldPanic) | 412 }, ShouldPanic) |
| 462 | 413 |
| 463 » » » » » » f := &Foo{} | 414 » » » » » » f := &Foo{Id: 1} |
| 464 » » » » » » getOne(ds, k, f) | 415 » » » » » » So(ds.Get(f), ShouldBeNil) |
| 465 So(f.Val, ShouldEqual, 10) | 416 So(f.Val, ShouldEqual, 10) |
| 466 }) | 417 }) |
| 467 }) | 418 }) |
| 468 }) | 419 }) |
| 469 }) | 420 }) |
| 470 | 421 |
| 471 }) | 422 }) |
| 472 } | 423 } |
| 473 | 424 |
| 474 const MaxUint = ^uint(0) | 425 const MaxUint = ^uint(0) |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 620 }) | 571 }) |
| 621 Convey("kindless with decending-__key__ orders", func()
{ | 572 Convey("kindless with decending-__key__ orders", func()
{ |
| 622 q := ds.NewQuery("").Order("-__key__") | 573 q := ds.NewQuery("").Order("-__key__") |
| 623 qi := q.(*queryImpl).checkCorrectness("", false) | 574 qi := q.(*queryImpl).checkCorrectness("", false) |
| 624 So(qi.err.Error(), ShouldContainSubstring, "kind
is required for all orders") | 575 So(qi.err.Error(), ShouldContainSubstring, "kind
is required for all orders") |
| 625 }) | 576 }) |
| 626 }) | 577 }) |
| 627 | 578 |
| 628 }) | 579 }) |
| 629 } | 580 } |
| OLD | NEW |