github.com/damirazo/docker@v1.9.0/pkg/integration/dockerCmd_utils_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"testing"
     8  
     9  	"io/ioutil"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/go-check/check"
    14  )
    15  
    16  const dockerBinary = "docker"
    17  
    18  // Setup go-check for this test
    19  func Test(t *testing.T) {
    20  	check.TestingT(t)
    21  }
    22  
    23  func init() {
    24  	check.Suite(&DockerCmdSuite{})
    25  }
    26  
    27  type DockerCmdSuite struct{}
    28  
    29  // Fake the exec.Command to use our mock.
    30  func (s *DockerCmdSuite) SetUpTest(c *check.C) {
    31  	execCommand = fakeExecCommand
    32  }
    33  
    34  // And bring it back to normal after the test.
    35  func (s *DockerCmdSuite) TearDownTest(c *check.C) {
    36  	execCommand = exec.Command
    37  }
    38  
    39  // DockerCmdWithError tests
    40  
    41  func (s *DockerCmdSuite) TestDockerCmdWithError(c *check.C) {
    42  	cmds := []struct {
    43  		binary           string
    44  		args             []string
    45  		expectedOut      string
    46  		expectedExitCode int
    47  		expectedError    error
    48  	}{
    49  		{
    50  			"doesnotexists",
    51  			[]string{},
    52  			"Command doesnotexists not found.",
    53  			1,
    54  			fmt.Errorf("exit status 1"),
    55  		},
    56  		{
    57  			dockerBinary,
    58  			[]string{"an", "error"},
    59  			"an error has occurred",
    60  			1,
    61  			fmt.Errorf("exit status 1"),
    62  		},
    63  		{
    64  			dockerBinary,
    65  			[]string{"an", "exitCode", "127"},
    66  			"an error has occurred with exitCode 127",
    67  			127,
    68  			fmt.Errorf("exit status 127"),
    69  		},
    70  		{
    71  			dockerBinary,
    72  			[]string{"run", "-ti", "ubuntu", "echo", "hello"},
    73  			"hello",
    74  			0,
    75  			nil,
    76  		},
    77  	}
    78  	for _, cmd := range cmds {
    79  		out, exitCode, error := DockerCmdWithError(cmd.binary, cmd.args...)
    80  		c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
    81  		c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
    82  		if cmd.expectedError != nil {
    83  			c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
    84  			c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
    85  		} else {
    86  			c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
    87  		}
    88  	}
    89  }
    90  
    91  // DockerCmdWithStdoutStderr tests
    92  
    93  type dockerCmdWithStdoutStderrErrorSuite struct{}
    94  
    95  func (s *dockerCmdWithStdoutStderrErrorSuite) Test(c *check.C) {
    96  	// Should fail, the test too
    97  	DockerCmdWithStdoutStderr(dockerBinary, c, "an", "error")
    98  }
    99  
   100  type dockerCmdWithStdoutStderrSuccessSuite struct{}
   101  
   102  func (s *dockerCmdWithStdoutStderrSuccessSuite) Test(c *check.C) {
   103  	stdout, stderr, exitCode := DockerCmdWithStdoutStderr(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello")
   104  	c.Assert(stdout, check.Equals, "hello")
   105  	c.Assert(stderr, check.Equals, "")
   106  	c.Assert(exitCode, check.Equals, 0)
   107  
   108  }
   109  
   110  func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrError(c *check.C) {
   111  	// Run error suite, should fail.
   112  	output := String{}
   113  	result := check.Run(&dockerCmdWithStdoutStderrErrorSuite{}, &check.RunConf{Output: &output})
   114  	c.Check(result.Succeeded, check.Equals, 0)
   115  	c.Check(result.Failed, check.Equals, 1)
   116  }
   117  
   118  func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrSuccess(c *check.C) {
   119  	// Run error suite, should fail.
   120  	output := String{}
   121  	result := check.Run(&dockerCmdWithStdoutStderrSuccessSuite{}, &check.RunConf{Output: &output})
   122  	c.Check(result.Succeeded, check.Equals, 1)
   123  	c.Check(result.Failed, check.Equals, 0)
   124  }
   125  
   126  // DockerCmd tests
   127  
   128  type dockerCmdErrorSuite struct{}
   129  
   130  func (s *dockerCmdErrorSuite) Test(c *check.C) {
   131  	// Should fail, the test too
   132  	DockerCmd(dockerBinary, c, "an", "error")
   133  }
   134  
   135  type dockerCmdSuccessSuite struct{}
   136  
   137  func (s *dockerCmdSuccessSuite) Test(c *check.C) {
   138  	stdout, exitCode := DockerCmd(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello")
   139  	c.Assert(stdout, check.Equals, "hello")
   140  	c.Assert(exitCode, check.Equals, 0)
   141  
   142  }
   143  
   144  func (s *DockerCmdSuite) TestDockerCmdError(c *check.C) {
   145  	// Run error suite, should fail.
   146  	output := String{}
   147  	result := check.Run(&dockerCmdErrorSuite{}, &check.RunConf{Output: &output})
   148  	c.Check(result.Succeeded, check.Equals, 0)
   149  	c.Check(result.Failed, check.Equals, 1)
   150  }
   151  
   152  func (s *DockerCmdSuite) TestDockerCmdSuccess(c *check.C) {
   153  	// Run error suite, should fail.
   154  	output := String{}
   155  	result := check.Run(&dockerCmdSuccessSuite{}, &check.RunConf{Output: &output})
   156  	c.Check(result.Succeeded, check.Equals, 1)
   157  	c.Check(result.Failed, check.Equals, 0)
   158  }
   159  
   160  // DockerCmdWithTimeout tests
   161  
   162  func (s *DockerCmdSuite) TestDockerCmdWithTimeout(c *check.C) {
   163  	cmds := []struct {
   164  		binary           string
   165  		args             []string
   166  		timeout          time.Duration
   167  		expectedOut      string
   168  		expectedExitCode int
   169  		expectedError    error
   170  	}{
   171  		{
   172  			"doesnotexists",
   173  			[]string{},
   174  			100 * time.Millisecond,
   175  			`Command doesnotexists not found.`,
   176  			1,
   177  			fmt.Errorf(`"" failed with errors: exit status 1 : "Command doesnotexists not found."`),
   178  		},
   179  		{
   180  			dockerBinary,
   181  			[]string{"an", "error"},
   182  			100 * time.Millisecond,
   183  			`an error has occurred`,
   184  			1,
   185  			fmt.Errorf(`"an error" failed with errors: exit status 1 : "an error has occurred"`),
   186  		},
   187  		{
   188  			dockerBinary,
   189  			[]string{"a", "command", "that", "times", "out"},
   190  			5 * time.Millisecond,
   191  			"",
   192  			0,
   193  			fmt.Errorf(`"a command that times out" failed with errors: command timed out : ""`),
   194  		},
   195  		{
   196  			dockerBinary,
   197  			[]string{"run", "-ti", "ubuntu", "echo", "hello"},
   198  			100 * time.Millisecond,
   199  			"hello",
   200  			0,
   201  			nil,
   202  		},
   203  	}
   204  	for _, cmd := range cmds {
   205  		out, exitCode, error := DockerCmdWithTimeout(cmd.binary, cmd.timeout, cmd.args...)
   206  		c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
   207  		c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
   208  		if cmd.expectedError != nil {
   209  			c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
   210  			c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
   211  		} else {
   212  			c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
   213  		}
   214  	}
   215  }
   216  
   217  // DockerCmdInDir tests
   218  
   219  func (s *DockerCmdSuite) TestDockerCmdInDir(c *check.C) {
   220  	tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
   221  	c.Assert(err, check.IsNil)
   222  
   223  	cmds := []struct {
   224  		binary           string
   225  		args             []string
   226  		expectedOut      string
   227  		expectedExitCode int
   228  		expectedError    error
   229  	}{
   230  		{
   231  			"doesnotexists",
   232  			[]string{},
   233  			`Command doesnotexists not found.`,
   234  			1,
   235  			fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
   236  		},
   237  		{
   238  			dockerBinary,
   239  			[]string{"an", "error"},
   240  			`an error has occurred`,
   241  			1,
   242  			fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
   243  		},
   244  		{
   245  			dockerBinary,
   246  			[]string{"run", "-ti", "ubuntu", "echo", "hello"},
   247  			"hello",
   248  			0,
   249  			nil,
   250  		},
   251  	}
   252  	for _, cmd := range cmds {
   253  		// We prepend the arguments with dir:thefolder.. the fake command will check
   254  		// that the current workdir is the same as the one we are passing.
   255  		args := append([]string{"dir:" + tempFolder}, cmd.args...)
   256  		out, exitCode, error := DockerCmdInDir(cmd.binary, tempFolder, args...)
   257  		c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
   258  		c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
   259  		if cmd.expectedError != nil {
   260  			c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
   261  			c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
   262  		} else {
   263  			c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
   264  		}
   265  	}
   266  }
   267  
   268  // DockerCmdInDirWithTimeout tests
   269  
   270  func (s *DockerCmdSuite) TestDockerCmdInDirWithTimeout(c *check.C) {
   271  	tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
   272  	c.Assert(err, check.IsNil)
   273  
   274  	cmds := []struct {
   275  		binary           string
   276  		args             []string
   277  		timeout          time.Duration
   278  		expectedOut      string
   279  		expectedExitCode int
   280  		expectedError    error
   281  	}{
   282  		{
   283  			"doesnotexists",
   284  			[]string{},
   285  			100 * time.Millisecond,
   286  			`Command doesnotexists not found.`,
   287  			1,
   288  			fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
   289  		},
   290  		{
   291  			dockerBinary,
   292  			[]string{"an", "error"},
   293  			100 * time.Millisecond,
   294  			`an error has occurred`,
   295  			1,
   296  			fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
   297  		},
   298  		{
   299  			dockerBinary,
   300  			[]string{"a", "command", "that", "times", "out"},
   301  			5 * time.Millisecond,
   302  			"",
   303  			0,
   304  			fmt.Errorf(`"dir:%s a command that times out" failed with errors: command timed out : ""`, tempFolder),
   305  		},
   306  		{
   307  			dockerBinary,
   308  			[]string{"run", "-ti", "ubuntu", "echo", "hello"},
   309  			100 * time.Millisecond,
   310  			"hello",
   311  			0,
   312  			nil,
   313  		},
   314  	}
   315  	for _, cmd := range cmds {
   316  		// We prepend the arguments with dir:thefolder.. the fake command will check
   317  		// that the current workdir is the same as the one we are passing.
   318  		args := append([]string{"dir:" + tempFolder}, cmd.args...)
   319  		out, exitCode, error := DockerCmdInDirWithTimeout(cmd.binary, cmd.timeout, tempFolder, args...)
   320  		c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
   321  		c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
   322  		if cmd.expectedError != nil {
   323  			c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
   324  			c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
   325  		} else {
   326  			c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
   327  		}
   328  	}
   329  }
   330  
   331  // Helpers :)
   332  
   333  // Type implementing the io.Writer interface for analyzing output.
   334  type String struct {
   335  	value string
   336  }
   337  
   338  // The only function required by the io.Writer interface.  Will append
   339  // written data to the String.value string.
   340  func (s *String) Write(p []byte) (n int, err error) {
   341  	s.value += string(p)
   342  	return len(p), nil
   343  }
   344  
   345  // Helper function that mock the exec.Command call (and call the test binary)
   346  func fakeExecCommand(command string, args ...string) *exec.Cmd {
   347  	cs := []string{"-test.run=TestHelperProcess", "--", command}
   348  	cs = append(cs, args...)
   349  	cmd := exec.Command(os.Args[0], cs...)
   350  	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
   351  	return cmd
   352  }
   353  
   354  func TestHelperProcess(t *testing.T) {
   355  	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
   356  		return
   357  	}
   358  	args := os.Args
   359  
   360  	// Previous arguments are tests stuff, that looks like :
   361  	// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --
   362  	cmd, args := args[3], args[4:]
   363  	// Handle the case where args[0] is dir:...
   364  	if len(args) > 0 && strings.HasPrefix(args[0], "dir:") {
   365  		expectedCwd := args[0][4:]
   366  		if len(args) > 1 {
   367  			args = args[1:]
   368  		}
   369  		cwd, err := os.Getwd()
   370  		if err != nil {
   371  			fmt.Fprintf(os.Stderr, "Failed to get workingdir: %v", err)
   372  			os.Exit(1)
   373  		}
   374  		// This checks that the given path is the same as the currend working dire
   375  		if expectedCwd != cwd {
   376  			fmt.Fprintf(os.Stderr, "Current workdir should be %q, but is %q", expectedCwd, cwd)
   377  		}
   378  	}
   379  	switch cmd {
   380  	case dockerBinary:
   381  		argsStr := strings.Join(args, " ")
   382  		switch argsStr {
   383  		case "an exitCode 127":
   384  			fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127")
   385  			os.Exit(127)
   386  		case "an error":
   387  			fmt.Fprintf(os.Stderr, "an error has occurred")
   388  			os.Exit(1)
   389  		case "a command that times out":
   390  			time.Sleep(10 * time.Millisecond)
   391  			fmt.Fprintf(os.Stdout, "too long, should be killed")
   392  			// A random exit code (that should never happened in tests)
   393  			os.Exit(7)
   394  		case "run -ti ubuntu echo hello":
   395  			fmt.Fprintf(os.Stdout, "hello")
   396  		default:
   397  			fmt.Fprintf(os.Stdout, "no arguments")
   398  		}
   399  	default:
   400  		fmt.Fprintf(os.Stderr, "Command %s not found.", cmd)
   401  		os.Exit(1)
   402  	}
   403  	// some code here to check arguments perhaps?
   404  	os.Exit(0)
   405  }