1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #16261 from vdemeester/integration-dockercmd

Move dockerCmd to pkg/integration and add tests to it
This commit is contained in:
Brian Goff 2015-09-16 17:40:33 -04:00
commit 677a6eaf8f
3 changed files with 481 additions and 28 deletions

View file

@ -24,6 +24,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/httputils"
"github.com/docker/docker/pkg/integration"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/stringutils"
"github.com/go-check/check"
@ -621,52 +622,30 @@ func pullImageIfNotExist(image string) (err error) {
}
func dockerCmdWithError(args ...string) (string, int, error) {
return runCommandWithOutput(exec.Command(dockerBinary, args...))
return integration.DockerCmdWithError(dockerBinary, args...)
}
func dockerCmdWithStdoutStderr(c *check.C, args ...string) (string, string, int) {
stdout, stderr, status, err := runCommandWithStdoutStderr(exec.Command(dockerBinary, args...))
if c != nil {
c.Assert(err, check.IsNil, check.Commentf("%q failed with errors: %s, %v", strings.Join(args, " "), stderr, err))
}
return stdout, stderr, status
return integration.DockerCmdWithStdoutStderr(dockerBinary, c, args...)
}
func dockerCmd(c *check.C, args ...string) (string, int) {
out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...))
c.Assert(err, check.IsNil, check.Commentf("%q failed with errors: %s, %v", strings.Join(args, " "), out, err))
return out, status
return integration.DockerCmd(dockerBinary, c, args...)
}
// execute a docker command with a timeout
func dockerCmdWithTimeout(timeout time.Duration, args ...string) (string, int, error) {
out, status, err := runCommandWithOutputAndTimeout(exec.Command(dockerBinary, args...), timeout)
if err != nil {
return out, status, fmt.Errorf("%q failed with errors: %v : %q)", strings.Join(args, " "), err, out)
}
return out, status, err
return integration.DockerCmdWithTimeout(dockerBinary, timeout, args...)
}
// execute a docker command in a directory
func dockerCmdInDir(c *check.C, path string, args ...string) (string, int, error) {
dockerCommand := exec.Command(dockerBinary, args...)
dockerCommand.Dir = path
out, status, err := runCommandWithOutput(dockerCommand)
if err != nil {
return out, status, fmt.Errorf("%q failed with errors: %v : %q)", strings.Join(args, " "), err, out)
}
return out, status, err
return integration.DockerCmdInDir(dockerBinary, path, args...)
}
// execute a docker command in a directory with a timeout
func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...string) (string, int, error) {
dockerCommand := exec.Command(dockerBinary, args...)
dockerCommand.Dir = path
out, status, err := runCommandWithOutputAndTimeout(dockerCommand, timeout)
if err != nil {
return out, status, fmt.Errorf("%q failed with errors: %v : %q)", strings.Join(args, " "), err, out)
}
return out, status, err
return integration.DockerCmdInDirWithTimeout(dockerBinary, timeout, path, args...)
}
func findContainerIP(c *check.C, id string, vargs ...string) string {

View file

@ -0,0 +1,71 @@
package integration
import (
"fmt"
"os/exec"
"strings"
"time"
"github.com/go-check/check"
)
var execCommand = exec.Command
// DockerCmdWithError executes a docker command that is supposed to fail and returns
// the output, the exit code and the error.
func DockerCmdWithError(dockerBinary string, args ...string) (string, int, error) {
return RunCommandWithOutput(execCommand(dockerBinary, args...))
}
// DockerCmdWithStdoutStderr executes a docker command and returns the content of the
// stdout, stderr and the exit code. If a check.C is passed, it will fail and stop tests
// if the error is not nil.
func DockerCmdWithStdoutStderr(dockerBinary string, c *check.C, args ...string) (string, string, int) {
stdout, stderr, status, err := RunCommandWithStdoutStderr(execCommand(dockerBinary, args...))
if c != nil {
c.Assert(err, check.IsNil, check.Commentf("%q failed with errors: %s, %v", strings.Join(args, " "), stderr, err))
}
return stdout, stderr, status
}
// DockerCmd executes a docker command and returns the output and the exit code. If the
// command returns an error, it will fail and stop the tests.
func DockerCmd(dockerBinary string, c *check.C, args ...string) (string, int) {
out, status, err := RunCommandWithOutput(execCommand(dockerBinary, args...))
c.Assert(err, check.IsNil, check.Commentf("%q failed with errors: %s, %v", strings.Join(args, " "), out, err))
return out, status
}
// DockerCmdWithTimeout executes a docker command with a timeout, and returns the output,
// the exit code and the error (if any).
func DockerCmdWithTimeout(dockerBinary string, timeout time.Duration, args ...string) (string, int, error) {
out, status, err := RunCommandWithOutputAndTimeout(execCommand(dockerBinary, args...), timeout)
if err != nil {
return out, status, fmt.Errorf("%q failed with errors: %v : %q", strings.Join(args, " "), err, out)
}
return out, status, err
}
// DockerCmdInDir executes a docker command in a directory and returns the output, the
// exit code and the error (if any).
func DockerCmdInDir(dockerBinary string, path string, args ...string) (string, int, error) {
dockerCommand := execCommand(dockerBinary, args...)
dockerCommand.Dir = path
out, status, err := RunCommandWithOutput(dockerCommand)
if err != nil {
return out, status, fmt.Errorf("%q failed with errors: %v : %q", strings.Join(args, " "), err, out)
}
return out, status, err
}
// DockerCmdInDirWithTimeout executes a docker command in a directory with a timeout and
// returns the output, the exit code and the error (if any).
func DockerCmdInDirWithTimeout(dockerBinary string, timeout time.Duration, path string, args ...string) (string, int, error) {
dockerCommand := execCommand(dockerBinary, args...)
dockerCommand.Dir = path
out, status, err := RunCommandWithOutputAndTimeout(dockerCommand, timeout)
if err != nil {
return out, status, fmt.Errorf("%q failed with errors: %v : %q", strings.Join(args, " "), err, out)
}
return out, status, err
}

View file

@ -0,0 +1,403 @@
package integration
import (
"fmt"
"os"
"os/exec"
"testing"
"github.com/go-check/check"
"io/ioutil"
"strings"
"time"
)
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{},
5 * time.Millisecond,
`Command doesnotexists not found.`,
1,
fmt.Errorf(`"" failed with errors: exit status 1 : "Command doesnotexists not found."`),
},
{
dockerBinary,
[]string{"an", "error"},
5 * 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"},
5 * 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{},
5 * 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"},
5 * 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"},
5 * 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.Millisecond)
fmt.Fprintf(os.Stdout, "too long, should be killed")
os.Exit(0)
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)
}