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 }