func TestMemcacheNamespace(t *testing.T) { c, closeFunc := NewContext(t) defer closeFunc() type testEntity struct { IntVal int } // Illegal namespace chars. nds.SetMemcacheNamespace("£££") key := datastore.NewKey(c, "Entity", "", 1, nil) if err := nds.Get(c, key, &testEntity{}); err == nil { t.Fatal("expected namespace error") } if _, err := nds.Put(c, key, &testEntity{}); err == nil { t.Fatal("expected namespace error") } if err := nds.Delete(c, key); err == nil { t.Fatal("expected namespace error") } if err := nds.RunInTransaction(c, func(tc context.Context) error { return nil }, nil); err == nil { t.Fatal("expected namespace error") } nds.SetMemcacheNamespace("") }
func TestDeleteIncompleteKey(t *testing.T) { c, closeFunc := NewContext(t) defer closeFunc() if err := nds.Delete(c, nil); err != datastore.ErrInvalidKey { t.Fatal("expected invalid key error") } }
// TestGetNamespacedKey ensures issue https://goo.gl/rXU8nK is fixed so that // memcache uses the namespace from the key instead of the context. func TestGetNamespacedKey(t *testing.T) { c, closeFunc := NewContext(t) defer closeFunc() const intVal = int64(12) type testEntity struct { IntVal int64 } namespacedCtx, err := appengine.Namespace(c, "keyNamespace") if err != nil { t.Fatal(err) } key := datastore.NewKey(c, "Entity", "", 1, nil) namespacedKey := datastore.NewKey(namespacedCtx, "Entity", "", key.IntID(), nil) entity := &testEntity{intVal} if namespacedKey, err = nds.Put(c, namespacedKey, entity); err != nil { t.Fatal(err) } // Prime cache. if err := nds.Get(namespacedCtx, namespacedKey, &testEntity{}); err != nil { t.Fatal(err) } // Ensure that we get a value back from the cache by checking if the // datastore is called at all. entityFromCache := true nds.SetDatastoreGetMulti(func(c context.Context, keys []*datastore.Key, vals interface{}) error { if len(keys) != 0 { entityFromCache = false } return nil }) if err := nds.Get(c, namespacedKey, &testEntity{}); err != nil { t.Fatal(err) } nds.SetDatastoreGetMulti(datastore.GetMulti) if !entityFromCache { t.Fatal("entity not obtained from cache") } if err := nds.Delete(namespacedCtx, namespacedKey); err != nil { t.Fatal(err) } entity = &testEntity{} if err := nds.Get(c, namespacedKey, entity); err == nil { t.Fatalf("expected no such entity error but got %+v", entity) } else if err != datastore.ErrNoSuchEntity { t.Fatal(err) } }
// ChangeEmail changes the email address of an account from oldEmail to newEmail. // It performs this operation atomically. func ChangeEmail(ctx context.Context, oldEmail, newEmail string) error { return nds.RunInTransaction(ctx, func(txCtx context.Context) error { // read out both the account at the old and the new email addresses var fromAccount, toAccount Account var errFrom, errTo error fromAccountKey := datastore.NewKey(txCtx, Entity, oldEmail, 0, nil) toAccountKey := datastore.NewKey(txCtx, Entity, newEmail, 0, nil) var s sync.WaitGroup s.Add(2) go func() { errFrom = nds.Get(txCtx, fromAccountKey, &fromAccount) s.Done() }() go func() { errTo = nds.Get(txCtx, toAccountKey, &toAccount) s.Done() }() s.Wait() if errFrom != nil { return errFrom } else if errTo != datastore.ErrNoSuchEntity { return ErrAccountExists } // at this point, we set FromAccount's email address to the new one fromAccount.Email = newEmail fromAccount.LastUpdatedAt = time.Now() s.Add(2) go func() { // delete the account at the old key errFrom = nds.Delete(txCtx, fromAccountKey) s.Done() }() go func() { // save the account at the new key _, errTo = nds.Put(txCtx, toAccountKey, &fromAccount) s.Done() }() s.Wait() if errFrom != nil { return errFrom } else if errTo != nil { return errTo } return nil }, xgTransaction) }
func TestPutGetDelete(t *testing.T) { c, closeFunc := NewContext(t) defer closeFunc() type testEntity struct { IntVal int } // Check we set memcahce, put datastore and delete memcache. seq := make(chan string, 3) nds.SetMemcacheSetMulti(func(c context.Context, items []*memcache.Item) error { seq <- "memcache.SetMulti" return memcache.SetMulti(c, items) }) nds.SetDatastorePutMulti(func(c context.Context, keys []*datastore.Key, vals interface{}) ([]*datastore.Key, error) { seq <- "datastore.PutMulti" return datastore.PutMulti(c, keys, vals) }) nds.SetMemcacheDeleteMulti(func(c context.Context, keys []string) error { seq <- "memcache.DeleteMulti" close(seq) return memcache.DeleteMulti(c, keys) }) incompleteKey := datastore.NewIncompleteKey(c, "Entity", nil) key, err := nds.Put(c, incompleteKey, &testEntity{43}) if err != nil { t.Fatal(err) } nds.SetMemcacheSetMulti(memcache.SetMulti) nds.SetDatastorePutMulti(datastore.PutMulti) nds.SetMemcacheDeleteMulti(memcache.DeleteMulti) if s := <-seq; s != "memcache.SetMulti" { t.Fatal("memcache.SetMulti not", s) } if s := <-seq; s != "datastore.PutMulti" { t.Fatal("datastore.PutMulti not", s) } if s := <-seq; s != "memcache.DeleteMulti" { t.Fatal("memcache.DeleteMulti not", s) } // Check chan is closed. <-seq if key.Incomplete() { t.Fatal("Key is incomplete") } te := &testEntity{} if err := nds.Get(c, key, te); err != nil { t.Fatal(err) } if te.IntVal != 43 { t.Fatal("te.Val != 43", te.IntVal) } // Get from cache. te = &testEntity{} if err := nds.Get(c, key, te); err != nil { t.Fatal(err) } if te.IntVal != 43 { t.Fatal("te.Val != 43", te.IntVal) } // Change value. if _, err := nds.Put(c, key, &testEntity{64}); err != nil { t.Fatal(err) } // Get from cache. te = &testEntity{} if err := nds.Get(c, key, te); err != nil { t.Fatal(err) } if te.IntVal != 64 { t.Fatal("te.Val != 64", te.IntVal) } if err := nds.Delete(c, key); err != nil { t.Fatal(err) } if err := nds.Get(c, key, &testEntity{}); err != datastore.ErrNoSuchEntity { t.Fatal("expected datastore.ErrNoSuchEntity") } }