| package integration |
| |
| import ( |
| "fmt" |
| "os" |
| "os/exec" |
| "testing" |
| |
| "io/ioutil" |
| "strings" |
| "time" |
| |
| "github.com/go-check/check" |
| ) |
| |
| const dockerBinary = "docker" |
| |
| // Setup go-check for this test |
| func Test(t *testing.T) { |
| check.TestingT(t) |
| } |
| |
| func init() { |
| check.Suite(&DockerCmdSuite{}) |
| } |
| |
| type DockerCmdSuite struct{} |
| |
| // Fake the exec.Command to use our mock. |
| func (s *DockerCmdSuite) SetUpTest(c *check.C) { |
| execCommand = fakeExecCommand |
| } |
| |
| // And bring it back to normal after the test. |
| func (s *DockerCmdSuite) TearDownTest(c *check.C) { |
| execCommand = exec.Command |
| } |
| |
| // DockerCmdWithError tests |
| |
| func (s *DockerCmdSuite) TestDockerCmdWithError(c *check.C) { |
| cmds := []struct { |
| binary string |
| args []string |
| expectedOut string |
| expectedExitCode int |
| expectedError error |
| }{ |
| { |
| "doesnotexists", |
| []string{}, |
| "Command doesnotexists not found.", |
| 1, |
| fmt.Errorf("exit status 1"), |
| }, |
| { |
| dockerBinary, |
| []string{"an", "error"}, |
| "an error has occurred", |
| 1, |
| fmt.Errorf("exit status 1"), |
| }, |
| { |
| dockerBinary, |
| []string{"an", "exitCode", "127"}, |
| "an error has occurred with exitCode 127", |
| 127, |
| fmt.Errorf("exit status 127"), |
| }, |
| { |
| dockerBinary, |
| []string{"run", "-ti", "ubuntu", "echo", "hello"}, |
| "hello", |
| 0, |
| nil, |
| }, |
| } |
| for _, cmd := range cmds { |
| out, exitCode, error := DockerCmdWithError(cmd.binary, cmd.args...) |
| c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) |
| c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) |
| if cmd.expectedError != nil { |
| c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) |
| 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())) |
| } else { |
| c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) |
| } |
| } |
| } |
| |
| // DockerCmdWithStdoutStderr tests |
| |
| type dockerCmdWithStdoutStderrErrorSuite struct{} |
| |
| func (s *dockerCmdWithStdoutStderrErrorSuite) Test(c *check.C) { |
| // Should fail, the test too |
| DockerCmdWithStdoutStderr(dockerBinary, c, "an", "error") |
| } |
| |
| type dockerCmdWithStdoutStderrSuccessSuite struct{} |
| |
| func (s *dockerCmdWithStdoutStderrSuccessSuite) Test(c *check.C) { |
| stdout, stderr, exitCode := DockerCmdWithStdoutStderr(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello") |
| c.Assert(stdout, check.Equals, "hello") |
| c.Assert(stderr, check.Equals, "") |
| c.Assert(exitCode, check.Equals, 0) |
| |
| } |
| |
| func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrError(c *check.C) { |
| // Run error suite, should fail. |
| output := String{} |
| result := check.Run(&dockerCmdWithStdoutStderrErrorSuite{}, &check.RunConf{Output: &output}) |
| c.Check(result.Succeeded, check.Equals, 0) |
| c.Check(result.Failed, check.Equals, 1) |
| } |
| |
| func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrSuccess(c *check.C) { |
| // Run error suite, should fail. |
| output := String{} |
| result := check.Run(&dockerCmdWithStdoutStderrSuccessSuite{}, &check.RunConf{Output: &output}) |
| c.Check(result.Succeeded, check.Equals, 1) |
| c.Check(result.Failed, check.Equals, 0) |
| } |
| |
| // DockerCmd tests |
| |
| type dockerCmdErrorSuite struct{} |
| |
| func (s *dockerCmdErrorSuite) Test(c *check.C) { |
| // Should fail, the test too |
| DockerCmd(dockerBinary, c, "an", "error") |
| } |
| |
| type dockerCmdSuccessSuite struct{} |
| |
| func (s *dockerCmdSuccessSuite) Test(c *check.C) { |
| stdout, exitCode := DockerCmd(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello") |
| c.Assert(stdout, check.Equals, "hello") |
| c.Assert(exitCode, check.Equals, 0) |
| |
| } |
| |
| func (s *DockerCmdSuite) TestDockerCmdError(c *check.C) { |
| // Run error suite, should fail. |
| output := String{} |
| result := check.Run(&dockerCmdErrorSuite{}, &check.RunConf{Output: &output}) |
| c.Check(result.Succeeded, check.Equals, 0) |
| c.Check(result.Failed, check.Equals, 1) |
| } |
| |
| func (s *DockerCmdSuite) TestDockerCmdSuccess(c *check.C) { |
| // Run error suite, should fail. |
| output := String{} |
| result := check.Run(&dockerCmdSuccessSuite{}, &check.RunConf{Output: &output}) |
| c.Check(result.Succeeded, check.Equals, 1) |
| c.Check(result.Failed, check.Equals, 0) |
| } |
| |
| // DockerCmdWithTimeout tests |
| |
| func (s *DockerCmdSuite) TestDockerCmdWithTimeout(c *check.C) { |
| cmds := []struct { |
| binary string |
| args []string |
| timeout time.Duration |
| expectedOut string |
| expectedExitCode int |
| expectedError error |
| }{ |
| { |
| "doesnotexists", |
| []string{}, |
| 200 * time.Millisecond, |
| `Command doesnotexists not found.`, |
| 1, |
| fmt.Errorf(`"" failed with errors: exit status 1 : "Command doesnotexists not found."`), |
| }, |
| { |
| dockerBinary, |
| []string{"an", "error"}, |
| 200 * time.Millisecond, |
| `an error has occurred`, |
| 1, |
| fmt.Errorf(`"an error" failed with errors: exit status 1 : "an error has occurred"`), |
| }, |
| { |
| dockerBinary, |
| []string{"a", "command", "that", "times", "out"}, |
| 5 * time.Millisecond, |
| "", |
| 0, |
| fmt.Errorf(`"a command that times out" failed with errors: command timed out : ""`), |
| }, |
| { |
| dockerBinary, |
| []string{"run", "-ti", "ubuntu", "echo", "hello"}, |
| 200 * time.Millisecond, |
| "hello", |
| 0, |
| nil, |
| }, |
| } |
| for _, cmd := range cmds { |
| out, exitCode, error := DockerCmdWithTimeout(cmd.binary, cmd.timeout, cmd.args...) |
| c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) |
| c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) |
| if cmd.expectedError != nil { |
| c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) |
| 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())) |
| } else { |
| c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) |
| } |
| } |
| } |
| |
| // DockerCmdInDir tests |
| |
| func (s *DockerCmdSuite) TestDockerCmdInDir(c *check.C) { |
| tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir") |
| c.Assert(err, check.IsNil) |
| |
| cmds := []struct { |
| binary string |
| args []string |
| expectedOut string |
| expectedExitCode int |
| expectedError error |
| }{ |
| { |
| "doesnotexists", |
| []string{}, |
| `Command doesnotexists not found.`, |
| 1, |
| fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder), |
| }, |
| { |
| dockerBinary, |
| []string{"an", "error"}, |
| `an error has occurred`, |
| 1, |
| fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder), |
| }, |
| { |
| dockerBinary, |
| []string{"run", "-ti", "ubuntu", "echo", "hello"}, |
| "hello", |
| 0, |
| nil, |
| }, |
| } |
| for _, cmd := range cmds { |
| // We prepend the arguments with dir:thefolder.. the fake command will check |
| // that the current workdir is the same as the one we are passing. |
| args := append([]string{"dir:" + tempFolder}, cmd.args...) |
| out, exitCode, error := DockerCmdInDir(cmd.binary, tempFolder, args...) |
| c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) |
| c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) |
| if cmd.expectedError != nil { |
| c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) |
| 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())) |
| } else { |
| c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) |
| } |
| } |
| } |
| |
| // DockerCmdInDirWithTimeout tests |
| |
| func (s *DockerCmdSuite) TestDockerCmdInDirWithTimeout(c *check.C) { |
| tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir") |
| c.Assert(err, check.IsNil) |
| |
| cmds := []struct { |
| binary string |
| args []string |
| timeout time.Duration |
| expectedOut string |
| expectedExitCode int |
| expectedError error |
| }{ |
| { |
| "doesnotexists", |
| []string{}, |
| 200 * time.Millisecond, |
| `Command doesnotexists not found.`, |
| 1, |
| fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder), |
| }, |
| { |
| dockerBinary, |
| []string{"an", "error"}, |
| 200 * time.Millisecond, |
| `an error has occurred`, |
| 1, |
| fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder), |
| }, |
| { |
| dockerBinary, |
| []string{"a", "command", "that", "times", "out"}, |
| 5 * time.Millisecond, |
| "", |
| 0, |
| fmt.Errorf(`"dir:%s a command that times out" failed with errors: command timed out : ""`, tempFolder), |
| }, |
| { |
| dockerBinary, |
| []string{"run", "-ti", "ubuntu", "echo", "hello"}, |
| 200 * time.Millisecond, |
| "hello", |
| 0, |
| nil, |
| }, |
| } |
| for _, cmd := range cmds { |
| // We prepend the arguments with dir:thefolder.. the fake command will check |
| // that the current workdir is the same as the one we are passing. |
| args := append([]string{"dir:" + tempFolder}, cmd.args...) |
| out, exitCode, error := DockerCmdInDirWithTimeout(cmd.binary, cmd.timeout, tempFolder, args...) |
| c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) |
| c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) |
| if cmd.expectedError != nil { |
| c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) |
| 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())) |
| } else { |
| c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) |
| } |
| } |
| } |
| |
| // Helpers :) |
| |
| // Type implementing the io.Writer interface for analyzing output. |
| type String struct { |
| value string |
| } |
| |
| // The only function required by the io.Writer interface. Will append |
| // written data to the String.value string. |
| func (s *String) Write(p []byte) (n int, err error) { |
| s.value += string(p) |
| return len(p), nil |
| } |
| |
| // Helper function that mock the exec.Command call (and call the test binary) |
| func fakeExecCommand(command string, args ...string) *exec.Cmd { |
| cs := []string{"-test.run=TestHelperProcess", "--", command} |
| cs = append(cs, args...) |
| cmd := exec.Command(os.Args[0], cs...) |
| cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} |
| return cmd |
| } |
| |
| func TestHelperProcess(t *testing.T) { |
| if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { |
| return |
| } |
| args := os.Args |
| |
| // Previous arguments are tests stuff, that looks like : |
| // /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess -- |
| cmd, args := args[3], args[4:] |
| // Handle the case where args[0] is dir:... |
| if len(args) > 0 && strings.HasPrefix(args[0], "dir:") { |
| expectedCwd := args[0][4:] |
| if len(args) > 1 { |
| args = args[1:] |
| } |
| cwd, err := os.Getwd() |
| if err != nil { |
| fmt.Fprintf(os.Stderr, "Failed to get workingdir: %v", err) |
| os.Exit(1) |
| } |
| // This checks that the given path is the same as the currend working dire |
| if expectedCwd != cwd { |
| fmt.Fprintf(os.Stderr, "Current workdir should be %q, but is %q", expectedCwd, cwd) |
| } |
| } |
| switch cmd { |
| case dockerBinary: |
| argsStr := strings.Join(args, " ") |
| switch argsStr { |
| case "an exitCode 127": |
| fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127") |
| os.Exit(127) |
| case "an error": |
| fmt.Fprintf(os.Stderr, "an error has occurred") |
| os.Exit(1) |
| case "a command that times out": |
| time.Sleep(10 * time.Second) |
| fmt.Fprintf(os.Stdout, "too long, should be killed") |
| // A random exit code (that should never happened in tests) |
| os.Exit(7) |
| case "run -ti ubuntu echo hello": |
| fmt.Fprintf(os.Stdout, "hello") |
| default: |
| fmt.Fprintf(os.Stdout, "no arguments") |
| } |
| default: |
| fmt.Fprintf(os.Stderr, "Command %s not found.", cmd) |
| os.Exit(1) |
| } |
| // some code here to check arguments perhaps? |
| os.Exit(0) |
| } |