github.com/evdatsion/aphelion-dpos-bft@v0.32.1/rpc/test/helpers.go (about) 1 package rpctest 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 "time" 10 11 abci "github.com/evdatsion/aphelion-dpos-bft/abci/types" 12 "github.com/evdatsion/aphelion-dpos-bft/libs/log" 13 14 cfg "github.com/evdatsion/aphelion-dpos-bft/config" 15 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 16 nm "github.com/evdatsion/aphelion-dpos-bft/node" 17 "github.com/evdatsion/aphelion-dpos-bft/p2p" 18 "github.com/evdatsion/aphelion-dpos-bft/privval" 19 "github.com/evdatsion/aphelion-dpos-bft/proxy" 20 ctypes "github.com/evdatsion/aphelion-dpos-bft/rpc/core/types" 21 core_grpc "github.com/evdatsion/aphelion-dpos-bft/rpc/grpc" 22 rpcclient "github.com/evdatsion/aphelion-dpos-bft/rpc/lib/client" 23 ) 24 25 // Options helps with specifying some parameters for our RPC testing for greater 26 // control. 27 type Options struct { 28 suppressStdout bool 29 recreateConfig bool 30 } 31 32 var globalConfig *cfg.Config 33 var defaultOptions = Options{ 34 suppressStdout: false, 35 recreateConfig: false, 36 } 37 38 func waitForRPC() { 39 laddr := GetConfig().RPC.ListenAddress 40 client := rpcclient.NewJSONRPCClient(laddr) 41 ctypes.RegisterAmino(client.Codec()) 42 result := new(ctypes.ResultStatus) 43 for { 44 _, err := client.Call("status", map[string]interface{}{}, result) 45 if err == nil { 46 return 47 } else { 48 fmt.Println("error", err) 49 time.Sleep(time.Millisecond) 50 } 51 } 52 } 53 54 func waitForGRPC() { 55 client := GetGRPCClient() 56 for { 57 _, err := client.Ping(context.Background(), &core_grpc.RequestPing{}) 58 if err == nil { 59 return 60 } 61 } 62 } 63 64 // f**ing long, but unique for each test 65 func makePathname() string { 66 // get path 67 p, err := os.Getwd() 68 if err != nil { 69 panic(err) 70 } 71 // fmt.Println(p) 72 sep := string(filepath.Separator) 73 return strings.Replace(p, sep, "_", -1) 74 } 75 76 func randPort() int { 77 port, err := cmn.GetFreePort() 78 if err != nil { 79 panic(err) 80 } 81 return port 82 } 83 84 func makeAddrs() (string, string, string) { 85 return fmt.Sprintf("tcp://0.0.0.0:%d", randPort()), 86 fmt.Sprintf("tcp://0.0.0.0:%d", randPort()), 87 fmt.Sprintf("tcp://0.0.0.0:%d", randPort()) 88 } 89 90 func createConfig() *cfg.Config { 91 pathname := makePathname() 92 c := cfg.ResetTestRoot(pathname) 93 94 // and we use random ports to run in parallel 95 tm, rpc, grpc := makeAddrs() 96 c.P2P.ListenAddress = tm 97 c.RPC.ListenAddress = rpc 98 c.RPC.CORSAllowedOrigins = []string{"https:/.com/"} 99 c.RPC.GRPCListenAddress = grpc 100 c.TxIndex.IndexTags = "app.creator,tx.height" // see kvstore application 101 return c 102 } 103 104 // GetConfig returns a config for the test cases as a singleton 105 func GetConfig(forceCreate ...bool) *cfg.Config { 106 if globalConfig == nil || (len(forceCreate) > 0 && forceCreate[0]) { 107 globalConfig = createConfig() 108 } 109 return globalConfig 110 } 111 112 func GetGRPCClient() core_grpc.BroadcastAPIClient { 113 grpcAddr := globalConfig.RPC.GRPCListenAddress 114 return core_grpc.StartGRPCClient(grpcAddr) 115 } 116 117 // StartTendermint starts a test tendermint server in a go routine and returns when it is initialized 118 func StartTendermint(app abci.Application, opts ...func(*Options)) *nm.Node { 119 nodeOpts := defaultOptions 120 for _, opt := range opts { 121 opt(&nodeOpts) 122 } 123 node := NewTendermint(app, &nodeOpts) 124 err := node.Start() 125 if err != nil { 126 panic(err) 127 } 128 129 // wait for rpc 130 waitForRPC() 131 waitForGRPC() 132 133 if !nodeOpts.suppressStdout { 134 fmt.Println("Tendermint running!") 135 } 136 137 return node 138 } 139 140 // StopTendermint stops a test tendermint server, waits until it's stopped and 141 // cleans up test/config files. 142 func StopTendermint(node *nm.Node) { 143 node.Stop() 144 node.Wait() 145 os.RemoveAll(node.Config().RootDir) 146 } 147 148 // NewTendermint creates a new tendermint server and sleeps forever 149 func NewTendermint(app abci.Application, opts *Options) *nm.Node { 150 // Create & start node 151 config := GetConfig(opts.recreateConfig) 152 var logger log.Logger 153 if opts.suppressStdout { 154 logger = log.NewNopLogger() 155 } else { 156 logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) 157 logger = log.NewFilter(logger, log.AllowError()) 158 } 159 pvKeyFile := config.PrivValidatorKeyFile() 160 pvKeyStateFile := config.PrivValidatorStateFile() 161 pv := privval.LoadOrGenFilePV(pvKeyFile, pvKeyStateFile) 162 papp := proxy.NewLocalClientCreator(app) 163 nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) 164 if err != nil { 165 panic(err) 166 } 167 node, err := nm.NewNode(config, pv, nodeKey, papp, 168 nm.DefaultGenesisDocProviderFunc(config), 169 nm.DefaultDBProvider, 170 nm.DefaultMetricsProvider(config.Instrumentation), 171 logger) 172 if err != nil { 173 panic(err) 174 } 175 return node 176 } 177 178 // SuppressStdout is an option that tries to make sure the RPC test Tendermint 179 // node doesn't log anything to stdout. 180 func SuppressStdout(o *Options) { 181 o.suppressStdout = true 182 } 183 184 // RecreateConfig instructs the RPC test to recreate the configuration each 185 // time, instead of treating it as a global singleton. 186 func RecreateConfig(o *Options) { 187 o.recreateConfig = true 188 }