You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
5.7 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package mock
  2. import (
  3. abci "github.com/tendermint/tendermint/abci/types"
  4. "github.com/tendermint/tendermint/rpc/client"
  5. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  6. "github.com/tendermint/tendermint/types"
  7. "github.com/tendermint/tendermint/version"
  8. cmn "github.com/tendermint/tendermint/libs/common"
  9. )
  10. // ABCIApp will send all abci related request to the named app,
  11. // so you can test app behavior from a client without needing
  12. // an entire tendermint node
  13. type ABCIApp struct {
  14. App abci.Application
  15. }
  16. var (
  17. _ client.ABCIClient = ABCIApp{}
  18. _ client.ABCIClient = ABCIMock{}
  19. _ client.ABCIClient = (*ABCIRecorder)(nil)
  20. )
  21. func (a ABCIApp) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
  22. return &ctypes.ResultABCIInfo{a.App.Info(abci.RequestInfo{Version: version.Version})}, nil
  23. }
  24. func (a ABCIApp) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) {
  25. return a.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
  26. }
  27. func (a ABCIApp) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
  28. q := a.App.Query(abci.RequestQuery{Data: data, Path: path, Height: opts.Height, Prove: opts.Trusted})
  29. return &ctypes.ResultABCIQuery{q}, nil
  30. }
  31. func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
  32. res := ctypes.ResultBroadcastTxCommit{}
  33. res.CheckTx = a.App.CheckTx(tx)
  34. if res.CheckTx.IsErr() {
  35. return &res, nil
  36. }
  37. res.DeliverTx = a.App.DeliverTx(tx)
  38. return &res, nil
  39. }
  40. func (a ABCIApp) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  41. c := a.App.CheckTx(tx)
  42. // and this gets written in a background thread...
  43. if !c.IsErr() {
  44. go func() { a.App.DeliverTx(tx) }() // nolint: errcheck
  45. }
  46. return &ctypes.ResultBroadcastTx{c.Code, c.Data, c.Log, tx.Hash()}, nil
  47. }
  48. func (a ABCIApp) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  49. c := a.App.CheckTx(tx)
  50. // and this gets written in a background thread...
  51. if !c.IsErr() {
  52. go func() { a.App.DeliverTx(tx) }() // nolint: errcheck
  53. }
  54. return &ctypes.ResultBroadcastTx{c.Code, c.Data, c.Log, tx.Hash()}, nil
  55. }
  56. // ABCIMock will send all abci related request to the named app,
  57. // so you can test app behavior from a client without needing
  58. // an entire tendermint node
  59. type ABCIMock struct {
  60. Info Call
  61. Query Call
  62. BroadcastCommit Call
  63. Broadcast Call
  64. }
  65. func (m ABCIMock) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
  66. res, err := m.Info.GetResponse(nil)
  67. if err != nil {
  68. return nil, err
  69. }
  70. return &ctypes.ResultABCIInfo{res.(abci.ResponseInfo)}, nil
  71. }
  72. func (m ABCIMock) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) {
  73. return m.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
  74. }
  75. func (m ABCIMock) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
  76. res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Trusted})
  77. if err != nil {
  78. return nil, err
  79. }
  80. resQuery := res.(abci.ResponseQuery)
  81. return &ctypes.ResultABCIQuery{resQuery}, nil
  82. }
  83. func (m ABCIMock) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
  84. res, err := m.BroadcastCommit.GetResponse(tx)
  85. if err != nil {
  86. return nil, err
  87. }
  88. return res.(*ctypes.ResultBroadcastTxCommit), nil
  89. }
  90. func (m ABCIMock) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  91. res, err := m.Broadcast.GetResponse(tx)
  92. if err != nil {
  93. return nil, err
  94. }
  95. return res.(*ctypes.ResultBroadcastTx), nil
  96. }
  97. func (m ABCIMock) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  98. res, err := m.Broadcast.GetResponse(tx)
  99. if err != nil {
  100. return nil, err
  101. }
  102. return res.(*ctypes.ResultBroadcastTx), nil
  103. }
  104. // ABCIRecorder can wrap another type (ABCIApp, ABCIMock, or Client)
  105. // and record all ABCI related calls.
  106. type ABCIRecorder struct {
  107. Client client.ABCIClient
  108. Calls []Call
  109. }
  110. func NewABCIRecorder(client client.ABCIClient) *ABCIRecorder {
  111. return &ABCIRecorder{
  112. Client: client,
  113. Calls: []Call{},
  114. }
  115. }
  116. type QueryArgs struct {
  117. Path string
  118. Data cmn.HexBytes
  119. Height int64
  120. Trusted bool
  121. }
  122. func (r *ABCIRecorder) addCall(call Call) {
  123. r.Calls = append(r.Calls, call)
  124. }
  125. func (r *ABCIRecorder) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
  126. res, err := r.Client.ABCIInfo()
  127. r.addCall(Call{
  128. Name: "abci_info",
  129. Response: res,
  130. Error: err,
  131. })
  132. return res, err
  133. }
  134. func (r *ABCIRecorder) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) {
  135. return r.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
  136. }
  137. func (r *ABCIRecorder) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
  138. res, err := r.Client.ABCIQueryWithOptions(path, data, opts)
  139. r.addCall(Call{
  140. Name: "abci_query",
  141. Args: QueryArgs{path, data, opts.Height, opts.Trusted},
  142. Response: res,
  143. Error: err,
  144. })
  145. return res, err
  146. }
  147. func (r *ABCIRecorder) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
  148. res, err := r.Client.BroadcastTxCommit(tx)
  149. r.addCall(Call{
  150. Name: "broadcast_tx_commit",
  151. Args: tx,
  152. Response: res,
  153. Error: err,
  154. })
  155. return res, err
  156. }
  157. func (r *ABCIRecorder) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  158. res, err := r.Client.BroadcastTxAsync(tx)
  159. r.addCall(Call{
  160. Name: "broadcast_tx_async",
  161. Args: tx,
  162. Response: res,
  163. Error: err,
  164. })
  165. return res, err
  166. }
  167. func (r *ABCIRecorder) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  168. res, err := r.Client.BroadcastTxSync(tx)
  169. r.addCall(Call{
  170. Name: "broadcast_tx_sync",
  171. Args: tx,
  172. Response: res,
  173. Error: err,
  174. })
  175. return res, err
  176. }