You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
4.8 KiB

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "github.com/spf13/cobra"
  7. "github.com/tendermint/tendermint/libs/log"
  8. e2e "github.com/tendermint/tendermint/test/e2e/pkg"
  9. )
  10. var (
  11. logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
  12. )
  13. func main() {
  14. NewCLI().Run()
  15. }
  16. // CLI is the Cobra-based command-line interface.
  17. type CLI struct {
  18. root *cobra.Command
  19. testnet *e2e.Testnet
  20. preserve bool
  21. }
  22. // NewCLI sets up the CLI.
  23. func NewCLI() *CLI {
  24. cli := &CLI{}
  25. cli.root = &cobra.Command{
  26. Use: "runner",
  27. Short: "End-to-end test runner",
  28. SilenceUsage: true,
  29. SilenceErrors: true, // we'll output them ourselves in Run()
  30. PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
  31. file, err := cmd.Flags().GetString("file")
  32. if err != nil {
  33. return err
  34. }
  35. testnet, err := e2e.LoadTestnet(file)
  36. if err != nil {
  37. return err
  38. }
  39. cli.testnet = testnet
  40. return nil
  41. },
  42. RunE: func(cmd *cobra.Command, args []string) error {
  43. if err := Cleanup(cli.testnet); err != nil {
  44. return err
  45. }
  46. if err := Setup(cli.testnet); err != nil {
  47. return err
  48. }
  49. chLoadResult := make(chan error)
  50. ctx, loadCancel := context.WithCancel(context.Background())
  51. defer loadCancel()
  52. go func() {
  53. err := Load(ctx, cli.testnet)
  54. if err != nil {
  55. logger.Error(fmt.Sprintf("Transaction load failed: %v", err.Error()))
  56. }
  57. chLoadResult <- err
  58. }()
  59. if err := Start(cli.testnet); err != nil {
  60. return err
  61. }
  62. if err := waitForAllMisbehaviors(cli.testnet); err != nil {
  63. return err
  64. }
  65. if err := Perturb(cli.testnet); err != nil {
  66. return err
  67. }
  68. if err := Wait(cli.testnet, interphaseWaitPeriod); err != nil { // allow some txs to go through
  69. return err
  70. }
  71. loadCancel()
  72. if err := <-chLoadResult; err != nil {
  73. return err
  74. }
  75. // wait for network to settle before tests
  76. if err := Wait(cli.testnet, interphaseWaitPeriod); err != nil {
  77. return err
  78. }
  79. if err := Test(cli.testnet); err != nil {
  80. return err
  81. }
  82. if !cli.preserve {
  83. if err := Cleanup(cli.testnet); err != nil {
  84. return err
  85. }
  86. }
  87. return nil
  88. },
  89. }
  90. cli.root.PersistentFlags().StringP("file", "f", "", "Testnet TOML manifest")
  91. _ = cli.root.MarkPersistentFlagRequired("file")
  92. cli.root.Flags().BoolVarP(&cli.preserve, "preserve", "p", false,
  93. "Preserves the running of the test net after tests are completed")
  94. cli.root.AddCommand(&cobra.Command{
  95. Use: "setup",
  96. Short: "Generates the testnet directory and configuration",
  97. RunE: func(cmd *cobra.Command, args []string) error {
  98. return Setup(cli.testnet)
  99. },
  100. })
  101. cli.root.AddCommand(&cobra.Command{
  102. Use: "start",
  103. Short: "Starts the Docker testnet, waiting for nodes to become available",
  104. RunE: func(cmd *cobra.Command, args []string) error {
  105. _, err := os.Stat(cli.testnet.Dir)
  106. if os.IsNotExist(err) {
  107. err = Setup(cli.testnet)
  108. }
  109. if err != nil {
  110. return err
  111. }
  112. return Start(cli.testnet)
  113. },
  114. })
  115. cli.root.AddCommand(&cobra.Command{
  116. Use: "perturb",
  117. Short: "Perturbs the Docker testnet, e.g. by restarting or disconnecting nodes",
  118. RunE: func(cmd *cobra.Command, args []string) error {
  119. return Perturb(cli.testnet)
  120. },
  121. })
  122. cli.root.AddCommand(&cobra.Command{
  123. Use: "wait",
  124. Short: "Waits for a few blocks to be produced and all nodes to catch up",
  125. RunE: func(cmd *cobra.Command, args []string) error {
  126. return Wait(cli.testnet, 5)
  127. },
  128. })
  129. cli.root.AddCommand(&cobra.Command{
  130. Use: "stop",
  131. Short: "Stops the Docker testnet",
  132. RunE: func(cmd *cobra.Command, args []string) error {
  133. logger.Info("Stopping testnet")
  134. return execCompose(cli.testnet.Dir, "down")
  135. },
  136. })
  137. cli.root.AddCommand(&cobra.Command{
  138. Use: "load",
  139. Short: "Generates transaction load until the command is cancelled",
  140. RunE: func(cmd *cobra.Command, args []string) error {
  141. return Load(context.Background(), cli.testnet)
  142. },
  143. })
  144. cli.root.AddCommand(&cobra.Command{
  145. Use: "test",
  146. Short: "Runs test cases against a running testnet",
  147. RunE: func(cmd *cobra.Command, args []string) error {
  148. return Test(cli.testnet)
  149. },
  150. })
  151. cli.root.AddCommand(&cobra.Command{
  152. Use: "cleanup",
  153. Short: "Removes the testnet directory",
  154. RunE: func(cmd *cobra.Command, args []string) error {
  155. return Cleanup(cli.testnet)
  156. },
  157. })
  158. cli.root.AddCommand(&cobra.Command{
  159. Use: "logs",
  160. Short: "Shows the testnet logs",
  161. RunE: func(cmd *cobra.Command, args []string) error {
  162. return execComposeVerbose(cli.testnet.Dir, "logs")
  163. },
  164. })
  165. cli.root.AddCommand(&cobra.Command{
  166. Use: "tail",
  167. Short: "Tails the testnet logs",
  168. RunE: func(cmd *cobra.Command, args []string) error {
  169. return execComposeVerbose(cli.testnet.Dir, "logs", "--follow")
  170. },
  171. })
  172. return cli
  173. }
  174. // Run runs the CLI.
  175. func (cli *CLI) Run() {
  176. if err := cli.root.Execute(); err != nil {
  177. logger.Error(err.Error())
  178. os.Exit(1)
  179. }
  180. }