github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/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/lazyledger/lazyledger-core/abci/types" 12 cfg "github.com/lazyledger/lazyledger-core/config" 13 "github.com/lazyledger/lazyledger-core/ipfs" 14 "github.com/lazyledger/lazyledger-core/libs/log" 15 tmnet "github.com/lazyledger/lazyledger-core/libs/net" 16 nm "github.com/lazyledger/lazyledger-core/node" 17 "github.com/lazyledger/lazyledger-core/p2p" 18 "github.com/lazyledger/lazyledger-core/privval" 19 "github.com/lazyledger/lazyledger-core/proxy" 20 ctypes "github.com/lazyledger/lazyledger-core/rpc/core/types" 21 core_grpc "github.com/lazyledger/lazyledger-core/rpc/grpc" 22 rpcclient "github.com/lazyledger/lazyledger-core/rpc/jsonrpc/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 loadIpfsPlugins bool 31 } 32 33 var globalConfig *cfg.Config 34 var defaultOptions = Options{ 35 suppressStdout: false, 36 recreateConfig: false, 37 loadIpfsPlugins: true, 38 } 39 40 func waitForRPC() { 41 laddr := GetConfig().RPC.ListenAddress 42 client, err := rpcclient.New(laddr) 43 if err != nil { 44 panic(err) 45 } 46 result := new(ctypes.ResultStatus) 47 for { 48 _, err := client.Call(context.Background(), "status", map[string]interface{}{}, result) 49 if err == nil { 50 return 51 } 52 53 fmt.Println("error", err) 54 time.Sleep(time.Millisecond) 55 } 56 } 57 58 func waitForGRPC() { 59 client := GetGRPCClient() 60 for { 61 _, err := client.Ping(context.Background(), &core_grpc.RequestPing{}) 62 if err == nil { 63 return 64 } 65 } 66 } 67 68 // f**ing long, but unique for each test 69 func makePathname() string { 70 // get path 71 p, err := os.Getwd() 72 if err != nil { 73 panic(err) 74 } 75 // fmt.Println(p) 76 sep := string(filepath.Separator) 77 return strings.ReplaceAll(p, sep, "_") 78 } 79 80 func randPort() int { 81 port, err := tmnet.GetFreePort() 82 if err != nil { 83 panic(err) 84 } 85 return port 86 } 87 88 func makeAddrs() (string, string, string) { 89 return fmt.Sprintf("tcp://127.0.0.1:%d", randPort()), 90 fmt.Sprintf("tcp://127.0.0.1:%d", randPort()), 91 fmt.Sprintf("tcp://127.0.0.1:%d", randPort()) 92 } 93 94 func createConfig() *cfg.Config { 95 pathname := makePathname() 96 c := cfg.ResetTestRoot(pathname) 97 98 // and we use random ports to run in parallel 99 tm, rpc, grpc := makeAddrs() 100 c.P2P.ListenAddress = tm 101 c.RPC.ListenAddress = rpc 102 c.RPC.CORSAllowedOrigins = []string{"https://tendermint.com/"} 103 c.RPC.GRPCListenAddress = grpc 104 return c 105 } 106 107 // GetConfig returns a config for the test cases as a singleton 108 func GetConfig(forceCreate ...bool) *cfg.Config { 109 if globalConfig == nil || (len(forceCreate) > 0 && forceCreate[0]) { 110 globalConfig = createConfig() 111 } 112 return globalConfig 113 } 114 115 func GetGRPCClient() core_grpc.BroadcastAPIClient { 116 grpcAddr := globalConfig.RPC.GRPCListenAddress 117 return core_grpc.StartGRPCClient(grpcAddr) 118 } 119 120 // StartTendermint starts a test tendermint server in a go routine and returns when it is initialized 121 func StartTendermint(app abci.Application, opts ...func(*Options)) *nm.Node { 122 nodeOpts := defaultOptions 123 for _, opt := range opts { 124 opt(&nodeOpts) 125 } 126 node := NewTendermint(app, &nodeOpts) 127 err := node.Start() 128 if err != nil { 129 panic(err) 130 } 131 132 // wait for rpc 133 waitForRPC() 134 waitForGRPC() 135 136 if !nodeOpts.suppressStdout { 137 fmt.Println("Tendermint running!") 138 } 139 140 return node 141 } 142 143 // StopTendermint stops a test tendermint server, waits until it's stopped and 144 // cleans up test/config files. 145 func StopTendermint(node *nm.Node) { 146 if err := node.Stop(); err != nil { 147 node.Logger.Error("Error when tryint to stop node", "err", err) 148 } 149 node.Wait() 150 os.RemoveAll(node.Config().RootDir) 151 } 152 153 // NewTendermint creates a new tendermint server and sleeps forever 154 func NewTendermint(app abci.Application, opts *Options) *nm.Node { 155 // Create & start node 156 config := GetConfig(opts.recreateConfig) 157 var logger log.Logger 158 if opts.suppressStdout { 159 logger = log.NewNopLogger() 160 } else { 161 logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) 162 logger = log.NewFilter(logger, log.AllowError()) 163 } 164 pvKeyFile := config.PrivValidatorKeyFile() 165 pvKeyStateFile := config.PrivValidatorStateFile() 166 pv, err := privval.LoadOrGenFilePV(pvKeyFile, pvKeyStateFile) 167 if err != nil { 168 panic(err) 169 } 170 papp := proxy.NewLocalClientCreator(app) 171 nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) 172 if err != nil { 173 panic(err) 174 } 175 176 node, err := nm.NewNode(config, pv, nodeKey, papp, 177 nm.DefaultGenesisDocProviderFunc(config), 178 nm.InMemDBProvider, 179 ipfs.Mock(), 180 nm.DefaultMetricsProvider(config.Instrumentation), 181 logger, 182 ) 183 if err != nil { 184 panic(err) 185 } 186 return node 187 } 188 189 // SuppressStdout is an option that tries to make sure the RPC test Tendermint 190 // node doesn't log anything to stdout. 191 func SuppressStdout(o *Options) { 192 o.suppressStdout = true 193 } 194 195 // RecreateConfig instructs the RPC test to recreate the configuration each 196 // time, instead of treating it as a global singleton. 197 func RecreateConfig(o *Options) { 198 o.recreateConfig = true 199 } 200 201 // DoNotLoadIpfsPlugins instructs the RPC test to not load the IPFS plugins, e.g., 202 // to prevent loading them several times. 203 func DoNotLoadIpfsPlugins(o *Options) { 204 o.loadIpfsPlugins = false 205 }