Index: service/datastore/datastore_test.go |
diff --git a/service/datastore/datastore_test.go b/service/datastore/datastore_test.go |
index 27db51af6233a23cbc17265eeecf2064951d65c3..09fa63515e1fbae50678fe7fe59c0eb9c70356f9 100644 |
--- a/service/datastore/datastore_test.go |
+++ b/service/datastore/datastore_test.go |
@@ -70,15 +70,20 @@ func (f *fakeDatastore) Run(fq *FinalizedQuery, cb RawRunCB) error { |
return nil |
} |
+var ( |
+ errFail = errors.New("Individual element fail") |
+ errFailAll = errors.New("Operation fail") |
+) |
+ |
func (f *fakeDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb PutMultiCB) error { |
if keys[0].Kind() == "FailAll" { |
- return errors.New("PutMulti fail all") |
+ return errFailAll |
} |
_, assertExtra := vals[0].GetMeta("assertExtra") |
for i, k := range keys { |
err := error(nil) |
if k.Kind() == "Fail" { |
- err = errors.New("PutMulti fail") |
+ err = errFail |
} else { |
So(vals[i]["Value"], ShouldResemble, []Property{MkProperty(i)}) |
if assertExtra { |
@@ -93,14 +98,16 @@ func (f *fakeDatastore) PutMulti(keys []*Key, vals []PropertyMap, cb PutMultiCB) |
return nil |
} |
+const noSuchEntityID = 0xdead |
+ |
func (f *fakeDatastore) GetMulti(keys []*Key, _meta MultiMetaGetter, cb GetMultiCB) error { |
if keys[0].Kind() == "FailAll" { |
- return errors.New("GetMulti fail all") |
+ return errFailAll |
} |
for i, k := range keys { |
if k.Kind() == "Fail" { |
- cb(nil, errors.New("GetMulti fail")) |
- } else if k.Kind() == "DNE" { |
+ cb(nil, errFail) |
+ } else if k.Kind() == "DNE" || k.IntID() == noSuchEntityID { |
cb(nil, ErrNoSuchEntity) |
} else { |
cb(PropertyMap{"Value": {MkProperty(i + 1)}}, nil) |
@@ -111,11 +118,13 @@ func (f *fakeDatastore) GetMulti(keys []*Key, _meta MultiMetaGetter, cb GetMulti |
func (f *fakeDatastore) DeleteMulti(keys []*Key, cb DeleteMultiCB) error { |
if keys[0].Kind() == "FailAll" { |
- return errors.New("DeleteMulti fail all") |
+ return errFailAll |
} |
for _, k := range keys { |
if k.Kind() == "Fail" { |
- cb(errors.New("DeleteMulti fail")) |
+ cb(errFail) |
+ } else if k.Kind() == "DNE" || k.IntID() == noSuchEntityID { |
+ cb(ErrNoSuchEntity) |
} else { |
cb(nil) |
} |
@@ -251,6 +260,33 @@ func (f *FakePLS) Problem() error { |
return nil |
} |
+// plsChan to test channel PLS types. |
+type plsChan chan Property |
+ |
+var _ PropertyLoadSaver = plsChan(nil) |
+ |
+func (c plsChan) Load(pm PropertyMap) error { return nil } |
+func (c plsChan) Save(withMeta bool) (PropertyMap, error) { return nil, nil } |
+func (c plsChan) SetMeta(key string, val interface{}) bool { return false } |
+func (c plsChan) Problem() error { return nil } |
+ |
+func (c plsChan) GetMeta(key string) (interface{}, bool) { |
+ switch key { |
+ case "kind": |
+ return "plsChan", true |
+ case "id": |
+ return "whyDoIExist", true |
+ } |
+ return nil, false |
+} |
+ |
+func (c plsChan) GetAllMeta() PropertyMap { |
+ return PropertyMap{ |
+ "kind": []Property{MkProperty("plsChan")}, |
+ "id": []Property{MkProperty("whyDoIExist")}, |
+ } |
+} |
+ |
type MGSWithNoKind struct { |
S string |
} |
@@ -260,7 +296,7 @@ func (s *MGSWithNoKind) GetMeta(key string) (interface{}, bool) { |
} |
func (s *MGSWithNoKind) GetAllMeta() PropertyMap { |
- return PropertyMap{} |
+ return PropertyMap{"$kind": []Property{MkProperty("ohai")}} |
} |
func (s *MGSWithNoKind) SetMeta(key string, val interface{}) bool { |
@@ -327,38 +363,6 @@ func TestKeyForObj(t *testing.T) { |
So(pls.SetMeta("parent", k), ShouldBeTrue) |
So(ds.KeyForObj(pls).String(), ShouldEqual, `s~aid:ns:/Hello,"world"/CommonStruct,1`) |
}) |
- |
- Convey("can see if things exist", func() { |
- e, err := ds.Exists(k) |
- So(err, ShouldBeNil) |
- So(e, ShouldBeTrue) |
- |
- bl, err := ds.ExistsMulti([]*Key{k, ds.MakeKey("hello", "other")}) |
- So(err, ShouldBeNil) |
- So(bl, ShouldResemble, BoolList{true, true}) |
- So(bl.All(), ShouldBeTrue) |
- So(bl.Any(), ShouldBeTrue) |
- |
- bl, err = ds.ExistsMulti([]*Key{k, ds.MakeKey("DNE", "other")}) |
- So(err, ShouldBeNil) |
- So(bl, ShouldResemble, BoolList{true, false}) |
- So(bl.All(), ShouldBeFalse) |
- So(bl.Any(), ShouldBeTrue) |
- |
- e, err = ds.Exists(ds.MakeKey("DNE", "nope")) |
- So(err, ShouldBeNil) |
- So(e, ShouldBeFalse) |
- |
- bl, err = ds.ExistsMulti([]*Key{ds.MakeKey("DNE", "nope"), ds.MakeKey("DNE", "other")}) |
- So(err, ShouldBeNil) |
- So(bl, ShouldResemble, BoolList{false, false}) |
- So(bl.All(), ShouldBeFalse) |
- So(bl.Any(), ShouldBeFalse) |
- |
- _, err = ds.Exists(ds.MakeKey("Fail", "boom")) |
- So(err, ShouldErrLike, "GetMulti fail") |
- }) |
- |
}) |
Convey("bad", func() { |
@@ -419,348 +423,537 @@ func TestPopulateKey(t *testing.T) { |
func TestPut(t *testing.T) { |
t.Parallel() |
- Convey("Test Put/PutMulti", t, func() { |
+ Convey("A testing environment", 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(func() { ds.PutMulti(bss) }, ShouldPanicLike, |
- `field "Compy" has invalid type`) |
- }) |
+ Convey("Testing Put", func() { |
+ Convey("bad", func() { |
+ Convey("static can't serialize", func() { |
+ bss := []badStruct{{}, {}} |
+ So(func() { ds.Put(bss) }, ShouldPanicLike, |
+ `field "Compy" has invalid type`) |
+ }) |
- Convey("static ptr can't serialize", func() { |
- bss := []*badStruct{{}, {}} |
- So(func() { ds.PutMulti(bss) }, ShouldPanicLike, |
- `field "Compy" has invalid type: complex64`) |
- }) |
+ Convey("static ptr can't serialize", func() { |
+ bss := []*badStruct{{}, {}} |
+ So(func() { ds.Put(bss) }, ShouldPanicLike, |
+ `field "Compy" has invalid type: complex64`) |
+ }) |
- Convey("static bad type (non-slice)", func() { |
- So(func() { ds.PutMulti(100) }, ShouldPanicLike, |
- "invalid argument type: expected slice, got int") |
- }) |
+ Convey("static bad type", func() { |
+ So(func() { ds.Put(100) }, ShouldPanicLike, |
+ "invalid input type (int): not a PLS or pointer-to-struct") |
+ }) |
- Convey("static bad type (slice of bad type)", func() { |
- So(func() { ds.PutMulti([]int{}) }, ShouldPanicLike, |
- "invalid argument type: []int") |
- }) |
+ Convey("static bad type (slice of bad type)", func() { |
+ So(func() { ds.Put([]int{}) }, ShouldPanicLike, |
+ "invalid input type ([]int): not a PLS or pointer-to-struct") |
+ }) |
- Convey("dynamic can't serialize", func() { |
- fplss := []FakePLS{{failSave: true}, {}} |
- So(ds.PutMulti(fplss), ShouldErrLike, "FakePLS.Save") |
- }) |
+ Convey("dynamic can't serialize", func() { |
+ fplss := []FakePLS{{failSave: true}, {}} |
+ So(ds.Put(fplss), ShouldErrLike, "FakePLS.Save") |
+ }) |
- Convey("can't get keys", func() { |
- fplss := []FakePLS{{failGetMeta: true}, {}} |
- So(ds.PutMulti(fplss), ShouldErrLike, "unable to extract $kind") |
- }) |
+ Convey("can't get keys", func() { |
+ fplss := []FakePLS{{failGetMeta: true}, {}} |
+ So(ds.Put(fplss), ShouldErrLike, "unable to extract $kind") |
+ }) |
- Convey("get single error for RPC failure", func() { |
- fplss := []FakePLS{{Kind: "FailAll"}, {}} |
- So(ds.PutMulti(fplss), ShouldErrLike, "PutMulti fail all") |
- }) |
+ Convey("get single error for RPC failure", func() { |
+ fplss := []FakePLS{{Kind: "FailAll"}, {}} |
+ So(ds.Put(fplss), ShouldEqual, errFailAll) |
+ }) |
- 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("get multi error for individual failures", func() { |
+ fplss := []FakePLS{{}, {Kind: "Fail"}} |
+ So(ds.Put(fplss), ShouldResemble, errors.MultiError{nil, errFail}) |
+ }) |
- Convey("put with non-modifyable type is an error", func() { |
- cs := CommonStruct{} |
- So(func() { ds.Put(cs) }, ShouldPanicLike, |
- "invalid Put input type (datastore.CommonStruct): not a pointer") |
- }) |
+ Convey("put with non-modifyable type is an error", func() { |
+ cs := CommonStruct{} |
+ So(func() { ds.Put(cs) }, ShouldPanicLike, |
+ "invalid input type (datastore.CommonStruct): not a pointer") |
+ }) |
- Convey("get with *Key is an error", func() { |
- So(func() { ds.Get(&Key{}) }, ShouldPanicLike, |
- "invalid Get input type (*datastore.Key): not user datatype") |
- }) |
+ Convey("get with *Key is an error", func() { |
+ So(func() { ds.Get(&Key{}) }, ShouldPanicLike, |
+ "invalid input type (*datastore.Key): not user datatype") |
+ }) |
- Convey("struct with no $kind is an error", func() { |
- s := MGSWithNoKind{} |
- So(ds.Put(&s), ShouldErrLike, "unable to extract $kind") |
- }) |
+ Convey("struct with no $kind is an error", func() { |
+ s := MGSWithNoKind{} |
+ So(ds.Put(&s), ShouldErrLike, "unable to extract $kind") |
+ }) |
- Convey("struct with invalid but non-nil key is an error", func() { |
- type BadParent struct { |
- ID int64 `gae:"$id"` |
- Parent *Key `gae:"$parent"` |
- } |
- // having an Incomplete parent makes an invalid key |
- bp := &BadParent{ID: 1, Parent: ds.MakeKey("Something", 0)} |
- So(ds.Put(bp), ShouldErrLike, ErrInvalidKey) |
+ Convey("struct with invalid but non-nil key is an error", func() { |
+ type BadParent struct { |
+ ID int64 `gae:"$id"` |
+ Parent *Key `gae:"$parent"` |
+ } |
+ // having an Incomplete parent makes an invalid key |
+ bp := &BadParent{ID: 1, Parent: ds.MakeKey("Something", 0)} |
+ So(ds.Put(bp), ShouldErrLike, ErrInvalidKey) |
+ }) |
+ |
+ Convey("vararg with errors", func() { |
+ successSlice := []CommonStruct{{Value: 0}, {Value: 1}} |
+ failSlice := []FakePLS{{Kind: "Fail"}, {Value: 3}} |
+ emptySlice := []CommonStruct(nil) |
+ cs0 := CommonStruct{Value: 4} |
+ cs1 := FakePLS{Kind: "Fail", Value: 5} |
+ fpls := FakePLS{StringID: "ohai", Value: 6} |
+ |
+ err := ds.Put(successSlice, failSlice, emptySlice, &cs0, &cs1, &fpls) |
+ So(err, ShouldResemble, errors.MultiError{ |
+ nil, errors.MultiError{errFail, nil}, nil, nil, errFail, nil}) |
+ So(successSlice[0].ID, ShouldEqual, 1) |
+ So(successSlice[1].ID, ShouldEqual, 2) |
+ So(cs0.ID, ShouldEqual, 5) |
+ }) |
}) |
- }) |
- Convey("ok", func() { |
- Convey("[]S", func() { |
- css := make([]CommonStruct, 7) |
- for i := range css { |
- if i == 4 { |
- css[i].ID = 200 |
+ 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) |
} |
- 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(ds.Put(css), ShouldBeNil) |
+ for i, cs := range css { |
+ expect := int64(i + 1) |
+ if i == 4 { |
+ expect = 200 |
+ } |
+ So(cs.ID, ShouldEqual, expect) |
} |
- 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 |
+ 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(ds.Put(css), ShouldBeNil) |
+ for i, cs := range css { |
+ expect := int64(i + 1) |
+ if i == 4 { |
+ expect = 200 |
+ } |
+ So(cs.ID, ShouldEqual, expect) |
} |
- So(cs.ID, ShouldEqual, expect) |
- } |
- s := &CommonStruct{} |
- So(ds.Put(s), ShouldBeNil) |
- So(s.ID, ShouldEqual, 1) |
- }) |
+ 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) |
+ 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(ds.Put(fplss), ShouldBeNil) |
+ for i, fpls := range fplss { |
+ expect := int64(i + 1) |
+ if i == 4 { |
+ expect = 200 |
+ } |
+ So(fpls.IntID, ShouldEqual, expect) |
} |
- 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) |
- }) |
+ 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)}, |
+ Convey("[]P (map)", func() { |
+ pms := make([]PropertyMap, 7) |
+ for i := range pms { |
+ pms[i] = PropertyMap{ |
+ "$kind": {MkProperty("Pmap")}, |
+ "Value": {MkProperty(i)}, |
+ } |
+ if i == 4 { |
+ So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue) |
+ } |
} |
- if i == 4 { |
- So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue) |
+ So(ds.Put(pms), ShouldBeNil) |
+ for i, pm := range pms { |
+ expect := int64(i + 1) |
+ if i == 4 { |
+ expect = 200 |
+ } |
+ So(ds.KeyForObj(pm).String(), ShouldEqual, fmt.Sprintf("s~aid:ns:/Pmap,%d", expect)) |
} |
- } |
- 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("s~aid:ns:/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) |
+ 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(ds.Put(fplss), ShouldBeNil) |
+ for i, fpls := range fplss { |
+ expect := int64(i + 1) |
+ if i == 4 { |
+ expect = 200 |
+ } |
+ So(fpls.IntID, ShouldEqual, expect) |
} |
- 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)}, |
+ Convey("[]*P (map)", func() { |
+ pms := make([]*PropertyMap, 7) |
+ for i := range pms { |
+ pms[i] = &PropertyMap{ |
+ "$kind": {MkProperty("Pmap")}, |
+ "Value": {MkProperty(i)}, |
+ } |
+ if i == 4 { |
+ So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue) |
+ } |
} |
- if i == 4 { |
- So(pms[i].SetMeta("id", int64(200)), ShouldBeTrue) |
+ So(ds.Put(pms), ShouldBeNil) |
+ for i, pm := range pms { |
+ expect := int64(i + 1) |
+ if i == 4 { |
+ expect = 200 |
+ } |
+ So(ds.KeyForObj(*pm).String(), ShouldEqual, fmt.Sprintf("s~aid:ns:/Pmap,%d", expect)) |
} |
- } |
- So(ds.PutMulti(pms), ShouldBeNil) |
- for i, pm := range pms { |
- expect := int64(i + 1) |
- if i == 4 { |
- expect = 200 |
+ }) |
+ |
+ 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.KeyForObj(*pm).String(), ShouldEqual, fmt.Sprintf("s~aid:ns:/Pmap,%d", expect)) |
- } |
+ So(ds.Put(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, "s~aid:ns:/Pmap,3") |
+ case 3: |
+ So(ds.KeyForObj(*ifs[i].(*PropertyMap)).String(), ShouldEqual, "s~aid:ns:/Pmap,4") |
+ } |
+ } |
+ }) |
}) |
+ }) |
- 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, "s~aid:ns:/Pmap,3") |
- case 3: |
- So(ds.KeyForObj(*ifs[i].(*PropertyMap)).String(), ShouldEqual, "s~aid:ns:/Pmap,4") |
- } |
- } |
+ Convey("Testing PutMulti", func() { |
+ Convey("Fails for something other than a slice.", func() { |
+ cs := CommonStruct{} |
+ So(func() { ds.PutMulti(&cs) }, ShouldPanicLike, |
+ "argument must be a slice, not *datastore.CommonStruct") |
+ }) |
+ |
+ Convey("Succeeds for a slice.", func() { |
+ cs := []CommonStruct{{Value: 0}, {Value: 1}} |
+ So(ds.PutMulti(cs), ShouldBeNil) |
+ So(cs[0].ID, ShouldEqual, 1) |
+ So(cs[1].ID, ShouldEqual, 2) |
}) |
+ Convey("Returns an item error in a MultiError.", func() { |
+ cs := []FakePLS{{Value: 0}, {Kind: "Fail"}} |
+ err := ds.PutMulti(cs) |
+ So(err, ShouldResemble, errors.MultiError{nil, errFail}) |
+ So(cs[0].IntID, ShouldEqual, 1) |
+ }) |
+ }) |
+ }) |
+} |
+ |
+func TestExists(t *testing.T) { |
+ t.Parallel() |
+ |
+ Convey("A testing environment", t, func() { |
+ c := info.Set(context.Background(), fakeInfo{}) |
+ c = SetRawFactory(c, fakeDatastoreFactory) |
+ ds := Get(c) |
+ |
+ k := ds.MakeKey("Hello", "world") |
+ |
+ Convey("Exists", func() { |
+ // Single key. |
+ er, err := ds.Exists(k) |
+ So(err, ShouldBeNil) |
+ So(er.All(), ShouldBeTrue) |
+ |
+ // Single key failure. |
+ _, err = ds.Exists(ds.MakeKey("Fail", "boom")) |
+ So(err, ShouldEqual, errFail) |
+ |
+ // Single slice of keys. |
+ er, err = ds.Exists([]*Key{k, ds.MakeKey("hello", "other")}) |
+ So(err, ShouldBeNil) |
+ So(er.All(), ShouldBeTrue) |
+ |
+ // Single slice of keys failure. |
+ er, err = ds.Exists([]*Key{k, ds.MakeKey("Fail", "boom")}) |
+ So(err, ShouldResemble, errors.MultiError{nil, errFail}) |
+ So(er.Get(0, 0), ShouldBeTrue) |
+ |
+ // Single key missing. |
+ er, err = ds.Exists(ds.MakeKey("DNE", "nope")) |
+ So(err, ShouldBeNil) |
+ So(er.Any(), ShouldBeFalse) |
+ |
+ // Multi-arg keys with one missing. |
+ er, err = ds.Exists(k, ds.MakeKey("DNE", "other")) |
+ So(err, ShouldBeNil) |
+ So(er.Get(0), ShouldBeTrue) |
+ So(er.Get(1), ShouldBeFalse) |
+ |
+ // Multi-arg keys with two missing. |
+ er, err = ds.Exists(ds.MakeKey("DNE", "nope"), ds.MakeKey("DNE", "other")) |
+ So(err, ShouldBeNil) |
+ So(er.Any(), ShouldBeFalse) |
+ |
+ // Multi-arg mixed key/struct/slices. |
+ er, err = ds.Exists(&CommonStruct{ID: 1}, []*CommonStruct(nil), []*Key{ds.MakeKey("DNE", "nope"), ds.MakeKey("hello", "ohai")}) |
+ So(err, ShouldBeNil) |
+ So(er.Get(0), ShouldBeTrue) |
+ So(er.Get(1), ShouldBeTrue) |
+ So(er.Get(2), ShouldBeFalse) |
+ So(er.Get(2, 0), ShouldBeFalse) |
+ So(er.Get(2, 1), ShouldBeTrue) |
}) |
+ Convey("ExistsMulti", func() { |
+ Convey("Returns no error if there are no failures.", func() { |
+ bl, err := ds.ExistsMulti([]*Key{k, ds.MakeKey("DNE", "nope"), ds.MakeKey("hello", "ohai")}) |
+ So(err, ShouldBeNil) |
+ So(bl, ShouldResemble, BoolList{true, false, true}) |
+ }) |
+ |
+ Convey("Returns an item error in a MultiError.", func() { |
+ _, err := ds.ExistsMulti([]*Key{k, ds.MakeKey("Fail", "boom")}) |
+ So(err, ShouldResemble, errors.MultiError{nil, errFail}) |
+ }) |
+ }) |
}) |
} |
func TestDelete(t *testing.T) { |
t.Parallel() |
- Convey("Test Delete/DeleteMulti", t, func() { |
+ Convey("A testing environment", 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{ |
- MakeKey("s~aid", "ns", "FailAll", 1), |
- MakeKey("s~aid", "ns", "Ok", 1), |
- } |
- So(ds.DeleteMulti(keys).Error(), ShouldEqual, "DeleteMulti fail all") |
- }) |
+ Convey("Testing Delete", func() { |
+ Convey("bad", func() { |
+ Convey("get single error for RPC failure", func() { |
+ keys := []*Key{ |
+ MakeKey("s~aid", "ns", "FailAll", 1), |
+ MakeKey("s~aid", "ns", "Ok", 1), |
+ } |
+ So(ds.Delete(keys), ShouldEqual, errFailAll) |
+ }) |
- Convey("get multi error for individual failure", func() { |
- keys := []*Key{ |
- ds.MakeKey("Ok", 1), |
- ds.MakeKey("Fail", 2), |
- } |
- So(ds.DeleteMulti(keys).Error(), ShouldEqual, "DeleteMulti fail") |
+ Convey("get multi error for individual failure", func() { |
+ keys := []*Key{ |
+ ds.MakeKey("Ok", 1), |
+ ds.MakeKey("Fail", 2), |
+ } |
+ So(ds.Delete(keys), ShouldResemble, errors.MultiError{nil, errFail}) |
+ }) |
+ |
+ Convey("get single error when deleting a single", func() { |
+ k := ds.MakeKey("Fail", 1) |
+ So(ds.Delete(k), ShouldEqual, errFail) |
+ }) |
}) |
- Convey("get single error when deleting a single", func() { |
- k := ds.MakeKey("Fail", 1) |
- So(ds.Delete(k).Error(), ShouldEqual, "DeleteMulti fail") |
+ Convey("good", func() { |
+ // Single struct. |
+ So(ds.Delete(&CommonStruct{ID: 1}), ShouldBeNil) |
+ |
+ // Single key. |
+ So(ds.Delete(ds.MakeKey("hello", "ohai")), ShouldBeNil) |
+ |
+ // Single struct DNE. |
+ So(ds.Delete(&CommonStruct{ID: noSuchEntityID}), ShouldEqual, ErrNoSuchEntity) |
+ |
+ // Single key DNE. |
+ So(ds.Delete(ds.MakeKey("DNE", "nope")), ShouldEqual, ErrNoSuchEntity) |
+ |
+ // Mixed key/struct/slices. |
+ err := ds.Delete(&CommonStruct{ID: 1}, []*Key{ds.MakeKey("hello", "ohai"), ds.MakeKey("DNE", "nope")}) |
+ So(err, ShouldResemble, errors.MultiError{nil, errors.MultiError{nil, ErrNoSuchEntity}}) |
}) |
}) |
+ Convey("Testing DeleteMulti", func() { |
+ Convey("Succeeds for valid keys.", func() { |
+ So(ds.DeleteMulti([]*Key{ds.MakeKey("hello", "ohai")}), ShouldBeNil) |
+ So(ds.DeleteMulti([]*Key{ds.MakeKey("hello", "ohai"), ds.MakeKey("hello", "sup")}), ShouldBeNil) |
+ }) |
+ |
+ Convey("Returns an item error in a MultiError.", func() { |
+ So(ds.DeleteMulti([]*Key{ds.MakeKey("DNE", "oops")}), ShouldResemble, errors.MultiError{ErrNoSuchEntity}) |
+ }) |
+ }) |
}) |
} |
func TestGet(t *testing.T) { |
t.Parallel() |
- Convey("Test Get/GetMulti", t, func() { |
+ Convey("A testing environment", 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(func() { ds.GetMulti(toGet) }, ShouldPanicLike, |
- `field "Compy" has invalid type: complex64`) |
- }) |
+ Convey("Testing Get", func() { |
+ Convey("bad", func() { |
+ Convey("static can't serialize", func() { |
+ toGet := []badStruct{{}, {}} |
+ So(func() { ds.Get(toGet) }, ShouldPanicLike, |
+ `field "Compy" has invalid type: complex64`) |
+ }) |
- Convey("can't get keys", func() { |
- fplss := []FakePLS{{failGetMeta: true}, {}} |
- So(ds.GetMulti(fplss), ShouldErrLike, "unable to extract $kind") |
- }) |
+ Convey("can't get keys", func() { |
+ fplss := []FakePLS{{failGetMeta: true}, {}} |
+ So(ds.Get(fplss), ShouldErrLike, "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 single error for RPC failure", func() { |
+ fplss := []FakePLS{ |
+ {IntID: 1, Kind: "FailAll"}, |
+ {IntID: 2}, |
+ } |
+ So(ds.Get(fplss), ShouldEqual, errFailAll) |
+ }) |
- 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 multi error for individual failures", func() { |
+ fplss := []FakePLS{{IntID: 1}, {IntID: 2, Kind: "Fail"}} |
+ So(ds.Get(fplss), ShouldResemble, errors.MultiError{nil, errFail}) |
+ }) |
- Convey("get with non-modifiable type is an error", func() { |
- cs := CommonStruct{} |
- So(func() { ds.Get(cs) }, ShouldPanicLike, |
- "invalid Get input type (datastore.CommonStruct): not a pointer") |
- }) |
+ Convey("get with non-modifiable type is an error", func() { |
+ cs := CommonStruct{} |
+ So(func() { ds.Get(cs) }, ShouldPanicLike, |
+ "invalid input type (datastore.CommonStruct): not a pointer") |
+ }) |
- Convey("get with nil is an error", func() { |
- So(func() { ds.Get(nil) }, ShouldPanicLike, |
- "invalid Get input type (<nil>): no type information") |
- }) |
+ Convey("get with nil is an error", func() { |
+ So(func() { ds.Get(nil) }, ShouldPanicLike, |
+ "cannot use nil as single argument") |
+ }) |
+ |
+ Convey("get with ptr-to-nonstruct is an error", func() { |
+ val := 100 |
+ So(func() { ds.Get(&val) }, ShouldPanicLike, |
+ "invalid input type (*int): not a PLS or pointer-to-struct") |
+ }) |
+ |
+ Convey("failure to save metadata is no problem though", func() { |
+ // It just won't save the key |
+ cs := &FakePLS{IntID: 10, failSetMeta: true} |
+ So(ds.Get(cs), ShouldBeNil) |
+ }) |
- Convey("get with ptr-to-nonstruct is an error", func() { |
- val := 100 |
- So(func() { ds.Get(&val) }, ShouldPanicLike, |
- "invalid Get input type (*int): does not point to a struct") |
+ Convey("vararg with errors", func() { |
+ successSlice := []CommonStruct{{ID: 1}, {ID: 2}} |
+ failSlice := []CommonStruct{{ID: noSuchEntityID}, {ID: 3}} |
+ emptySlice := []CommonStruct(nil) |
+ cs0 := CommonStruct{ID: 4} |
+ cs1 := CommonStruct{ID: noSuchEntityID} |
+ fpls := FakePLS{StringID: "ohai"} |
+ |
+ err := ds.Get(successSlice, failSlice, emptySlice, &cs0, &cs1, &fpls) |
+ So(err, ShouldResemble, errors.MultiError{ |
+ nil, errors.MultiError{ErrNoSuchEntity, nil}, nil, nil, ErrNoSuchEntity, nil}) |
+ So(successSlice[0].Value, ShouldEqual, 1) |
+ So(successSlice[1].Value, ShouldEqual, 2) |
+ So(cs0.Value, ShouldEqual, 5) |
+ So(fpls.Value, ShouldEqual, 7) |
+ }) |
}) |
- Convey("failure to save metadata is no problem though", func() { |
- // It just won't save the key |
- cs := &FakePLS{IntID: 10, failSetMeta: true} |
- So(ds.Get(cs), ShouldBeNil) |
+ 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() |
+ keys := []*Key{ds.MakeKey("Kind", 1)} |
+ So(rds.GetMulti(keys, nil, func(pm PropertyMap, err error) error { |
+ So(err, ShouldBeNil) |
+ So(pm["Value"][0].Value(), ShouldEqual, 1) |
+ return nil |
+ }), ShouldBeNil) |
+ }) |
+ |
+ Convey("but general failure to save is fine on a Get", func() { |
+ cs := &FakePLS{failSave: true, IntID: 7} |
+ So(ds.Get(cs), ShouldBeNil) |
+ }) |
+ |
+ Convey("vararg", func() { |
+ successSlice := []CommonStruct{{ID: 1}, {ID: 2}} |
+ cs := CommonStruct{ID: 3} |
+ |
+ err := ds.Get(successSlice, &cs) |
+ So(err, ShouldBeNil) |
+ So(successSlice[0].Value, ShouldEqual, 1) |
+ So(successSlice[1].Value, ShouldEqual, 2) |
+ So(cs.Value, ShouldEqual, 3) |
+ }) |
}) |
}) |
- Convey("ok", func() { |
- Convey("Get", func() { |
- cs := &CommonStruct{ID: 1} |
- So(ds.Get(cs), ShouldBeNil) |
- So(cs.Value, ShouldEqual, 1) |
+ Convey("Testing GetMulti", func() { |
+ Convey("Fails for something other than a slice.", func() { |
+ cs := CommonStruct{} |
+ So(func() { ds.GetMulti(&cs) }, ShouldPanicLike, |
+ "argument must be a slice, not *datastore.CommonStruct") |
}) |
- Convey("Raw access too", func() { |
- rds := ds.Raw() |
- keys := []*Key{ds.MakeKey("Kind", 1)} |
- So(rds.GetMulti(keys, nil, func(pm PropertyMap, err error) error { |
- So(err, ShouldBeNil) |
- So(pm["Value"][0].Value(), ShouldEqual, 1) |
- return nil |
- }), ShouldBeNil) |
+ Convey("Succeeds for a slice.", func() { |
+ cs := []CommonStruct{{ID: 1}} |
+ So(ds.GetMulti(cs), ShouldBeNil) |
+ So(cs[0].Value, ShouldEqual, 1) |
}) |
- Convey("but general failure to save is fine on a Get", func() { |
- cs := &FakePLS{failSave: true, IntID: 7} |
- So(ds.Get(cs), ShouldBeNil) |
+ Convey("Returns an item error in a MultiError.", func() { |
+ cs := []CommonStruct{{ID: 1}, {ID: noSuchEntityID}} |
+ err := ds.GetMulti(cs) |
+ So(err, ShouldResemble, errors.MultiError{nil, ErrNoSuchEntity}) |
+ So(cs[0].Value, ShouldEqual, 1) |
}) |
}) |
- |
}) |
} |
@@ -843,6 +1036,15 @@ func TestGetAll(t *testing.T) { |
} |
}) |
+ Convey("*[]P (chan)", func() { |
+ output := []plsChan(nil) |
+ So(ds.GetAll(q, &output), ShouldBeNil) |
+ So(output, ShouldHaveLength, 5) |
+ for _, o := range output { |
+ So(ds.KeyForObj(o).StringID(), ShouldEqual, "whyDoIExist") |
+ } |
+ }) |
+ |
Convey("*[]*P", func() { |
output := []*FakePLS(nil) |
So(ds.GetAll(q, &output), ShouldBeNil) |
@@ -867,6 +1069,15 @@ func TestGetAll(t *testing.T) { |
} |
}) |
+ Convey("*[]*P (chan)", func() { |
+ output := []*plsChan(nil) |
+ So(ds.GetAll(q, &output), ShouldBeNil) |
+ So(output, ShouldHaveLength, 5) |
+ for _, o := range output { |
+ So(ds.KeyForObj(o).StringID(), ShouldEqual, "whyDoIExist") |
+ } |
+ }) |
+ |
Convey("*[]*Key", func() { |
output := []*Key(nil) |
So(ds.GetAll(q, &output), ShouldBeNil) |
@@ -914,7 +1125,7 @@ func TestRun(t *testing.T) { |
panic("never here!") |
} |
So(func() { ds.Run(q, cb) }, ShouldPanicLike, |
- "invalid argument type: int") |
+ "invalid argument type: int is not a PLS or pointer-to-struct") |
}) |
Convey("wrong # args", func() { |
@@ -1019,6 +1230,12 @@ func TestRun(t *testing.T) { |
}), ShouldBeNil) |
}) |
+ Convey("*P (chan)", func() { |
+ So(ds.Run(q, func(c *plsChan) { |
+ So(ds.KeyForObj(c).StringID(), ShouldEqual, "whyDoIExist") |
+ }), ShouldBeNil) |
+ }) |
+ |
Convey("S", func() { |
i := 0 |
So(ds.Run(q, func(cs CommonStruct) { |
@@ -1049,6 +1266,12 @@ func TestRun(t *testing.T) { |
}), ShouldBeNil) |
}) |
+ Convey("P (chan)", func() { |
+ So(ds.Run(q, func(c plsChan) { |
+ So(ds.KeyForObj(c).StringID(), ShouldEqual, "whyDoIExist") |
+ }), ShouldBeNil) |
+ }) |
+ |
Convey("Key", func() { |
i := 0 |
So(ds.Run(q, func(k *Key) { |