Exemple #1
0
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("")
}
Exemple #2
0
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")
	}
}
Exemple #3
0
// 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)
	}
}
Exemple #4
0
// 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)

}
Exemple #5
0
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")
	}
}