github.com/soomindae/tendermint@v0.0.5-0.20210528140126-84a0c70c8162/test/e2e/runner/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/spf13/cobra"
     9  
    10  	"github.com/soomindae/tendermint/libs/log"
    11  	e2e "github.com/soomindae/tendermint/test/e2e/pkg"
    12  )
    13  
    14  var (
    15  	logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
    16  )
    17  
    18  func main() {
    19  	NewCLI().Run()
    20  }
    21  
    22  // CLI is the Cobra-based command-line interface.
    23  type CLI struct {
    24  	root     *cobra.Command
    25  	testnet  *e2e.Testnet
    26  	preserve bool
    27  }
    28  
    29  // NewCLI sets up the CLI.
    30  func NewCLI() *CLI {
    31  	cli := &CLI{}
    32  	cli.root = &cobra.Command{
    33  		Use:           "runner",
    34  		Short:         "End-to-end test runner",
    35  		SilenceUsage:  true,
    36  		SilenceErrors: true, // we'll output them ourselves in Run()
    37  		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
    38  			file, err := cmd.Flags().GetString("file")
    39  			if err != nil {
    40  				return err
    41  			}
    42  			testnet, err := e2e.LoadTestnet(file)
    43  			if err != nil {
    44  				return err
    45  			}
    46  
    47  			cli.testnet = testnet
    48  			return nil
    49  		},
    50  		RunE: func(cmd *cobra.Command, args []string) error {
    51  			if err := Cleanup(cli.testnet); err != nil {
    52  				return err
    53  			}
    54  			if err := Setup(cli.testnet); err != nil {
    55  				return err
    56  			}
    57  
    58  			chLoadResult := make(chan error)
    59  			ctx, loadCancel := context.WithCancel(context.Background())
    60  			defer loadCancel()
    61  			go func() {
    62  				err := Load(ctx, cli.testnet)
    63  				if err != nil {
    64  					logger.Error(fmt.Sprintf("Transaction load failed: %v", err.Error()))
    65  				}
    66  				chLoadResult <- err
    67  			}()
    68  
    69  			if err := Start(cli.testnet); err != nil {
    70  				return err
    71  			}
    72  
    73  			if lastMisbehavior := cli.testnet.LastMisbehaviorHeight(); lastMisbehavior > 0 {
    74  				// wait for misbehaviors before starting perturbations. We do a separate
    75  				// wait for another 5 blocks, since the last misbehavior height may be
    76  				// in the past depending on network startup ordering.
    77  				if err := WaitUntil(cli.testnet, lastMisbehavior); err != nil {
    78  					return err
    79  				}
    80  			}
    81  			if err := Wait(cli.testnet, 5); err != nil { // allow some txs to go through
    82  				return err
    83  			}
    84  
    85  			if cli.testnet.HasPerturbations() {
    86  				if err := Perturb(cli.testnet); err != nil {
    87  					return err
    88  				}
    89  				if err := Wait(cli.testnet, 5); err != nil { // allow some txs to go through
    90  					return err
    91  				}
    92  			}
    93  
    94  			loadCancel()
    95  			if err := <-chLoadResult; err != nil {
    96  				return err
    97  			}
    98  			if err := Wait(cli.testnet, 5); err != nil { // wait for network to settle before tests
    99  				return err
   100  			}
   101  			if err := Test(cli.testnet); err != nil {
   102  				return err
   103  			}
   104  			if !cli.preserve {
   105  				if err := Cleanup(cli.testnet); err != nil {
   106  					return err
   107  				}
   108  			}
   109  			return nil
   110  		},
   111  	}
   112  
   113  	cli.root.PersistentFlags().StringP("file", "f", "", "Testnet TOML manifest")
   114  	_ = cli.root.MarkPersistentFlagRequired("file")
   115  
   116  	cli.root.Flags().BoolVarP(&cli.preserve, "preserve", "p", false,
   117  		"Preserves the running of the test net after tests are completed")
   118  
   119  	cli.root.AddCommand(&cobra.Command{
   120  		Use:   "setup",
   121  		Short: "Generates the testnet directory and configuration",
   122  		RunE: func(cmd *cobra.Command, args []string) error {
   123  			return Setup(cli.testnet)
   124  		},
   125  	})
   126  
   127  	cli.root.AddCommand(&cobra.Command{
   128  		Use:   "start",
   129  		Short: "Starts the Docker testnet, waiting for nodes to become available",
   130  		RunE: func(cmd *cobra.Command, args []string) error {
   131  			_, err := os.Stat(cli.testnet.Dir)
   132  			if os.IsNotExist(err) {
   133  				err = Setup(cli.testnet)
   134  			}
   135  			if err != nil {
   136  				return err
   137  			}
   138  			return Start(cli.testnet)
   139  		},
   140  	})
   141  
   142  	cli.root.AddCommand(&cobra.Command{
   143  		Use:   "perturb",
   144  		Short: "Perturbs the Docker testnet, e.g. by restarting or disconnecting nodes",
   145  		RunE: func(cmd *cobra.Command, args []string) error {
   146  			return Perturb(cli.testnet)
   147  		},
   148  	})
   149  
   150  	cli.root.AddCommand(&cobra.Command{
   151  		Use:   "wait",
   152  		Short: "Waits for a few blocks to be produced and all nodes to catch up",
   153  		RunE: func(cmd *cobra.Command, args []string) error {
   154  			return Wait(cli.testnet, 5)
   155  		},
   156  	})
   157  
   158  	cli.root.AddCommand(&cobra.Command{
   159  		Use:   "stop",
   160  		Short: "Stops the Docker testnet",
   161  		RunE: func(cmd *cobra.Command, args []string) error {
   162  			logger.Info("Stopping testnet")
   163  			return execCompose(cli.testnet.Dir, "down")
   164  		},
   165  	})
   166  
   167  	cli.root.AddCommand(&cobra.Command{
   168  		Use:   "load",
   169  		Short: "Generates transaction load until the command is cancelled",
   170  		RunE: func(cmd *cobra.Command, args []string) error {
   171  			return Load(context.Background(), cli.testnet)
   172  		},
   173  	})
   174  
   175  	cli.root.AddCommand(&cobra.Command{
   176  		Use:   "test",
   177  		Short: "Runs test cases against a running testnet",
   178  		RunE: func(cmd *cobra.Command, args []string) error {
   179  			return Test(cli.testnet)
   180  		},
   181  	})
   182  
   183  	cli.root.AddCommand(&cobra.Command{
   184  		Use:   "cleanup",
   185  		Short: "Removes the testnet directory",
   186  		RunE: func(cmd *cobra.Command, args []string) error {
   187  			return Cleanup(cli.testnet)
   188  		},
   189  	})
   190  
   191  	cli.root.AddCommand(&cobra.Command{
   192  		Use:   "logs",
   193  		Short: "Shows the testnet logs",
   194  		RunE: func(cmd *cobra.Command, args []string) error {
   195  			return execComposeVerbose(cli.testnet.Dir, "logs")
   196  		},
   197  	})
   198  
   199  	cli.root.AddCommand(&cobra.Command{
   200  		Use:   "tail",
   201  		Short: "Tails the testnet logs",
   202  		RunE: func(cmd *cobra.Command, args []string) error {
   203  			return execComposeVerbose(cli.testnet.Dir, "logs", "--follow")
   204  		},
   205  	})
   206  
   207  	cli.root.AddCommand(&cobra.Command{
   208  		Use:   "benchmark",
   209  		Short: "Benchmarks testnet",
   210  		Long: `Benchmarks the following metrics:
   211  	Mean Block Interval
   212  	Standard Deviation
   213  	Min Block Interval
   214  	Max Block Interval
   215  over a 100 block sampling period.
   216  		
   217  Does not run any perbutations.
   218  		`,
   219  		RunE: func(cmd *cobra.Command, args []string) error {
   220  			if err := Cleanup(cli.testnet); err != nil {
   221  				return err
   222  			}
   223  			if err := Setup(cli.testnet); err != nil {
   224  				return err
   225  			}
   226  
   227  			chLoadResult := make(chan error)
   228  			ctx, loadCancel := context.WithCancel(context.Background())
   229  			defer loadCancel()
   230  			go func() {
   231  				err := Load(ctx, cli.testnet)
   232  				if err != nil {
   233  					logger.Error(fmt.Sprintf("Transaction load failed: %v", err.Error()))
   234  				}
   235  				chLoadResult <- err
   236  			}()
   237  
   238  			if err := Start(cli.testnet); err != nil {
   239  				return err
   240  			}
   241  
   242  			if err := Wait(cli.testnet, 5); err != nil { // allow some txs to go through
   243  				return err
   244  			}
   245  
   246  			// we benchmark performance over the next 100 blocks
   247  			if err := Benchmark(cli.testnet, 100); err != nil {
   248  				return err
   249  			}
   250  
   251  			loadCancel()
   252  			if err := <-chLoadResult; err != nil {
   253  				return err
   254  			}
   255  
   256  			if err := Cleanup(cli.testnet); err != nil {
   257  				return err
   258  			}
   259  
   260  			return nil
   261  		},
   262  	})
   263  
   264  	return cli
   265  }
   266  
   267  // Run runs the CLI.
   268  func (cli *CLI) Run() {
   269  	if err := cli.root.Execute(); err != nil {
   270  		logger.Error(err.Error())
   271  		os.Exit(1)
   272  	}
   273  }