func TestGetMultiLockReturnEntitySetValueFail(t *testing.T) { c, closeFunc := NewContext(t) defer closeFunc() type testEntity struct { IntVal int64 } keys := []*datastore.Key{} entities := []testEntity{} for i := int64(1); i < 3; i++ { keys = append(keys, datastore.NewKey(c, "Entity", "", i, nil)) entities = append(entities, testEntity{i}) } if _, err := nds.PutMulti(c, keys, entities); err != nil { t.Fatal(err) } // Fail to unmarshal test. memcacheGetChan := make(chan func(c context.Context, keys []string) ( map[string]*memcache.Item, error), 2) memcacheGetChan <- memcache.GetMulti memcacheGetChan <- func(c context.Context, keys []string) (map[string]*memcache.Item, error) { items, err := memcache.GetMulti(c, keys) if err != nil { return nil, err } pl := datastore.PropertyList{ datastore.Property{"One", 1, false, false}, } value, err := nds.MarshalPropertyList(pl) if err != nil { return nil, err } items[keys[0]].Flags = nds.EntityItem items[keys[0]].Value = value items[keys[1]].Flags = nds.EntityItem items[keys[1]].Value = value return items, nil } nds.SetMemcacheGetMulti(func(c context.Context, keys []string) (map[string]*memcache.Item, error) { f := <-memcacheGetChan return f(c, keys) }) response := make([]testEntity, len(keys)) if err := nds.GetMulti(c, keys, response); err != nil { t.Fatal(err) } defer nds.SetMemcacheGetMulti(memcache.GetMulti) for i := 0; i < len(keys); i++ { if entities[i].IntVal != response[i].IntVal { t.Fatal("IntVal not equal") } } }
func TestGetMultiLockReturnUnknown(t *testing.T) { c, closeFunc := NewContext(t) defer closeFunc() type testEntity struct { IntVal int64 } keys := []*datastore.Key{} entities := []testEntity{} for i := int64(1); i < 3; i++ { keys = append(keys, datastore.NewKey(c, "Entity", "", i, nil)) entities = append(entities, testEntity{i}) } if _, err := nds.PutMulti(c, keys, entities); err != nil { t.Fatal(err) } memcacheGetChan := make(chan func(c context.Context, keys []string) ( map[string]*memcache.Item, error), 2) memcacheGetChan <- memcache.GetMulti memcacheGetChan <- func(c context.Context, keys []string) (map[string]*memcache.Item, error) { items, err := memcache.GetMulti(c, keys) if err != nil { return nil, err } // Unknown lock values. items[keys[0]].Flags = 23 items[keys[1]].Flags = 24 return items, nil } nds.SetMemcacheGetMulti(func(c context.Context, keys []string) (map[string]*memcache.Item, error) { f := <-memcacheGetChan return f(c, keys) }) response := make([]testEntity, len(keys)) if err := nds.GetMulti(c, keys, response); err != nil { t.Fatal(err) } defer nds.SetMemcacheGetMulti(memcache.GetMulti) for i := 0; i < len(keys); i++ { if entities[i].IntVal != response[i].IntVal { t.Fatal("IntVal not equal") } } }
func TestGetMultiPaths(t *testing.T) { expectedErr := errors.New("expected error") type memcacheGetMultiFunc func(c context.Context, keys []string) (map[string]*memcache.Item, error) memcacheGetMultiFail := func(c context.Context, keys []string) (map[string]*memcache.Item, error) { return nil, expectedErr } type memcacheAddMultiFunc func(c context.Context, items []*memcache.Item) error memcacheAddMultiFail := func(c context.Context, items []*memcache.Item) error { return expectedErr } type memcacheCompareAndSwapMultiFunc func(c context.Context, items []*memcache.Item) error memcacheCompareAndSwapMultiFail := func(c context.Context, items []*memcache.Item) error { return expectedErr } type datastoreGetMultiFunc func(c context.Context, keys []*datastore.Key, vals interface{}) error datastoreGetMultiFail := func(c context.Context, keys []*datastore.Key, vals interface{}) error { return expectedErr } type marshalFunc func(pl datastore.PropertyList) ([]byte, error) marshalFail := func(pl datastore.PropertyList) ([]byte, error) { return nil, expectedErr } type unmarshalFunc func(data []byte, pl *datastore.PropertyList) error /* unmarshalFail := func(data []byte, pl *datastore.PropertyList) error { return expectedErr } */ c, closeFunc := NewContext(t) defer closeFunc() type testEntity struct { IntVal int64 } keysVals := func(c context.Context, count int64) ( []*datastore.Key, []testEntity) { keys, vals := make([]*datastore.Key, count), make([]testEntity, count) for i := int64(0); i < count; i++ { keys[i] = datastore.NewKey(c, "Entity", "", i+1, nil) vals[i] = testEntity{i + 1} } return keys, vals } tests := []struct { description string // Number of keys used to as GetMulti params. keyCount int64 // Number of times GetMulti is called. callCount int // There are 2 memcacheGetMulti calls for every GetMulti call. memcacheGetMultis []memcacheGetMultiFunc memcacheAddMulti memcacheAddMultiFunc memcacheCompareAndSwapMulti memcacheCompareAndSwapMultiFunc datastoreGetMulti datastoreGetMultiFunc marshal marshalFunc // There are 2 unmarshal calls for every GetMultiCall. unmarshals []unmarshalFunc expectedErrs []error }{ { "no errors", 20, 1, []memcacheGetMultiFunc{ memcache.GetMulti, memcache.GetMulti, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil}, }, { "datastore unknown error", 2, 1, []memcacheGetMultiFunc{ memcache.GetMulti, memcache.GetMulti, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastoreGetMultiFail, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{expectedErr}, }, { "datastore unknown multierror", 2, 1, []memcacheGetMultiFunc{ memcache.GetMulti, memcache.GetMulti, }, memcache.AddMulti, memcache.CompareAndSwapMulti, func(c context.Context, keys []*datastore.Key, vals interface{}) error { me := make(appengine.MultiError, len(keys)) for i := range me { me[i] = expectedErr } return me }, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{ appengine.MultiError{expectedErr, expectedErr}, }, }, { "marshal error", 5, 1, []memcacheGetMultiFunc{ memcache.GetMulti, memcache.GetMulti, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, marshalFail, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil}, }, { "total memcache fail", 20, 1, []memcacheGetMultiFunc{ memcacheGetMultiFail, memcacheGetMultiFail, }, memcacheAddMultiFail, memcacheCompareAndSwapMultiFail, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil}, }, { "lock memcache fail", 20, 1, []memcacheGetMultiFunc{ memcache.GetMulti, memcacheGetMultiFail, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil}, }, { "memcache corrupt", 2, 2, []memcacheGetMultiFunc{ // Charge memcache. memcache.GetMulti, memcache.GetMulti, // Corrupt memcache. func(c context.Context, keys []string) ( map[string]*memcache.Item, error) { items, err := memcache.GetMulti(c, keys) // Corrupt items. for _, item := range items { item.Value = []byte("corrupt string") } return items, err }, memcache.GetMulti, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil, nil}, }, { "memcache flag corrupt", 2, 2, []memcacheGetMultiFunc{ // Charge memcache. memcache.GetMulti, memcache.GetMulti, // Corrupt memcache flags. func(c context.Context, keys []string) ( map[string]*memcache.Item, error) { items, err := memcache.GetMulti(c, keys) // Corrupt flags with unknown number. for _, item := range items { item.Flags = 56 } return items, err }, memcache.GetMulti, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil, nil}, }, { "lock memcache value fail", 20, 1, []memcacheGetMultiFunc{ memcache.GetMulti, func(c context.Context, keys []string) ( map[string]*memcache.Item, error) { items, err := memcache.GetMulti(c, keys) // Corrupt flags with unknown number. for _, item := range items { item.Value = []byte("corrupt value") } return items, err }, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil}, }, { "lock memcache value none item", 2, 1, []memcacheGetMultiFunc{ memcache.GetMulti, func(c context.Context, keys []string) ( map[string]*memcache.Item, error) { items, err := memcache.GetMulti(c, keys) // Corrupt flags with unknown number. for _, item := range items { item.Flags = nds.NoneItem } return items, err }, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{ appengine.MultiError{ datastore.ErrNoSuchEntity, datastore.ErrNoSuchEntity, }, }, }, { "memcache get no entity unmarshal fail", 2, 1, []memcacheGetMultiFunc{ memcache.GetMulti, func(c context.Context, keys []string) ( map[string]*memcache.Item, error) { items, err := memcache.GetMulti(c, keys) // Corrupt flags with unknown number. for _, item := range items { item.Flags = nds.EntityItem } return items, err }, }, memcache.AddMulti, memcache.CompareAndSwapMulti, datastore.GetMulti, nds.MarshalPropertyList, []unmarshalFunc{ nds.UnmarshalPropertyList, nds.UnmarshalPropertyList, }, []error{nil}, }, } for _, test := range tests { t.Log("Start", test.description) keys, putVals := keysVals(c, test.keyCount) if _, err := nds.PutMulti(c, keys, putVals); err != nil { t.Fatal(err) } memcacheGetChan := make(chan memcacheGetMultiFunc, len(test.memcacheGetMultis)) for _, fn := range test.memcacheGetMultis { memcacheGetChan <- fn } nds.SetMemcacheGetMulti(func(c context.Context, keys []string) ( map[string]*memcache.Item, error) { fn := <-memcacheGetChan return fn(c, keys) }) nds.SetMemcacheAddMulti(test.memcacheAddMulti) nds.SetMemcacheCompareAndSwapMulti(test.memcacheCompareAndSwapMulti) nds.SetDatastoreGetMulti(test.datastoreGetMulti) nds.SetMarshal(test.marshal) unmarshalChan := make(chan unmarshalFunc, len(test.unmarshals)) for _, fn := range test.unmarshals { unmarshalChan <- fn } nds.SetUnmarshal(func(data []byte, pl *datastore.PropertyList) error { fn := <-unmarshalChan return fn(data, pl) }) for i := 0; i < test.callCount; i++ { getVals := make([]testEntity, test.keyCount) err := nds.GetMulti(c, keys, getVals) expectedErr := test.expectedErrs[i] if expectedErr == nil { if err != nil { t.Fatal(err) } for i := range getVals { if getVals[i].IntVal != putVals[i].IntVal { t.Fatal("incorrect IntVal") } } continue } if err == nil { t.Fatal("expected error") } expectedMultiErr, isMultiErr := expectedErr.(appengine.MultiError) if isMultiErr { me, ok := err.(appengine.MultiError) if !ok { t.Fatal("expected appengine.MultiError but got", err) } if len(me) != len(expectedMultiErr) { t.Fatal("appengine.MultiError length incorrect") } for i, e := range me { if e != expectedMultiErr[i] { t.Fatal("non matching errors", e, expectedMultiErr[i]) } if e == nil { if getVals[i].IntVal != putVals[i].IntVal { t.Fatal("incorrect IntVal") } } } } } // Reset App Engine API calls. nds.SetMemcacheGetMulti(memcache.GetMulti) nds.SetMemcacheAddMulti(memcache.AddMulti) nds.SetMemcacheCompareAndSwapMulti(memcache.CompareAndSwapMulti) nds.SetDatastoreGetMulti(datastore.GetMulti) nds.SetMarshal(nds.MarshalPropertyList) nds.SetUnmarshal(nds.UnmarshalPropertyList) if err := nds.DeleteMulti(c, keys); err != nil { t.Fatal(err) } t.Log("End", test.description) } }