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  }