OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 // adapted from github.com/golang/appengine/datastore | |
6 | |
7 package datastore | |
8 | |
9 import ( | |
10 "fmt" | |
11 "testing" | |
12 | |
13 "github.com/luci/gae/service/info" | |
14 "github.com/luci/luci-go/common/errors" | |
15 . "github.com/smartystreets/goconvey/convey" | |
16 "golang.org/x/net/context" | |
17 ) | |
18 | |
19 func fakeDatastoreFactory(c context.Context) RawInterface { | |
iannucci
2015/08/03 04:00:34
This file is basically completely different now. D
| |
20 i := info.Get(c) | |
21 return &fakeDatastore{ | |
22 aid: i.AppID(), | |
23 ns: i.GetNamespace(), | |
24 } | |
25 } | |
26 | |
27 type fakeQuery struct { | |
28 Query | |
29 | |
30 limit int | |
31 | |
32 err error | |
33 errSingle error | |
34 errSingleIdx int | |
35 } | |
36 | |
37 func (q *fakeQuery) KeysOnly() Query { | |
38 return q | |
39 } | |
40 | |
41 func (q *fakeQuery) Limit(i int) Query { | |
42 q.limit = i | |
43 return q | |
44 } | |
45 | |
46 func (q *fakeQuery) FailAll() Query { | |
47 q.err = errors.New("Query fail all") | |
48 return q | |
49 } | |
50 | |
51 func (q *fakeQuery) Fail(i int) Query { | |
52 q.errSingleIdx = i | |
53 q.errSingle = errors.New("Query fail") | |
54 return q | |
55 } | |
56 | |
57 type fakeDatastore struct { | |
58 RawInterface | |
59 aid string | |
60 ns string | |
61 } | |
62 | |
63 func (f *fakeDatastore) NewKey(kind, stringID string, intID int64, parent Key) K ey { | |
64 return NewKey(f.aid, f.ns, kind, stringID, intID, parent) | |
65 } | |
66 | |
67 func (f *fakeDatastore) NewQuery(string) Query { | |
68 return &fakeQuery{} | |
69 } | |
70 | |
71 func (f *fakeDatastore) Run(q Query, cb RawRunCB) error { | |
72 rq := q.(*fakeQuery) | |
73 if rq.err != nil { | |
74 return rq.err | |
75 } | |
76 for i := 0; i < rq.limit; i++ { | |
77 if rq.errSingle != nil && i == rq.errSingleIdx { | |
78 return rq.errSingle | |
79 } else { | |
80 k := f.NewKey("Kind", "", int64(i+1), nil) | |
81 if i == 10 { | |
82 k = f.NewKey("Kind", "eleven", 0, nil) | |
83 } | |
84 pm := PropertyMap{"Value": {MkProperty(i)}} | |
85 if !cb(k, pm, nil) { | |
86 break | |
87 } | |
88 } | |
89 } | |
90 return nil | |
91 } | |
92 | |
93 func (f *fakeDatastore) PutMulti(keys []Key, vals []PropertyMap, cb PutMultiCB) error { | |
94 if keys[0].Kind() == "FailAll" { | |
95 return errors.New("PutMulti fail all") | |
96 } | |
97 assertExtra := false | |
98 if _, err := vals[0].GetMeta("assertExtra"); err == nil { | |
99 assertExtra = true | |
100 } | |
101 for i, k := range keys { | |
102 err := error(nil) | |
103 if k.Kind() == "Fail" { | |
104 err = errors.New("PutMulti fail") | |
105 } else { | |
106 So(vals[i]["Value"], ShouldResemble, []Property{MkProper ty(i)}) | |
107 if assertExtra { | |
108 So(vals[i]["Extra"], ShouldResemble, []Property{ MkProperty("whoa")}) | |
109 } | |
110 if KeyIncomplete(k) { | |
111 k = NewKey(k.AppID(), k.Namespace(), k.Kind(), " ", int64(i+1), k.Parent()) | |
112 } | |
113 } | |
114 cb(k, err) | |
115 } | |
116 return nil | |
117 } | |
118 | |
119 func (f *fakeDatastore) GetMulti(keys []Key, cb GetMultiCB) error { | |
120 if keys[0].Kind() == "FailAll" { | |
121 return errors.New("GetMulti fail all") | |
122 } | |
123 for i, k := range keys { | |
124 if k.Kind() == "Fail" { | |
125 cb(nil, errors.New("GetMulti fail")) | |
126 } else { | |
127 cb(PropertyMap{"Value": {MkProperty(i + 1)}}, nil) | |
128 } | |
129 } | |
130 return nil | |
131 } | |
132 | |
133 func (f *fakeDatastore) DeleteMulti(keys []Key, cb DeleteMultiCB) error { | |
134 if keys[0].Kind() == "FailAll" { | |
135 return errors.New("DeleteMulti fail all") | |
136 } | |
137 for _, k := range keys { | |
138 if k.Kind() == "Fail" { | |
139 cb(errors.New("DeleteMulti fail")) | |
140 } else { | |
141 cb(nil) | |
142 } | |
143 } | |
144 return nil | |
145 } | |
146 | |
147 type badStruct struct { | |
148 ID int64 `gae:"$id"` | |
149 Compy complex64 // bad type | |
150 } | |
151 | |
152 type CommonStruct struct { | |
153 ID int64 `gae:"$id"` | |
154 Parent Key `gae:"$parent"` | |
155 | |
156 Value int64 | |
157 } | |
158 | |
159 type permaBad struct { | |
160 PropertyLoadSaver | |
161 } | |
162 | |
163 func (f *permaBad) Load(pm PropertyMap) error { | |
164 return errors.New("permaBad") | |
165 } | |
166 | |
167 type FakePLS struct { | |
168 IntID int64 | |
169 StringID string | |
170 Kind string | |
171 | |
172 Value int64 | |
173 gotLoaded bool | |
174 | |
175 failGetMeta bool | |
176 failLoad bool | |
177 failProblem bool | |
178 failSave bool | |
179 failSaveMeta bool | |
180 } | |
181 | |
182 func (f *FakePLS) Load(pm PropertyMap) error { | |
183 if f.failLoad { | |
184 return errors.New("FakePLS.Load") | |
185 } | |
186 f.gotLoaded = true | |
187 f.Value = pm["Value"][0].Value().(int64) | |
188 return nil | |
189 } | |
190 | |
191 func (f *FakePLS) Save(withMeta bool) (PropertyMap, error) { | |
192 if f.failSave { | |
193 return nil, errors.New("FakePLS.Save") | |
194 } | |
195 ret := PropertyMap{ | |
196 "Value": {MkProperty(f.Value)}, | |
197 "Extra": {MkProperty("whoa")}, | |
198 } | |
199 if withMeta { | |
200 id, _ := f.GetMeta("id") | |
201 ret.SetMeta("id", id) | |
202 if f.Kind == "" { | |
203 ret.SetMeta("kind", "FakePLS") | |
204 } else { | |
205 ret.SetMeta("kind", f.Kind) | |
206 } | |
207 ret.SetMeta("assertExtra", true) | |
208 } | |
209 return ret, nil | |
210 } | |
211 | |
212 func (f *FakePLS) GetMeta(key string) (interface{}, error) { | |
213 if f.failGetMeta { | |
214 return nil, errors.New("FakePLS.GetMeta") | |
215 } | |
216 switch key { | |
217 case "id": | |
218 if f.StringID != "" { | |
219 return f.StringID, nil | |
220 } | |
221 return f.IntID, nil | |
222 case "kind": | |
223 if f.Kind == "" { | |
224 return "FakePLS", nil | |
225 } | |
226 return f.Kind, nil | |
227 } | |
228 return nil, ErrMetaFieldUnset | |
229 } | |
230 | |
231 func (f *FakePLS) SetMeta(key string, val interface{}) error { | |
232 if f.failSaveMeta { | |
233 return errors.New("FakePL.SetMeta") | |
234 } | |
235 if key == "id" { | |
236 switch x := val.(type) { | |
237 case int64: | |
238 f.IntID = x | |
239 case string: | |
240 f.StringID = x | |
241 } | |
242 return nil | |
243 } | |
244 if key == "kind" { | |
245 f.Kind = val.(string) | |
246 return nil | |
247 } | |
248 return ErrMetaFieldUnset | |
249 } | |
250 | |
251 func (f *FakePLS) Problem() error { | |
252 if f.failProblem { | |
253 return errors.New("FakePLS.Problem") | |
254 } | |
255 return nil | |
256 } | |
257 | |
258 func TestKeyForObj(t *testing.T) { | |
259 t.Parallel() | |
260 | |
261 Convey("Test interface.KeyForObj", t, func() { | |
262 c := info.Set(context.Background(), fakeInfo{}) | |
263 c = SetRawFactory(c, fakeDatastoreFactory) | |
264 ds := Get(c) | |
265 | |
266 k := ds.NewKey("Hello", "world", 0, nil) | |
267 | |
268 Convey("good", func() { | |
269 Convey("struct containing $key", func() { | |
270 type keyStruct struct { | |
271 Key Key `gae:"$key"` | |
272 } | |
273 | |
274 ks := &keyStruct{k} | |
275 So(ds.KeyForObj(ks), ShouldEqual, k) | |
276 }) | |
277 | |
278 Convey("struct containing default $id and $kind", func() { | |
279 type idStruct struct { | |
280 id string `gae:"$id,wut"` | |
281 knd string `gae:"$kind,SuperKind"` | |
282 } | |
283 | |
284 So(ds.KeyForObj(&idStruct{}).String(), ShouldEqu al, `/SuperKind,wut`) | |
285 }) | |
286 | |
287 Convey("struct containing $id and $parent", func() { | |
288 So(ds.KeyForObj(&CommonStruct{ID: 4}).String(), ShouldEqual, `/CommonStruct,4`) | |
289 | |
290 So(ds.KeyForObj(&CommonStruct{ID: 4, Parent: k}) .String(), ShouldEqual, `/Hello,world/CommonStruct,4`) | |
291 }) | |
292 | |
293 Convey("a propmap with $key", func() { | |
294 pm := PropertyMap{} | |
295 pm.SetMeta("key", k) | |
296 So(ds.KeyForObj(pm).String(), ShouldEqual, `/Hel lo,world`) | |
297 }) | |
298 | |
299 Convey("a propmap with $id, $kind, $parent", func() { | |
300 pm := PropertyMap{} | |
301 pm.SetMeta("id", 100) | |
302 pm.SetMeta("kind", "Sup") | |
303 So(ds.KeyForObj(pm).String(), ShouldEqual, `/Sup ,100`) | |
304 | |
305 pm.SetMeta("parent", k) | |
306 So(ds.KeyForObj(pm).String(), ShouldEqual, `/Hel lo,world/Sup,100`) | |
307 }) | |
308 | |
309 Convey("a pls with $id, $parent", func() { | |
310 pls := GetPLS(&CommonStruct{ID: 1}) | |
311 So(ds.KeyForObj(pls).String(), ShouldEqual, `/Co mmonStruct,1`) | |
312 | |
313 pls.SetMeta("parent", k) | |
314 So(ds.KeyForObj(pls).String(), ShouldEqual, `/He llo,world/CommonStruct,1`) | |
315 }) | |
316 | |
317 }) | |
318 | |
319 Convey("bad", func() { | |
320 Convey("a propmap without $kind", func() { | |
321 pm := PropertyMap{} | |
322 pm.SetMeta("id", 100) | |
323 So(func() { ds.KeyForObj(pm) }, ShouldPanic) | |
324 }) | |
325 }) | |
326 }) | |
327 } | |
328 | |
329 func TestPut(t *testing.T) { | |
330 t.Parallel() | |
331 | |
332 Convey("Test Put/PutMulti", t, func() { | |
333 c := info.Set(context.Background(), fakeInfo{}) | |
334 c = SetRawFactory(c, fakeDatastoreFactory) | |
335 ds := Get(c) | |
336 | |
337 Convey("bad", func() { | |
338 Convey("static can't serialize", func() { | |
339 bss := []badStruct{{}, {}} | |
340 So(ds.PutMulti(bss).Error(), ShouldContainSubstr ing, "invalid PutMulti input") | |
341 }) | |
342 | |
343 Convey("static ptr can't serialize", func() { | |
344 bss := []*badStruct{{}, {}} | |
345 So(ds.PutMulti(bss).Error(), ShouldContainSubstr ing, "invalid PutMulti input") | |
346 }) | |
347 | |
348 Convey("static bad type (non-slice)", func() { | |
349 So(ds.PutMulti(100).Error(), ShouldContainSubstr ing, "invalid PutMulti input") | |
350 }) | |
351 | |
352 Convey("static bad type (slice of bad type)", func() { | |
353 So(ds.PutMulti([]int{}).Error(), ShouldContainSu bstring, "invalid PutMulti input") | |
354 }) | |
355 | |
356 Convey("dynamic can't serialize", func() { | |
357 fplss := []FakePLS{{failSave: true}, {}} | |
358 So(ds.PutMulti(fplss).Error(), ShouldContainSubs tring, "FakePLS.Save") | |
359 }) | |
360 | |
361 Convey("can't get keys", func() { | |
362 fplss := []FakePLS{{failGetMeta: true}, {}} | |
363 So(ds.PutMulti(fplss).Error(), ShouldContainSubs tring, "unable to extract $kind") | |
364 }) | |
365 | |
366 Convey("get single error for RPC failure", func() { | |
367 fplss := []FakePLS{{Kind: "FailAll"}, {}} | |
368 So(ds.PutMulti(fplss).Error(), ShouldEqual, "Put Multi fail all") | |
369 }) | |
370 | |
371 Convey("get multi error for individual failures", func() { | |
372 fplss := []FakePLS{{}, {Kind: "Fail"}} | |
373 So(ds.PutMulti(fplss), ShouldResemble, errors.Mu ltiError{nil, errors.New("PutMulti fail")}) | |
374 }) | |
375 | |
376 Convey("put with non-modifyable type is an error", func( ) { | |
377 cs := CommonStruct{} | |
378 So(ds.Put(cs).Error(), ShouldContainSubstring, " invalid Put input type") | |
379 }) | |
380 }) | |
381 | |
382 Convey("ok", func() { | |
383 Convey("[]S", func() { | |
384 css := make([]CommonStruct, 7) | |
385 for i := range css { | |
386 if i == 4 { | |
387 css[i].ID = 200 | |
388 } | |
389 css[i].Value = int64(i) | |
390 } | |
391 So(ds.PutMulti(css), ShouldBeNil) | |
392 for i, cs := range css { | |
393 expect := int64(i + 1) | |
394 if i == 4 { | |
395 expect = 200 | |
396 } | |
397 So(cs.ID, ShouldEqual, expect) | |
398 } | |
399 }) | |
400 | |
401 Convey("[]*S", func() { | |
402 css := make([]*CommonStruct, 7) | |
403 for i := range css { | |
404 css[i] = &CommonStruct{Value: int64(i)} | |
405 if i == 4 { | |
406 css[i].ID = 200 | |
407 } | |
408 } | |
409 So(ds.PutMulti(css), ShouldBeNil) | |
410 for i, cs := range css { | |
411 expect := int64(i + 1) | |
412 if i == 4 { | |
413 expect = 200 | |
414 } | |
415 So(cs.ID, ShouldEqual, expect) | |
416 } | |
417 | |
418 s := &CommonStruct{} | |
419 So(ds.Put(s), ShouldBeNil) | |
420 So(s.ID, ShouldEqual, 1) | |
421 }) | |
422 | |
423 Convey("[]P", func() { | |
424 fplss := make([]FakePLS, 7) | |
425 for i := range fplss { | |
426 fplss[i].Value = int64(i) | |
427 if i == 4 { | |
428 fplss[i].IntID = int64(200) | |
429 } | |
430 } | |
431 So(ds.PutMulti(fplss), ShouldBeNil) | |
432 for i, fpls := range fplss { | |
433 expect := int64(i + 1) | |
434 if i == 4 { | |
435 expect = 200 | |
436 } | |
437 So(fpls.IntID, ShouldEqual, expect) | |
438 } | |
439 | |
440 pm := PropertyMap{"Value": {MkProperty(0)}, "$ki nd": {MkPropertyNI("Pmap")}} | |
441 So(ds.Put(pm), ShouldBeNil) | |
442 So(ds.KeyForObj(pm).IntID(), ShouldEqual, 1) | |
443 }) | |
444 | |
445 Convey("[]P (map)", func() { | |
446 pms := make([]PropertyMap, 7) | |
447 for i := range pms { | |
448 pms[i] = PropertyMap{ | |
449 "$kind": {MkProperty("Pmap")}, | |
450 "Value": {MkProperty(i)}, | |
451 } | |
452 if i == 4 { | |
453 pms[i].SetMeta("id", int64(200)) | |
454 } | |
455 } | |
456 So(ds.PutMulti(pms), ShouldBeNil) | |
457 for i, pm := range pms { | |
458 expect := int64(i + 1) | |
459 if i == 4 { | |
460 expect = 200 | |
461 } | |
462 So(ds.KeyForObj(pm).String(), ShouldEqua l, fmt.Sprintf("/Pmap,%d", expect)) | |
463 } | |
464 }) | |
465 | |
466 Convey("[]*P", func() { | |
467 fplss := make([]*FakePLS, 7) | |
468 for i := range fplss { | |
469 fplss[i] = &FakePLS{Value: int64(i)} | |
470 if i == 4 { | |
471 fplss[i].IntID = int64(200) | |
472 } | |
473 } | |
474 So(ds.PutMulti(fplss), ShouldBeNil) | |
475 for i, fpls := range fplss { | |
476 expect := int64(i + 1) | |
477 if i == 4 { | |
478 expect = 200 | |
479 } | |
480 So(fpls.IntID, ShouldEqual, expect) | |
481 } | |
482 }) | |
483 | |
484 Convey("[]*P (map)", func() { | |
485 pms := make([]*PropertyMap, 7) | |
486 for i := range pms { | |
487 pms[i] = &PropertyMap{ | |
488 "$kind": {MkProperty("Pmap")}, | |
489 "Value": {MkProperty(i)}, | |
490 } | |
491 if i == 4 { | |
492 pms[i].SetMeta("id", int64(200)) | |
493 } | |
494 } | |
495 So(ds.PutMulti(pms), ShouldBeNil) | |
496 for i, pm := range pms { | |
497 expect := int64(i + 1) | |
498 if i == 4 { | |
499 expect = 200 | |
500 } | |
501 So(ds.KeyForObj(*pm).String(), ShouldEqu al, fmt.Sprintf("/Pmap,%d", expect)) | |
502 } | |
503 }) | |
504 | |
505 Convey("[]I", func() { | |
506 ifs := []interface{}{ | |
507 &CommonStruct{Value: 0}, | |
508 &FakePLS{Value: 1}, | |
509 PropertyMap{"Value": {MkProperty(2)}, "$ kind": {MkPropertyNI("Pmap")}}, | |
510 &PropertyMap{"Value": {MkProperty(3)}, " $kind": {MkPropertyNI("Pmap")}}, | |
511 } | |
512 So(ds.PutMulti(ifs), ShouldBeNil) | |
513 for i := range ifs { | |
514 switch i { | |
515 case 0: | |
516 So(ifs[i].(*CommonStruct).ID, Sh ouldEqual, 1) | |
517 case 1: | |
518 fpls := ifs[i].(*FakePLS) | |
519 So(fpls.IntID, ShouldEqual, 2) | |
520 case 2: | |
521 So(ds.KeyForObj(ifs[i].(Property Map)).String(), ShouldEqual, "/Pmap,3") | |
522 case 3: | |
523 So(ds.KeyForObj(*ifs[i].(*Proper tyMap)).String(), ShouldEqual, "/Pmap,4") | |
524 } | |
525 } | |
526 }) | |
527 | |
528 }) | |
529 | |
530 }) | |
531 } | |
532 | |
533 func TestDelete(t *testing.T) { | |
534 t.Parallel() | |
535 | |
536 Convey("Test Delete/DeleteMulti", t, func() { | |
537 c := info.Set(context.Background(), fakeInfo{}) | |
538 c = SetRawFactory(c, fakeDatastoreFactory) | |
539 ds := Get(c) | |
540 So(ds, ShouldNotBeNil) | |
541 | |
542 Convey("bad", func() { | |
543 Convey("get single error for RPC failure", func() { | |
544 keys := []Key{ | |
545 NewKey("aid", "ns", "FailAll", "", 1, ni l), | |
546 NewKey("aid", "ns", "Ok", "", 1, nil), | |
547 } | |
548 So(ds.DeleteMulti(keys).Error(), ShouldEqual, "D eleteMulti fail all") | |
549 }) | |
550 | |
551 Convey("get multi error for individual failure", func() { | |
552 keys := []Key{ | |
553 ds.NewKey("Ok", "", 1, nil), | |
554 ds.NewKey("Fail", "", 2, nil), | |
555 } | |
556 So(ds.DeleteMulti(keys).Error(), ShouldEqual, "D eleteMulti fail") | |
557 }) | |
558 | |
559 Convey("get single error when deleting a single", func() { | |
560 k := ds.NewKey("Fail", "", 1, nil) | |
561 So(ds.Delete(k).Error(), ShouldEqual, "DeleteMul ti fail") | |
562 }) | |
563 }) | |
564 | |
565 }) | |
566 } | |
567 | |
568 func TestGet(t *testing.T) { | |
569 t.Parallel() | |
570 | |
571 Convey("Test Get/GetMulti", t, func() { | |
572 c := info.Set(context.Background(), fakeInfo{}) | |
573 c = SetRawFactory(c, fakeDatastoreFactory) | |
574 ds := Get(c) | |
575 So(ds, ShouldNotBeNil) | |
576 | |
577 Convey("bad", func() { | |
578 Convey("static can't serialize", func() { | |
579 toGet := []badStruct{{}, {}} | |
580 So(ds.GetMulti(toGet).Error(), ShouldContainSubs tring, "invalid GetMulti input") | |
581 }) | |
582 | |
583 Convey("can't get keys", func() { | |
584 fplss := []FakePLS{{failGetMeta: true}, {}} | |
585 So(ds.GetMulti(fplss).Error(), ShouldContainSubs tring, "unable to extract $kind") | |
586 }) | |
587 | |
588 Convey("get single error for RPC failure", func() { | |
589 fplss := []FakePLS{ | |
590 {IntID: 1, Kind: "FailAll"}, | |
591 {IntID: 2}, | |
592 } | |
593 So(ds.GetMulti(fplss).Error(), ShouldEqual, "Get Multi fail all") | |
594 }) | |
595 | |
596 Convey("get multi error for individual failures", func() { | |
597 fplss := []FakePLS{{IntID: 1}, {IntID: 2, Kind: "Fail"}} | |
598 So(ds.GetMulti(fplss), ShouldResemble, errors.Mu ltiError{nil, errors.New("GetMulti fail")}) | |
599 }) | |
600 | |
601 Convey("get with non-modifiable type is an error", func( ) { | |
602 cs := CommonStruct{} | |
603 So(ds.Get(cs).Error(), ShouldContainSubstring, " invalid Get input type") | |
604 }) | |
605 }) | |
606 | |
607 Convey("ok", func() { | |
608 Convey("Get", func() { | |
609 cs := &CommonStruct{ID: 1} | |
610 So(ds.Get(cs), ShouldBeNil) | |
611 So(cs.Value, ShouldEqual, 1) | |
612 }) | |
613 | |
614 Convey("Raw access too", func() { | |
615 rds := ds.Raw() | |
616 So(rds.GetMulti([]Key{rds.NewKey("Kind", "", 1, nil)}, func(pm PropertyMap, err error) { | |
617 So(err, ShouldBeNil) | |
618 So(pm["Value"][0].Value(), ShouldEqual, 1) | |
619 }), ShouldBeNil) | |
620 }) | |
621 }) | |
622 | |
623 }) | |
624 } | |
625 | |
626 func TestGetAll(t *testing.T) { | |
627 t.Parallel() | |
628 | |
629 Convey("Test GetAll", t, func() { | |
630 c := info.Set(context.Background(), fakeInfo{}) | |
631 c = SetRawFactory(c, fakeDatastoreFactory) | |
632 ds := Get(c) | |
633 So(ds, ShouldNotBeNil) | |
634 | |
635 q := ds.NewQuery("").Limit(5) | |
636 | |
637 Convey("bad", func() { | |
638 Convey("nil target", func() { | |
639 So(ds.GetAll(q, (*[]PropertyMap)(nil)).Error(), ShouldContainSubstring, "dst: <nil>") | |
640 }) | |
641 | |
642 Convey("bad type", func() { | |
643 output := 100 | |
644 So(ds.GetAll(q, &output).Error(), ShouldContainS ubstring, "invalid GetAll input type") | |
645 }) | |
646 | |
647 Convey("bad type (non pointer)", func() { | |
648 So(ds.GetAll(q, "moo").Error(), ShouldContainSub string, "must have a ptr-to-slice") | |
649 }) | |
650 | |
651 Convey("bad type (underspecified)", func() { | |
652 output := []PropertyLoadSaver(nil) | |
653 So(ds.GetAll(q, &output).Error(), ShouldContainS ubstring, "invalid GetAll input type") | |
654 }) | |
655 }) | |
656 | |
657 Convey("ok", func() { | |
658 Convey("*[]S", func() { | |
659 output := []CommonStruct(nil) | |
660 So(ds.GetAll(q, &output), ShouldBeNil) | |
661 So(len(output), ShouldEqual, 5) | |
662 for i, o := range output { | |
663 So(o.ID, ShouldEqual, i+1) | |
664 So(o.Value, ShouldEqual, i) | |
665 } | |
666 }) | |
667 | |
668 Convey("*[]*S", func() { | |
669 output := []*CommonStruct(nil) | |
670 So(ds.GetAll(q, &output), ShouldBeNil) | |
671 So(len(output), ShouldEqual, 5) | |
672 for i, o := range output { | |
673 So(o.ID, ShouldEqual, i+1) | |
674 So(o.Value, ShouldEqual, i) | |
675 } | |
676 }) | |
677 | |
678 Convey("*[]P", func() { | |
679 output := []FakePLS(nil) | |
680 So(ds.GetAll(q, &output), ShouldBeNil) | |
681 So(len(output), ShouldEqual, 5) | |
682 for i, o := range output { | |
683 So(o.gotLoaded, ShouldBeTrue) | |
684 So(o.IntID, ShouldEqual, i+1) | |
685 So(o.Value, ShouldEqual, i) | |
686 } | |
687 }) | |
688 | |
689 Convey("*[]P (map)", func() { | |
690 output := []PropertyMap(nil) | |
691 So(ds.GetAll(q, &output), ShouldBeNil) | |
692 So(len(output), ShouldEqual, 5) | |
693 for i, o := range output { | |
694 k, err := o.GetMeta("key") | |
695 So(err, ShouldBeNil) | |
696 So(k.(Key).IntID(), ShouldEqual, i+1) | |
697 So(o["Value"][0].Value().(int64), Should Equal, i) | |
698 } | |
699 }) | |
700 | |
701 Convey("*[]*P", func() { | |
702 output := []*FakePLS(nil) | |
703 So(ds.GetAll(q, &output), ShouldBeNil) | |
704 So(len(output), ShouldEqual, 5) | |
705 for i, o := range output { | |
706 So(o.gotLoaded, ShouldBeTrue) | |
707 So(o.IntID, ShouldEqual, i+1) | |
708 So(o.Value, ShouldEqual, i) | |
709 } | |
710 }) | |
711 | |
712 Convey("*[]*P (map)", func() { | |
713 output := []*PropertyMap(nil) | |
714 So(ds.GetAll(q, &output), ShouldBeNil) | |
715 So(len(output), ShouldEqual, 5) | |
716 for i, op := range output { | |
717 o := *op | |
718 k, err := o.GetMeta("key") | |
719 So(err, ShouldBeNil) | |
720 So(k.(Key).IntID(), ShouldEqual, i+1) | |
721 So(o["Value"][0].Value().(int64), Should Equal, i) | |
722 } | |
723 }) | |
724 | |
725 Convey("*[]Key", func() { | |
726 output := []Key(nil) | |
727 So(ds.GetAll(q, &output), ShouldBeNil) | |
728 So(len(output), ShouldEqual, 5) | |
729 for i, k := range output { | |
730 So(k.IntID(), ShouldEqual, i+1) | |
731 } | |
732 }) | |
733 | |
734 }) | |
735 }) | |
736 } | |
737 | |
738 func TestRun(t *testing.T) { | |
739 t.Parallel() | |
740 | |
741 Convey("Test Run", t, func() { | |
742 c := info.Set(context.Background(), fakeInfo{}) | |
743 c = SetRawFactory(c, fakeDatastoreFactory) | |
744 ds := Get(c) | |
745 So(ds, ShouldNotBeNil) | |
746 | |
747 q := ds.NewQuery("").Limit(5) | |
748 | |
749 Convey("bad", func() { | |
750 Convey("bad proto type", func() { | |
751 So(ds.Run(q, 100, func(obj interface{}, _ func() (Cursor, error)) bool { | |
752 panic("never here!") | |
753 }).Error(), ShouldContainSubstring, "invalid Run proto type") | |
754 }) | |
755 | |
756 Convey("early abort on error", func() { | |
757 rq := q.(*fakeQuery).Fail(3) | |
758 i := 0 | |
759 So(ds.Run(rq, CommonStruct{}, func(_ interface{} , _ func() (Cursor, error)) bool { | |
760 i++ | |
761 return true | |
762 }).Error(), ShouldEqual, "Query fail") | |
763 So(i, ShouldEqual, 3) | |
764 }) | |
765 | |
766 Convey("return error on serialization failure", func() { | |
767 So(ds.Run(q, permaBad{}, func(_ interface{}, _ f unc() (Cursor, error)) bool { | |
768 panic("never here") | |
769 }).Error(), ShouldEqual, "permaBad") | |
770 }) | |
771 }) | |
772 | |
773 Convey("ok", func() { | |
774 Convey("*S", func() { | |
775 i := 0 | |
776 So(ds.Run(q, (*CommonStruct)(nil), func(obj inte rface{}, _ func() (Cursor, error)) bool { | |
777 cs := obj.(*CommonStruct) | |
778 So(cs.ID, ShouldEqual, i+1) | |
779 So(cs.Value, ShouldEqual, i) | |
780 i++ | |
781 return true | |
782 }), ShouldBeNil) | |
783 }) | |
784 | |
785 Convey("*P", func() { | |
786 i := 0 | |
787 So(ds.Run(q.Limit(12), (*FakePLS)(nil), func(obj interface{}, _ func() (Cursor, error)) bool { | |
788 fpls := obj.(*FakePLS) | |
789 So(fpls.gotLoaded, ShouldBeTrue) | |
790 if i == 10 { | |
791 So(fpls.StringID, ShouldEqual, " eleven") | |
792 } else { | |
793 So(fpls.IntID, ShouldEqual, i+1) | |
794 } | |
795 So(fpls.Value, ShouldEqual, i) | |
796 i++ | |
797 return true | |
798 }), ShouldBeNil) | |
799 }) | |
800 | |
801 Convey("*P (map)", func() { | |
802 i := 0 | |
803 So(ds.Run(q, (*PropertyMap)(nil), func(obj inter face{}, _ func() (Cursor, error)) bool { | |
804 pm := *obj.(*PropertyMap) | |
805 k, err := pm.GetMeta("key") | |
806 So(err, ShouldBeNil) | |
807 So(k.(Key).IntID(), ShouldEqual, i+1) | |
808 So(pm["Value"][0].Value(), ShouldEqual, i) | |
809 i++ | |
810 return true | |
811 }), ShouldBeNil) | |
812 }) | |
813 | |
814 Convey("S", func() { | |
815 i := 0 | |
816 So(ds.Run(q, CommonStruct{}, func(obj interface{ }, _ func() (Cursor, error)) bool { | |
817 cs := obj.(CommonStruct) | |
818 So(cs.ID, ShouldEqual, i+1) | |
819 So(cs.Value, ShouldEqual, i) | |
820 i++ | |
821 return true | |
822 }), ShouldBeNil) | |
823 }) | |
824 | |
825 Convey("P", func() { | |
826 i := 0 | |
827 So(ds.Run(q, FakePLS{}, func(obj interface{}, _ func() (Cursor, error)) bool { | |
828 fpls := obj.(FakePLS) | |
829 So(fpls.gotLoaded, ShouldBeTrue) | |
830 So(fpls.IntID, ShouldEqual, i+1) | |
831 So(fpls.Value, ShouldEqual, i) | |
832 i++ | |
833 return true | |
834 }), ShouldBeNil) | |
835 }) | |
836 | |
837 Convey("P (map)", func() { | |
838 i := 0 | |
839 So(ds.Run(q, (PropertyMap)(nil), func(obj interf ace{}, _ func() (Cursor, error)) bool { | |
840 pm := obj.(PropertyMap) | |
841 k, err := pm.GetMeta("key") | |
842 So(err, ShouldBeNil) | |
843 So(k.(Key).IntID(), ShouldEqual, i+1) | |
844 So(pm["Value"][0].Value(), ShouldEqual, i) | |
845 i++ | |
846 return true | |
847 }), ShouldBeNil) | |
848 }) | |
849 | |
850 Convey("*Key", func() { | |
851 i := 0 | |
852 So(ds.Run(q, (*Key)(nil), func(obj interface{}, _ func() (Cursor, error)) bool { | |
853 So(obj.(Key).IntID(), ShouldEqual, i+1) | |
854 i++ | |
855 return true | |
856 }), ShouldBeNil) | |
857 }) | |
858 | |
859 }) | |
860 }) | |
861 } | |
OLD | NEW |