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.

211 lines
5.9 KiB

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