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.

183 lines
4.8 KiB

8 years ago
  1. package rpctest
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/require"
  11. logger "github.com/tendermint/go-logger"
  12. wire "github.com/tendermint/go-wire"
  13. abci "github.com/tendermint/abci/types"
  14. cfg "github.com/tendermint/go-config"
  15. client "github.com/tendermint/go-rpc/client"
  16. "github.com/tendermint/tendermint/config/tendermint_test"
  17. nm "github.com/tendermint/tendermint/node"
  18. "github.com/tendermint/tendermint/proxy"
  19. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  20. core_grpc "github.com/tendermint/tendermint/rpc/grpc"
  21. "github.com/tendermint/tendermint/types"
  22. )
  23. var (
  24. config cfg.Config
  25. )
  26. const tmLogLevel = "error"
  27. // f**ing long, but unique for each test
  28. func makePathname() string {
  29. // get path
  30. p, err := os.Getwd()
  31. if err != nil {
  32. panic(err)
  33. }
  34. fmt.Println(p)
  35. sep := string(filepath.Separator)
  36. return strings.Replace(p, sep, "_", -1)
  37. }
  38. func randPort() int {
  39. // returns between base and base + spread
  40. base, spread := 20000, 20000
  41. return base + rand.Intn(spread)
  42. }
  43. func makeAddrs() (string, string, string) {
  44. start := randPort()
  45. return fmt.Sprintf("tcp://0.0.0.0:%d", start),
  46. fmt.Sprintf("tcp://0.0.0.0:%d", start+1),
  47. fmt.Sprintf("tcp://0.0.0.0:%d", start+2)
  48. }
  49. // GetConfig returns a config for the test cases as a singleton
  50. func GetConfig() cfg.Config {
  51. if config == nil {
  52. pathname := makePathname()
  53. config = tendermint_test.ResetConfig(pathname)
  54. // Shut up the logging
  55. logger.SetLogLevel(tmLogLevel)
  56. // and we use random ports to run in parallel
  57. tm, rpc, grpc := makeAddrs()
  58. config.Set("node_laddr", tm)
  59. config.Set("rpc_laddr", rpc)
  60. config.Set("grpc_laddr", grpc)
  61. }
  62. return config
  63. }
  64. // GetURIClient gets a uri client pointing to the test tendermint rpc
  65. func GetURIClient() *client.ClientURI {
  66. rpcAddr := GetConfig().GetString("rpc_laddr")
  67. return client.NewClientURI(rpcAddr)
  68. }
  69. // GetJSONClient gets a http/json client pointing to the test tendermint rpc
  70. func GetJSONClient() *client.ClientJSONRPC {
  71. rpcAddr := GetConfig().GetString("rpc_laddr")
  72. return client.NewClientJSONRPC(rpcAddr)
  73. }
  74. func GetGRPCClient() core_grpc.BroadcastAPIClient {
  75. grpcAddr := config.GetString("grpc_laddr")
  76. return core_grpc.StartGRPCClient(grpcAddr)
  77. }
  78. func GetWSClient() *client.WSClient {
  79. rpcAddr := GetConfig().GetString("rpc_laddr")
  80. wsc := client.NewWSClient(rpcAddr, "/websocket")
  81. if _, err := wsc.Start(); err != nil {
  82. panic(err)
  83. }
  84. return wsc
  85. }
  86. // StartTendermint starts a test tendermint server in a go routine and returns when it is initialized
  87. func StartTendermint(app abci.Application) *nm.Node {
  88. node := NewTendermint(app)
  89. node.Start()
  90. fmt.Println("Tendermint running!")
  91. return node
  92. }
  93. // NewTendermint creates a new tendermint server and sleeps forever
  94. func NewTendermint(app abci.Application) *nm.Node {
  95. // Create & start node
  96. config := GetConfig()
  97. privValidatorFile := config.GetString("priv_validator_file")
  98. privValidator := types.LoadOrGenPrivValidator(privValidatorFile)
  99. papp := proxy.NewLocalClientCreator(app)
  100. node := nm.NewNode(config, privValidator, papp)
  101. return node
  102. }
  103. //--------------------------------------------------------------------------------
  104. // Utilities for testing the websocket service
  105. // wait for an event; do things that might trigger events, and check them when they are received
  106. // the check function takes an event id and the byte slice read off the ws
  107. func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, dieOnTimeout bool, f func(), check func(string, interface{}) error) {
  108. // go routine to wait for webscoket msg
  109. goodCh := make(chan interface{})
  110. errCh := make(chan error)
  111. // Read message
  112. go func() {
  113. var err error
  114. LOOP:
  115. for {
  116. select {
  117. case r := <-wsc.ResultsCh:
  118. result := new(ctypes.TMResult)
  119. wire.ReadJSONPtr(result, r, &err)
  120. if err != nil {
  121. errCh <- err
  122. break LOOP
  123. }
  124. event, ok := (*result).(*ctypes.ResultEvent)
  125. if ok && event.Name == eventid {
  126. goodCh <- event.Data
  127. break LOOP
  128. }
  129. case err := <-wsc.ErrorsCh:
  130. errCh <- err
  131. break LOOP
  132. case <-wsc.Quit:
  133. break LOOP
  134. }
  135. }
  136. }()
  137. // do stuff (transactions)
  138. f()
  139. // wait for an event or timeout
  140. timeout := time.NewTimer(10 * time.Second)
  141. select {
  142. case <-timeout.C:
  143. if dieOnTimeout {
  144. wsc.Stop()
  145. require.True(t, false, "%s event was not received in time", eventid)
  146. }
  147. // else that's great, we didn't hear the event
  148. // and we shouldn't have
  149. case eventData := <-goodCh:
  150. if dieOnTimeout {
  151. // message was received and expected
  152. // run the check
  153. require.Nil(t, check(eventid, eventData))
  154. } else {
  155. wsc.Stop()
  156. require.True(t, false, "%s event was not expected", eventid)
  157. }
  158. case err := <-errCh:
  159. panic(err) // Show the stack trace.
  160. }
  161. }
  162. //--------------------------------------------------------------------------------