github.com/okex/exchain@v1.8.0/libs/tendermint/rpc/client/mock/abci.go (about)

     1  package mock
     2  
     3  import (
     4  	abci "github.com/okex/exchain/libs/tendermint/abci/types"
     5  	"github.com/okex/exchain/libs/tendermint/libs/bytes"
     6  	"github.com/okex/exchain/libs/tendermint/proxy"
     7  	"github.com/okex/exchain/libs/tendermint/rpc/client"
     8  	ctypes "github.com/okex/exchain/libs/tendermint/rpc/core/types"
     9  	"github.com/okex/exchain/libs/tendermint/types"
    10  )
    11  
    12  // ABCIApp will send all abci related request to the named app,
    13  // so you can test app behavior from a client without needing
    14  // an entire tendermint node
    15  type ABCIApp struct {
    16  	App abci.Application
    17  }
    18  
    19  var (
    20  	_ client.ABCIClient = ABCIApp{}
    21  	_ client.ABCIClient = ABCIMock{}
    22  	_ client.ABCIClient = (*ABCIRecorder)(nil)
    23  )
    24  
    25  func (a ABCIApp) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
    26  	return &ctypes.ResultABCIInfo{Response: a.App.Info(proxy.RequestInfo)}, nil
    27  }
    28  
    29  func (a ABCIApp) ABCIQuery(path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
    30  	return a.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
    31  }
    32  
    33  func (a ABCIApp) ABCIQueryWithOptions(
    34  	path string,
    35  	data bytes.HexBytes,
    36  	opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
    37  	q := a.App.Query(abci.RequestQuery{
    38  		Data:   data,
    39  		Path:   path,
    40  		Height: opts.Height,
    41  		Prove:  opts.Prove,
    42  	})
    43  	return &ctypes.ResultABCIQuery{Response: q}, nil
    44  }
    45  
    46  // NOTE: Caller should call a.App.Commit() separately,
    47  // this function does not actually wait for a commit.
    48  // TODO: Make it wait for a commit and set res.Height appropriately.
    49  func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
    50  	res := ctypes.ResultBroadcastTxCommit{}
    51  	res.CheckTx = a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
    52  	if res.CheckTx.IsErr() {
    53  		return &res, nil
    54  	}
    55  	res.DeliverTx = a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx})
    56  	res.Height = -1 // TODO
    57  	return &res, nil
    58  }
    59  
    60  func (a ABCIApp) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    61  	a.ABCIInfo()
    62  	c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
    63  	// and this gets written in a background thread...
    64  	if !c.IsErr() {
    65  		go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }() // nolint: errcheck
    66  	}
    67  	resp := a.App.Info(abci.RequestInfo{})
    68  	return &ctypes.ResultBroadcastTx{
    69  		Code:      c.Code,
    70  		Data:      c.Data,
    71  		Log:       c.Log,
    72  		Codespace: c.Codespace,
    73  		Hash:      tx.Hash(resp.LastBlockHeight),
    74  	}, nil
    75  }
    76  
    77  func (a ABCIApp) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    78  	c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
    79  	// and this gets written in a background thread...
    80  	if !c.IsErr() {
    81  		go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }() // nolint: errcheck
    82  	}
    83  	resp := a.App.Info(abci.RequestInfo{})
    84  	return &ctypes.ResultBroadcastTx{
    85  		Code:      c.Code,
    86  		Data:      c.Data,
    87  		Log:       c.Log,
    88  		Codespace: c.Codespace,
    89  		Hash:      tx.Hash(resp.LastBlockHeight),
    90  	}, nil
    91  }
    92  
    93  // ABCIMock will send all abci related request to the named app,
    94  // so you can test app behavior from a client without needing
    95  // an entire tendermint node
    96  type ABCIMock struct {
    97  	Info            Call
    98  	Query           Call
    99  	BroadcastCommit Call
   100  	Broadcast       Call
   101  }
   102  
   103  func (m ABCIMock) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
   104  	res, err := m.Info.GetResponse(nil)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	return &ctypes.ResultABCIInfo{Response: res.(abci.ResponseInfo)}, nil
   109  }
   110  
   111  func (m ABCIMock) ABCIQuery(path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
   112  	return m.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
   113  }
   114  
   115  func (m ABCIMock) ABCIQueryWithOptions(
   116  	path string,
   117  	data bytes.HexBytes,
   118  	opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
   119  	res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Prove})
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	resQuery := res.(abci.ResponseQuery)
   124  	return &ctypes.ResultABCIQuery{Response: resQuery}, nil
   125  }
   126  
   127  func (m ABCIMock) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
   128  	res, err := m.BroadcastCommit.GetResponse(tx)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	return res.(*ctypes.ResultBroadcastTxCommit), nil
   133  }
   134  
   135  func (m ABCIMock) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   136  	res, err := m.Broadcast.GetResponse(tx)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	return res.(*ctypes.ResultBroadcastTx), nil
   141  }
   142  
   143  func (m ABCIMock) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   144  	res, err := m.Broadcast.GetResponse(tx)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	return res.(*ctypes.ResultBroadcastTx), nil
   149  }
   150  
   151  // ABCIRecorder can wrap another type (ABCIApp, ABCIMock, or Client)
   152  // and record all ABCI related calls.
   153  type ABCIRecorder struct {
   154  	Client client.ABCIClient
   155  	Calls  []Call
   156  }
   157  
   158  func NewABCIRecorder(client client.ABCIClient) *ABCIRecorder {
   159  	return &ABCIRecorder{
   160  		Client: client,
   161  		Calls:  []Call{},
   162  	}
   163  }
   164  
   165  type QueryArgs struct {
   166  	Path   string
   167  	Data   bytes.HexBytes
   168  	Height int64
   169  	Prove  bool
   170  }
   171  
   172  func (r *ABCIRecorder) addCall(call Call) {
   173  	r.Calls = append(r.Calls, call)
   174  }
   175  
   176  func (r *ABCIRecorder) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
   177  	res, err := r.Client.ABCIInfo()
   178  	r.addCall(Call{
   179  		Name:     "abci_info",
   180  		Response: res,
   181  		Error:    err,
   182  	})
   183  	return res, err
   184  }
   185  
   186  func (r *ABCIRecorder) ABCIQuery(path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
   187  	return r.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
   188  }
   189  
   190  func (r *ABCIRecorder) ABCIQueryWithOptions(
   191  	path string,
   192  	data bytes.HexBytes,
   193  	opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
   194  	res, err := r.Client.ABCIQueryWithOptions(path, data, opts)
   195  	r.addCall(Call{
   196  		Name:     "abci_query",
   197  		Args:     QueryArgs{path, data, opts.Height, opts.Prove},
   198  		Response: res,
   199  		Error:    err,
   200  	})
   201  	return res, err
   202  }
   203  
   204  func (r *ABCIRecorder) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
   205  	res, err := r.Client.BroadcastTxCommit(tx)
   206  	r.addCall(Call{
   207  		Name:     "broadcast_tx_commit",
   208  		Args:     tx,
   209  		Response: res,
   210  		Error:    err,
   211  	})
   212  	return res, err
   213  }
   214  
   215  func (r *ABCIRecorder) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   216  	res, err := r.Client.BroadcastTxAsync(tx)
   217  	r.addCall(Call{
   218  		Name:     "broadcast_tx_async",
   219  		Args:     tx,
   220  		Response: res,
   221  		Error:    err,
   222  	})
   223  	return res, err
   224  }
   225  
   226  func (r *ABCIRecorder) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   227  	res, err := r.Client.BroadcastTxSync(tx)
   228  	r.addCall(Call{
   229  		Name:     "broadcast_tx_sync",
   230  		Args:     tx,
   231  		Response: res,
   232  		Error:    err,
   233  	})
   234  	return res, err
   235  }