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  }