cli.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package cli
  2. import (
  3. "fmt"
  4. "io"
  5. "strings"
  6. "sync"
  7. "time"
  8. "github.com/docker/docker/integration-cli/daemon"
  9. "github.com/docker/docker/integration-cli/environment"
  10. icmd "github.com/docker/docker/pkg/testutil/cmd"
  11. "github.com/pkg/errors"
  12. )
  13. var (
  14. testEnv *environment.Execution
  15. onlyOnce sync.Once
  16. )
  17. // EnsureTestEnvIsLoaded make sure the test environment is loaded for this package
  18. func EnsureTestEnvIsLoaded(t testingT) {
  19. var doIt bool
  20. var err error
  21. onlyOnce.Do(func() {
  22. doIt = true
  23. })
  24. if !doIt {
  25. return
  26. }
  27. testEnv, err = environment.New()
  28. if err != nil {
  29. t.Fatalf("error loading testenv : %v", err)
  30. }
  31. }
  32. // CmdOperator defines functions that can modify a command
  33. type CmdOperator func(*icmd.Cmd) func()
  34. type testingT interface {
  35. Fatal(args ...interface{})
  36. Fatalf(string, ...interface{})
  37. }
  38. // DockerCmd executes the specified docker command and expect a success
  39. func DockerCmd(t testingT, args ...string) *icmd.Result {
  40. return Docker(Args(args...)).Assert(t, icmd.Success)
  41. }
  42. // BuildCmd executes the specified docker build command and expect a success
  43. func BuildCmd(t testingT, name string, cmdOperators ...CmdOperator) *icmd.Result {
  44. return Docker(Build(name), cmdOperators...).Assert(t, icmd.Success)
  45. }
  46. // InspectCmd executes the specified docker inspect command and expect a success
  47. func InspectCmd(t testingT, name string, cmdOperators ...CmdOperator) *icmd.Result {
  48. return Docker(Inspect(name), cmdOperators...).Assert(t, icmd.Success)
  49. }
  50. // Docker executes the specified docker command
  51. func Docker(cmd icmd.Cmd, cmdOperators ...CmdOperator) *icmd.Result {
  52. for _, op := range cmdOperators {
  53. deferFn := op(&cmd)
  54. if deferFn != nil {
  55. defer deferFn()
  56. }
  57. }
  58. appendDocker(&cmd)
  59. if err := validateArgs(cmd.Command...); err != nil {
  60. return &icmd.Result{
  61. Error: err,
  62. }
  63. }
  64. return icmd.RunCmd(cmd)
  65. }
  66. // validateArgs is a checker to ensure tests are not running commands which are
  67. // not supported on platforms. Specifically on Windows this is 'busybox top'.
  68. func validateArgs(args ...string) error {
  69. if testEnv.DaemonPlatform() != "windows" {
  70. return nil
  71. }
  72. foundBusybox := -1
  73. for key, value := range args {
  74. if strings.ToLower(value) == "busybox" {
  75. foundBusybox = key
  76. }
  77. if (foundBusybox != -1) && (key == foundBusybox+1) && (strings.ToLower(value) == "top") {
  78. return errors.New("cannot use 'busybox top' in tests on Windows. Use runSleepingContainer()")
  79. }
  80. }
  81. return nil
  82. }
  83. // Build executes the specified docker build command
  84. func Build(name string) icmd.Cmd {
  85. return icmd.Command("build", "-t", name)
  86. }
  87. // Inspect executes the specified docker inspect command
  88. func Inspect(name string) icmd.Cmd {
  89. return icmd.Command("inspect", name)
  90. }
  91. // Format sets the specified format with --format flag
  92. func Format(format string) func(*icmd.Cmd) func() {
  93. return func(cmd *icmd.Cmd) func() {
  94. cmd.Command = append(
  95. []string{cmd.Command[0]},
  96. append([]string{"--format", fmt.Sprintf("{{%s}}", format)}, cmd.Command[1:]...)...,
  97. )
  98. return nil
  99. }
  100. }
  101. func appendDocker(cmd *icmd.Cmd) {
  102. cmd.Command = append([]string{testEnv.DockerBinary()}, cmd.Command...)
  103. }
  104. // Args build an icmd.Cmd struct from the specified arguments
  105. func Args(args ...string) icmd.Cmd {
  106. switch len(args) {
  107. case 0:
  108. return icmd.Cmd{}
  109. case 1:
  110. return icmd.Command(args[0])
  111. default:
  112. return icmd.Command(args[0], args[1:]...)
  113. }
  114. }
  115. // Daemon points to the specified daemon
  116. func Daemon(d *daemon.Daemon) func(*icmd.Cmd) func() {
  117. return func(cmd *icmd.Cmd) func() {
  118. cmd.Command = append([]string{"--host", d.Sock()}, cmd.Command...)
  119. return nil
  120. }
  121. }
  122. // WithTimeout sets the timeout for the command to run
  123. func WithTimeout(timeout time.Duration) func(cmd *icmd.Cmd) func() {
  124. return func(cmd *icmd.Cmd) func() {
  125. cmd.Timeout = timeout
  126. return nil
  127. }
  128. }
  129. // WithEnvironmentVariables sets the specified environment variables for the command to run
  130. func WithEnvironmentVariables(envs ...string) func(cmd *icmd.Cmd) func() {
  131. return func(cmd *icmd.Cmd) func() {
  132. cmd.Env = envs
  133. return nil
  134. }
  135. }
  136. // WithFlags sets the specified flags for the command to run
  137. func WithFlags(flags ...string) func(*icmd.Cmd) func() {
  138. return func(cmd *icmd.Cmd) func() {
  139. cmd.Command = append(cmd.Command, flags...)
  140. return nil
  141. }
  142. }
  143. // InDir sets the folder in which the command should be executed
  144. func InDir(path string) func(*icmd.Cmd) func() {
  145. return func(cmd *icmd.Cmd) func() {
  146. cmd.Dir = path
  147. return nil
  148. }
  149. }
  150. // WithStdout sets the standard output writer of the command
  151. func WithStdout(writer io.Writer) func(*icmd.Cmd) func() {
  152. return func(cmd *icmd.Cmd) func() {
  153. cmd.Stdout = writer
  154. return nil
  155. }
  156. }