I have the func
func(context.Context, *domain.Scorecard) (*domain.Scorecard, error)
And i want pass this as a param that receive a interface
warehouse interface {
Get(context.Context, *domain.Scorecard) (*domain.Scorecard, error)
}
Ex:
warehouseMock :=
usecase.WithScenarioFinder(
func(player *domain.Player) (*domain.Scenario, error) {
return nil,nil
)
The traditional form is create a struct that have the method Get, but i have curiosity if exist the way to tell "hey, that is a simple func, is the same firm (with no name), accept it"
Functions do not implement interfaces with only a single method of that same signature. See this Go issue for a discussion on the topic.
Create an adaptor type to convert a function to an interface:
type WarehouseFunc func(context.Context, *domain.Scorecard) (*domain.Scorecard, error)
func (f WarehouseFunc) Get(c context.Context, d *domain.Scorecard) (*domain.Scorecard, error) {
return f(c, d)
}
Convert an anonymous function to an interface like this:
itf = WarehouseFunc(func(c context.Context, d *domain.Scorecard) (*domain.Scorecard, error) {
return nil, nil
})
The package 'gopkg.in/redis.v3' contains some code
type Client struct {
}
func (*client) Eval (string, []string, []string) *Cmd {
}
type Cmd struct {
}
func (*Cmd) Result () (interface{}, error) {
}
Which works successfully in the following way
func myFunc (cli *redis.Client) {
result, err := cli.Eval('my script').Result()
}
The problem is that sometimes the Redis cluster gets hammered, has a moment, and the interface returned as a result is nil.
This is reasonably easy to handle but I wish to put a test in place that will ensure that it is actually handled and no type assertion panic occurs.
Traditionally I would insert a mock Redis client into myFunc that can ultimately return nil.
type redisClient interface {
Eval(string, []string, []string) redisCmd
}
type redisCmd interface {
Result() (interface{}, error)
}
func myFunc (cli redisClient) {
result, err := cli.Eval('my script').Result()
}
The problem I am facing is the compiler doesn't recognise that redis.Client satisfies the interface redisClient because it doesn't recognise that the redis.Cmd returned from Eval satisfies redisCmd.
> cannot use client (type *redis.Client) as type redisClient in argument to myFunc:
> *redis.Client does not implement redisClient (wrong type for Eval method)
> have Eval(sting, []string, []string) *redis.Cmd
> want Eval(sting, []string, []string) redisCmd
The problem is that your interface does not match the redis client. If you change the interface to:
type redisClient interface {
Eval(string, []string, []string) *redis.Cmd
}
it will compile. That being said, it looks like you really want rediscmd, so you will need to make a wrapper around the redis client:
type wrapper struct{
c *redis.Client
}
func (w wrapper) Eval(x sting, y []string, z []string) redisCmd {
return w.c.Eval(x,y,z) // This assumes that *redis.Cmd implements rediscmd
}
Have following struct:
package dto
type CapacityResponse struct{
Val int
Err error
TransactionID string
}
func (r *CapacityResponse) GetError() (error) {
return r.Err
}
func (r *CapacityResponse) SetError(err error) {
r.Err = err
}
func (r *CapacityResponse) Read() interface{} {
return r.Val
}
func (r *CapacityResponse) GetTransactionId() string {
return r.TransactionID
}
It's interface:
package dto
type Responder interface {
Read() (interface{})
GetError() (error)
SetError(error)
GetTransactionId() (string)
}
And following logic:
func handler(w http.ResponseWriter, r *http.Request) {
cr := request2CacheRequest(r)
responseChan := make(chan dto.Responder)
go func() {
responder := processReq(cr)
responseChan <- responder
}()
go func() {
for r := range responseChan {
if (r.GetTransactionId() == cr.TransactionID) {
switch r.(type) {
//case dto.KeysResponse:
//case dto.GetResponse:
//case dto.RemoveResponse:
//case dto.SetResponse:
case dto.CapacityResponse:
if i, ok := r.Read().(int); ok {
fmt.Fprintf(w, fmt.Sprintf("{'capasity': %d, 'err': %s}", i, r.GetError()))
}
}
}
}
}()
}
I am getting exception:
impossible type switch case: r (type dto.Responder) cannot have dynamic type dto.CapacityResponse (missing GetError method)
Could you, please, help me to understand what is wrong here?
The error message is saying that a dto.Responder value cannot contain a dto.CapacityResponse because dto.CapacityResponse is missing one of the dto.Responder methods (GetError).
The pointer type implements the interface. Change the case to:
case *dto.CapacityResponse:
You have this error because dto.CapacityResponse type is different from *dto.CapacityResponse type.
Because you are using local variable r of interface type dto.Responder the only concrete types you can use in case statements are those that implement this interface and dto.CapacityResponse isn't one of them, because it is not a pointer type and you have declared receivers as pointers for dto.CapacityResponse. Please take a look on playground example
I am attempting to create a wrapper for test emulating around the Go Flex SDK for Google Cloud Datastore. While I am currently successfully running the localhost emulator using
gcloud beta emulators datastore start --no-store-on-disk
in a separate terminal from my testing window, I would prefer to create a mock database emulator that runs as part of the test process itself (without execing the above) so that I can run multiple tests in parallel, each with its own database emulator.
I have run into a problem with the Google SDK not implementing my interface.
My wrapper contains this code:
package google
import (
"context"
"cloud.google.com/go/datastore"
)
type (
// Datastore is a wrapper for the Google Cloud Datastore Client.
Datastore datastore.Client
// Datastorer represents things that can operate like a datastore.Client.
Datastorer interface {
Delete(context.Context, *datastore.Key) error
Get(context.Context, *datastore.Key, interface{}) error
GetAll(context.Context, *datastore.Query, interface{}) ([]*datastore.Key, error)
Put(context.Context, *datastore.Key, interface{}) (*datastore.Key, error)
PutMulti(context.Context, []*datastore.Key, interface{}) ([]*datastore.Key, error)
RunInTransaction(context.Context, func(Transactioner) error, ...datastore.TransactionOption) (*datastore.Commit, error)
}
// Transactioner represents things that can operate like a datastore.Transaction.
Transactioner interface {
Commit() (*datastore.Commit, error)
Delete(*datastore.Key) error
DeleteMulti([]*datastore.Key) error
Get(*datastore.Key, interface{}) error
GetMulti([]*datastore.Key, interface{}) error
Put(*datastore.Key, interface{}) (*datastore.PendingKey, error)
PutMulti([]*datastore.Key, interface{}) ([]*datastore.PendingKey, error)
Rollback() error
}
)
// Delete deletes the entity for the given key.
func (d *Datastore) Delete(ctx context.Context, key *datastore.Key) error {
return (*datastore.Client)(d).Delete(ctx, key)
}
// Get retrieves the entity for the given key.
func (d *Datastore) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
return (*datastore.Client)(d).Get(ctx, key, dst)
}
// GetAll retrieves all entities for the given query.
func (d *Datastore) GetAll(ctx context.Context, q *datastore.Query, dst interface{}) ([]*datastore.Key, error) {
return (*datastore.Client)(d).GetAll(ctx, q, dst)
}
// Put stores an entity for the given key.
func (d *Datastore) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
return (*datastore.Client)(d).Put(ctx, key, src)
}
// PutMulti is a batch version of Put.
func (d *Datastore) PutMulti(ctx context.Context, keys []*datastore.Key, src interface{}) ([]*datastore.Key, error) {
return (*datastore.Client)(d).PutMulti(ctx, keys, src)
}
// RunInTransaction runs the given function in a transaction.
func (d *Datastore) RunInTransaction(ctx context.Context, f func(tx Transactioner) error, opts ...datastore.TransactionOption) (*datastore.Commit, error) {
return (*datastore.Client)(d).RunInTransaction(ctx, func(t *datastore.Transaction) error {
return f(t)
}, opts...)
}
Note that these interfaces do not emulate the complete SDK. I am only including functions that I actually call in my code. I'll add new ones as needed later.
When I try to use an instance of *datastore.Client as a Datastorer, I get the following error:
cannot use client (type *"cloud.google.com/go/datastore".Client) as type Datastorer in field value:
*"cloud.google.com/go/datastore".Client does not implement Datastorer (wrong type for RunInTransaction method)
have RunInTransaction(context.Context, func(*"cloud.google.com/go/datastore".Transaction) error, ..."cloud.google.com/go/datastore".TransactionOption) (*"cloud.google.com/go/datastore".Commit, error)
want RunInTransaction(context.Context, func(Transactioner) error, ..."cloud.google.com/go/datastore".TransactionOption) (*"cloud.google.com/go/datastore".Commit, error)
because *datastore.Client requires a function that takes a func(*datastore.Transaction) error and my interface wants a func(Transactioner) error.
Is there any way to change this so that it compiles?
If I can get it working, I plan to create types that implement my Datastorer and Transactioner interfaces and use maps to mock the real database. As far as tranactions go, for testing I can use sync.Mutex if I need them, but since each test is a single thread and will get its own database object, I may not need to lock them.
I've gotten it to compile by using this code:
package google
import (
"context"
"cloud.google.com/go/datastore"
)
type (
// Datastore is a wrapper for the Google Cloud Datastore Client.
Datastore struct {
*datastore.Client
}
// Datastorer represents things that can operate like a datastore.Client.
Datastorer interface {
Delete(context.Context, *datastore.Key) error
Get(context.Context, *datastore.Key, interface{}) error
GetAll(context.Context, interface{}, interface{}) ([]*datastore.Key, error)
Put(context.Context, *datastore.Key, interface{}) (*datastore.Key, error)
PutMulti(context.Context, []*datastore.Key, interface{}) ([]*datastore.Key, error)
RunInTransaction(context.Context, func(Transactioner) error, ...datastore.TransactionOption) (*datastore.Commit, error)
}
// Querier represents things that can operate like a datastore.Query.
Querier interface {
Filter(string, interface{}) Querier
}
// Transactioner represents things that can operate like a datastore.Transaction.
Transactioner interface {
Commit() (*datastore.Commit, error)
Delete(*datastore.Key) error
DeleteMulti([]*datastore.Key) error
Get(*datastore.Key, interface{}) error
GetMulti([]*datastore.Key, interface{}) error
Put(*datastore.Key, interface{}) (*datastore.PendingKey, error)
PutMulti([]*datastore.Key, interface{}) ([]*datastore.PendingKey, error)
Rollback() error
}
)
// Delete deletes the entity for the given key.
func (d *Datastore) Delete(ctx context.Context, key *datastore.Key) error {
return d.Client.Delete(ctx, key)
}
// Get retrieves the entity for the given key.
func (d *Datastore) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
return d.Client.Get(ctx, key, dst)
}
// GetAll retrieves all entities for the given query.
func (d *Datastore) GetAll(ctx context.Context, q interface{}, dst interface{}) ([]*datastore.Key, error) {
return d.Client.GetAll(ctx, q.(*datastore.Query), dst)
}
// Put stores an entity for the given key.
func (d *Datastore) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
return d.Client.Put(ctx, key, src)
}
// PutMulti is a batch version of Put.
func (d *Datastore) PutMulti(ctx context.Context, keys []*datastore.Key, src interface{}) ([]*datastore.Key, error) {
return d.Client.PutMulti(ctx, keys, src)
}
// RunInTransaction runs the given function in a transaction.
func (d *Datastore) RunInTransaction(ctx context.Context, f func(tx Transactioner) error, opts ...datastore.TransactionOption) (*datastore.Commit, error) {
return d.Client.RunInTransaction(ctx, func(t *datastore.Transaction) error {
return f(t)
}, opts...)
}
I changed DataStore to a struct containing the datastore.Client and added a new interface Querier that contains the functions that I am using from datastore.Query. I also updated GetAll to accept an interface{} instead of a *datastore.Query and then type-assert it to be a *datastore.Query. I cannot have it accept a Querier because then I cannot pass variables of type *datastore.Query because they do not satisfy the Querier interface (Filter returns a Querier instead of a *datastore.Query).
All existing tests using the emulator running in a separate process are passing.
UPDATE:
I changed Datastore to
Datastore datastore.Client
and added a wrapper Query around datastore.Query:
Query datastore.Query
Now, the Datastorer interface contains
GetAll(context.Context, Querier, interface{}) ([]*datastore.Key, error)
and the GetAll function is defined as
func (d *Datastore) GetAll(ctx context.Context, q Querier, dst interface{}) ([]*datastore.Key, error) {
return (*datastore.Client)(d).GetAll(ctx, (*datastore.Query)(q.(*Query)), dst)
}
and Query.Filter is defined as
func (q *Query) Filter(filterStr string, value interface{}) Querier {
return (*Query)((*datastore.Query)(q).Filter(filterStr, value))
}
In calling code, I use
q := datastore.NewQuery(entity).Filter("Deleted =", false)
_, err := r.client.GetAll(ctx, (*Query)(q), data)
This compiles and all tests are passing.
I know that question has been asked a long time ago but in case one still may wondering how to Mock Google Datastore Client and Transaction here is a snapshot of how I got it to work.
type Client interface {
Get(ctx context.Context, key *datastore.Key, dst interface{}) (err error)
NewTransaction(ctx context.Context, opts ...datastore.TransactionOption) (t Transaction, err error)
Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error)
}
type Transaction interface {
Commit() (c *datastore.Commit, err error)
Rollback() (err error)
Get(key *datastore.Key, dst interface{}) (err error)
Put(key *datastore.Key, src interface{}) (*datastore.PendingKey, error)
Delete(key *datastore.Key) error
}
type Datastore struct {
*datastore.Client
}
func (d *Datastore) NewTransaction(ctx context.Context, opts ...datastore.TransactionOption) (t Transaction, err error) {
return d.Client.NewTransaction(ctx, opts...)
}
Of course, If you are using different method against Datastore it's up to you to implement them.
In my tests, I can now Mock Datastore Client and Transaction like :
mockedClient := mock_gcloud.NewMockClient(ctrl)
mockedTransaction := mock_gcloud.NewMockTransaction(ctrl)
...
mockedClient.EXPECT().NewTransaction(context.Background()).Return(mockedTransaction, nil).Times(1)
Et voilĂ .
Let we have 2 methods
func createClient(db *sql.DB, ...) error // creates a new client
func createOrder(db *sql.DB, ...) error // creates a new order
Each of these method can be run on some *sql.DB, for example,
var mainDb *sql.DB // initialized somewhere in main() method
func orderHandler(r,w) {
...
err := createOrder(mainDb, ...)
...
}
But what if i want to run both these methods in one transaction. For example,
func importOrdersHandler(r,w) {
...
tx, err:= mainDb.Begin()
...
err = createClient(tx, clientData) // but method defined on *sql.DB, not *sql.Tx ?!
err = createOrder(tx, orderData)
...
My solution:
Define a wrapper around *sql.DB, *sql.Tx:
type Database struct {
db *sql.DB
tx *sql.Tx
}
// Redefine all standart methods from sql package, such as
// Exec(...)
// Query(..)
// QueryRow(...)
// Also method to run commands in one transaction:
func TransactionDo(db *sql.DB, body func(*Database) error) error {
tx, err := db.Begin()
...
d, err := NewDb(nil, tx)
....
err = body(d)
...
return tx.Commit()
}
In this way our ordersImportHandler can be realized like that:
func importOrdersHandler(r,w) {
for row := range parseFile(formFile(r)) {
...
err := TransactionDo(mainDb, func(d *Database) error {
err = createClient(d, clientData)
...
err = createOrder(d, orderData)
// if an error occurs in TransactionDo then transaction wiil be
// rollbacked, else commit it
createClient, createOrder must be rewrited to use *Database object insted of *sql.DB
What do you think about such solution? May be there another better and idiomatic
way to do that
I used an interface (that the library squirrel also uses)
type Database interface {
Exec(query string, args ...interface{}) (sql.Result, error)
Query(query string, args ...interface{}) (*sql.Rows, error)
QueryRow(query string, args ...interface{}) *sql.Row
}
Then you can just pass write the functions
func createClient(db *Database, ...) error // creates a new client
func createOrder(db *Database, ...) error // creates a new order
Simpler way is to use interfaces.
type Execer interface {
Exec(query string, args ...interface{}) (sql.Result, error)
}
Both sql.Tx and sql.Db satisfy this interface so you can redefine you createClient and createOrder funtions to take an Execer as an argument and there, you can now pass either Tx or Db to them.