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