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.

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