github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/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  	c.Skip("racey test")
   164  	cmds := []struct {
   165  		binary           string
   166  		args             []string
   167  		timeout          time.Duration
   168  		expectedOut      string
   169  		expectedExitCode int
   170  		expectedError    error
   171  	}{
   172  		{
   173  			"doesnotexists",
   174  			[]string{},
   175  			5 * time.Millisecond,
   176  			`Command doesnotexists not found.`,
   177  			1,
   178  			fmt.Errorf(`"" failed with errors: exit status 1 : "Command doesnotexists not found."`),
   179  		},
   180  		{
   181  			dockerBinary,
   182  			[]string{"an", "error"},
   183  			5 * time.Millisecond,
   184  			`an error has occurred`,
   185  			1,
   186  			fmt.Errorf(`"an error" failed with errors: exit status 1 : "an error has occurred"`),
   187  		},
   188  		{
   189  			dockerBinary,
   190  			[]string{"a", "command", "that", "times", "out"},
   191  			5 * time.Millisecond,
   192  			"",
   193  			0,
   194  			fmt.Errorf(`"a command that times out" failed with errors: command timed out : ""`),
   195  		},
   196  		{
   197  			dockerBinary,
   198  			[]string{"run", "-ti", "ubuntu", "echo", "hello"},
   199  			5 * time.Millisecond,
   200  			"hello",
   201  			0,
   202  			nil,
   203  		},
   204  	}
   205  	for _, cmd := range cmds {
   206  		out, exitCode, error := DockerCmdWithTimeout(cmd.binary, cmd.timeout, cmd.args...)
   207  		c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
   208  		c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
   209  		if cmd.expectedError != nil {
   210  			c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
   211  			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()))
   212  		} else {
   213  			c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
   214  		}
   215  	}
   216  }
   217  
   218  // DockerCmdInDir tests
   219  
   220  func (s *DockerCmdSuite) TestDockerCmdInDir(c *check.C) {
   221  	tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
   222  	c.Assert(err, check.IsNil)
   223  
   224  	cmds := []struct {
   225  		binary           string
   226  		args             []string
   227  		expectedOut      string
   228  		expectedExitCode int
   229  		expectedError    error
   230  	}{
   231  		{
   232  			"doesnotexists",
   233  			[]string{},
   234  			`Command doesnotexists not found.`,
   235  			1,
   236  			fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
   237  		},
   238  		{
   239  			dockerBinary,
   240  			[]string{"an", "error"},
   241  			`an error has occurred`,
   242  			1,
   243  			fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
   244  		},
   245  		{
   246  			dockerBinary,
   247  			[]string{"run", "-ti", "ubuntu", "echo", "hello"},
   248  			"hello",
   249  			0,
   250  			nil,
   251  		},
   252  	}
   253  	for _, cmd := range cmds {
   254  		// We prepend the arguments with dir:thefolder.. the fake command will check
   255  		// that the current workdir is the same as the one we are passing.
   256  		args := append([]string{"dir:" + tempFolder}, cmd.args...)
   257  		out, exitCode, error := DockerCmdInDir(cmd.binary, tempFolder, args...)
   258  		c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
   259  		c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
   260  		if cmd.expectedError != nil {
   261  			c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
   262  			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()))
   263  		} else {
   264  			c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
   265  		}
   266  	}
   267  }
   268  
   269  // DockerCmdInDirWithTimeout tests
   270  
   271  func (s *DockerCmdSuite) TestDockerCmdInDirWithTimeout(c *check.C) {
   272  	c.Skip("racey test")
   273  	tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
   274  	c.Assert(err, check.IsNil)
   275  
   276  	cmds := []struct {
   277  		binary           string
   278  		args             []string
   279  		timeout          time.Duration
   280  		expectedOut      string
   281  		expectedExitCode int
   282  		expectedError    error
   283  	}{
   284  		{
   285  			"doesnotexists",
   286  			[]string{},
   287  			5 * time.Millisecond,
   288  			`Command doesnotexists not found.`,
   289  			1,
   290  			fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
   291  		},
   292  		{
   293  			dockerBinary,
   294  			[]string{"an", "error"},
   295  			5 * time.Millisecond,
   296  			`an error has occurred`,
   297  			1,
   298  			fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
   299  		},
   300  		{
   301  			dockerBinary,
   302  			[]string{"a", "command", "that", "times", "out"},
   303  			5 * time.Millisecond,
   304  			"",
   305  			0,
   306  			fmt.Errorf(`"dir:%s a command that times out" failed with errors: command timed out : ""`, tempFolder),
   307  		},
   308  		{
   309  			dockerBinary,
   310  			[]string{"run", "-ti", "ubuntu", "echo", "hello"},
   311  			5 * time.Millisecond,
   312  			"hello",
   313  			0,
   314  			nil,
   315  		},
   316  	}
   317  	for _, cmd := range cmds {
   318  		// We prepend the arguments with dir:thefolder.. the fake command will check
   319  		// that the current workdir is the same as the one we are passing.
   320  		args := append([]string{"dir:" + tempFolder}, cmd.args...)
   321  		out, exitCode, error := DockerCmdInDirWithTimeout(cmd.binary, cmd.timeout, tempFolder, args...)
   322  		c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
   323  		c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
   324  		if cmd.expectedError != nil {
   325  			c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
   326  			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()))
   327  		} else {
   328  			c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
   329  		}
   330  	}
   331  }
   332  
   333  // Helpers :)
   334  
   335  // Type implementing the io.Writer interface for analyzing output.
   336  type String struct {
   337  	value string
   338  }
   339  
   340  // The only function required by the io.Writer interface.  Will append
   341  // written data to the String.value string.
   342  func (s *String) Write(p []byte) (n int, err error) {
   343  	s.value += string(p)
   344  	return len(p), nil
   345  }
   346  
   347  // Helper function that mock the exec.Command call (and call the test binary)
   348  func fakeExecCommand(command string, args ...string) *exec.Cmd {
   349  	cs := []string{"-test.run=TestHelperProcess", "--", command}
   350  	cs = append(cs, args...)
   351  	cmd := exec.Command(os.Args[0], cs...)
   352  	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
   353  	return cmd
   354  }
   355  
   356  func TestHelperProcess(t *testing.T) {
   357  	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
   358  		return
   359  	}
   360  	args := os.Args
   361  
   362  	// Previous arguments are tests stuff, that looks like :
   363  	// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --
   364  	cmd, args := args[3], args[4:]
   365  	// Handle the case where args[0] is dir:...
   366  	if len(args) > 0 && strings.HasPrefix(args[0], "dir:") {
   367  		expectedCwd := args[0][4:]
   368  		if len(args) > 1 {
   369  			args = args[1:]
   370  		}
   371  		cwd, err := os.Getwd()
   372  		if err != nil {
   373  			fmt.Fprintf(os.Stderr, "Failed to get workingdir: %v", err)
   374  			os.Exit(1)
   375  		}
   376  		// This checks that the given path is the same as the currend working dire
   377  		if expectedCwd != cwd {
   378  			fmt.Fprintf(os.Stderr, "Current workdir should be %q, but is %q", expectedCwd, cwd)
   379  		}
   380  	}
   381  	switch cmd {
   382  	case dockerBinary:
   383  		argsStr := strings.Join(args, " ")
   384  		switch argsStr {
   385  		case "an exitCode 127":
   386  			fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127")
   387  			os.Exit(127)
   388  		case "an error":
   389  			fmt.Fprintf(os.Stderr, "an error has occurred")
   390  			os.Exit(1)
   391  		case "a command that times out":
   392  			time.Sleep(10 * time.Millisecond)
   393  			fmt.Fprintf(os.Stdout, "too long, should be killed")
   394  			os.Exit(0)
   395  		case "run -ti ubuntu echo hello":
   396  			fmt.Fprintf(os.Stdout, "hello")
   397  		default:
   398  			fmt.Fprintf(os.Stdout, "no arguments")
   399  		}
   400  	default:
   401  		fmt.Fprintf(os.Stderr, "Command %s not found.", cmd)
   402  		os.Exit(1)
   403  	}
   404  	// some code here to check arguments perhaps?
   405  	os.Exit(0)
   406  }