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