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

Unified Diff: service/datastore/datastore_test.go

Issue 1259593005: Add 'user friendly' datastore API. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: 100% coverage of new code Created 5 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: service/datastore/datastore_test.go
diff --git a/service/datastore/datastore_test.go b/service/datastore/datastore_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..383a39ef0f1fd713522a77e9ce2369f5b37c22e4
--- /dev/null
+++ b/service/datastore/datastore_test.go
@@ -0,0 +1,861 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// adapted from github.com/golang/appengine/datastore
+
+package datastore
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/luci/gae/service/info"
+ "github.com/luci/luci-go/common/errors"
+ . "github.com/smartystreets/goconvey/convey"
+ "golang.org/x/net/context"
+)
+
+func fakeDatastoreFactory(c context.Context) RawInterface {
iannucci 2015/08/03 04:00:34 This file is basically completely different now. D
+ i := info.Get(c)
+ return &fakeDatastore{
+ aid: i.AppID(),
+ ns: i.GetNamespace(),
+ }
+}
+
+type fakeQuery struct {
+ Query
+
+ limit int
+
+ err error
+ errSingle error
+ errSingleIdx int
+}
+
+func (q *fakeQuery) KeysOnly() Query {
+ return q
+}
+
+func (q *fakeQuery) Limit(i int) Query {
+ q.limit = i
+ return q
+}
+
+func (q *fakeQuery) FailAll() Query {
+ q.err = errors.New("Query fail all")
+ return q
+}
+
+func (q *fakeQuery) Fail(i int) Query {
+ q.errSingleIdx = i
+ q.errSingle = errors.New("Query fail")
+ return q
+}
+
+type fakeDatastore struct {
+ RawInterface
+ aid string
+ ns string
+}
+
+func (f *fakeDatastore) NewKey(kind, stringID string, intID int64, parent Key) Key {
+ return NewKey(f.aid, f.ns, kind, stringID, intID, parent)
+}
+
+func (f *fakeDatastore) NewQuery(string) Query {
+ return &fakeQuery{}
+}
+
+func (f *fakeDatastore) Run(q Query, cb RawRunCB) error {
+ rq := q.(*fakeQuery)
+ if rq.err != nil {
+ return rq.err
+ }
+ for i := 0; i < rq.limit; i++ {
+ if rq.errSingle != nil && i == rq.errSingleIdx {
+ return rq.errSingle
+ } else {
+ k := f.NewKey("Kind", "", int64(i+1), nil)
+ if i == 10 {
+ k = f.NewKey("Kind", "eleven", 0, nil)
+ }
+ pm := PropertyMap{"Value": {MkProperty(i)}}
+ if !cb(k, pm, nil) {
+ break
+ }
+ }
+ }
+ return nil
+}
+
+func (f *fakeDatastore) PutMulti(keys []Key, vals []PropertyMap, cb PutMultiCB) error {
+ if keys[0].Kind() == "FailAll" {
+ return errors.New("PutMulti fail all")
+ }
+ assertExtra := false
+ if _, err := vals[0].GetMeta("assertExtra"); err == nil {
+ assertExtra = true
+ }
+ for i, k := range keys {
+ err := error(nil)
+ if k.Kind() == "Fail" {
+ err = errors.New("PutMulti fail")
+ } else {
+ So(vals[i]["Value"], ShouldResemble, []Property{MkProperty(i)})
+ if assertExtra {
+ So(vals[i]["Extra"], ShouldResemble, []Property{MkProperty("whoa")})
+ }
+ if KeyIncomplete(k) {
+ k = NewKey(k.AppID(), k.Namespace(), k.Kind(), "", int64(i+1), k.Parent())
+ }
+ }
+ cb(k, err)
+ }
+ return nil
+}
+
+func (f *fakeDatastore) GetMulti(keys []Key, cb GetMultiCB) error {
+ if keys[0].Kind() == "FailAll" {
+ return errors.New("GetMulti fail all")
+ }
+ for i, k := range keys {
+ if k.Kind() == "Fail" {
+ cb(nil, errors.New("GetMulti fail"))
+ } else {
+ cb(PropertyMap{"Value": {MkProperty(i + 1)}}, nil)
+ }
+ }
+ return nil
+}
+
+func (f *fakeDatastore) DeleteMulti(keys []Key, cb DeleteMultiCB) error {
+ if keys[0].Kind() == "FailAll" {
+ return errors.New("DeleteMulti fail all")
+ }
+ for _, k := range keys {
+ if k.Kind() == "Fail" {
+ cb(errors.New("DeleteMulti fail"))
+ } else {
+ cb(nil)
+ }
+ }
+ return nil
+}
+
+type badStruct struct {
+ ID int64 `gae:"$id"`
+ Compy complex64 // bad type
+}
+
+type CommonStruct struct {
+ ID int64 `gae:"$id"`
+ Parent Key `gae:"$parent"`
+
+ Value int64
+}
+
+type permaBad struct {
+ PropertyLoadSaver
+}
+
+func (f *permaBad) Load(pm PropertyMap) error {
+ return errors.New("permaBad")
+}
+
+type FakePLS struct {
+ IntID int64
+ StringID string
+ Kind string
+
+ Value int64
+ gotLoaded bool
+
+ failGetMeta bool
+ failLoad bool
+ failProblem bool
+ failSave bool
+ failSaveMeta bool
+}
+
+func (f *FakePLS) Load(pm PropertyMap) error {
+ if f.failLoad {
+ return errors.New("FakePLS.Load")
+ }
+ f.gotLoaded = true
+ f.Value = pm["Value"][0].Value().(int64)
+ return nil
+}
+
+func (f *FakePLS) Save(withMeta bool) (PropertyMap, error) {
+ if f.failSave {
+ return nil, errors.New("FakePLS.Save")
+ }
+ ret := PropertyMap{
+ "Value": {MkProperty(f.Value)},
+ "Extra": {MkProperty("whoa")},
+ }
+ if withMeta {
+ id, _ := f.GetMeta("id")
+ ret.SetMeta("id", id)
+ if f.Kind == "" {
+ ret.SetMeta("kind", "FakePLS")
+ } else {
+ ret.SetMeta("kind", f.Kind)
+ }
+ ret.SetMeta("assertExtra", true)
+ }
+ return ret, nil
+}
+
+func (f *FakePLS) GetMeta(key string) (interface{}, error) {
+ if f.failGetMeta {
+ return nil, errors.New("FakePLS.GetMeta")
+ }
+ switch key {
+ case "id":
+ if f.StringID != "" {
+ return f.StringID, nil
+ }
+ return f.IntID, nil
+ case "kind":
+ if f.Kind == "" {
+ return "FakePLS", nil
+ }
+ return f.Kind, nil
+ }
+ return nil, ErrMetaFieldUnset
+}
+
+func (f *FakePLS) SetMeta(key string, val interface{}) error {
+ if f.failSaveMeta {
+ return errors.New("FakePL.SetMeta")
+ }
+ if key == "id" {
+ switch x := val.(type) {
+ case int64:
+ f.IntID = x
+ case string:
+ f.StringID = x
+ }
+ return nil
+ }
+ if key == "kind" {
+ f.Kind = val.(string)
+ return nil
+ }
+ return ErrMetaFieldUnset
+}
+
+func (f *FakePLS) Problem() error {
+ if f.failProblem {
+ return errors.New("FakePLS.Problem")
+ }
+ return nil
+}
+
+func TestKeyForObj(t *testing.T) {
+ t.Parallel()
+
+ Convey("Test interface.KeyForObj", t, func() {
+ c := info.Set(context.Background(), fakeInfo{})
+ c = SetRawFactory(c, fakeDatastoreFactory)
+ ds := Get(c)
+
+ k := ds.NewKey("Hello", "world", 0, nil)
+
+ Convey("good", func() {
+ Convey("struct containing $key", func() {
+ type keyStruct struct {
+ Key Key `gae:"$key"`
+ }
+
+ ks := &keyStruct{k}
+ So(ds.KeyForObj(ks), ShouldEqual, k)
+ })
+
+ Convey("struct containing default $id and $kind", func() {
+ type idStruct struct {
+ id string `gae:"$id,wut"`
+ knd string `gae:"$kind,SuperKind"`
+ }
+
+ So(ds.KeyForObj(&idStruct{}).String(), ShouldEqual, `/SuperKind,wut`)
+ })
+
+ Convey("struct containing $id and $parent", func() {
+ So(ds.KeyForObj(&CommonStruct{ID: 4}).String(), ShouldEqual, `/CommonStruct,4`)
+
+ So(ds.KeyForObj(&CommonStruct{ID: 4, Parent: k}).String(), ShouldEqual, `/Hello,world/CommonStruct,4`)
+ })
+
+ Convey("a propmap with $key", func() {
+ pm := PropertyMap{}
+ pm.SetMeta("key", k)
+ So(ds.KeyForObj(pm).String(), ShouldEqual, `/Hello,world`)
+ })
+
+ Convey("a propmap with $id, $kind, $parent", func() {
+ pm := PropertyMap{}
+ pm.SetMeta("id", 100)
+ pm.SetMeta("kind", "Sup")
+ So(ds.KeyForObj(pm).String(), ShouldEqual, `/Sup,100`)
+
+ pm.SetMeta("parent", k)
+ So(ds.KeyForObj(pm).String(), ShouldEqual, `/Hello,world/Sup,100`)
+ })
+
+ Convey("a pls with $id, $parent", func() {
+ pls := GetPLS(&CommonStruct{ID: 1})
+ So(ds.KeyForObj(pls).String(), ShouldEqual, `/CommonStruct,1`)
+
+ pls.SetMeta("parent", k)
+ So(ds.KeyForObj(pls).String(), ShouldEqual, `/Hello,world/CommonStruct,1`)
+ })
+
+ })
+
+ Convey("bad", func() {
+ Convey("a propmap without $kind", func() {
+ pm := PropertyMap{}
+ pm.SetMeta("id", 100)
+ So(func() { ds.KeyForObj(pm) }, ShouldPanic)
+ })
+ })
+ })
+}
+
+func TestPut(t *testing.T) {
+ t.Parallel()
+
+ Convey("Test Put/PutMulti", t, func() {
+ c := info.Set(context.Background(), fakeInfo{})
+ c = SetRawFactory(c, fakeDatastoreFactory)
+ ds := Get(c)
+
+ Convey("bad", func() {
+ Convey("static can't serialize", func() {
+ bss := []badStruct{{}, {}}
+ So(ds.PutMulti(bss).Error(), ShouldContainSubstring, "invalid PutMulti input")
+ })
+
+ Convey("static ptr can't serialize", func() {
+ bss := []*badStruct{{}, {}}
+ So(ds.PutMulti(bss).Error(), ShouldContainSubstring, "invalid PutMulti input")
+ })
+
+ Convey("static bad type (non-slice)", func() {
+ So(ds.PutMulti(100).Error(), ShouldContainSubstring, "invalid PutMulti input")
+ })
+
+ Convey("static bad type (slice of bad type)", func() {
+ So(ds.PutMulti([]int{}).Error(), ShouldContainSubstring, "invalid PutMulti input")
+ })
+
+ Convey("dynamic can't serialize", func() {
+ fplss := []FakePLS{{failSave: true}, {}}
+ So(ds.PutMulti(fplss).Error(), ShouldContainSubstring, "FakePLS.Save")
+ })
+
+ Convey("can't get keys", func() {
+ fplss := []FakePLS{{failGetMeta: true}, {}}
+ So(ds.PutMulti(fplss).Error(), ShouldContainSubstring, "unable to extract $kind")
+ })
+
+ Convey("get single error for RPC failure", func() {
+ fplss := []FakePLS{{Kind: "FailAll"}, {}}
+ So(ds.PutMulti(fplss).Error(), ShouldEqual, "PutMulti fail all")
+ })
+
+ Convey("get multi error for individual failures", func() {
+ fplss := []FakePLS{{}, {Kind: "Fail"}}
+ So(ds.PutMulti(fplss), ShouldResemble, errors.MultiError{nil, errors.New("PutMulti fail")})
+ })
+
+ Convey("put with non-modifyable type is an error", func() {
+ cs := CommonStruct{}
+ So(ds.Put(cs).Error(), ShouldContainSubstring, "invalid Put input type")
+ })
+ })
+
+ Convey("ok", func() {
+ Convey("[]S", func() {
+ css := make([]CommonStruct, 7)
+ for i := range css {
+ if i == 4 {
+ css[i].ID = 200
+ }
+ css[i].Value = int64(i)
+ }
+ So(ds.PutMulti(css), ShouldBeNil)
+ for i, cs := range css {
+ expect := int64(i + 1)
+ if i == 4 {
+ expect = 200
+ }
+ So(cs.ID, ShouldEqual, expect)
+ }
+ })
+
+ Convey("[]*S", func() {
+ css := make([]*CommonStruct, 7)
+ for i := range css {
+ css[i] = &CommonStruct{Value: int64(i)}
+ if i == 4 {
+ css[i].ID = 200
+ }
+ }
+ So(ds.PutMulti(css), ShouldBeNil)
+ for i, cs := range css {
+ expect := int64(i + 1)
+ if i == 4 {
+ expect = 200
+ }
+ So(cs.ID, ShouldEqual, expect)
+ }
+
+ s := &CommonStruct{}
+ So(ds.Put(s), ShouldBeNil)
+ So(s.ID, ShouldEqual, 1)
+ })
+
+ Convey("[]P", func() {
+ fplss := make([]FakePLS, 7)
+ for i := range fplss {
+ fplss[i].Value = int64(i)
+ if i == 4 {
+ fplss[i].IntID = int64(200)
+ }
+ }
+ So(ds.PutMulti(fplss), ShouldBeNil)
+ for i, fpls := range fplss {
+ expect := int64(i + 1)
+ if i == 4 {
+ expect = 200
+ }
+ So(fpls.IntID, ShouldEqual, expect)
+ }
+
+ pm := PropertyMap{"Value": {MkProperty(0)}, "$kind": {MkPropertyNI("Pmap")}}
+ So(ds.Put(pm), ShouldBeNil)
+ So(ds.KeyForObj(pm).IntID(), ShouldEqual, 1)
+ })
+
+ Convey("[]P (map)", func() {
+ pms := make([]PropertyMap, 7)
+ for i := range pms {
+ pms[i] = PropertyMap{
+ "$kind": {MkProperty("Pmap")},
+ "Value": {MkProperty(i)},
+ }
+ if i == 4 {
+ pms[i].SetMeta("id", int64(200))
+ }
+ }
+ So(ds.PutMulti(pms), ShouldBeNil)
+ for i, pm := range pms {
+ expect := int64(i + 1)
+ if i == 4 {
+ expect = 200
+ }
+ So(ds.KeyForObj(pm).String(), ShouldEqual, fmt.Sprintf("/Pmap,%d", expect))
+ }
+ })
+
+ Convey("[]*P", func() {
+ fplss := make([]*FakePLS, 7)
+ for i := range fplss {
+ fplss[i] = &FakePLS{Value: int64(i)}
+ if i == 4 {
+ fplss[i].IntID = int64(200)
+ }
+ }
+ So(ds.PutMulti(fplss), ShouldBeNil)
+ for i, fpls := range fplss {
+ expect := int64(i + 1)
+ if i == 4 {
+ expect = 200
+ }
+ So(fpls.IntID, ShouldEqual, expect)
+ }
+ })
+
+ Convey("[]*P (map)", func() {
+ pms := make([]*PropertyMap, 7)
+ for i := range pms {
+ pms[i] = &PropertyMap{
+ "$kind": {MkProperty("Pmap")},
+ "Value": {MkProperty(i)},
+ }
+ if i == 4 {
+ pms[i].SetMeta("id", int64(200))
+ }
+ }
+ So(ds.PutMulti(pms), ShouldBeNil)
+ for i, pm := range pms {
+ expect := int64(i + 1)
+ if i == 4 {
+ expect = 200
+ }
+ So(ds.KeyForObj(*pm).String(), ShouldEqual, fmt.Sprintf("/Pmap,%d", expect))
+ }
+ })
+
+ Convey("[]I", func() {
+ ifs := []interface{}{
+ &CommonStruct{Value: 0},
+ &FakePLS{Value: 1},
+ PropertyMap{"Value": {MkProperty(2)}, "$kind": {MkPropertyNI("Pmap")}},
+ &PropertyMap{"Value": {MkProperty(3)}, "$kind": {MkPropertyNI("Pmap")}},
+ }
+ So(ds.PutMulti(ifs), ShouldBeNil)
+ for i := range ifs {
+ switch i {
+ case 0:
+ So(ifs[i].(*CommonStruct).ID, ShouldEqual, 1)
+ case 1:
+ fpls := ifs[i].(*FakePLS)
+ So(fpls.IntID, ShouldEqual, 2)
+ case 2:
+ So(ds.KeyForObj(ifs[i].(PropertyMap)).String(), ShouldEqual, "/Pmap,3")
+ case 3:
+ So(ds.KeyForObj(*ifs[i].(*PropertyMap)).String(), ShouldEqual, "/Pmap,4")
+ }
+ }
+ })
+
+ })
+
+ })
+}
+
+func TestDelete(t *testing.T) {
+ t.Parallel()
+
+ Convey("Test Delete/DeleteMulti", t, func() {
+ c := info.Set(context.Background(), fakeInfo{})
+ c = SetRawFactory(c, fakeDatastoreFactory)
+ ds := Get(c)
+ So(ds, ShouldNotBeNil)
+
+ Convey("bad", func() {
+ Convey("get single error for RPC failure", func() {
+ keys := []Key{
+ NewKey("aid", "ns", "FailAll", "", 1, nil),
+ NewKey("aid", "ns", "Ok", "", 1, nil),
+ }
+ So(ds.DeleteMulti(keys).Error(), ShouldEqual, "DeleteMulti fail all")
+ })
+
+ Convey("get multi error for individual failure", func() {
+ keys := []Key{
+ ds.NewKey("Ok", "", 1, nil),
+ ds.NewKey("Fail", "", 2, nil),
+ }
+ So(ds.DeleteMulti(keys).Error(), ShouldEqual, "DeleteMulti fail")
+ })
+
+ Convey("get single error when deleting a single", func() {
+ k := ds.NewKey("Fail", "", 1, nil)
+ So(ds.Delete(k).Error(), ShouldEqual, "DeleteMulti fail")
+ })
+ })
+
+ })
+}
+
+func TestGet(t *testing.T) {
+ t.Parallel()
+
+ Convey("Test Get/GetMulti", t, func() {
+ c := info.Set(context.Background(), fakeInfo{})
+ c = SetRawFactory(c, fakeDatastoreFactory)
+ ds := Get(c)
+ So(ds, ShouldNotBeNil)
+
+ Convey("bad", func() {
+ Convey("static can't serialize", func() {
+ toGet := []badStruct{{}, {}}
+ So(ds.GetMulti(toGet).Error(), ShouldContainSubstring, "invalid GetMulti input")
+ })
+
+ Convey("can't get keys", func() {
+ fplss := []FakePLS{{failGetMeta: true}, {}}
+ So(ds.GetMulti(fplss).Error(), ShouldContainSubstring, "unable to extract $kind")
+ })
+
+ Convey("get single error for RPC failure", func() {
+ fplss := []FakePLS{
+ {IntID: 1, Kind: "FailAll"},
+ {IntID: 2},
+ }
+ So(ds.GetMulti(fplss).Error(), ShouldEqual, "GetMulti fail all")
+ })
+
+ Convey("get multi error for individual failures", func() {
+ fplss := []FakePLS{{IntID: 1}, {IntID: 2, Kind: "Fail"}}
+ So(ds.GetMulti(fplss), ShouldResemble, errors.MultiError{nil, errors.New("GetMulti fail")})
+ })
+
+ Convey("get with non-modifiable type is an error", func() {
+ cs := CommonStruct{}
+ So(ds.Get(cs).Error(), ShouldContainSubstring, "invalid Get input type")
+ })
+ })
+
+ Convey("ok", func() {
+ Convey("Get", func() {
+ cs := &CommonStruct{ID: 1}
+ So(ds.Get(cs), ShouldBeNil)
+ So(cs.Value, ShouldEqual, 1)
+ })
+
+ Convey("Raw access too", func() {
+ rds := ds.Raw()
+ So(rds.GetMulti([]Key{rds.NewKey("Kind", "", 1, nil)}, func(pm PropertyMap, err error) {
+ So(err, ShouldBeNil)
+ So(pm["Value"][0].Value(), ShouldEqual, 1)
+ }), ShouldBeNil)
+ })
+ })
+
+ })
+}
+
+func TestGetAll(t *testing.T) {
+ t.Parallel()
+
+ Convey("Test GetAll", t, func() {
+ c := info.Set(context.Background(), fakeInfo{})
+ c = SetRawFactory(c, fakeDatastoreFactory)
+ ds := Get(c)
+ So(ds, ShouldNotBeNil)
+
+ q := ds.NewQuery("").Limit(5)
+
+ Convey("bad", func() {
+ Convey("nil target", func() {
+ So(ds.GetAll(q, (*[]PropertyMap)(nil)).Error(), ShouldContainSubstring, "dst: <nil>")
+ })
+
+ Convey("bad type", func() {
+ output := 100
+ So(ds.GetAll(q, &output).Error(), ShouldContainSubstring, "invalid GetAll input type")
+ })
+
+ Convey("bad type (non pointer)", func() {
+ So(ds.GetAll(q, "moo").Error(), ShouldContainSubstring, "must have a ptr-to-slice")
+ })
+
+ Convey("bad type (underspecified)", func() {
+ output := []PropertyLoadSaver(nil)
+ So(ds.GetAll(q, &output).Error(), ShouldContainSubstring, "invalid GetAll input type")
+ })
+ })
+
+ Convey("ok", func() {
+ Convey("*[]S", func() {
+ output := []CommonStruct(nil)
+ So(ds.GetAll(q, &output), ShouldBeNil)
+ So(len(output), ShouldEqual, 5)
+ for i, o := range output {
+ So(o.ID, ShouldEqual, i+1)
+ So(o.Value, ShouldEqual, i)
+ }
+ })
+
+ Convey("*[]*S", func() {
+ output := []*CommonStruct(nil)
+ So(ds.GetAll(q, &output), ShouldBeNil)
+ So(len(output), ShouldEqual, 5)
+ for i, o := range output {
+ So(o.ID, ShouldEqual, i+1)
+ So(o.Value, ShouldEqual, i)
+ }
+ })
+
+ Convey("*[]P", func() {
+ output := []FakePLS(nil)
+ So(ds.GetAll(q, &output), ShouldBeNil)
+ So(len(output), ShouldEqual, 5)
+ for i, o := range output {
+ So(o.gotLoaded, ShouldBeTrue)
+ So(o.IntID, ShouldEqual, i+1)
+ So(o.Value, ShouldEqual, i)
+ }
+ })
+
+ Convey("*[]P (map)", func() {
+ output := []PropertyMap(nil)
+ So(ds.GetAll(q, &output), ShouldBeNil)
+ So(len(output), ShouldEqual, 5)
+ for i, o := range output {
+ k, err := o.GetMeta("key")
+ So(err, ShouldBeNil)
+ So(k.(Key).IntID(), ShouldEqual, i+1)
+ So(o["Value"][0].Value().(int64), ShouldEqual, i)
+ }
+ })
+
+ Convey("*[]*P", func() {
+ output := []*FakePLS(nil)
+ So(ds.GetAll(q, &output), ShouldBeNil)
+ So(len(output), ShouldEqual, 5)
+ for i, o := range output {
+ So(o.gotLoaded, ShouldBeTrue)
+ So(o.IntID, ShouldEqual, i+1)
+ So(o.Value, ShouldEqual, i)
+ }
+ })
+
+ Convey("*[]*P (map)", func() {
+ output := []*PropertyMap(nil)
+ So(ds.GetAll(q, &output), ShouldBeNil)
+ So(len(output), ShouldEqual, 5)
+ for i, op := range output {
+ o := *op
+ k, err := o.GetMeta("key")
+ So(err, ShouldBeNil)
+ So(k.(Key).IntID(), ShouldEqual, i+1)
+ So(o["Value"][0].Value().(int64), ShouldEqual, i)
+ }
+ })
+
+ Convey("*[]Key", func() {
+ output := []Key(nil)
+ So(ds.GetAll(q, &output), ShouldBeNil)
+ So(len(output), ShouldEqual, 5)
+ for i, k := range output {
+ So(k.IntID(), ShouldEqual, i+1)
+ }
+ })
+
+ })
+ })
+}
+
+func TestRun(t *testing.T) {
+ t.Parallel()
+
+ Convey("Test Run", t, func() {
+ c := info.Set(context.Background(), fakeInfo{})
+ c = SetRawFactory(c, fakeDatastoreFactory)
+ ds := Get(c)
+ So(ds, ShouldNotBeNil)
+
+ q := ds.NewQuery("").Limit(5)
+
+ Convey("bad", func() {
+ Convey("bad proto type", func() {
+ So(ds.Run(q, 100, func(obj interface{}, _ func() (Cursor, error)) bool {
+ panic("never here!")
+ }).Error(), ShouldContainSubstring, "invalid Run proto type")
+ })
+
+ Convey("early abort on error", func() {
+ rq := q.(*fakeQuery).Fail(3)
+ i := 0
+ So(ds.Run(rq, CommonStruct{}, func(_ interface{}, _ func() (Cursor, error)) bool {
+ i++
+ return true
+ }).Error(), ShouldEqual, "Query fail")
+ So(i, ShouldEqual, 3)
+ })
+
+ Convey("return error on serialization failure", func() {
+ So(ds.Run(q, permaBad{}, func(_ interface{}, _ func() (Cursor, error)) bool {
+ panic("never here")
+ }).Error(), ShouldEqual, "permaBad")
+ })
+ })
+
+ Convey("ok", func() {
+ Convey("*S", func() {
+ i := 0
+ So(ds.Run(q, (*CommonStruct)(nil), func(obj interface{}, _ func() (Cursor, error)) bool {
+ cs := obj.(*CommonStruct)
+ So(cs.ID, ShouldEqual, i+1)
+ So(cs.Value, ShouldEqual, i)
+ i++
+ return true
+ }), ShouldBeNil)
+ })
+
+ Convey("*P", func() {
+ i := 0
+ So(ds.Run(q.Limit(12), (*FakePLS)(nil), func(obj interface{}, _ func() (Cursor, error)) bool {
+ fpls := obj.(*FakePLS)
+ So(fpls.gotLoaded, ShouldBeTrue)
+ if i == 10 {
+ So(fpls.StringID, ShouldEqual, "eleven")
+ } else {
+ So(fpls.IntID, ShouldEqual, i+1)
+ }
+ So(fpls.Value, ShouldEqual, i)
+ i++
+ return true
+ }), ShouldBeNil)
+ })
+
+ Convey("*P (map)", func() {
+ i := 0
+ So(ds.Run(q, (*PropertyMap)(nil), func(obj interface{}, _ func() (Cursor, error)) bool {
+ pm := *obj.(*PropertyMap)
+ k, err := pm.GetMeta("key")
+ So(err, ShouldBeNil)
+ So(k.(Key).IntID(), ShouldEqual, i+1)
+ So(pm["Value"][0].Value(), ShouldEqual, i)
+ i++
+ return true
+ }), ShouldBeNil)
+ })
+
+ Convey("S", func() {
+ i := 0
+ So(ds.Run(q, CommonStruct{}, func(obj interface{}, _ func() (Cursor, error)) bool {
+ cs := obj.(CommonStruct)
+ So(cs.ID, ShouldEqual, i+1)
+ So(cs.Value, ShouldEqual, i)
+ i++
+ return true
+ }), ShouldBeNil)
+ })
+
+ Convey("P", func() {
+ i := 0
+ So(ds.Run(q, FakePLS{}, func(obj interface{}, _ func() (Cursor, error)) bool {
+ fpls := obj.(FakePLS)
+ So(fpls.gotLoaded, ShouldBeTrue)
+ So(fpls.IntID, ShouldEqual, i+1)
+ So(fpls.Value, ShouldEqual, i)
+ i++
+ return true
+ }), ShouldBeNil)
+ })
+
+ Convey("P (map)", func() {
+ i := 0
+ So(ds.Run(q, (PropertyMap)(nil), func(obj interface{}, _ func() (Cursor, error)) bool {
+ pm := obj.(PropertyMap)
+ k, err := pm.GetMeta("key")
+ So(err, ShouldBeNil)
+ So(k.(Key).IntID(), ShouldEqual, i+1)
+ So(pm["Value"][0].Value(), ShouldEqual, i)
+ i++
+ return true
+ }), ShouldBeNil)
+ })
+
+ Convey("*Key", func() {
+ i := 0
+ So(ds.Run(q, (*Key)(nil), func(obj interface{}, _ func() (Cursor, error)) bool {
+ So(obj.(Key).IntID(), ShouldEqual, i+1)
+ i++
+ return true
+ }), ShouldBeNil)
+ })
+
+ })
+ })
+}

Powered by Google App Engine
This is Rietveld 408576698