github.com/aakash4dev/cometbft@v0.38.2/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/aakash4dev/cometbft/abci/types" 12 "github.com/aakash4dev/cometbft/internal/test" 13 "github.com/aakash4dev/cometbft/libs/log" 14 15 cfg "github.com/aakash4dev/cometbft/config" 16 cmtnet "github.com/aakash4dev/cometbft/libs/net" 17 nm "github.com/aakash4dev/cometbft/node" 18 "github.com/aakash4dev/cometbft/p2p" 19 "github.com/aakash4dev/cometbft/privval" 20 "github.com/aakash4dev/cometbft/proxy" 21 ctypes "github.com/aakash4dev/cometbft/rpc/core/types" 22 rpcclient "github.com/aakash4dev/cometbft/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 } 31 32 var ( 33 globalConfig *cfg.Config 34 defaultOptions = Options{ 35 suppressStdout: false, 36 recreateConfig: false, 37 } 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 // f**ing long, but unique for each test 59 func makePathname() string { 60 // get path 61 p, err := os.Getwd() 62 if err != nil { 63 panic(err) 64 } 65 // fmt.Println(p) 66 sep := string(filepath.Separator) 67 return strings.ReplaceAll(p, sep, "_") 68 } 69 70 func randPort() int { 71 port, err := cmtnet.GetFreePort() 72 if err != nil { 73 panic(err) 74 } 75 return port 76 } 77 78 func makeAddrs() (string, string) { 79 return fmt.Sprintf("tcp://127.0.0.1:%d", randPort()), 80 fmt.Sprintf("tcp://127.0.0.1:%d", randPort()) 81 } 82 83 func createConfig() *cfg.Config { 84 pathname := makePathname() 85 c := test.ResetTestRoot(pathname) 86 87 // and we use random ports to run in parallel 88 tm, rpc := makeAddrs() 89 c.P2P.ListenAddress = tm 90 c.RPC.ListenAddress = rpc 91 c.RPC.CORSAllowedOrigins = []string{"https://cometbft.com/"} 92 return c 93 } 94 95 // GetConfig returns a config for the test cases as a singleton 96 func GetConfig(forceCreate ...bool) *cfg.Config { 97 if globalConfig == nil || (len(forceCreate) > 0 && forceCreate[0]) { 98 globalConfig = createConfig() 99 } 100 return globalConfig 101 } 102 103 // StartTendermint starts a test CometBFT server in a go routine and returns when it is initialized 104 func StartTendermint(app abci.Application, opts ...func(*Options)) *nm.Node { 105 nodeOpts := defaultOptions 106 for _, opt := range opts { 107 opt(&nodeOpts) 108 } 109 node := NewTendermint(app, &nodeOpts) 110 err := node.Start() 111 if err != nil { 112 panic(err) 113 } 114 115 // wait for rpc 116 waitForRPC() 117 118 if !nodeOpts.suppressStdout { 119 fmt.Println("CometBFT running!") 120 } 121 122 return node 123 } 124 125 // StopTendermint stops a test CometBFT server, waits until it's stopped and 126 // cleans up test/config files. 127 func StopTendermint(node *nm.Node) { 128 if err := node.Stop(); err != nil { 129 node.Logger.Error("Error when trying to stop node", "err", err) 130 } 131 node.Wait() 132 os.RemoveAll(node.Config().RootDir) 133 } 134 135 // NewTendermint creates a new CometBFT server and sleeps forever 136 func NewTendermint(app abci.Application, opts *Options) *nm.Node { 137 // Create & start node 138 config := GetConfig(opts.recreateConfig) 139 var logger log.Logger 140 if opts.suppressStdout { 141 logger = log.NewNopLogger() 142 } else { 143 logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) 144 logger = log.NewFilter(logger, log.AllowError()) 145 } 146 pvKeyFile := config.PrivValidatorKeyFile() 147 pvKeyStateFile := config.PrivValidatorStateFile() 148 pv := privval.LoadOrGenFilePV(pvKeyFile, pvKeyStateFile) 149 papp := proxy.NewLocalClientCreator(app) 150 nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) 151 if err != nil { 152 panic(err) 153 } 154 node, err := nm.NewNode(context.Background(), config, pv, nodeKey, papp, 155 nm.DefaultGenesisDocProviderFunc(config), 156 cfg.DefaultDBProvider, 157 nm.DefaultMetricsProvider(config.Instrumentation), 158 logger) 159 if err != nil { 160 panic(err) 161 } 162 return node 163 } 164 165 // SuppressStdout is an option that tries to make sure the RPC test CometBFT 166 // node doesn't log anything to stdout. 167 func SuppressStdout(o *Options) { 168 o.suppressStdout = true 169 } 170 171 // RecreateConfig instructs the RPC test to recreate the configuration each 172 // time, instead of treating it as a global singleton. 173 func RecreateConfig(o *Options) { 174 o.recreateConfig = true 175 }