123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- package cli // import "github.com/docker/docker/integration-cli/cli"
- import (
- "fmt"
- "io"
- "strings"
- "testing"
- "time"
- "github.com/docker/docker/integration-cli/daemon"
- "github.com/docker/docker/integration-cli/environment"
- "github.com/pkg/errors"
- "gotest.tools/v3/icmd"
- )
- var testEnv *environment.Execution
- // SetTestEnvironment sets a static test environment
- // TODO: decouple this package from environment
- func SetTestEnvironment(env *environment.Execution) {
- testEnv = env
- }
- // CmdOperator defines functions that can modify a command
- type CmdOperator func(*icmd.Cmd) func()
- // DockerCmd executes the specified docker command and expect a success
- func DockerCmd(t testing.TB, args ...string) *icmd.Result {
- t.Helper()
- return Docker(Args(args...)).Assert(t, icmd.Success)
- }
- // BuildCmd executes the specified docker build command and expect a success
- func BuildCmd(t testing.TB, name string, cmdOperators ...CmdOperator) *icmd.Result {
- return Docker(Build(name), cmdOperators...).Assert(t, icmd.Success)
- }
- // InspectCmd executes the specified docker inspect command and expect a success
- func InspectCmd(t testing.TB, name string, cmdOperators ...CmdOperator) *icmd.Result {
- return Docker(Inspect(name), cmdOperators...).Assert(t, icmd.Success)
- }
- // WaitRun will wait for the specified container to be running, maximum 5 seconds.
- func WaitRun(t testing.TB, name string, cmdOperators ...CmdOperator) {
- WaitForInspectResult(t, name, "{{.State.Running}}", "true", 5*time.Second, cmdOperators...)
- }
- // WaitExited will wait for the specified container to state exit, subject
- // to a maximum time limit in seconds supplied by the caller
- func WaitExited(t testing.TB, name string, timeout time.Duration, cmdOperators ...CmdOperator) {
- WaitForInspectResult(t, name, "{{.State.Status}}", "exited", timeout, cmdOperators...)
- }
- // WaitRestart will wait for the specified container to restart once
- func WaitRestart(t testing.TB, name string, timeout time.Duration, cmdOperators ...CmdOperator) {
- WaitForInspectResult(t, name, "{{.RestartCount}}", "1", timeout, cmdOperators...)
- }
- // WaitForInspectResult waits for the specified expression to be equals to the specified expected string in the given time.
- func WaitForInspectResult(t testing.TB, name, expr, expected string, timeout time.Duration, cmdOperators ...CmdOperator) {
- after := time.After(timeout)
- args := []string{"inspect", "-f", expr, name}
- for {
- result := Docker(Args(args...), cmdOperators...)
- if result.Error != nil {
- if !strings.Contains(strings.ToLower(result.Stderr()), "no such") {
- t.Fatalf("error executing docker inspect: %v\n%s",
- result.Stderr(), result.Stdout())
- }
- select {
- case <-after:
- t.Fatal(result.Error)
- default:
- time.Sleep(10 * time.Millisecond)
- continue
- }
- }
- out := strings.TrimSpace(result.Stdout())
- if out == expected {
- break
- }
- select {
- case <-after:
- t.Fatalf("condition \"%q == %q\" not true in time (%v)", out, expected, timeout)
- default:
- }
- time.Sleep(100 * time.Millisecond)
- }
- }
- // Docker executes the specified docker command
- func Docker(cmd icmd.Cmd, cmdOperators ...CmdOperator) *icmd.Result {
- for _, op := range cmdOperators {
- deferFn := op(&cmd)
- if deferFn != nil {
- defer deferFn()
- }
- }
- appendDocker(&cmd)
- if err := validateArgs(cmd.Command...); err != nil {
- return &icmd.Result{
- Error: err,
- }
- }
- return icmd.RunCmd(cmd)
- }
- // validateArgs is a checker to ensure tests are not running commands which are
- // not supported on platforms. Specifically on Windows this is 'busybox top'.
- func validateArgs(args ...string) error {
- if testEnv.OSType != "windows" {
- return nil
- }
- foundBusybox := -1
- for key, value := range args {
- if strings.ToLower(value) == "busybox" {
- foundBusybox = key
- }
- if (foundBusybox != -1) && (key == foundBusybox+1) && (strings.ToLower(value) == "top") {
- return errors.New("cannot use 'busybox top' in tests on Windows. Use runSleepingContainer()")
- }
- }
- return nil
- }
- // Build executes the specified docker build command
- func Build(name string) icmd.Cmd {
- return icmd.Command("build", "-t", name)
- }
- // Inspect executes the specified docker inspect command
- func Inspect(name string) icmd.Cmd {
- return icmd.Command("inspect", name)
- }
- // Format sets the specified format with --format flag
- func Format(format string) func(*icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Command = append(
- []string{cmd.Command[0]},
- append([]string{"--format", fmt.Sprintf("{{%s}}", format)}, cmd.Command[1:]...)...,
- )
- return nil
- }
- }
- func appendDocker(cmd *icmd.Cmd) {
- cmd.Command = append([]string{testEnv.DockerBinary()}, cmd.Command...)
- }
- // Args build an icmd.Cmd struct from the specified arguments
- func Args(args ...string) icmd.Cmd {
- switch len(args) {
- case 0:
- return icmd.Cmd{}
- case 1:
- return icmd.Command(args[0])
- default:
- return icmd.Command(args[0], args[1:]...)
- }
- }
- // Daemon points to the specified daemon
- func Daemon(d *daemon.Daemon) func(*icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Command = append([]string{"--host", d.Sock()}, cmd.Command...)
- return nil
- }
- }
- // WithTimeout sets the timeout for the command to run
- func WithTimeout(timeout time.Duration) func(cmd *icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Timeout = timeout
- return nil
- }
- }
- // WithEnvironmentVariables sets the specified environment variables for the command to run
- func WithEnvironmentVariables(envs ...string) func(cmd *icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Env = envs
- return nil
- }
- }
- // WithFlags sets the specified flags for the command to run
- func WithFlags(flags ...string) func(*icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Command = append(cmd.Command, flags...)
- return nil
- }
- }
- // InDir sets the folder in which the command should be executed
- func InDir(path string) func(*icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Dir = path
- return nil
- }
- }
- // WithStdout sets the standard output writer of the command
- func WithStdout(writer io.Writer) func(*icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Stdout = writer
- return nil
- }
- }
- // WithStdin sets the standard input reader for the command
- func WithStdin(stdin io.Reader) func(*icmd.Cmd) func() {
- return func(cmd *icmd.Cmd) func() {
- cmd.Stdin = stdin
- return nil
- }
- }
|