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.

182 lines
4.8 KiB

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