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

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

Issue 2302743002: Interface update, per-method Contexts. (Closed)
Patch Set: Lightning talk licenses. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « impl/memory/datastore_query_test.go ('k') | impl/memory/info.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package memory 5 package memory
6 6
7 import ( 7 import (
8 "errors"
8 "fmt" 9 "fmt"
9 "testing" 10 "testing"
10 "time" 11 "time"
11 12
12 » dsS "github.com/luci/gae/service/datastore" 13 » ds "github.com/luci/gae/service/datastore"
13 "github.com/luci/gae/service/datastore/serialize" 14 "github.com/luci/gae/service/datastore/serialize"
14 infoS "github.com/luci/gae/service/info" 15 infoS "github.com/luci/gae/service/info"
16
17 "golang.org/x/net/context"
18
15 . "github.com/luci/luci-go/common/testing/assertions" 19 . "github.com/luci/luci-go/common/testing/assertions"
16 . "github.com/smartystreets/goconvey/convey" 20 . "github.com/smartystreets/goconvey/convey"
17 "golang.org/x/net/context"
18 ) 21 )
19 22
20 type MetaGroup struct { 23 type MetaGroup struct {
21 » _id int64 `gae:"$id,1"` 24 » _id int64 `gae:"$id,1"`
22 » _kind string `gae:"$kind,__entity_group__"` 25 » _kind string `gae:"$kind,__entity_group__"`
23 » Parent *dsS.Key `gae:"$parent"` 26 » Parent *ds.Key `gae:"$parent"`
24 27
25 Version int64 `gae:"__version__"` 28 Version int64 `gae:"__version__"`
26 } 29 }
27 30
28 func testGetMeta(c context.Context, k *dsS.Key) int64 { 31 func testGetMeta(c context.Context, k *ds.Key) int64 {
29 » ds := dsS.Get(c)
30 mg := &MetaGroup{Parent: k.Root()} 32 mg := &MetaGroup{Parent: k.Root()}
31 » if err := ds.Get(mg); err != nil { 33 » if err := ds.Get(c, mg); err != nil {
32 panic(err) 34 panic(err)
33 } 35 }
34 return mg.Version 36 return mg.Version
35 } 37 }
36 38
37 var pls = dsS.GetPLS 39 var pls = ds.GetPLS
38 40
39 type Foo struct { 41 type Foo struct {
40 » ID int64 `gae:"$id"` 42 » ID int64 `gae:"$id"`
41 » Parent *dsS.Key `gae:"$parent"` 43 » Parent *ds.Key `gae:"$parent"`
42 44
43 Val int 45 Val int
44 Name string 46 Name string
45 Multi []string 47 Multi []string
46 } 48 }
47 49
48 func TestDatastoreSingleReadWriter(t *testing.T) { 50 func TestDatastoreSingleReadWriter(t *testing.T) {
49 t.Parallel() 51 t.Parallel()
50 52
51 Convey("Datastore single reads and writes", t, func() { 53 Convey("Datastore single reads and writes", t, func() {
52 c := Use(context.Background()) 54 c := Use(context.Background())
53 » » ds := dsS.Get(c) 55 » » So(ds.Raw(c), ShouldNotBeNil)
54 » » So(ds, ShouldNotBeNil)
55 56
56 Convey("getting objects that DNE is an error", func() { 57 Convey("getting objects that DNE is an error", func() {
57 » » » So(ds.Get(&Foo{ID: 1}), ShouldEqual, dsS.ErrNoSuchEntity ) 58 » » » So(ds.Get(c, &Foo{ID: 1}), ShouldEqual, ds.ErrNoSuchEnti ty)
58 }) 59 })
59 60
60 Convey("bad namespaces fail", func() { 61 Convey("bad namespaces fail", func() {
61 » » » _, err := infoS.Get(c).Namespace("$$blzyall") 62 » » » _, err := infoS.Namespace(c, "$$blzyall")
62 So(err.Error(), ShouldContainSubstring, "namespace \"$$b lzyall\" does not match") 63 So(err.Error(), ShouldContainSubstring, "namespace \"$$b lzyall\" does not match")
63 }) 64 })
64 65
65 Convey("Can Put stuff", func() { 66 Convey("Can Put stuff", func() {
66 // with an incomplete key! 67 // with an incomplete key!
67 f := &Foo{Val: 10, Multi: []string{"foo", "bar"}} 68 f := &Foo{Val: 10, Multi: []string{"foo", "bar"}}
68 » » » So(ds.Put(f), ShouldBeNil) 69 » » » So(ds.Put(c, f), ShouldBeNil)
69 » » » k := ds.KeyForObj(f) 70 » » » k := ds.KeyForObj(c, f)
70 So(k.String(), ShouldEqual, "dev~app::/Foo,1") 71 So(k.String(), ShouldEqual, "dev~app::/Foo,1")
71 72
72 Convey("and Get it back", func() { 73 Convey("and Get it back", func() {
73 newFoo := &Foo{ID: 1} 74 newFoo := &Foo{ID: 1}
74 » » » » So(ds.Get(newFoo), ShouldBeNil) 75 » » » » So(ds.Get(c, newFoo), ShouldBeNil)
75 So(newFoo, ShouldResemble, f) 76 So(newFoo, ShouldResemble, f)
76 77
77 Convey("but it's hidden from a different namespa ce", func() { 78 Convey("but it's hidden from a different namespa ce", func() {
78 » » » » » c, err := infoS.Get(c).Namespace("whomba t") 79 » » » » » c, err := infoS.Namespace(c, "whombat")
79 So(err, ShouldBeNil) 80 So(err, ShouldBeNil)
80 » » » » » ds = dsS.Get(c) 81 » » » » » So(ds.Get(c, f), ShouldEqual, ds.ErrNoSu chEntity)
81 » » » » » So(ds.Get(f), ShouldEqual, dsS.ErrNoSuch Entity)
82 }) 82 })
83 83
84 Convey("and we can Delete it", func() { 84 Convey("and we can Delete it", func() {
85 » » » » » So(ds.Delete(k), ShouldBeNil) 85 » » » » » So(ds.Delete(c, k), ShouldBeNil)
86 » » » » » So(ds.Get(newFoo), ShouldEqual, dsS.ErrN oSuchEntity) 86 » » » » » So(ds.Get(c, newFoo), ShouldEqual, ds.Er rNoSuchEntity)
87 }) 87 })
88 88
89 }) 89 })
90 Convey("Can Get it back as a PropertyMap", func() { 90 Convey("Can Get it back as a PropertyMap", func() {
91 » » » » pmap := dsS.PropertyMap{ 91 » » » » pmap := ds.PropertyMap{
92 "$id": propNI(1), 92 "$id": propNI(1),
93 "$kind": propNI("Foo"), 93 "$kind": propNI("Foo"),
94 } 94 }
95 » » » » So(ds.Get(pmap), ShouldBeNil) 95 » » » » So(ds.Get(c, pmap), ShouldBeNil)
96 » » » » So(pmap, ShouldResemble, dsS.PropertyMap{ 96 » » » » So(pmap, ShouldResemble, ds.PropertyMap{
97 "$id": propNI(1), 97 "$id": propNI(1),
98 "$kind": propNI("Foo"), 98 "$kind": propNI("Foo"),
99 "Name": prop(""), 99 "Name": prop(""),
100 "Val": prop(10), 100 "Val": prop(10),
101 » » » » » "Multi": dsS.PropertySlice{prop("foo"), prop("bar")}, 101 » » » » » "Multi": ds.PropertySlice{prop("foo"), p rop("bar")},
102 }) 102 })
103 }) 103 })
104 Convey("Deleteing with a bogus key is bad", func() { 104 Convey("Deleteing with a bogus key is bad", func() {
105 » » » » So(ds.Delete(ds.NewKey("Foo", "wat", 100, nil)), ShouldEqual, dsS.ErrInvalidKey) 105 » » » » So(ds.Delete(c, ds.NewKey(c, "Foo", "wat", 100, nil)), ShouldEqual, ds.ErrInvalidKey)
106 }) 106 })
107 Convey("Deleteing a DNE entity is fine", func() { 107 Convey("Deleteing a DNE entity is fine", func() {
108 » » » » So(ds.Delete(ds.NewKey("Foo", "wat", 0, nil)), S houldBeNil) 108 » » » » So(ds.Delete(c, ds.NewKey(c, "Foo", "wat", 0, ni l)), ShouldBeNil)
109 }) 109 })
110 110
111 Convey("Deleting entities from a nonexistant namespace w orks", func() { 111 Convey("Deleting entities from a nonexistant namespace w orks", func() {
112 » » » » aid := infoS.Get(c).FullyQualifiedAppID() 112 » » » » c := infoS.MustNamespace(c, "noexist")
113 » » » » keys := make([]*dsS.Key, 10) 113 » » » » keys := make([]*ds.Key, 10)
114 for i := range keys { 114 for i := range keys {
115 » » » » » keys[i] = ds.MakeKey(aid, "noexist", "Ki nd", i+1) 115 » » » » » keys[i] = ds.MakeKey(c, "Kind", i+1)
116 } 116 }
117 » » » » So(ds.DeleteMulti(keys), ShouldBeNil) 117 » » » » So(ds.Delete(c, keys), ShouldBeNil)
118 count := 0 118 count := 0
119 » » » » So(ds.Raw().DeleteMulti(keys, func(err error) er ror { 119 » » » » So(ds.Raw(c).DeleteMulti(keys, func(err error) e rror {
120 count++ 120 count++
121 So(err, ShouldBeNil) 121 So(err, ShouldBeNil)
122 return nil 122 return nil
123 }), ShouldBeNil) 123 }), ShouldBeNil)
124 So(count, ShouldEqual, len(keys)) 124 So(count, ShouldEqual, len(keys))
125 }) 125 })
126 126
127 Convey("with multiple puts", func() { 127 Convey("with multiple puts", func() {
128 So(testGetMeta(c, k), ShouldEqual, 1) 128 So(testGetMeta(c, k), ShouldEqual, 1)
129 129
130 foos := make([]Foo, 10) 130 foos := make([]Foo, 10)
131 for i := range foos { 131 for i := range foos {
132 foos[i].Val = 10 132 foos[i].Val = 10
133 foos[i].Parent = k 133 foos[i].Parent = k
134 } 134 }
135 » » » » So(ds.PutMulti(foos), ShouldBeNil) 135 » » » » So(ds.Put(c, foos), ShouldBeNil)
136 So(testGetMeta(c, k), ShouldEqual, 11) 136 So(testGetMeta(c, k), ShouldEqual, 11)
137 137
138 » » » » keys := make([]*dsS.Key, len(foos)) 138 » » » » keys := make([]*ds.Key, len(foos))
139 for i, f := range foos { 139 for i, f := range foos {
140 » » » » » keys[i] = ds.KeyForObj(&f) 140 » » » » » keys[i] = ds.KeyForObj(c, &f)
141 } 141 }
142 142
143 Convey("ensure that group versions persist acros s deletes", func() { 143 Convey("ensure that group versions persist acros s deletes", func() {
144 » » » » » So(ds.DeleteMulti(append(keys, k)), Shou ldBeNil) 144 » » » » » So(ds.Delete(c, append(keys, k)), Should BeNil)
145 145
146 » » » » » ds.Testable().CatchupIndexes() 146 » » » » » ds.GetTestable(c).CatchupIndexes()
147 147
148 count := 0 148 count := 0
149 » » » » » So(ds.Run(dsS.NewQuery(""), func(_ *dsS. Key) { 149 » » » » » So(ds.Run(c, ds.NewQuery(""), func(_ *ds .Key) {
150 count++ 150 count++
151 }), ShouldBeNil) 151 }), ShouldBeNil)
152 So(count, ShouldEqual, 3) 152 So(count, ShouldEqual, 3)
153 153
154 So(testGetMeta(c, k), ShouldEqual, 22) 154 So(testGetMeta(c, k), ShouldEqual, 22)
155 155
156 » » » » » So(ds.Put(&Foo{ID: 1}), ShouldBeNil) 156 » » » » » So(ds.Put(c, &Foo{ID: 1}), ShouldBeNil)
157 So(testGetMeta(c, k), ShouldEqual, 23) 157 So(testGetMeta(c, k), ShouldEqual, 23)
158 }) 158 })
159 159
160 Convey("can Get", func() { 160 Convey("can Get", func() {
161 » » » » » vals := make([]dsS.PropertyMap, len(keys )) 161 » » » » » vals := make([]ds.PropertyMap, len(keys) )
162 for i := range vals { 162 for i := range vals {
163 » » » » » » vals[i] = dsS.PropertyMap{} 163 » » » » » » vals[i] = ds.PropertyMap{}
164 So(vals[i].SetMeta("key", keys[i ]), ShouldBeTrue) 164 So(vals[i].SetMeta("key", keys[i ]), ShouldBeTrue)
165 } 165 }
166 » » » » » So(ds.GetMulti(vals), ShouldBeNil) 166 » » » » » So(ds.Get(c, vals), ShouldBeNil)
167 167
168 for i, val := range vals { 168 for i, val := range vals {
169 » » » » » » So(val, ShouldResemble, dsS.Prop ertyMap{ 169 » » » » » » So(val, ShouldResemble, ds.Prope rtyMap{
170 » » » » » » » "Val": dsS.MkProperty(1 0), 170 » » » » » » » "Val": ds.MkProperty(10 ),
171 » » » » » » » "Name": dsS.MkProperty(" "), 171 » » » » » » » "Name": ds.MkProperty("" ),
172 » » » » » » » "$key": dsS.MkPropertyNI (keys[i]), 172 » » » » » » » "$key": ds.MkPropertyNI( keys[i]),
173 }) 173 })
174 } 174 }
175 }) 175 })
176 176
177 }) 177 })
178 178
179 Convey("allocating ids prevents their use", func() { 179 Convey("allocating ids prevents their use", func() {
180 » » » » keys := ds.NewIncompleteKeys(100, "Foo", nil) 180 » » » » keys := ds.NewIncompleteKeys(c, 100, "Foo", nil)
181 » » » » So(ds.AllocateIDs(keys), ShouldBeNil) 181 » » » » So(ds.AllocateIDs(c, keys), ShouldBeNil)
182 So(len(keys), ShouldEqual, 100) 182 So(len(keys), ShouldEqual, 100)
183 183
184 // Assert that none of our keys share the same I D. 184 // Assert that none of our keys share the same I D.
185 ids := make(map[int64]struct{}) 185 ids := make(map[int64]struct{})
186 for _, k := range keys { 186 for _, k := range keys {
187 ids[k.IntID()] = struct{}{} 187 ids[k.IntID()] = struct{}{}
188 } 188 }
189 So(len(ids), ShouldEqual, len(keys)) 189 So(len(ids), ShouldEqual, len(keys))
190 190
191 // Put a new object and ensure that it is alloca ted an unused ID. 191 // Put a new object and ensure that it is alloca ted an unused ID.
192 f := &Foo{Val: 10} 192 f := &Foo{Val: 10}
193 » » » » So(ds.Put(f), ShouldBeNil) 193 » » » » So(ds.Put(c, f), ShouldBeNil)
194 » » » » k := ds.KeyForObj(f) 194 » » » » k := ds.KeyForObj(c, f)
195 So(k.String(), ShouldEqual, "dev~app::/Foo,102") 195 So(k.String(), ShouldEqual, "dev~app::/Foo,102")
196 196
197 _, ok := ids[k.IntID()] 197 _, ok := ids[k.IntID()]
198 So(ok, ShouldBeFalse) 198 So(ok, ShouldBeFalse)
199 }) 199 })
200 }) 200 })
201 201
202 Convey("implements DSTransactioner", func() { 202 Convey("implements DSTransactioner", func() {
203 Convey("Put", func() { 203 Convey("Put", func() {
204 f := &Foo{Val: 10} 204 f := &Foo{Val: 10}
205 » » » » So(ds.Put(f), ShouldBeNil) 205 » » » » So(ds.Put(c, f), ShouldBeNil)
206 » » » » k := ds.KeyForObj(f) 206 » » » » k := ds.KeyForObj(c, f)
207 So(k.String(), ShouldEqual, "dev~app::/Foo,1") 207 So(k.String(), ShouldEqual, "dev~app::/Foo,1")
208 208
209 Convey("can describe its transaction state", fun c() {
210 So(ds.CurrentTransaction(c), ShouldBeNil )
211
212 err := ds.RunInTransaction(c, func(c con text.Context) error {
213 So(ds.CurrentTransaction(c), Sho uldNotBeNil)
214
215 // Can reset to nil.
216 nc := ds.WithoutTransaction(c)
217 So(ds.CurrentTransaction(nc), Sh ouldBeNil)
218 return nil
219 }, nil)
220 So(err, ShouldBeNil)
221 })
222
209 Convey("can Put new entity groups", func() { 223 Convey("can Put new entity groups", func() {
210 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 224 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
211 » » » » » » ds := dsS.Get(c)
212
213 f := &Foo{Val: 100} 225 f := &Foo{Val: 100}
214 » » » » » » So(ds.Put(f), ShouldBeNil) 226 » » » » » » So(ds.Put(c, f), ShouldBeNil)
215 So(f.ID, ShouldEqual, 2) 227 So(f.ID, ShouldEqual, 2)
216 228
217 f.ID = 0 229 f.ID = 0
218 f.Val = 200 230 f.Val = 200
219 » » » » » » So(ds.Put(f), ShouldBeNil) 231 » » » » » » So(ds.Put(c, f), ShouldBeNil)
220 So(f.ID, ShouldEqual, 3) 232 So(f.ID, ShouldEqual, 3)
221 233
222 return nil 234 return nil
223 » » » » » }, &dsS.TransactionOptions{XG: true}) 235 » » » » » }, &ds.TransactionOptions{XG: true})
224 So(err, ShouldBeNil) 236 So(err, ShouldBeNil)
225 237
226 f := &Foo{ID: 2} 238 f := &Foo{ID: 2}
227 » » » » » So(ds.Get(f), ShouldBeNil) 239 » » » » » So(ds.Get(c, f), ShouldBeNil)
228 So(f.Val, ShouldEqual, 100) 240 So(f.Val, ShouldEqual, 100)
229 241
230 f.ID = 3 242 f.ID = 3
231 » » » » » So(ds.Get(f), ShouldBeNil) 243 » » » » » So(ds.Get(c, f), ShouldBeNil)
232 So(f.Val, ShouldEqual, 200) 244 So(f.Val, ShouldEqual, 200)
233 }) 245 })
234 246
235 Convey("can Put new entities in a current group" , func() { 247 Convey("can Put new entities in a current group" , func() {
236 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 248 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
237 » » » » » » ds := dsS.Get(c)
238
239 f := &Foo{Val: 100, Parent: k} 249 f := &Foo{Val: 100, Parent: k}
240 » » » » » » So(ds.Put(f), ShouldBeNil) 250 » » » » » » So(ds.Put(c, f), ShouldBeNil)
241 » » » » » » So(ds.KeyForObj(f).String(), Sho uldEqual, "dev~app::/Foo,1/Foo,1") 251 » » » » » » So(ds.KeyForObj(c, f).String(), ShouldEqual, "dev~app::/Foo,1/Foo,1")
242 252
243 f.ID = 0 253 f.ID = 0
244 f.Val = 200 254 f.Val = 200
245 » » » » » » So(ds.Put(f), ShouldBeNil) 255 » » » » » » So(ds.Put(c, f), ShouldBeNil)
246 » » » » » » So(ds.KeyForObj(f).String(), Sho uldEqual, "dev~app::/Foo,1/Foo,2") 256 » » » » » » So(ds.KeyForObj(c, f).String(), ShouldEqual, "dev~app::/Foo,1/Foo,2")
247 257
248 return nil 258 return nil
249 }, nil) 259 }, nil)
250 So(err, ShouldBeNil) 260 So(err, ShouldBeNil)
251 261
252 f := &Foo{ID: 1, Parent: k} 262 f := &Foo{ID: 1, Parent: k}
253 » » » » » So(ds.Get(f), ShouldBeNil) 263 » » » » » So(ds.Get(c, f), ShouldBeNil)
254 So(f.Val, ShouldEqual, 100) 264 So(f.Val, ShouldEqual, 100)
255 265
256 f.ID = 2 266 f.ID = 2
257 » » » » » So(ds.Get(f), ShouldBeNil) 267 » » » » » So(ds.Get(c, f), ShouldBeNil)
258 So(f.Val, ShouldEqual, 200) 268 So(f.Val, ShouldEqual, 200)
259 }) 269 })
260 270
261 Convey("Deletes work too", func() { 271 Convey("Deletes work too", func() {
262 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 272 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
263 » » » » » » return dsS.Get(c).Delete(k) 273 » » » » » » return ds.Delete(c, k)
264 }, nil) 274 }, nil)
265 So(err, ShouldBeNil) 275 So(err, ShouldBeNil)
266 » » » » » So(ds.Get(&Foo{ID: 1}), ShouldEqual, dsS .ErrNoSuchEntity) 276 » » » » » So(ds.Get(c, &Foo{ID: 1}), ShouldEqual, ds.ErrNoSuchEntity)
267 }) 277 })
268 278
269 Convey("A Get counts against your group count", func() { 279 Convey("A Get counts against your group count", func() {
270 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 280 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
271 » » » » » » ds := dsS.Get(c) 281 » » » » » » pm := ds.PropertyMap{}
272 282 » » » » » » So(pm.SetMeta("key", ds.NewKey(c , "Foo", "", 20, nil)), ShouldBeTrue)
273 » » » » » » pm := dsS.PropertyMap{} 283 » » » » » » So(ds.Get(c, pm), ShouldEqual, d s.ErrNoSuchEntity)
274 » » » » » » So(pm.SetMeta("key", ds.NewKey(" Foo", "", 20, nil)), ShouldBeTrue)
275 » » » » » » So(ds.Get(pm), ShouldEqual, dsS. ErrNoSuchEntity)
276 284
277 So(pm.SetMeta("key", k), ShouldB eTrue) 285 So(pm.SetMeta("key", k), ShouldB eTrue)
278 » » » » » » So(ds.Get(pm).Error(), ShouldCon tainSubstring, "cross-group") 286 » » » » » » So(ds.Get(c, pm).Error(), Should ContainSubstring, "cross-group")
279 return nil 287 return nil
280 }, nil) 288 }, nil)
281 So(err, ShouldBeNil) 289 So(err, ShouldBeNil)
282 }) 290 })
283 291
284 Convey("Get takes a snapshot", func() { 292 Convey("Get takes a snapshot", func() {
285 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 293 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
286 » » » » » » ds := dsS.Get(c) 294 » » » » » » So(ds.Get(c, f), ShouldBeNil)
287
288 » » » » » » So(ds.Get(f), ShouldBeNil)
289 So(f.Val, ShouldEqual, 10) 295 So(f.Val, ShouldEqual, 10)
290 296
291 // Don't ever do this in a real program unless you want to guarantee 297 // Don't ever do this in a real program unless you want to guarantee
292 // a failed transaction :) 298 // a failed transaction :)
293 f.Val = 11 299 f.Val = 11
294 » » » » » » So(dsS.GetNoTxn(c).Put(f), Shoul dBeNil) 300 » » » » » » So(ds.Put(ds.WithoutTransaction( c), f), ShouldBeNil)
295 301
296 » » » » » » So(ds.Get(f), ShouldBeNil) 302 » » » » » » So(ds.Get(c, f), ShouldBeNil)
297 So(f.Val, ShouldEqual, 10) 303 So(f.Val, ShouldEqual, 10)
298 304
299 return nil 305 return nil
300 }, nil) 306 }, nil)
301 So(err, ShouldBeNil) 307 So(err, ShouldBeNil)
302 308
303 f := &Foo{ID: 1} 309 f := &Foo{ID: 1}
304 » » » » » So(ds.Get(f), ShouldBeNil) 310 » » » » » So(ds.Get(c, f), ShouldBeNil)
305 So(f.Val, ShouldEqual, 11) 311 So(f.Val, ShouldEqual, 11)
306 }) 312 })
307 313
308 Convey("and snapshots are consistent even after Puts", func() { 314 Convey("and snapshots are consistent even after Puts", func() {
309 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 315 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
310 » » » » » » ds := dsS.Get(c)
311
312 f := &Foo{ID: 1} 316 f := &Foo{ID: 1}
313 » » » » » » So(ds.Get(f), ShouldBeNil) 317 » » » » » » So(ds.Get(c, f), ShouldBeNil)
314 So(f.Val, ShouldEqual, 10) 318 So(f.Val, ShouldEqual, 10)
315 319
316 // Don't ever do this in a real program unless you want to guarantee 320 // Don't ever do this in a real program unless you want to guarantee
317 // a failed transaction :) 321 // a failed transaction :)
318 f.Val = 11 322 f.Val = 11
319 » » » » » » So(dsS.GetNoTxn(c).Put(f), Shoul dBeNil) 323 » » » » » » So(ds.Put(ds.WithoutTransaction( c), f), ShouldBeNil)
320 324
321 » » » » » » So(ds.Get(f), ShouldBeNil) 325 » » » » » » So(ds.Get(c, f), ShouldBeNil)
322 So(f.Val, ShouldEqual, 10) 326 So(f.Val, ShouldEqual, 10)
323 327
324 f.Val = 20 328 f.Val = 20
325 » » » » » » So(ds.Put(f), ShouldBeNil) 329 » » » » » » So(ds.Put(c, f), ShouldBeNil)
326 330
327 » » » » » » So(ds.Get(f), ShouldBeNil) 331 » » » » » » So(ds.Get(c, f), ShouldBeNil)
328 So(f.Val, ShouldEqual, 10) // st ill gets 10 332 So(f.Val, ShouldEqual, 10) // st ill gets 10
329 333
330 return nil 334 return nil
331 » » » » » }, &dsS.TransactionOptions{Attempts: 1}) 335 » » » » » }, &ds.TransactionOptions{Attempts: 1})
332 So(err.Error(), ShouldContainSubstring, "concurrent") 336 So(err.Error(), ShouldContainSubstring, "concurrent")
333 337
334 f := &Foo{ID: 1} 338 f := &Foo{ID: 1}
335 » » » » » So(ds.Get(f), ShouldBeNil) 339 » » » » » So(ds.Get(c, f), ShouldBeNil)
336 So(f.Val, ShouldEqual, 11) 340 So(f.Val, ShouldEqual, 11)
337 }) 341 })
338 342
339 Convey("Reusing a transaction context is bad new s", func() { 343 Convey("Reusing a transaction context is bad new s", func() {
340 » » » » » txnDS := dsS.Interface(nil) 344 » » » » » var txnCtx context.Context
341 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 345 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
342 » » » » » » txnDS = dsS.Get(c) 346 » » » » » » txnCtx = c
343 » » » » » » So(txnDS.Get(f), ShouldBeNil) 347 » » » » » » So(ds.Get(c, f), ShouldBeNil)
344 return nil 348 return nil
345 }, nil) 349 }, nil)
346 So(err, ShouldBeNil) 350 So(err, ShouldBeNil)
347 » » » » » So(txnDS.Get(f).Error(), ShouldContainSu bstring, "expired") 351 » » » » » So(ds.Get(txnCtx, f).Error(), ShouldCont ainSubstring, "expired")
348 }) 352 })
349 353
350 Convey("Nested transactions are rejected", func( ) { 354 Convey("Nested transactions are rejected", func( ) {
351 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 355 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
352 » » » » » » err := dsS.Get(c).RunInTransacti on(func(c context.Context) error { 356 » » » » » » err := ds.RunInTransaction(c, fu nc(c context.Context) error {
353 panic("noooo") 357 panic("noooo")
354 }, nil) 358 }, nil)
355 So(err.Error(), ShouldContainSub string, "nested transactions") 359 So(err.Error(), ShouldContainSub string, "nested transactions")
356 return nil 360 return nil
357 }, nil) 361 }, nil)
358 So(err, ShouldBeNil) 362 So(err, ShouldBeNil)
359 }) 363 })
360 364
365 Convey("Transactions can be escaped.", func() {
366 testError := errors.New("test error")
367 noTxnPM := ds.PropertyMap{
368 "$kind": ds.MkProperty("Test"),
369 "$id": ds.MkProperty("no txn") ,
370 }
371
372 err := ds.RunInTransaction(c, func(c con text.Context) error {
373 So(ds.CurrentTransaction(c), Sho uldNotBeNil)
374
375 pmap := ds.PropertyMap{
376 "$kind": ds.MkProperty(" Test"),
377 "$id": ds.MkProperty(" quux"),
378 }
379 if err := ds.Put(c, pmap); err ! = nil {
380 return err
381 }
382
383 // Put an entity outside of the transaction so we can confirm that
384 // it was added even when the tr ansaction fails.
385 if err := ds.Put(ds.WithoutTrans action(c), noTxnPM); err != nil {
386 return err
387 }
388 return testError
389 }, nil)
390 So(err, ShouldEqual, testError)
391
392 // Confirm that noTxnPM was added.
393 So(ds.CurrentTransaction(c), ShouldBeNil )
394 So(ds.Get(c, noTxnPM), ShouldBeNil)
395 })
396
361 Convey("Concurrent transactions only accept one set of changes", func() { 397 Convey("Concurrent transactions only accept one set of changes", func() {
362 // Note: I think this implementation is actually /slightly/ wrong. 398 // Note: I think this implementation is actually /slightly/ wrong.
363 // According to my read of the docs for appengine, when you open a 399 // According to my read of the docs for appengine, when you open a
364 // transaction it actually (essentially) holds a reference to the 400 // transaction it actually (essentially) holds a reference to the
365 // entire datastore. Our implementation takes a snapshot of the 401 // entire datastore. Our implementation takes a snapshot of the
366 // entity group as soon as something obs erves/affects it. 402 // entity group as soon as something obs erves/affects it.
367 // 403 //
368 // That said... I'm not sure if there's really a semantic difference. 404 // That said... I'm not sure if there's really a semantic difference.
369 » » » » » err := ds.RunInTransaction(func(c contex t.Context) error { 405 » » » » » err := ds.RunInTransaction(c, func(c con text.Context) error {
370 » » » » » » So(dsS.Get(c).Put(&Foo{ID: 1, Va l: 21}), ShouldBeNil) 406 » » » » » » So(ds.Put(c, &Foo{ID: 1, Val: 21 }), ShouldBeNil)
371 407
372 » » » » » » err := dsS.GetNoTxn(c).RunInTran saction(func(c context.Context) error { 408 » » » » » » err := ds.RunInTransaction(ds.Wi thoutTransaction(c), func(c context.Context) error {
373 » » » » » » » So(dsS.Get(c).Put(&Foo{I D: 1, Val: 27}), ShouldBeNil) 409 » » » » » » » So(ds.Put(c, &Foo{ID: 1, Val: 27}), ShouldBeNil)
374 return nil 410 return nil
375 }, nil) 411 }, nil)
376 So(err, ShouldBeNil) 412 So(err, ShouldBeNil)
377 413
378 return nil 414 return nil
379 }, nil) 415 }, nil)
380 So(err.Error(), ShouldContainSubstring, "concurrent") 416 So(err.Error(), ShouldContainSubstring, "concurrent")
381 417
382 f := &Foo{ID: 1} 418 f := &Foo{ID: 1}
383 » » » » » So(ds.Get(f), ShouldBeNil) 419 » » » » » So(ds.Get(c, f), ShouldBeNil)
384 So(f.Val, ShouldEqual, 27) 420 So(f.Val, ShouldEqual, 27)
385 }) 421 })
386 422
387 Convey("XG", func() { 423 Convey("XG", func() {
388 Convey("Modifying two groups with XG=fal se is invalid", func() { 424 Convey("Modifying two groups with XG=fal se is invalid", func() {
389 » » » » » » err := ds.RunInTransaction(func( c context.Context) error { 425 » » » » » » err := ds.RunInTransaction(c, fu nc(c context.Context) error {
390 » » » » » » » ds := dsS.Get(c)
391 f := &Foo{ID: 1, Val: 20 0} 426 f := &Foo{ID: 1, Val: 20 0}
392 » » » » » » » So(ds.Put(f), ShouldBeNi l) 427 » » » » » » » So(ds.Put(c, f), ShouldB eNil)
393 428
394 f.ID = 2 429 f.ID = 2
395 » » » » » » » err := ds.Put(f) 430 » » » » » » » err := ds.Put(c, f)
396 So(err.Error(), ShouldCo ntainSubstring, "cross-group") 431 So(err.Error(), ShouldCo ntainSubstring, "cross-group")
397 return err 432 return err
398 }, nil) 433 }, nil)
399 So(err.Error(), ShouldContainSub string, "cross-group") 434 So(err.Error(), ShouldContainSub string, "cross-group")
400 }) 435 })
401 436
402 Convey("Modifying >25 groups with XG=tru e is invald", func() { 437 Convey("Modifying >25 groups with XG=tru e is invald", func() {
403 » » » » » » err := ds.RunInTransaction(func( c context.Context) error { 438 » » » » » » err := ds.RunInTransaction(c, fu nc(c context.Context) error {
404 » » » » » » » ds := dsS.Get(c)
405 foos := make([]Foo, 25) 439 foos := make([]Foo, 25)
406 for i := int64(1); i < 2 6; i++ { 440 for i := int64(1); i < 2 6; i++ {
407 foos[i-1].ID = i 441 foos[i-1].ID = i
408 foos[i-1].Val = 200 442 foos[i-1].Val = 200
409 } 443 }
410 » » » » » » » So(ds.PutMulti(foos), Sh ouldBeNil) 444 » » » » » » » So(ds.Put(c, foos), Shou ldBeNil)
411 » » » » » » » err := ds.Put(&Foo{ID: 2 6}) 445 » » » » » » » err := ds.Put(c, &Foo{ID : 26})
412 So(err.Error(), ShouldCo ntainSubstring, "too many entity groups") 446 So(err.Error(), ShouldCo ntainSubstring, "too many entity groups")
413 return err 447 return err
414 » » » » » » }, &dsS.TransactionOptions{XG: t rue}) 448 » » » » » » }, &ds.TransactionOptions{XG: tr ue})
415 So(err.Error(), ShouldContainSub string, "too many entity groups") 449 So(err.Error(), ShouldContainSub string, "too many entity groups")
416 }) 450 })
417 }) 451 })
418 452
419 Convey("Errors and panics", func() { 453 Convey("Errors and panics", func() {
420 Convey("returning an error aborts", func () { 454 Convey("returning an error aborts", func () {
421 » » » » » » err := ds.RunInTransaction(func( c context.Context) error { 455 » » » » » » err := ds.RunInTransaction(c, fu nc(c context.Context) error {
422 » » » » » » » ds := dsS.Get(c) 456 » » » » » » » So(ds.Put(c, &Foo{ID: 1, Val: 200}), ShouldBeNil)
423 » » » » » » » So(ds.Put(&Foo{ID: 1, Va l: 200}), ShouldBeNil)
424 return fmt.Errorf("thing y") 457 return fmt.Errorf("thing y")
425 }, nil) 458 }, nil)
426 So(err.Error(), ShouldEqual, "th ingy") 459 So(err.Error(), ShouldEqual, "th ingy")
427 460
428 f := &Foo{ID: 1} 461 f := &Foo{ID: 1}
429 » » » » » » So(ds.Get(f), ShouldBeNil) 462 » » » » » » So(ds.Get(c, f), ShouldBeNil)
430 So(f.Val, ShouldEqual, 10) 463 So(f.Val, ShouldEqual, 10)
431 }) 464 })
432 465
433 Convey("panicing aborts", func() { 466 Convey("panicing aborts", func() {
434 So(func() { 467 So(func() {
435 » » » » » » » So(ds.RunInTransaction(f unc(c context.Context) error { 468 » » » » » » » So(ds.RunInTransaction(c , func(c context.Context) error {
436 » » » » » » » » ds := dsS.Get(c) 469 » » » » » » » » So(ds.Put(c, &Fo o{Val: 200}), ShouldBeNil)
437 » » » » » » » » So(ds.Put(&Foo{V al: 200}), ShouldBeNil)
438 panic("wheeeeee" ) 470 panic("wheeeeee" )
439 }, nil), ShouldBeNil) 471 }, nil), ShouldBeNil)
440 }, ShouldPanic) 472 }, ShouldPanic)
441 473
442 f := &Foo{ID: 1} 474 f := &Foo{ID: 1}
443 » » » » » » So(ds.Get(f), ShouldBeNil) 475 » » » » » » So(ds.Get(c, f), ShouldBeNil)
444 So(f.Val, ShouldEqual, 10) 476 So(f.Val, ShouldEqual, 10)
445 }) 477 })
446 }) 478 })
447 479
448 Convey("Transaction retries", func() { 480 Convey("Transaction retries", func() {
449 » » » » » tst := ds.Testable() 481 » » » » » tst := ds.GetTestable(c)
450 Reset(func() { tst.SetTransactionRetryCo unt(0) }) 482 Reset(func() { tst.SetTransactionRetryCo unt(0) })
451 483
452 Convey("SetTransactionRetryCount set to zero", func() { 484 Convey("SetTransactionRetryCount set to zero", func() {
453 tst.SetTransactionRetryCount(0) 485 tst.SetTransactionRetryCount(0)
454 calls := 0 486 calls := 0
455 » » » » » » So(ds.RunInTransaction(func(c co ntext.Context) error { 487 » » » » » » So(ds.RunInTransaction(c, func(c context.Context) error {
456 calls++ 488 calls++
457 return nil 489 return nil
458 }, nil), ShouldBeNil) 490 }, nil), ShouldBeNil)
459 So(calls, ShouldEqual, 1) 491 So(calls, ShouldEqual, 1)
460 }) 492 })
461 493
462 Convey("default TransactionOptions is 3 attempts", func() { 494 Convey("default TransactionOptions is 3 attempts", func() {
463 tst.SetTransactionRetryCount(100 ) // more than 3 495 tst.SetTransactionRetryCount(100 ) // more than 3
464 calls := 0 496 calls := 0
465 » » » » » » So(ds.RunInTransaction(func(c co ntext.Context) error { 497 » » » » » » So(ds.RunInTransaction(c, func(c context.Context) error {
466 calls++ 498 calls++
467 return nil 499 return nil
468 » » » » » » }, nil), ShouldEqual, dsS.ErrCon currentTransaction) 500 » » » » » » }, nil), ShouldEqual, ds.ErrConc urrentTransaction)
469 So(calls, ShouldEqual, 3) 501 So(calls, ShouldEqual, 3)
470 }) 502 })
471 503
472 Convey("non-default TransactionOptions " , func() { 504 Convey("non-default TransactionOptions " , func() {
473 tst.SetTransactionRetryCount(100 ) // more than 20 505 tst.SetTransactionRetryCount(100 ) // more than 20
474 calls := 0 506 calls := 0
475 » » » » » » So(ds.RunInTransaction(func(c co ntext.Context) error { 507 » » » » » » So(ds.RunInTransaction(c, func(c context.Context) error {
476 calls++ 508 calls++
477 return nil 509 return nil
478 » » » » » » }, &dsS.TransactionOptions{Attem pts: 20}), ShouldEqual, dsS.ErrConcurrentTransaction) 510 » » » » » » }, &ds.TransactionOptions{Attemp ts: 20}), ShouldEqual, ds.ErrConcurrentTransaction)
479 So(calls, ShouldEqual, 20) 511 So(calls, ShouldEqual, 20)
480 }) 512 })
481 513
482 Convey("SetTransactionRetryCount is resp ected", func() { 514 Convey("SetTransactionRetryCount is resp ected", func() {
483 tst.SetTransactionRetryCount(1) // less than 3 515 tst.SetTransactionRetryCount(1) // less than 3
484 calls := 0 516 calls := 0
485 » » » » » » So(ds.RunInTransaction(func(c co ntext.Context) error { 517 » » » » » » So(ds.RunInTransaction(c, func(c context.Context) error {
486 calls++ 518 calls++
487 return nil 519 return nil
488 }, nil), ShouldBeNil) 520 }, nil), ShouldBeNil)
489 So(calls, ShouldEqual, 2) 521 So(calls, ShouldEqual, 2)
490 }) 522 })
491 523
492 Convey("fatal errors are not retried", f unc() { 524 Convey("fatal errors are not retried", f unc() {
493 tst.SetTransactionRetryCount(1) 525 tst.SetTransactionRetryCount(1)
494 calls := 0 526 calls := 0
495 » » » » » » So(ds.RunInTransaction(func(c co ntext.Context) error { 527 » » » » » » So(ds.RunInTransaction(c, func(c context.Context) error {
496 calls++ 528 calls++
497 return fmt.Errorf("omg") 529 return fmt.Errorf("omg")
498 }, nil).Error(), ShouldEqual, "o mg") 530 }, nil).Error(), ShouldEqual, "o mg")
499 So(calls, ShouldEqual, 1) 531 So(calls, ShouldEqual, 1)
500 }) 532 })
501 }) 533 })
502 }) 534 })
503 }) 535 })
504 536
505 Convey("Testable.Consistent", func() { 537 Convey("Testable.Consistent", func() {
506 Convey("false", func() { 538 Convey("false", func() {
507 » » » » ds.Testable().Consistent(false) // the default 539 » » » » ds.GetTestable(c).Consistent(false) // the defau lt
508 for i := 0; i < 10; i++ { 540 for i := 0; i < 10; i++ {
509 » » » » » So(ds.Put(&Foo{ID: int64(i + 1), Val: i + 1}), ShouldBeNil) 541 » » » » » So(ds.Put(c, &Foo{ID: int64(i + 1), Val: i + 1}), ShouldBeNil)
510 } 542 }
511 » » » » q := dsS.NewQuery("Foo").Gt("Val", 3) 543 » » » » q := ds.NewQuery("Foo").Gt("Val", 3)
512 » » » » count, err := ds.Count(q) 544 » » » » count, err := ds.Count(c, q)
513 So(err, ShouldBeNil) 545 So(err, ShouldBeNil)
514 So(count, ShouldEqual, 0) 546 So(count, ShouldEqual, 0)
515 547
516 » » » » So(ds.Delete(ds.MakeKey("Foo", 4)), ShouldBeNil) 548 » » » » So(ds.Delete(c, ds.MakeKey(c, "Foo", 4)), Should BeNil)
517 549
518 » » » » count, err = ds.Count(q) 550 » » » » count, err = ds.Count(c, q)
519 So(err, ShouldBeNil) 551 So(err, ShouldBeNil)
520 So(count, ShouldEqual, 0) 552 So(count, ShouldEqual, 0)
521 553
522 » » » » ds.Testable().Consistent(true) 554 » » » » ds.GetTestable(c).Consistent(true)
523 » » » » count, err = ds.Count(q) 555 » » » » count, err = ds.Count(c, q)
524 So(err, ShouldBeNil) 556 So(err, ShouldBeNil)
525 So(count, ShouldEqual, 6) 557 So(count, ShouldEqual, 6)
526 }) 558 })
527 559
528 Convey("true", func() { 560 Convey("true", func() {
529 » » » » ds.Testable().Consistent(true) 561 » » » » ds.GetTestable(c).Consistent(true)
530 for i := 0; i < 10; i++ { 562 for i := 0; i < 10; i++ {
531 » » » » » So(ds.Put(&Foo{ID: int64(i + 1), Val: i + 1}), ShouldBeNil) 563 » » » » » So(ds.Put(c, &Foo{ID: int64(i + 1), Val: i + 1}), ShouldBeNil)
532 } 564 }
533 » » » » q := dsS.NewQuery("Foo").Gt("Val", 3) 565 » » » » q := ds.NewQuery("Foo").Gt("Val", 3)
534 » » » » count, err := ds.Count(q) 566 » » » » count, err := ds.Count(c, q)
535 So(err, ShouldBeNil) 567 So(err, ShouldBeNil)
536 So(count, ShouldEqual, 7) 568 So(count, ShouldEqual, 7)
537 569
538 » » » » So(ds.Delete(ds.MakeKey("Foo", 4)), ShouldBeNil) 570 » » » » So(ds.Delete(c, ds.MakeKey(c, "Foo", 4)), Should BeNil)
539 571
540 » » » » count, err = ds.Count(q) 572 » » » » count, err = ds.Count(c, q)
541 So(err, ShouldBeNil) 573 So(err, ShouldBeNil)
542 So(count, ShouldEqual, 6) 574 So(count, ShouldEqual, 6)
543 }) 575 })
544 }) 576 })
545 577
546 Convey("Testable.DisableSpecialEntities", func() { 578 Convey("Testable.DisableSpecialEntities", func() {
547 » » » ds.Testable().DisableSpecialEntities(true) 579 » » » ds.GetTestable(c).DisableSpecialEntities(true)
548 580
549 » » » So(ds.Put(&Foo{}), ShouldErrLike, "allocateIDs is disabl ed") 581 » » » So(ds.Put(c, &Foo{}), ShouldErrLike, "allocateIDs is dis abled")
550 582
551 » » » So(ds.Put(&Foo{ID: 1}), ShouldBeNil) 583 » » » So(ds.Put(c, &Foo{ID: 1}), ShouldBeNil)
552 584
553 » » » ds.Testable().CatchupIndexes() 585 » » » ds.GetTestable(c).CatchupIndexes()
554 586
555 » » » count, err := ds.Count(dsS.NewQuery("")) 587 » » » count, err := ds.Count(c, ds.NewQuery(""))
556 So(err, ShouldBeNil) 588 So(err, ShouldBeNil)
557 So(count, ShouldEqual, 1) // normally this would include __entity_group__ 589 So(count, ShouldEqual, 1) // normally this would include __entity_group__
558 }) 590 })
559 591
560 Convey("Datastore namespace interaction", func() { 592 Convey("Datastore namespace interaction", func() {
561 run := func(rc context.Context, txn bool) (putErr, getEr r, queryErr, countErr error) { 593 run := func(rc context.Context, txn bool) (putErr, getEr r, queryErr, countErr error) {
562 var foo Foo 594 var foo Foo
563 595
564 putFunc := func(doC context.Context) error { 596 putFunc := func(doC context.Context) error {
565 » » » » » return dsS.Get(doC).Put(&foo) 597 » » » » » return ds.Put(doC, &foo)
566 } 598 }
567 599
568 doFunc := func(doC context.Context) { 600 doFunc := func(doC context.Context) {
569 » » » » » ds := dsS.Get(doC) 601 » » » » » getErr = ds.Get(doC, &foo)
570 » » » » » getErr = ds.Get(&foo)
571 602
572 » » » » » q := dsS.NewQuery("Foo").Ancestor(ds.Key ForObj(&foo)) 603 » » » » » q := ds.NewQuery("Foo").Ancestor(ds.KeyF orObj(doC, &foo))
573 » » » » » queryErr = ds.Run(q, func(f *Foo) error { return nil }) 604 » » » » » queryErr = ds.Run(doC, q, func(f *Foo) e rror { return nil })
574 » » » » » _, countErr = ds.Count(q) 605 » » » » » _, countErr = ds.Count(doC, q)
575 } 606 }
576 607
577 if txn { 608 if txn {
578 » » » » » putErr = dsS.Get(rc).RunInTransaction(fu nc(ic context.Context) error { 609 » » » » » putErr = ds.RunInTransaction(rc, func(ic context.Context) error {
579 return putFunc(ic) 610 return putFunc(ic)
580 }, nil) 611 }, nil)
581 if putErr != nil { 612 if putErr != nil {
582 return 613 return
583 } 614 }
584 615
585 » » » » » dsS.Get(rc).Testable().CatchupIndexes() 616 » » » » » ds.GetTestable(rc).CatchupIndexes()
586 » » » » » dsS.Get(rc).RunInTransaction(func(ic con text.Context) error { 617 » » » » » ds.RunInTransaction(rc, func(ic context. Context) error {
587 doFunc(ic) 618 doFunc(ic)
588 return nil 619 return nil
589 }, nil) 620 }, nil)
590 } else { 621 } else {
591 putErr = putFunc(rc) 622 putErr = putFunc(rc)
592 if putErr != nil { 623 if putErr != nil {
593 return 624 return
594 } 625 }
595 » » » » » dsS.Get(rc).Testable().CatchupIndexes() 626 » » » » » ds.GetTestable(rc).CatchupIndexes()
596 doFunc(rc) 627 doFunc(rc)
597 } 628 }
598 return 629 return
599 } 630 }
600 631
601 for _, txn := range []bool{false, true} { 632 for _, txn := range []bool{false, true} {
602 Convey(fmt.Sprintf("In transaction? %v", txn), f unc() { 633 Convey(fmt.Sprintf("In transaction? %v", txn), f unc() {
603 Convey("With no namespace installed, can Put, Get, Query, and Count.", func() { 634 Convey("With no namespace installed, can Put, Get, Query, and Count.", func() {
604 » » » » » » _, has := infoS.Get(c).GetNamesp ace() 635 » » » » » » So(infoS.GetNamespace(c), Should Equal, "")
605 » » » » » » So(has, ShouldBeFalse)
606 636
607 putErr, getErr, queryErr, countE rr := run(c, txn) 637 putErr, getErr, queryErr, countE rr := run(c, txn)
608 So(putErr, ShouldBeNil) 638 So(putErr, ShouldBeNil)
609 So(getErr, ShouldBeNil) 639 So(getErr, ShouldBeNil)
610 So(queryErr, ShouldBeNil) 640 So(queryErr, ShouldBeNil)
611 So(countErr, ShouldBeNil) 641 So(countErr, ShouldBeNil)
612 }) 642 })
613 643
614 Convey("With a namespace installed, can Put, Get, Query, and Count.", func() { 644 Convey("With a namespace installed, can Put, Get, Query, and Count.", func() {
615 » » » » » » putErr, getErr, queryErr, countE rr := run(infoS.Get(c).MustNamespace("foo"), txn) 645 » » » » » » putErr, getErr, queryErr, countE rr := run(infoS.MustNamespace(c, "foo"), txn)
616 So(putErr, ShouldBeNil) 646 So(putErr, ShouldBeNil)
617 So(getErr, ShouldBeNil) 647 So(getErr, ShouldBeNil)
618 So(queryErr, ShouldBeNil) 648 So(queryErr, ShouldBeNil)
619 So(countErr, ShouldBeNil) 649 So(countErr, ShouldBeNil)
620 }) 650 })
621 }) 651 })
622 } 652 }
623 }) 653 })
624 }) 654 })
625 } 655 }
626 656
627 func TestCompoundIndexes(t *testing.T) { 657 func TestCompoundIndexes(t *testing.T) {
628 t.Parallel() 658 t.Parallel()
629 659
630 » idxKey := func(def dsS.IndexDefinition) string { 660 » idxKey := func(def ds.IndexDefinition) string {
631 So(def, ShouldNotBeNil) 661 So(def, ShouldNotBeNil)
632 return "idx::" + string(serialize.ToBytes(*def.PrepForIdxTable() )) 662 return "idx::" + string(serialize.ToBytes(*def.PrepForIdxTable() ))
633 } 663 }
634 664
635 numItms := func(c memCollection) uint64 { 665 numItms := func(c memCollection) uint64 {
636 ret, _ := c.GetTotals() 666 ret, _ := c.GetTotals()
637 return ret 667 return ret
638 } 668 }
639 669
640 Convey("Test Compound indexes", t, func() { 670 Convey("Test Compound indexes", t, func() {
641 type Model struct { 671 type Model struct {
642 ID int64 `gae:"$id"` 672 ID int64 `gae:"$id"`
643 673
644 Field1 []string 674 Field1 []string
645 Field2 []int64 675 Field2 []int64
646 } 676 }
647 677
648 c := Use(context.Background()) 678 c := Use(context.Background())
649 » » ds := dsS.Get(c) 679 » » t := ds.GetTestable(c).(*dsImpl)
650 » » t := ds.Testable().(*dsImpl)
651 head := t.data.head 680 head := t.data.head
652 681
653 » » So(ds.Put(&Model{1, []string{"hello", "world"}, []int64{10, 11}} ), ShouldBeNil) 682 » » So(ds.Put(c, &Model{1, []string{"hello", "world"}, []int64{10, 1 1}}), ShouldBeNil)
654 683
655 » » idx := dsS.IndexDefinition{ 684 » » idx := ds.IndexDefinition{
656 Kind: "Model", 685 Kind: "Model",
657 » » » SortBy: []dsS.IndexColumn{ 686 » » » SortBy: []ds.IndexColumn{
658 {Property: "Field2"}, 687 {Property: "Field2"},
659 }, 688 },
660 } 689 }
661 690
662 coll := head.GetCollection(idxKey(idx)) 691 coll := head.GetCollection(idxKey(idx))
663 So(coll, ShouldNotBeNil) 692 So(coll, ShouldNotBeNil)
664 So(numItms(coll), ShouldEqual, 2) 693 So(numItms(coll), ShouldEqual, 2)
665 694
666 idx.SortBy[0].Property = "Field1" 695 idx.SortBy[0].Property = "Field1"
667 coll = head.GetCollection(idxKey(idx)) 696 coll = head.GetCollection(idxKey(idx))
668 So(coll, ShouldNotBeNil) 697 So(coll, ShouldNotBeNil)
669 So(numItms(coll), ShouldEqual, 2) 698 So(numItms(coll), ShouldEqual, 2)
670 699
671 » » idx.SortBy = append(idx.SortBy, dsS.IndexColumn{Property: "Field 1"}) 700 » » idx.SortBy = append(idx.SortBy, ds.IndexColumn{Property: "Field1 "})
672 So(head.GetCollection(idxKey(idx)), ShouldBeNil) 701 So(head.GetCollection(idxKey(idx)), ShouldBeNil)
673 702
674 t.AddIndexes(&idx) 703 t.AddIndexes(&idx)
675 coll = head.GetCollection(idxKey(idx)) 704 coll = head.GetCollection(idxKey(idx))
676 So(coll, ShouldNotBeNil) 705 So(coll, ShouldNotBeNil)
677 So(numItms(coll), ShouldEqual, 4) 706 So(numItms(coll), ShouldEqual, 4)
678 }) 707 })
679 } 708 }
680 709
681 // High level test for regression in how zero time is stored, 710 // High level test for regression in how zero time is stored,
682 // see https://codereview.chromium.org/1334043003/ 711 // see https://codereview.chromium.org/1334043003/
683 func TestDefaultTimeField(t *testing.T) { 712 func TestDefaultTimeField(t *testing.T) {
684 t.Parallel() 713 t.Parallel()
685 714
686 Convey("Default time.Time{} can be stored", t, func() { 715 Convey("Default time.Time{} can be stored", t, func() {
687 type Model struct { 716 type Model struct {
688 ID int64 `gae:"$id"` 717 ID int64 `gae:"$id"`
689 Time time.Time 718 Time time.Time
690 } 719 }
691 » » ds := dsS.Get(Use(context.Background())) 720 » » c := Use(context.Background())
692 m := Model{ID: 1} 721 m := Model{ID: 1}
693 » » So(ds.Put(&m), ShouldBeNil) 722 » » So(ds.Put(c, &m), ShouldBeNil)
694 723
695 // Reset to something non zero to ensure zero is fetched. 724 // Reset to something non zero to ensure zero is fetched.
696 m.Time = time.Now().UTC() 725 m.Time = time.Now().UTC()
697 » » So(ds.Get(&m), ShouldBeNil) 726 » » So(ds.Get(c, &m), ShouldBeNil)
698 So(m.Time.IsZero(), ShouldBeTrue) 727 So(m.Time.IsZero(), ShouldBeTrue)
699 }) 728 })
700 } 729 }
701 730
702 func TestNewDatastore(t *testing.T) { 731 func TestNewDatastore(t *testing.T) {
703 t.Parallel() 732 t.Parallel()
704 733
705 Convey("Can get and use a NewDatastore", t, func() { 734 Convey("Can get and use a NewDatastore", t, func() {
706 c := UseWithAppID(context.Background(), "dev~aid") 735 c := UseWithAppID(context.Background(), "dev~aid")
707 » » c = infoS.Get(c).MustNamespace("ns") 736 » » c = infoS.MustNamespace(c, "ns")
708 » » ds := NewDatastore(infoS.Get(c))
709 737
710 » » k := ds.MakeKey("Something", 1) 738 » » dsInst := NewDatastore(c, infoS.Raw(c))
739 » » c = ds.SetRaw(c, dsInst)
740
741 » » k := ds.MakeKey(c, "Something", 1)
711 So(k.AppID(), ShouldEqual, "dev~aid") 742 So(k.AppID(), ShouldEqual, "dev~aid")
712 So(k.Namespace(), ShouldEqual, "ns") 743 So(k.Namespace(), ShouldEqual, "ns")
713 744
714 type Model struct { 745 type Model struct {
715 ID int64 `gae:"$id"` 746 ID int64 `gae:"$id"`
716 Value []int64 747 Value []int64
717 } 748 }
718 » » So(ds.Put(&Model{ID: 1, Value: []int64{20, 30}}), ShouldBeNil) 749 » » So(ds.Put(c, &Model{ID: 1, Value: []int64{20, 30}}), ShouldBeNil )
719 750
720 » » vals := []dsS.PropertyMap{} 751 » » vals := []ds.PropertyMap{}
721 » » So(ds.GetAll(dsS.NewQuery("Model").Project("Value"), &vals), Sho uldBeNil) 752 » » So(ds.GetAll(c, ds.NewQuery("Model").Project("Value"), &vals), S houldBeNil)
722 So(len(vals), ShouldEqual, 2) 753 So(len(vals), ShouldEqual, 2)
723 754
724 So(vals[0].Slice("Value")[0].Value(), ShouldEqual, 20) 755 So(vals[0].Slice("Value")[0].Value(), ShouldEqual, 20)
725 So(vals[1].Slice("Value")[0].Value(), ShouldEqual, 30) 756 So(vals[1].Slice("Value")[0].Value(), ShouldEqual, 30)
726 }) 757 })
727 } 758 }
728 759
729 func TestAddIndexes(t *testing.T) { 760 func TestAddIndexes(t *testing.T) {
730 t.Parallel() 761 t.Parallel()
731 762
732 Convey("Test Testable.AddIndexes", t, func() { 763 Convey("Test Testable.AddIndexes", t, func() {
733 ctx := UseWithAppID(context.Background(), "aid") 764 ctx := UseWithAppID(context.Background(), "aid")
734 namespaces := []string{"", "good", "news", "everyone"} 765 namespaces := []string{"", "good", "news", "everyone"}
735 766
736 Convey("After adding datastore entries, can query against indexe s in various namespaces", func() { 767 Convey("After adding datastore entries, can query against indexe s in various namespaces", func() {
737 foos := []*Foo{ 768 foos := []*Foo{
738 {ID: 1, Val: 1, Name: "foo"}, 769 {ID: 1, Val: 1, Name: "foo"},
739 {ID: 2, Val: 2, Name: "bar"}, 770 {ID: 2, Val: 2, Name: "bar"},
740 {ID: 3, Val: 2, Name: "baz"}, 771 {ID: 3, Val: 2, Name: "baz"},
741 } 772 }
742 for _, ns := range namespaces { 773 for _, ns := range namespaces {
743 » » » » So(dsS.Get(infoS.Get(ctx).MustNamespace(ns)).Put Multi(foos), ShouldBeNil) 774 » » » » So(ds.Put(infoS.MustNamespace(ctx, ns), foos), S houldBeNil)
744 } 775 }
745 776
746 // Initial query, no indexes, will fail. 777 // Initial query, no indexes, will fail.
747 » » » dsS.Get(ctx).Testable().CatchupIndexes() 778 » » » ds.GetTestable(ctx).CatchupIndexes()
748 779
749 var results []*Foo 780 var results []*Foo
750 » » » q := dsS.NewQuery("Foo").Eq("Val", 2).Gte("Name", "bar") 781 » » » q := ds.NewQuery("Foo").Eq("Val", 2).Gte("Name", "bar")
751 » » » So(dsS.Get(ctx).GetAll(q, &results), ShouldErrLike, "Ins ufficient indexes") 782 » » » So(ds.GetAll(ctx, q, &results), ShouldErrLike, "Insuffic ient indexes")
752 783
753 // Add index for default namespace. 784 // Add index for default namespace.
754 » » » dsS.Get(ctx).Testable().AddIndexes(&dsS.IndexDefinition{ 785 » » » ds.GetTestable(ctx).AddIndexes(&ds.IndexDefinition{
755 Kind: "Foo", 786 Kind: "Foo",
756 » » » » SortBy: []dsS.IndexColumn{ 787 » » » » SortBy: []ds.IndexColumn{
757 {Property: "Val"}, 788 {Property: "Val"},
758 {Property: "Name"}, 789 {Property: "Name"},
759 }, 790 },
760 }) 791 })
761 » » » dsS.Get(ctx).Testable().CatchupIndexes() 792 » » » ds.GetTestable(ctx).CatchupIndexes()
762 793
763 for _, ns := range namespaces { 794 for _, ns := range namespaces {
764 if ns == "" { 795 if ns == "" {
765 // Skip query test for empty namespace, as this is invalid. 796 // Skip query test for empty namespace, as this is invalid.
766 continue 797 continue
767 } 798 }
768 799
769 results = nil 800 results = nil
770 » » » » So(dsS.Get(infoS.Get(ctx).MustNamespace(ns)).Get All(q, &results), ShouldBeNil) 801 » » » » So(ds.GetAll(infoS.MustNamespace(ctx, ns), q, &r esults), ShouldBeNil)
771 So(len(results), ShouldEqual, 2) 802 So(len(results), ShouldEqual, 2)
772 } 803 }
773 804
774 // Add "foos" to a new namespace, then confirm that it g ets indexed. 805 // Add "foos" to a new namespace, then confirm that it g ets indexed.
775 » » » So(dsS.Get(infoS.Get(ctx).MustNamespace("qux")).PutMulti (foos), ShouldBeNil) 806 » » » So(ds.Put(infoS.MustNamespace(ctx, "qux"), foos), Should BeNil)
776 » » » dsS.Get(ctx).Testable().CatchupIndexes() 807 » » » ds.GetTestable(ctx).CatchupIndexes()
777 808
778 results = nil 809 results = nil
779 » » » So(dsS.Get(infoS.Get(ctx).MustNamespace("qux")).GetAll(q , &results), ShouldBeNil) 810 » » » So(ds.GetAll(infoS.MustNamespace(ctx, "qux"), q, &result s), ShouldBeNil)
780 So(len(results), ShouldEqual, 2) 811 So(len(results), ShouldEqual, 2)
781 }) 812 })
782 }) 813 })
783 } 814 }
OLDNEW
« no previous file with comments | « impl/memory/datastore_query_test.go ('k') | impl/memory/info.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698