blob: 08bb9606c7beaadf68f8dddd9d2696270882ae91 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package fake provides a fake implementation of a Datastore client
// to use in testing.
package fake
import (
"bytes"
"context"
"encoding/gob"
"log"
"reflect"
"sync"
"cloud.google.com/go/datastore"
"github.com/googleapis/google-cloud-go-testing/datastore/dsiface"
)
// Client is a fake implementation of dsiface.Client to use in
// testing.
type Client struct {
dsiface.Client
m sync.Mutex
db map[string]map[string][]byte
}
var _ dsiface.Client = &Client{}
// Close is unimplemented and panics.
func (f *Client) Close() error {
panic("unimplemented")
}
// AllocateIDs is unimplemented and panics.
func (f *Client) AllocateIDs(context.Context, []*datastore.Key) ([]*datastore.Key, error) {
panic("unimplemented")
}
// Count is unimplemented and panics.
func (f *Client) Count(context.Context, *datastore.Query) (n int, err error) {
panic("unimplemented")
}
// Delete is unimplemented and panics.
func (f *Client) Delete(context.Context, *datastore.Key) error {
panic("unimplemented")
}
// DeleteMulti is unimplemented and panics.
func (f *Client) DeleteMulti(context.Context, []*datastore.Key) (err error) {
panic("unimplemented")
}
// Get loads the entity stored for key into dst, which must be a
// struct pointer.
func (f *Client) Get(_ context.Context, key *datastore.Key, dst interface{}) (err error) {
f.m.Lock()
defer f.m.Unlock()
// get catches nil interfaces; we need to catch nil ptr here
if dst == nil {
return datastore.ErrInvalidEntityType
}
if key == nil {
return datastore.ErrInvalidKey
}
kdb := f.db[key.Kind]
if kdb == nil {
return datastore.ErrNoSuchEntity
}
rv := reflect.ValueOf(dst)
if rv.Kind() != reflect.Ptr {
return datastore.ErrInvalidEntityType
}
v := kdb[key.Encode()]
if v == nil {
return datastore.ErrNoSuchEntity
}
d := gob.NewDecoder(bytes.NewReader(v))
return d.Decode(dst)
}
// GetAll runs the provided query in the given context and returns all
// keys that match that query, as well as appending the values to dst.
//
// GetAll currently only supports a query of all entities of a given
// Kind, and a dst of a slice of pointers to structs.
func (f *Client) GetAll(_ context.Context, q *datastore.Query, dst interface{}) (keys []*datastore.Key, err error) {
f.m.Lock()
defer f.m.Unlock()
fv := reflect.ValueOf(q).Elem().FieldByName("kind")
kdb := f.db[fv.String()]
if kdb == nil {
return
}
s := reflect.ValueOf(dst).Elem()
for k, v := range kdb {
dk, err := datastore.DecodeKey(k)
if err != nil {
log.Printf("f.GetAll() failed to decode key %q: %v", k, err)
continue
}
keys = append(keys, dk)
// This value is expected to represent a slice of pointers to structs.
ev := reflect.New(s.Type().Elem().Elem())
d := gob.NewDecoder(bytes.NewReader(v))
if err := d.DecodeValue(ev); err != nil {
return nil, err
}
s.Set(reflect.Append(s, ev))
}
return
}
// GetMulti is unimplemented and panics.
func (f *Client) GetMulti(context.Context, []*datastore.Key, interface{}) (err error) {
panic("unimplemented")
}
// Mutate is unimplemented and panics.
func (f *Client) Mutate(context.Context, ...*datastore.Mutation) (ret []*datastore.Key, err error) {
panic("unimplemented")
}
// NewTransaction is unimplemented and panics.
func (f *Client) NewTransaction(context.Context, ...datastore.TransactionOption) (t dsiface.Transaction, err error) {
panic("unimplemented")
}
// Put saves the entity src into the datastore with the given key. src
// must be a struct pointer.
func (f *Client) Put(_ context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
f.m.Lock()
defer f.m.Unlock()
if f.db == nil {
f.db = make(map[string]map[string][]byte)
}
kdb := f.db[key.Kind]
if kdb == nil {
f.db[key.Kind] = make(map[string][]byte)
kdb = f.db[key.Kind]
}
dst := bytes.Buffer{}
e := gob.NewEncoder(&dst)
if err := e.Encode(src); err != nil {
return nil, err
}
kdb[key.Encode()] = dst.Bytes()
return key, nil
}
// PutMulti is unimplemented and panics.
func (f *Client) PutMulti(context.Context, []*datastore.Key, interface{}) (ret []*datastore.Key, err error) {
panic("unimplemented")
}
// Run is unimplemented and panics.
func (f *Client) Run(context.Context, *datastore.Query) dsiface.Iterator {
panic("unimplemented")
}
// RunInTransaction is unimplemented and panics.
func (f *Client) RunInTransaction(context.Context, func(tx dsiface.Transaction) error, ...datastore.TransactionOption) (cmt dsiface.Commit, err error) {
panic("unimplemented")
}