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

Side by Side Diff: impl/memory/raw_datastore_test.go

Issue 1259593005: Add 'user friendly' datastore API. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 » rdsS "github.com/luci/gae/service/rawdatastore" 12 » dsS "github.com/luci/gae/service/datastore"
13 . "github.com/smartystreets/goconvey/convey" 13 . "github.com/smartystreets/goconvey/convey"
14 "golang.org/x/net/context" 14 "golang.org/x/net/context"
15 ) 15 )
16 16
17 func TestDatastoreKinder(t *testing.T) { 17 func TestDatastoreKinder(t *testing.T) {
18 t.Parallel() 18 t.Parallel()
19 19
20 Convey("Datastore keys", t, func() { 20 Convey("Datastore keys", t, func() {
21 c := Use(context.Background()) 21 c := Use(context.Background())
22 » » rds := rdsS.Get(c) 22 » » ds := dsS.Get(c)
23 » » So(rds, ShouldNotBeNil) 23 » » So(ds, ShouldNotBeNil)
24 24
25 Convey("implements DSNewKeyer", func() { 25 Convey("implements DSNewKeyer", func() {
26 Convey("NewKey", func() { 26 Convey("NewKey", func() {
27 » » » » key := rds.NewKey("nerd", "stringID", 0, nil) 27 » » » » key := ds.NewKey("nerd", "stringID", 0, nil)
28 So(key, ShouldNotBeNil) 28 So(key, ShouldNotBeNil)
29 So(key.Kind(), ShouldEqual, "nerd") 29 So(key.Kind(), ShouldEqual, "nerd")
30 So(key.StringID(), ShouldEqual, "stringID") 30 So(key.StringID(), ShouldEqual, "stringID")
31 So(key.IntID(), ShouldEqual, 0) 31 So(key.IntID(), ShouldEqual, 0)
32 So(key.Parent(), ShouldBeNil) 32 So(key.Parent(), ShouldBeNil)
33 So(key.AppID(), ShouldEqual, "dev~app") 33 So(key.AppID(), ShouldEqual, "dev~app")
34 So(key.Namespace(), ShouldEqual, "") 34 So(key.Namespace(), ShouldEqual, "")
35 So(key.String(), ShouldEqual, "/nerd,stringID") 35 So(key.String(), ShouldEqual, "/nerd,stringID")
36 » » » » So(rdsS.KeyIncomplete(key), ShouldBeFalse) 36 » » » » So(dsS.KeyIncomplete(key), ShouldBeFalse)
37 » » » » So(rdsS.KeyValid(key, false, "dev~app", ""), Sho uldBeTrue) 37 » » » » So(dsS.KeyValid(key, false, "dev~app", ""), Shou ldBeTrue)
38 }) 38 })
39 }) 39 })
40 40
41 }) 41 })
42 } 42 }
43 43
44 func testGetMeta(c context.Context, k rdsS.Key) int64 { 44 type MetaGroup struct {
45 » rds := rdsS.Get(c) 45 » _id int64 `gae:"$id,1"`
46 » retval := int64(0) 46 » _kind string `gae:"$kind,__entity_group__"`
47 » err := rds.GetMulti([]rdsS.Key{rds.NewKey("__entity_group__", "", 1, rds S.KeyRoot(k))}, func(val rdsS.PropertyMap, err error) { 47 » Parent dsS.Key `gae:"$parent"`
48 » » if err != nil { 48
49 » » » panic(err) 49 » Version int64 `gae:"__version__"`
50 » » } 50 }
51 » » retval = val["__version__"][0].Value().(int64) 51
52 » }) 52 func testGetMeta(c context.Context, k dsS.Key) int64 {
53 » if err != nil { 53 » ds := dsS.Get(c)
54 » mg := &MetaGroup{Parent: dsS.KeyRoot(k)}
55 » if err := ds.Get(mg); err != nil {
54 panic(err) 56 panic(err)
55 } 57 }
56 » return retval 58 » return mg.Version
57 } 59 }
58 60
59 var pls = rdsS.GetPLS 61 var pls = dsS.GetPLS
62
63 type Foo struct {
64 » Id int64 `gae:"$id"`
65 » Parent dsS.Key `gae:"$parent"`
66
67 » Val int
68 }
60 69
61 func TestDatastoreSingleReadWriter(t *testing.T) { 70 func TestDatastoreSingleReadWriter(t *testing.T) {
62 t.Parallel() 71 t.Parallel()
63 72
64 getOnePM := func(rds rdsS.Interface, key rdsS.Key) (pmap rdsS.PropertyMa p, err error) {
65 blankErr := rds.GetMulti([]rdsS.Key{key}, func(itmPmap rdsS.Prop ertyMap, itmErr error) {
66 pmap = itmPmap
67 err = itmErr
68 })
69 So(blankErr, ShouldBeNil)
70 return
71 }
72
73 delOneErr := func(rds rdsS.Interface, key rdsS.Key) (err error) {
74 blankErr := rds.DeleteMulti([]rdsS.Key{key}, func(itmErr error) {
75 err = itmErr
76 })
77 So(blankErr, ShouldBeNil)
78 return
79 }
80
81 delOne := func(rds rdsS.Interface, key rdsS.Key) {
82 So(delOneErr(rds, key), ShouldBeNil)
83 }
84
85 getOne := func(rds rdsS.Interface, key rdsS.Key, dst interface{}) {
86 pm, err := getOnePM(rds, key)
87 So(err, ShouldBeNil)
88 So(pls(dst).Load(pm), ShouldBeNil)
89 }
90
91 putOneErr := func(rds rdsS.Interface, key rdsS.Key, val interface{}) (re tKey rdsS.Key, err error) {
92 blankErr := rds.PutMulti([]rdsS.Key{key}, []rdsS.PropertyLoadSav er{pls(val)}, func(itmKey rdsS.Key, itmErr error) {
93 err = itmErr
94 retKey = itmKey
95 })
96 So(blankErr, ShouldBeNil)
97 return
98 }
99
100 putOne := func(rds rdsS.Interface, key rdsS.Key, val interface{}) (retKe y rdsS.Key) {
101 key, err := putOneErr(rds, key, val)
102 So(err, ShouldBeNil)
103 return key
104 }
105
106 Convey("Datastore single reads and writes", t, func() { 73 Convey("Datastore single reads and writes", t, func() {
107 c := Use(context.Background()) 74 c := Use(context.Background())
108 » » rds := rdsS.Get(c) 75 » » ds := dsS.Get(c)
109 » » So(rds, ShouldNotBeNil) 76 » » So(ds, ShouldNotBeNil)
110 77
111 Convey("implements DSSingleReadWriter", func() { 78 Convey("implements DSSingleReadWriter", func() {
112 type Foo struct {
113 Val int
114 }
115
116 Convey("getting objects that DNE is an error", func() { 79 Convey("getting objects that DNE is an error", func() {
117 » » » » _, err := getOnePM(rds, rds.NewKey("Foo", "", 1, nil)) 80 » » » » So(ds.Get(&Foo{Id: 1}), ShouldEqual, dsS.ErrNoSu chEntity)
118 » » » » So(err, ShouldEqual, rdsS.ErrNoSuchEntity)
119 }) 81 })
120 82
121 Convey("Can Put stuff", func() { 83 Convey("Can Put stuff", func() {
122 // with an incomplete key! 84 // with an incomplete key!
123 k := rds.NewKey("Foo", "", 0, nil)
124 f := &Foo{Val: 10} 85 f := &Foo{Val: 10}
125 » » » » k = putOne(rds, k, f) 86 » » » » So(ds.Put(f), ShouldBeNil)
87 » » » » k := ds.NewKeyObj(f)
126 So(k.String(), ShouldEqual, "/Foo,1") 88 So(k.String(), ShouldEqual, "/Foo,1")
127 89
128 Convey("and Get it back", func() { 90 Convey("and Get it back", func() {
129 » » » » » newFoo := &Foo{} 91 » » » » » newFoo := &Foo{Id: 1}
130 » » » » » getOne(rds, k, newFoo) 92 » » » » » So(ds.Get(newFoo), ShouldBeNil)
131 So(newFoo, ShouldResemble, f) 93 So(newFoo, ShouldResemble, f)
132 94
133 Convey("and we can Delete it", func() { 95 Convey("and we can Delete it", func() {
134 » » » » » » delOne(rds, k) 96 » » » » » » So(ds.Delete(k), ShouldBeNil)
135 » » » » » » _, err := getOnePM(rds, k) 97 » » » » » » So(ds.Get(newFoo), ShouldEqual, dsS.ErrNoSuchEntity)
136 » » » » » » So(err, ShouldEqual, rdsS.ErrNoS uchEntity)
137 }) 98 })
138 }) 99 })
139 Convey("Deleteing with a bogus key is bad", func () { 100 Convey("Deleteing with a bogus key is bad", func () {
140 » » » » » So(delOneErr(rds, rds.NewKey("Foo", "wat ", 100, nil)), ShouldEqual, rdsS.ErrInvalidKey) 101 » » » » » So(ds.Delete(ds.NewKey("Foo", "wat", 100 , nil)), ShouldEqual, dsS.ErrInvalidKey)
141 }) 102 })
142 Convey("Deleteing a DNE entity is fine", func() { 103 Convey("Deleteing a DNE entity is fine", func() {
143 » » » » » delOne(rds, rds.NewKey("Foo", "wat", 0, nil)) 104 » » » » » So(ds.Delete(ds.NewKey("Foo", "wat", 0, nil)), ShouldBeNil)
144 }) 105 })
145 106
146 Convey("with multiple puts", func() { 107 Convey("with multiple puts", func() {
147 So(testGetMeta(c, k), ShouldEqual, 1) 108 So(testGetMeta(c, k), ShouldEqual, 1)
148 109
149 » » » » » keys := []rdsS.Key{} 110 » » » » » foos := make([]Foo, 10)
150 » » » » » vals := []rdsS.PropertyLoadSaver{} 111 » » » » » for i := range foos {
151 112 » » » » » » foos[i].Val = 10
152 » » » » » pkey := k 113 » » » » » » foos[i].Parent = k
153 » » » » » for i := 0; i < 10; i++ {
154 » » » » » » keys = append(keys, rds.NewKey(" Foo", "", 0, pkey))
155 » » » » » » vals = append(vals, pls(&Foo{Val : 10}))
156 } 114 }
157 » » » » » i := 0 115 » » » » » So(ds.PutMulti(foos), ShouldBeNil)
158 » » » » » err := rds.PutMulti(keys, vals, func(k r dsS.Key, err error) {
159 » » » » » » So(err, ShouldBeNil)
160 » » » » » » keys[i] = k
161 » » » » » » i++
162 » » » » » })
163 » » » » » So(err, ShouldBeNil)
164 So(testGetMeta(c, k), ShouldEqual, 11) 116 So(testGetMeta(c, k), ShouldEqual, 11)
165 117
118 keys := make([]dsS.Key, len(foos))
119 for i, f := range foos {
120 keys[i] = ds.NewKeyObj(&f)
121 }
122
166 Convey("ensure that group versions persi st across deletes", func() { 123 Convey("ensure that group versions persi st across deletes", func() {
167 » » » » » » keys = append(keys, pkey) 124 » » » » » » So(ds.DeleteMulti(append(keys, k )), ShouldBeNil)
168 » » » » » » err := rds.DeleteMulti(keys, fun c(err error) {
169 » » » » » » » So(err, ShouldBeNil)
170 » » » » » » })
171 » » » » » » So(err, ShouldBeNil)
172 125
173 // TODO(riannucci): replace with a Count query instead of this cast 126 // TODO(riannucci): replace with a Count query instead of this cast
174 /* 127 /*
175 » » » » » » » ents := rds.(*dsImpl).da ta.store.GetCollection("ents:") 128 » » » » » » » ents := ds.(*dsImpl).dat a.store.GetCollection("ents:")
176 num, _ := ents.GetTotals () 129 num, _ := ents.GetTotals ()
177 // /__entity_root_ids__, Foo 130 // /__entity_root_ids__, Foo
178 // /Foo,1/__entity_group __,1 131 // /Foo,1/__entity_group __,1
179 // /Foo,1/__entity_group _ids__,1 132 // /Foo,1/__entity_group _ids__,1
180 So(num, ShouldEqual, 3) 133 So(num, ShouldEqual, 3)
181 */ 134 */
182 135
183 So(testGetMeta(c, k), ShouldEqua l, 22) 136 So(testGetMeta(c, k), ShouldEqua l, 22)
184 137
185 » » » » » » putOne(rds, k, f) 138 » » » » » » So(ds.Put(&Foo{Id: 1}), ShouldBe Nil)
186 So(testGetMeta(c, k), ShouldEqua l, 23) 139 So(testGetMeta(c, k), ShouldEqua l, 23)
187 }) 140 })
188 141
189 Convey("can Get", func() { 142 Convey("can Get", func() {
190 » » » » » » vals := []rdsS.PropertyMap{} 143 » » » » » » vals := make([]dsS.PropertyMap, len(keys))
191 » » » » » » err := rds.GetMulti(keys, func(p m rdsS.PropertyMap, err error) { 144 » » » » » » for i := range vals {
192 » » » » » » » So(err, ShouldBeNil) 145 » » » » » » » vals[i] = dsS.PropertyMa p{}
193 » » » » » » » vals = append(vals, pm) 146 » » » » » » » vals[i].SetMeta("key", k eys[i])
194 » » » » » » }) 147 » » » » » » }
195 » » » » » » So(err, ShouldBeNil) 148 » » » » » » So(ds.GetMulti(vals), ShouldBeNi l)
196 149
197 » » » » » » for _, val := range vals { 150 » » » » » » for i, val := range vals {
198 » » » » » » » So(val, ShouldResemble, rdsS.PropertyMap{"Val": {rdsS.MkProperty(10)}}) 151 » » » » » » » So(val, ShouldResemble, dsS.PropertyMap{
152 » » » » » » » » "Val": {dsS.MkP roperty(10)},
153 » » » » » » » » "$key": {dsS.MkP ropertyNI(keys[i])},
154 » » » » » » » })
199 } 155 }
200 }) 156 })
201 }) 157 })
202 }) 158 })
203 }) 159 })
204 160
205 Convey("implements DSTransactioner", func() { 161 Convey("implements DSTransactioner", func() {
206 type Foo struct {
207 Val int
208 }
209 Convey("Put", func() { 162 Convey("Put", func() {
210 f := &Foo{Val: 10} 163 f := &Foo{Val: 10}
211 » » » » origKey := rds.NewKey("Foo", "", 0, nil) 164 » » » » So(ds.Put(f), ShouldBeNil)
212 » » » » k := putOne(rds, origKey, f) 165 » » » » k := ds.NewKeyObj(f)
213 So(k.String(), ShouldEqual, "/Foo,1") 166 So(k.String(), ShouldEqual, "/Foo,1")
214 167
215 Convey("can Put new entity groups", func() { 168 Convey("can Put new entity groups", func() {
216 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 169 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
217 » » » » » » rds := rdsS.Get(c) 170 » » » » » » ds := dsS.Get(c)
218 171
219 » » » » » » f1 := &Foo{Val: 100} 172 » » » » » » f := &Foo{Val: 100}
220 » » » » » » k := putOne(rds, origKey, f1) 173 » » » » » » So(ds.Put(f), ShouldBeNil)
221 » » » » » » So(k.String(), ShouldEqual, "/Fo o,2") 174 » » » » » » So(f.Id, ShouldEqual, 2)
222 175
223 » » » » » » f2 := &Foo{Val: 200} 176 » » » » » » f.Id = 0
224 » » » » » » k = putOne(rds, origKey, f2) 177 » » » » » » f.Val = 200
225 » » » » » » So(k.String(), ShouldEqual, "/Fo o,3") 178 » » » » » » So(ds.Put(f), ShouldBeNil)
179 » » » » » » So(f.Id, ShouldEqual, 3)
226 180
227 return nil 181 return nil
228 » » » » » }, &rdsS.TransactionOptions{XG: true}) 182 » » » » » }, &dsS.TransactionOptions{XG: true})
229 So(err, ShouldBeNil) 183 So(err, ShouldBeNil)
230 184
231 » » » » » f := &Foo{} 185 » » » » » f := &Foo{Id: 2}
232 » » » » » getOne(rds, rds.NewKey("Foo", "", 2, nil ), f) 186 » » » » » So(ds.Get(f), ShouldBeNil)
233 So(f.Val, ShouldEqual, 100) 187 So(f.Val, ShouldEqual, 100)
234 188
235 » » » » » getOne(rds, rds.NewKey("Foo", "", 3, nil ), f) 189 » » » » » f.Id = 3
190 » » » » » So(ds.Get(f), ShouldBeNil)
236 So(f.Val, ShouldEqual, 200) 191 So(f.Val, ShouldEqual, 200)
237 }) 192 })
238 193
239 Convey("can Put new entities in a current group" , func() { 194 Convey("can Put new entities in a current group" , func() {
240 » » » » » par := k 195 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
241 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 196 » » » » » » ds := dsS.Get(c)
242 » » » » » » rds := rdsS.Get(c)
243 » » » » » » So(rds, ShouldNotBeNil)
244 197
245 » » » » » » f1 := &Foo{Val: 100} 198 » » » » » » f := &Foo{Val: 100, Parent: k}
246 » » » » » » k := putOne(rds, rds.NewKey("Foo ", "", 0, par), f1) 199 » » » » » » So(ds.Put(f), ShouldBeNil)
247 » » » » » » So(k.String(), ShouldEqual, "/Fo o,1/Foo,1") 200 » » » » » » So(ds.NewKeyObj(f).String(), Sho uldEqual, "/Foo,1/Foo,1")
248 201
249 » » » » » » f2 := &Foo{Val: 200} 202 » » » » » » f.Id = 0
250 » » » » » » k = putOne(rds, rds.NewKey("Foo" , "", 0, par), f2) 203 » » » » » » f.Val = 200
251 » » » » » » So(k.String(), ShouldEqual, "/Fo o,1/Foo,2") 204 » » » » » » So(ds.Put(f), ShouldBeNil)
205 » » » » » » So(ds.NewKeyObj(f).String(), Sho uldEqual, "/Foo,1/Foo,2")
252 206
253 return nil 207 return nil
254 }, nil) 208 }, nil)
255 So(err, ShouldBeNil) 209 So(err, ShouldBeNil)
256 210
257 » » » » » f := &Foo{} 211 » » » » » f := &Foo{Id: 1, Parent: k}
258 » » » » » getOne(rds, rds.NewKey("Foo", "", 1, k), f) 212 » » » » » So(ds.Get(f), ShouldBeNil)
259 So(f.Val, ShouldEqual, 100) 213 So(f.Val, ShouldEqual, 100)
260 214
261 » » » » » getOne(rds, rds.NewKey("Foo", "", 2, k), f) 215 » » » » » f.Id = 2
216 » » » » » So(ds.Get(f), ShouldBeNil)
262 So(f.Val, ShouldEqual, 200) 217 So(f.Val, ShouldEqual, 200)
263 }) 218 })
264 219
265 Convey("Deletes work too", func() { 220 Convey("Deletes work too", func() {
266 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 221 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
267 » » » » » » rds := rdsS.Get(c) 222 » » » » » » return dsS.Get(c).Delete(k)
268 » » » » » » So(rds, ShouldNotBeNil)
269 » » » » » » delOne(rds, k)
270 » » » » » » return nil
271 }, nil) 223 }, nil)
272 So(err, ShouldBeNil) 224 So(err, ShouldBeNil)
273 » » » » » _, err = getOnePM(rds, k) 225 » » » » » So(ds.Get(&Foo{Id: 1}), ShouldEqual, dsS .ErrNoSuchEntity)
274 » » » » » So(err, ShouldEqual, rdsS.ErrNoSuchEntit y)
275 }) 226 })
276 227
277 Convey("A Get counts against your group count", func() { 228 Convey("A Get counts against your group count", func() {
278 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 229 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
279 » » » » » » rds := rdsS.Get(c) 230 » » » » » » ds := dsS.Get(c)
280 231
281 » » » » » » _, err := getOnePM(rds, rds.NewK ey("Foo", "", 20, nil)) 232 » » » » » » pm := dsS.PropertyMap{}
282 » » » » » » So(err, ShouldEqual, rdsS.ErrNoS uchEntity) 233 » » » » » » pm.SetMeta("key", ds.NewKey("Foo ", "", 20, nil))
234 » » » » » » So(ds.Get(pm), ShouldEqual, dsS. ErrNoSuchEntity)
283 235
284 » » » » » » err = rds.GetMulti([]rdsS.Key{k} , func(_ rdsS.PropertyMap, err error) { 236 » » » » » » pm.SetMeta("key", k)
285 » » » » » » » So(err, ShouldBeNil) 237 » » » » » » So(ds.Get(pm).Error(), ShouldCon tainSubstring, "cross-group")
286 » » » » » » })
287 » » » » » » So(err.Error(), ShouldContainSub string, "cross-group")
288 return nil 238 return nil
289 }, nil) 239 }, nil)
290 So(err, ShouldBeNil) 240 So(err, ShouldBeNil)
291 }) 241 })
292 242
293 Convey("Get takes a snapshot", func() { 243 Convey("Get takes a snapshot", func() {
294 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 244 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
295 » » » » » » txnDS := rdsS.Get(c) 245 » » » » » » txnDS := dsS.Get(c)
296 » » » » » » So(txnDS, ShouldNotBeNil)
297 246
298 » » » » » » getOne(txnDS, k, f) 247 » » » » » » So(txnDS.Get(f), ShouldBeNil)
299 So(f.Val, ShouldEqual, 10) 248 So(f.Val, ShouldEqual, 10)
300 249
301 // Don't ever do this in a real program unless you want to guarantee 250 // Don't ever do this in a real program unless you want to guarantee
302 // a failed transaction :) 251 // a failed transaction :)
303 f.Val = 11 252 f.Val = 11
304 » » » » » » putOne(rds, k, f) 253 » » » » » » So(ds.Put(f), ShouldBeNil)
305 254
306 » » » » » » getOne(txnDS, k, f) 255 » » » » » » So(txnDS.Get(f), ShouldBeNil)
307 So(f.Val, ShouldEqual, 10) 256 So(f.Val, ShouldEqual, 10)
308 257
309 return nil 258 return nil
310 }, nil) 259 }, nil)
311 So(err, ShouldBeNil) 260 So(err, ShouldBeNil)
312 261
313 » » » » » f := &Foo{} 262 » » » » » f := &Foo{Id: 1}
314 » » » » » getOne(rds, k, f) 263 » » » » » So(ds.Get(f), ShouldBeNil)
315 So(f.Val, ShouldEqual, 11) 264 So(f.Val, ShouldEqual, 11)
316 }) 265 })
317 266
318 Convey("and snapshots are consistent even after Puts", func() { 267 Convey("and snapshots are consistent even after Puts", func() {
319 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 268 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
320 » » » » » » txnDS := rdsS.Get(c) 269 » » » » » » txnDS := dsS.Get(c)
321 » » » » » » So(txnDS, ShouldNotBeNil)
322 270
323 » » » » » » f := &Foo{} 271 » » » » » » f := &Foo{Id: 1}
324 » » » » » » getOne(txnDS, k, f) 272 » » » » » » So(txnDS.Get(f), ShouldBeNil)
325 So(f.Val, ShouldEqual, 10) 273 So(f.Val, ShouldEqual, 10)
326 274
327 // Don't ever do this in a real program unless you want to guarantee 275 // Don't ever do this in a real program unless you want to guarantee
328 // a failed transaction :) 276 // a failed transaction :)
329 f.Val = 11 277 f.Val = 11
330 » » » » » » putOne(rds, k, f) 278 » » » » » » So(ds.Put(f), ShouldBeNil)
331 279
332 » » » » » » getOne(txnDS, k, f) 280 » » » » » » So(txnDS.Get(f), ShouldBeNil)
333 So(f.Val, ShouldEqual, 10) 281 So(f.Val, ShouldEqual, 10)
334 282
335 f.Val = 20 283 f.Val = 20
336 » » » » » » putOne(txnDS, k, f) 284 » » » » » » So(txnDS.Put(f), ShouldBeNil)
337 285
338 » » » » » » getOne(txnDS, k, f) 286 » » » » » » So(txnDS.Get(f), ShouldBeNil)
339 So(f.Val, ShouldEqual, 10) // st ill gets 10 287 So(f.Val, ShouldEqual, 10) // st ill gets 10
340 288
341 return nil 289 return nil
342 }, nil) 290 }, nil)
343 So(err.Error(), ShouldContainSubstring, "concurrent") 291 So(err.Error(), ShouldContainSubstring, "concurrent")
344 292
345 » » » » » f := &Foo{} 293 » » » » » f := &Foo{Id: 1}
346 » » » » » getOne(rds, k, f) 294 » » » » » So(ds.Get(f), ShouldBeNil)
347 So(f.Val, ShouldEqual, 11) 295 So(f.Val, ShouldEqual, 11)
348 }) 296 })
349 297
350 Convey("Reusing a transaction context is bad new s", func() { 298 Convey("Reusing a transaction context is bad new s", func() {
351 » » » » » k := rds.NewKey("Foo", "", 1, nil) 299 » » » » » txnDS := dsS.Interface(nil)
352 » » » » » txnDS := rdsS.Interface(nil) 300 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
353 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 301 » » » » » » txnDS = dsS.Get(c)
354 » » » » » » txnDS = rdsS.Get(c) 302 » » » » » » So(txnDS.Get(f), ShouldBeNil)
355 » » » » » » getOnePM(txnDS, k)
356 return nil 303 return nil
357 }, nil) 304 }, nil)
358 So(err, ShouldBeNil) 305 So(err, ShouldBeNil)
359 » » » » » err = txnDS.GetMulti([]rdsS.Key{k}, func (_ rdsS.PropertyMap, err error) { 306 » » » » » So(txnDS.Get(f).Error(), ShouldContainSu bstring, "expired")
360 » » » » » » So(err, ShouldBeNil)
361 » » » » » })
362 » » » » » So(err.Error(), ShouldContainSubstring, "expired")
363 }) 307 })
364 308
365 Convey("Nested transactions are rejected", func( ) { 309 Convey("Nested transactions are rejected", func( ) {
366 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 310 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
367 » » » » » » err := rdsS.Get(c).RunInTransact ion(func(c context.Context) error { 311 » » » » » » err := dsS.Get(c).RunInTransacti on(func(c context.Context) error {
368 panic("noooo") 312 panic("noooo")
369 }, nil) 313 }, nil)
370 So(err.Error(), ShouldContainSub string, "nested transactions") 314 So(err.Error(), ShouldContainSub string, "nested transactions")
371 return nil 315 return nil
372 }, nil) 316 }, nil)
373 So(err, ShouldBeNil) 317 So(err, ShouldBeNil)
374 }) 318 })
375 319
376 Convey("Concurrent transactions only accept one set of changes", func() { 320 Convey("Concurrent transactions only accept one set of changes", func() {
377 // Note: I think this implementation is actually /slightly/ wrong. 321 // Note: I think this implementation is actually /slightly/ wrong.
378 // Accorting to my read of the docs for appengine, when you open a 322 // Accorting to my read of the docs for appengine, when you open a
379 // transaction it actually (essentially) holds a reference to the 323 // transaction it actually (essentially) holds a reference to the
380 // entire datastore. Our implementation takes a snapshot of the 324 // entire datastore. Our implementation takes a snapshot of the
381 // entity group as soon as something obs erves/affects it. 325 // entity group as soon as something obs erves/affects it.
382 // 326 //
383 // That said... I'm not sure if there's really a semantic difference. 327 // That said... I'm not sure if there's really a semantic difference.
384 » » » » » err := rds.RunInTransaction(func(c conte xt.Context) error { 328 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error {
385 » » » » » » txnDS := rdsS.Get(c) 329 » » » » » » So(dsS.Get(c).Put(&Foo{Id: 1, Va l: 21}), ShouldBeNil)
386 » » » » » » f := &Foo{Val: 21}
387 » » » » » » putOne(txnDS, k, f)
388 330
389 » » » » » » err := rds.RunInTransaction(func (c context.Context) error { 331 » » » » » » err := ds.RunInTransaction(func( c context.Context) error {
390 » » » » » » » txnDS := rdsS.Get(c) 332 » » » » » » » 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 333 return nil
394 }, nil) 334 }, nil)
395 So(err, ShouldBeNil) 335 So(err, ShouldBeNil)
396 336
397 return nil 337 return nil
398 }, nil) 338 }, nil)
399 So(err.Error(), ShouldContainSubstring, "concurrent") 339 So(err.Error(), ShouldContainSubstring, "concurrent")
400 340
401 » » » » » f := &Foo{} 341 » » » » » f := &Foo{Id: 1}
402 » » » » » getOne(rds, k, f) 342 » » » » » So(ds.Get(f), ShouldBeNil)
403 So(f.Val, ShouldEqual, 27) 343 So(f.Val, ShouldEqual, 27)
404 }) 344 })
405 345
406 Convey("XG", func() { 346 Convey("XG", func() {
407 Convey("Modifying two groups with XG=fal se is invalid", func() { 347 Convey("Modifying two groups with XG=fal se is invalid", func() {
408 » » » » » » err := rds.RunInTransaction(func (c context.Context) error { 348 » » » » » » err := ds.RunInTransaction(func( c context.Context) error {
409 » » » » » » » rds := rdsS.Get(c) 349 » » » » » » » ds := dsS.Get(c)
410 » » » » » » » f := &Foo{Val: 200} 350 » » » » » » » f := &Foo{Id: 1, Val: 20 0}
411 » » » » » » » putOne(rds, k, f) 351 » » » » » » » So(ds.Put(f), ShouldBeNi l)
412 352
413 » » » » » » » _, err := putOneErr(rds, rds.NewKey("Foo", "", 2, nil), f) 353 » » » » » » » f.Id = 2
354 » » » » » » » err := ds.Put(f)
414 So(err.Error(), ShouldCo ntainSubstring, "cross-group") 355 So(err.Error(), ShouldCo ntainSubstring, "cross-group")
415 return err 356 return err
416 }, nil) 357 }, nil)
417 So(err.Error(), ShouldContainSub string, "cross-group") 358 So(err.Error(), ShouldContainSub string, "cross-group")
418 }) 359 })
419 360
420 Convey("Modifying >25 groups with XG=tru e is invald", func() { 361 Convey("Modifying >25 groups with XG=tru e is invald", func() {
421 » » » » » » err := rds.RunInTransaction(func (c context.Context) error { 362 » » » » » » err := ds.RunInTransaction(func( c context.Context) error {
422 » » » » » » » rds := rdsS.Get(c) 363 » » » » » » » ds := dsS.Get(c)
364 » » » » » » » foos := make([]Foo, 25)
423 for i := int64(1); i < 2 6; i++ { 365 for i := int64(1); i < 2 6; i++ {
424 » » » » » » » » k := rds.NewKey( "Foo", "", i, nil) 366 » » » » » » » » foos[i-1].Id = i
425 » » » » » » » » f := &Foo{Val: 2 00} 367 » » » » » » » » foos[i-1].Val = 200
426 » » » » » » » » putOne(rds, k, f )
427 } 368 }
428 » » » » » » » f := &Foo{Val: 200} 369 » » » » » » » So(ds.PutMulti(foos), Sh ouldBeNil)
429 » » » » » » » _, err := putOneErr(rds, rds.NewKey("Foo", "", 27, nil), f) 370 » » » » » » » err := ds.Put(&Foo{Id: 2 6})
430 So(err.Error(), ShouldCo ntainSubstring, "too many entity groups") 371 So(err.Error(), ShouldCo ntainSubstring, "too many entity groups")
431 return err 372 return err
432 » » » » » » }, &rdsS.TransactionOptions{XG: true}) 373 » » » » » » }, &dsS.TransactionOptions{XG: t rue})
433 So(err.Error(), ShouldContainSub string, "too many entity groups") 374 So(err.Error(), ShouldContainSub string, "too many entity groups")
434 }) 375 })
435 }) 376 })
436 377
437 Convey("Errors and panics", func() { 378 Convey("Errors and panics", func() {
438 Convey("returning an error aborts", func () { 379 Convey("returning an error aborts", func () {
439 » » » » » » err := rds.RunInTransaction(func (c context.Context) error { 380 » » » » » » err := ds.RunInTransaction(func( c context.Context) error {
440 » » » » » » » rds := rdsS.Get(c) 381 » » » » » » » ds := dsS.Get(c)
441 » » » » » » » f := &Foo{Val: 200} 382 » » » » » » » So(ds.Put(&Foo{Id: 1, Va l: 200}), ShouldBeNil)
442 » » » » » » » putOne(rds, k, f)
443
444 return fmt.Errorf("thing y") 383 return fmt.Errorf("thing y")
445 }, nil) 384 }, nil)
446 So(err.Error(), ShouldEqual, "th ingy") 385 So(err.Error(), ShouldEqual, "th ingy")
447 386
448 » » » » » » f := &Foo{} 387 » » » » » » f := &Foo{Id: 1}
449 » » » » » » getOne(rds, k, f) 388 » » » » » » So(ds.Get(f), ShouldBeNil)
450 So(f.Val, ShouldEqual, 10) 389 So(f.Val, ShouldEqual, 10)
451 }) 390 })
452 391
453 Convey("panicing aborts", func() { 392 Convey("panicing aborts", func() {
454 So(func() { 393 So(func() {
455 » » » » » » » rds.RunInTransaction(fun c(c context.Context) error { 394 » » » » » » » ds.RunInTransaction(func (c context.Context) error {
456 » » » » » » » » rds := rdsS.Get( c) 395 » » » » » » » » ds := dsS.Get(c)
457 » » » » » » » » f := &Foo{Val: 2 00} 396 » » » » » » » » So(ds.Put(&Foo{V al: 200}), ShouldBeNil)
458 » » » » » » » » putOne(rds, k, f )
459 panic("wheeeeee" ) 397 panic("wheeeeee" )
460 }, nil) 398 }, nil)
461 }, ShouldPanic) 399 }, ShouldPanic)
462 400
463 » » » » » » f := &Foo{} 401 » » » » » » f := &Foo{Id: 1}
464 » » » » » » getOne(rds, k, f) 402 » » » » » » So(ds.Get(f), ShouldBeNil)
465 So(f.Val, ShouldEqual, 10) 403 So(f.Val, ShouldEqual, 10)
466 }) 404 })
467 }) 405 })
468 }) 406 })
469 }) 407 })
470 408
471 }) 409 })
472 } 410 }
473 411
474 const MaxUint = ^uint(0) 412 const MaxUint = ^uint(0)
475 const MaxInt = int(MaxUint >> 1) 413 const MaxInt = int(MaxUint >> 1)
476 const IntIs32Bits = int64(MaxInt) < math.MaxInt64 414 const IntIs32Bits = int64(MaxInt) < math.MaxInt64
477 415
478 func TestDatastoreQueryer(t *testing.T) { 416 func TestDatastoreQueryer(t *testing.T) {
479 Convey("Datastore Query suport", t, func() { 417 Convey("Datastore Query suport", t, func() {
480 c := Use(context.Background()) 418 c := Use(context.Background())
481 » » rds := rdsS.Get(c) 419 » » ds := dsS.Get(c)
482 » » So(rds, ShouldNotBeNil) 420 » » So(ds, ShouldNotBeNil)
483 421
484 Convey("can create good queries", func() { 422 Convey("can create good queries", func() {
485 » » » q := rds.NewQuery("Foo").KeysOnly().Limit(10).Offset(39) 423 » » » q := ds.NewQuery("Foo").KeysOnly().Limit(10).Offset(39)
486 q = q.Start(queryCursor("kosmik")).End(queryCursor("krab s")) 424 q = q.Start(queryCursor("kosmik")).End(queryCursor("krab s"))
487 So(q, ShouldNotBeNil) 425 So(q, ShouldNotBeNil)
488 So(q.(*queryImpl).err, ShouldBeNil) 426 So(q.(*queryImpl).err, ShouldBeNil)
489 qi := q.(*queryImpl).checkCorrectness("", false) 427 qi := q.(*queryImpl).checkCorrectness("", false)
490 So(qi.err, ShouldBeNil) 428 So(qi.err, ShouldBeNil)
491 }) 429 })
492 430
493 Convey("normalize ensures orders make sense", func() { 431 Convey("normalize ensures orders make sense", func() {
494 » » » q := rds.NewQuery("Cool") 432 » » » q := ds.NewQuery("Cool")
495 q = q.Filter("cat =", 19).Filter("bob =", 10).Order("bob ").Order("bob") 433 q = q.Filter("cat =", 19).Filter("bob =", 10).Order("bob ").Order("bob")
496 434
497 Convey("removes dups and equality orders", func() { 435 Convey("removes dups and equality orders", func() {
498 q = q.Order("wat") 436 q = q.Order("wat")
499 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false) 437 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false)
500 So(qi.err, ShouldBeNil) 438 So(qi.err, ShouldBeNil)
501 So(qi.order, ShouldResemble, []queryOrder{{"wat" , qASC}}) 439 So(qi.order, ShouldResemble, []queryOrder{{"wat" , qASC}})
502 }) 440 })
503 441
504 Convey("keeps inequality orders", func() { 442 Convey("keeps inequality orders", func() {
505 q = q.Order("wat") 443 q = q.Order("wat")
506 q := q.Filter("bob >", 10).Filter("wat <", 29) 444 q := q.Filter("bob >", 10).Filter("wat <", 29)
507 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false) 445 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false)
508 So(qi.order, ShouldResemble, []queryOrder{{"bob" , qASC}, {"wat", qASC}}) 446 So(qi.order, ShouldResemble, []queryOrder{{"bob" , qASC}, {"wat", qASC}})
509 So(qi.err.Error(), ShouldContainSubstring, "Only one inequality") 447 So(qi.err.Error(), ShouldContainSubstring, "Only one inequality")
510 }) 448 })
511 449
512 Convey("if we equality-filter on __key__, order is ditch ed", func() { 450 Convey("if we equality-filter on __key__, order is ditch ed", func() {
513 q = q.Order("wat") 451 q = q.Order("wat")
514 » » » » q := q.Filter("__key__ =", rds.NewKey("Foo", "wa t", 0, nil)) 452 » » » » q := q.Filter("__key__ =", ds.NewKey("Foo", "wat ", 0, nil))
515 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false) 453 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false)
516 So(qi.order, ShouldResemble, []queryOrder(nil)) 454 So(qi.order, ShouldResemble, []queryOrder(nil))
517 So(qi.err, ShouldBeNil) 455 So(qi.err, ShouldBeNil)
518 }) 456 })
519 457
520 Convey("if we order by key and something else, key domin ates", func() { 458 Convey("if we order by key and something else, key domin ates", func() {
521 q := q.Order("__key__").Order("wat") 459 q := q.Order("__key__").Order("wat")
522 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false) 460 qi := q.(*queryImpl).normalize().checkCorrectnes s("", false)
523 So(qi.order, ShouldResemble, []queryOrder{{"__ke y__", qASC}}) 461 So(qi.order, ShouldResemble, []queryOrder{{"__ke y__", qASC}})
524 So(qi.err, ShouldBeNil) 462 So(qi.err, ShouldBeNil)
525 }) 463 })
526 }) 464 })
527 465
528 Convey("can create bad queries", func() { 466 Convey("can create bad queries", func() {
529 » » » q := rds.NewQuery("Foo") 467 » » » q := ds.NewQuery("Foo")
530 468
531 Convey("bad filter ops", func() { 469 Convey("bad filter ops", func() {
532 q := q.Filter("Bob !", "value") 470 q := q.Filter("Bob !", "value")
533 So(q.(*queryImpl).err.Error(), ShouldContainSubs tring, "invalid operator \"!\"") 471 So(q.(*queryImpl).err.Error(), ShouldContainSubs tring, "invalid operator \"!\"")
534 }) 472 })
535 Convey("bad filter", func() { 473 Convey("bad filter", func() {
536 q := q.Filter("Bob", "value") 474 q := q.Filter("Bob", "value")
537 So(q.(*queryImpl).err.Error(), ShouldContainSubs tring, "invalid filter") 475 So(q.(*queryImpl).err.Error(), ShouldContainSubs tring, "invalid filter")
538 }) 476 })
539 Convey("bad order", func() { 477 Convey("bad order", func() {
(...skipping 20 matching lines...) Expand all
560 if !IntIs32Bits { 498 if !IntIs32Bits {
561 q := q.Offset(MaxInt) 499 q := q.Offset(MaxInt)
562 So(q.(*queryImpl).err.Error(), ShouldCon tainSubstring, "query offset overflow") 500 So(q.(*queryImpl).err.Error(), ShouldCon tainSubstring, "query offset overflow")
563 } 501 }
564 }) 502 })
565 Convey("Bad cursors", func() { 503 Convey("Bad cursors", func() {
566 q := q.Start(queryCursor("")).End(queryCursor("" )) 504 q := q.Start(queryCursor("")).End(queryCursor("" ))
567 So(q.(*queryImpl).err.Error(), ShouldContainSubs tring, "invalid cursor") 505 So(q.(*queryImpl).err.Error(), ShouldContainSubs tring, "invalid cursor")
568 }) 506 })
569 Convey("Bad ancestors", func() { 507 Convey("Bad ancestors", func() {
570 » » » » q := q.Ancestor(rds.NewKey("Goop", "wat", 10, ni l)) 508 » » » » q := q.Ancestor(ds.NewKey("Goop", "wat", 10, nil ))
571 So(q, ShouldNotBeNil) 509 So(q, ShouldNotBeNil)
572 qi := q.(*queryImpl).checkCorrectness("", false) 510 qi := q.(*queryImpl).checkCorrectness("", false)
573 » » » » So(qi.err, ShouldEqual, rdsS.ErrInvalidKey) 511 » » » » So(qi.err, ShouldEqual, dsS.ErrInvalidKey)
574 }) 512 })
575 Convey("nil ancestors", func() { 513 Convey("nil ancestors", func() {
576 qi := q.Ancestor(nil).(*queryImpl).checkCorrectn ess("", false) 514 qi := q.Ancestor(nil).(*queryImpl).checkCorrectn ess("", false)
577 So(qi.err.Error(), ShouldContainSubstring, "nil query ancestor") 515 So(qi.err.Error(), ShouldContainSubstring, "nil query ancestor")
578 }) 516 })
579 Convey("Bad key filters", func() { 517 Convey("Bad key filters", func() {
580 » » » » q := q.Filter("__key__ =", rds.NewKey("Goop", "w at", 10, nil)) 518 » » » » q := q.Filter("__key__ =", ds.NewKey("Goop", "wa t", 10, nil))
581 qi := q.(*queryImpl).checkCorrectness("", false) 519 qi := q.(*queryImpl).checkCorrectness("", false)
582 » » » » So(qi.err, ShouldEqual, rdsS.ErrInvalidKey) 520 » » » » So(qi.err, ShouldEqual, dsS.ErrInvalidKey)
583 }) 521 })
584 Convey("non-ancestor queries in a transaction", func() { 522 Convey("non-ancestor queries in a transaction", func() {
585 qi := q.(*queryImpl).checkCorrectness("", true) 523 qi := q.(*queryImpl).checkCorrectness("", true)
586 So(qi.err.Error(), ShouldContainSubstring, "Only ancestor queries") 524 So(qi.err.Error(), ShouldContainSubstring, "Only ancestor queries")
587 }) 525 })
588 Convey("absurd numbers of filters are prohibited", func( ) { 526 Convey("absurd numbers of filters are prohibited", func( ) {
589 » » » » q := q.Ancestor(rds.NewKey("thing", "wat", 0, ni l)) 527 » » » » q := q.Ancestor(ds.NewKey("thing", "wat", 0, nil ))
590 for i := 0; i < 100; i++ { 528 for i := 0; i < 100; i++ {
591 q = q.Filter("something =", 10) 529 q = q.Filter("something =", 10)
592 } 530 }
593 qi := q.(*queryImpl).checkCorrectness("", false) 531 qi := q.(*queryImpl).checkCorrectness("", false)
594 So(qi.err.Error(), ShouldContainSubstring, "quer y is too large") 532 So(qi.err.Error(), ShouldContainSubstring, "quer y is too large")
595 }) 533 })
596 Convey("filters for __key__ that aren't keys", func() { 534 Convey("filters for __key__ that aren't keys", func() {
597 q := q.Filter("__key__ = ", 10) 535 q := q.Filter("__key__ = ", 10)
598 qi := q.(*queryImpl).checkCorrectness("", false) 536 qi := q.(*queryImpl).checkCorrectness("", false)
599 So(qi.err.Error(), ShouldContainSubstring, "must be a Key") 537 So(qi.err.Error(), ShouldContainSubstring, "must be a Key")
600 }) 538 })
601 Convey("multiple inequalities", func() { 539 Convey("multiple inequalities", func() {
602 q := q.Filter("bob > ", 19).Filter("charlie < ", 20) 540 q := q.Filter("bob > ", 19).Filter("charlie < ", 20)
603 qi := q.(*queryImpl).checkCorrectness("", false) 541 qi := q.(*queryImpl).checkCorrectness("", false)
604 So(qi.err.Error(), ShouldContainSubstring, "one inequality filter") 542 So(qi.err.Error(), ShouldContainSubstring, "one inequality filter")
605 }) 543 })
606 Convey("bad sort orders", func() { 544 Convey("bad sort orders", func() {
607 q := q.Filter("bob > ", 19).Order("-charlie") 545 q := q.Filter("bob > ", 19).Order("-charlie")
608 qi := q.(*queryImpl).checkCorrectness("", false) 546 qi := q.(*queryImpl).checkCorrectness("", false)
609 So(qi.err.Error(), ShouldContainSubstring, "firs t sort property") 547 So(qi.err.Error(), ShouldContainSubstring, "firs t sort property")
610 }) 548 })
611 Convey("kindless with non-__key__ filters", func() { 549 Convey("kindless with non-__key__ filters", func() {
612 » » » » q := rds.NewQuery("").Filter("face <", 25.3) 550 » » » » q := ds.NewQuery("").Filter("face <", 25.3)
613 qi := q.(*queryImpl).checkCorrectness("", false) 551 qi := q.(*queryImpl).checkCorrectness("", false)
614 So(qi.err.Error(), ShouldContainSubstring, "kind is required for non-__key__") 552 So(qi.err.Error(), ShouldContainSubstring, "kind is required for non-__key__")
615 }) 553 })
616 Convey("kindless with non-__key__ orders", func() { 554 Convey("kindless with non-__key__ orders", func() {
617 » » » » q := rds.NewQuery("").Order("face") 555 » » » » q := ds.NewQuery("").Order("face")
618 qi := q.(*queryImpl).checkCorrectness("", false) 556 qi := q.(*queryImpl).checkCorrectness("", false)
619 So(qi.err.Error(), ShouldContainSubstring, "kind is required for all orders") 557 So(qi.err.Error(), ShouldContainSubstring, "kind is required for all orders")
620 }) 558 })
621 Convey("kindless with decending-__key__ orders", func() { 559 Convey("kindless with decending-__key__ orders", func() {
622 » » » » q := rds.NewQuery("").Order("-__key__") 560 » » » » q := ds.NewQuery("").Order("-__key__")
623 qi := q.(*queryImpl).checkCorrectness("", false) 561 qi := q.(*queryImpl).checkCorrectness("", false)
624 So(qi.err.Error(), ShouldContainSubstring, "kind is required for all orders") 562 So(qi.err.Error(), ShouldContainSubstring, "kind is required for all orders")
625 }) 563 })
626 }) 564 })
627 565
628 }) 566 })
629 } 567 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698